Browse code
Trim trailing whitespaces in smtp.lisp
Orivej Desh authored on 10/02/2012 11:07:26
Showing 1 changed files
Showing 1 changed files
... | ... |
@@ -32,7 +32,7 @@ v5: rm stray force-output of t; send-smtp-1: New external-format keyword arg." |
32 | 32 |
;; |
33 | 33 |
;; This code is free software; you can redistribute it and/or |
34 | 34 |
;; modify it under the terms of the version 2.1 of |
35 |
-;; the GNU Lesser General Public License as published by |
|
35 |
+;; the GNU Lesser General Public License as published by |
|
36 | 36 |
;; the Free Software Foundation, as clarified by the AllegroServe |
37 | 37 |
;; prequel found in license-allegroserve.txt. |
38 | 38 |
;; |
... | ... |
@@ -41,11 +41,11 @@ v5: rm stray force-output of t; send-smtp-1: New external-format keyword arg." |
41 | 41 |
;; merchantability or fitness for a particular purpose. See the GNU |
42 | 42 |
;; Lesser General Public License for more details. |
43 | 43 |
;; |
44 |
-;; Version 2.1 of the GNU Lesser General Public License is in the file |
|
44 |
+;; Version 2.1 of the GNU Lesser General Public License is in the file |
|
45 | 45 |
;; license-lgpl.txt that was distributed with this file. |
46 | 46 |
;; If it is not present, you can access it from |
47 | 47 |
;; http://www.gnu.org/copyleft/lesser.txt (until superseded by a newer |
48 |
-;; version) or write to the Free Software Foundation, Inc., 59 Temple Place, |
|
48 |
+;; version) or write to the Free Software Foundation, Inc., 59 Temple Place, |
|
49 | 49 |
;; Suite 330, Boston, MA 02111-1307 USA |
50 | 50 |
;; |
51 | 51 |
;; |
... | ... |
@@ -61,7 +61,7 @@ v5: rm stray force-output of t; send-smtp-1: New external-format keyword arg." |
61 | 61 |
|
62 | 62 |
(defpackage :net.post-office |
63 | 63 |
(:use #:lisp #:excl) |
64 |
- (:export |
|
64 |
+ (:export |
|
65 | 65 |
#:send-letter |
66 | 66 |
#:send-smtp |
67 | 67 |
#:send-smtp-auth |
... | ... |
@@ -76,14 +76,14 @@ v5: rm stray force-output of t; send-smtp-1: New external-format keyword arg." |
76 | 76 |
|
77 | 77 |
;; the exported functions: |
78 | 78 |
|
79 |
-;; (send-letter "mail-server" "from" "to" "message" |
|
79 |
+;; (send-letter "mail-server" "from" "to" "message" |
|
80 | 80 |
;; &key cc bcc subject reply-to headers) |
81 |
-;; |
|
82 |
-;; |
|
81 |
+;; |
|
82 |
+;; |
|
83 | 83 |
;; sends a message to the mail server (which may be a relay server |
84 | 84 |
;; or the final destination). "from" is the address to be given |
85 | 85 |
;; as the sender. "to" can be a string or a list of strings naming |
86 |
-;; recipients. |
|
86 |
+;; recipients. |
|
87 | 87 |
;; "message" is the message to be sent. It can be a string or a stream. |
88 | 88 |
;; cc and bcc can be either be a string or a list of strings |
89 | 89 |
;; naming recipients. All cc's and bcc's are sent the message |
... | ... |
@@ -93,7 +93,7 @@ v5: rm stray force-output of t; send-smtp-1: New external-format keyword arg." |
93 | 93 |
;; headers is a string or list of stings. These are raw header lines |
94 | 94 |
;; added to the header build to send out. |
95 | 95 |
;; |
96 |
-;; This builds a header and inserts the optional cc, bcc, |
|
96 |
+;; This builds a header and inserts the optional cc, bcc, |
|
97 | 97 |
;; subject and reply-to lines. |
98 | 98 |
;; |
99 | 99 |
;; (send-smtp "mail-server" "from" "to" &rest messages) |
... | ... |
@@ -123,9 +123,9 @@ v5: rm stray force-output of t; send-smtp-1: New external-format keyword arg." |
123 | 123 |
;; code of the response. |
124 | 124 |
;; smtp-response, if given, will be bound to string that is |
125 | 125 |
;; the actual response |
126 |
- ;; |
|
126 |
+ ;; |
|
127 | 127 |
(let ((response-class (gensym))) |
128 |
- `(multiple-value-bind (,response-class |
|
128 |
+ `(multiple-value-bind (,response-class |
|
129 | 129 |
,@(if* smtp-response then (list smtp-response)) |
130 | 130 |
,@(if* response-code then (list response-code))) |
131 | 131 |
(progn (force-output ,smtp-stream) |
... | ... |
@@ -152,7 +152,7 @@ v5: rm stray force-output of t; send-smtp-1: New external-format keyword arg." |
152 | 152 |
"SMTP transaction failed. We said: ~s, and the server replied: ~s" |
153 | 153 |
(quote ,sent) |
154 | 154 |
(quote ,smtp-response)))) |
155 |
- |
|
155 |
+ |
|
156 | 156 |
(response-case (,stream ,smtp-response ,response-code) |
157 | 157 |
,@case-clauses))))) |
158 | 158 |
|
... | ... |
@@ -166,69 +166,69 @@ v5: rm stray force-output of t; send-smtp-1: New external-format keyword arg." |
166 | 166 |
;; |
167 | 167 |
;; see documentation at the head of this file |
168 | 168 |
;; |
169 |
- |
|
169 |
+ |
|
170 | 170 |
(if* (mime-part-constructed-p message) |
171 | 171 |
then (if* (and (not (multipart-mixed-p message)) attachments) |
172 | 172 |
then (error "~ |
173 | 173 |
attachments are not allowed for non-multipart/mixed messages.")) |
174 | 174 |
else (let ((part |
175 | 175 |
(if* (streamp message) |
176 |
- then |
|
176 |
+ then |
|
177 | 177 |
(make-mime-part :file message) |
178 | 178 |
elseif (stringp message) |
179 | 179 |
then (make-mime-part :text message) |
180 | 180 |
else (error "~ |
181 | 181 |
message must be a string, stream, or mime-part-constructed, not ~s" message)))) |
182 |
- |
|
182 |
+ |
|
183 | 183 |
(setf message |
184 | 184 |
(if* attachments |
185 | 185 |
then (make-mime-part :subparts (list part)) |
186 | 186 |
else part)))) |
187 |
- |
|
187 |
+ |
|
188 | 188 |
(let ((hdrs nil) |
189 | 189 |
(user-headers "") |
190 |
- (tos (if* (stringp to) |
|
191 |
- then (list to) |
|
190 |
+ (tos (if* (stringp to) |
|
191 |
+ then (list to) |
|
192 | 192 |
elseif (consp to) |
193 | 193 |
then to |
194 | 194 |
else (error "to should be a string or list, not ~s" to))) |
195 | 195 |
(ccs |
196 | 196 |
(if* (null cc) |
197 | 197 |
then nil |
198 |
- elseif (stringp cc) |
|
199 |
- then (list cc) |
|
198 |
+ elseif (stringp cc) |
|
199 |
+ then (list cc) |
|
200 | 200 |
elseif (consp cc) |
201 | 201 |
then cc |
202 | 202 |
else (error "cc should be a string or list, not ~s" cc))) |
203 | 203 |
(bccs (if* (null bcc) |
204 | 204 |
then nil |
205 |
- elseif (stringp bcc) |
|
206 |
- then (list bcc) |
|
205 |
+ elseif (stringp bcc) |
|
206 |
+ then (list bcc) |
|
207 | 207 |
elseif (consp bcc) |
208 | 208 |
then bcc |
209 | 209 |
else (error "bcc should be a string or list, not ~s" bcc)))) |
210 |
- |
|
210 |
+ |
|
211 | 211 |
(setf hdrs |
212 | 212 |
(with-output-to-string (hdrs) |
213 |
- (macrolet ((already-have (name) |
|
213 |
+ (macrolet ((already-have (name) |
|
214 | 214 |
`(mime-get-header ,name message))) |
215 |
- |
|
215 |
+ |
|
216 | 216 |
;; Give priority to headers already provided in a mime-part. |
217 | 217 |
(if* (not (already-have "From")) |
218 | 218 |
then (format hdrs "From: ~a~%" from)) |
219 |
- |
|
219 |
+ |
|
220 | 220 |
(if* (not (already-have "To")) |
221 | 221 |
then (format hdrs "To: ~a~%" (list-to-delimited-string tos ", "))) |
222 |
- |
|
222 |
+ |
|
223 | 223 |
(if* (and ccs (not (already-have "Cc"))) |
224 | 224 |
then (format hdrs "Cc: ~a~%" (list-to-delimited-string ccs ", "))) |
225 |
- |
|
225 |
+ |
|
226 | 226 |
(if* (and subject (not (already-have "Subject"))) |
227 | 227 |
then (format hdrs "Subject: ~a~%" subject)) |
228 |
- |
|
228 |
+ |
|
229 | 229 |
(if* (and reply-to (not (already-have "Reply-To"))) |
230 | 230 |
then (format hdrs "Reply-To: ~a~%" reply-to))))) |
231 |
- |
|
231 |
+ |
|
232 | 232 |
(if* headers |
233 | 233 |
then (if* (stringp headers) |
234 | 234 |
then (setq headers (list headers)) |
... | ... |
@@ -237,7 +237,7 @@ message must be a string, stream, or mime-part-constructed, not ~s" message)))) |
237 | 237 |
else (error "Unknown headers format: ~s." headers)) |
238 | 238 |
(setf user-headers |
239 | 239 |
(with-output-to-string (header) |
240 |
- (dolist (h headers) |
|
240 |
+ (dolist (h headers) |
|
241 | 241 |
(format header "~a~%" h))))) |
242 | 242 |
|
243 | 243 |
;; Temporarily modifies 'message', which may be user-provided. |
... | ... |
@@ -245,7 +245,7 @@ message must be a string, stream, or mime-part-constructed, not ~s" message)))) |
245 | 245 |
(if* attachments |
246 | 246 |
then (if (not (consp attachments)) |
247 | 247 |
(setf attachments (list attachments))) |
248 |
- |
|
248 |
+ |
|
249 | 249 |
(let (res) |
250 | 250 |
(dolist (attachment attachments) |
251 | 251 |
(if* (mime-part-constructed-p attachment) |
... | ... |
@@ -257,23 +257,23 @@ message must be a string, stream, or mime-part-constructed, not ~s" message)))) |
257 | 257 |
Attachments must be filenames, streams, or mime-part-constructed, not ~s" |
258 | 258 |
attachment)) |
259 | 259 |
(push attachment res)) |
260 |
- |
|
260 |
+ |
|
261 | 261 |
(setf (mime-part-parts message) (append parts-save res)))) |
262 |
- |
|
262 |
+ |
|
263 | 263 |
(with-mime-part-constructed-stream (s message) |
264 | 264 |
(send-smtp-auth server from (append tos ccs bccs) |
265 | 265 |
login password |
266 | 266 |
hdrs |
267 | 267 |
user-headers |
268 | 268 |
s)) |
269 |
- |
|
269 |
+ |
|
270 | 270 |
(setf (mime-part-parts message) parts-save) |
271 | 271 |
t))) |
272 |
- |
|
273 |
- |
|
272 |
+ |
|
273 |
+ |
|
274 | 274 |
(defun send-smtp (server from to &rest messages) |
275 | 275 |
(send-smtp-1 server from to nil nil messages)) |
276 |
- |
|
276 |
+ |
|
277 | 277 |
(defun send-smtp-auth (server from to login password &rest messages) |
278 | 278 |
(send-smtp-1 server from to login password messages)) |
279 | 279 |
|
... | ... |
@@ -291,15 +291,15 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s" |
291 | 291 |
|
292 | 292 |
(unwind-protect |
293 | 293 |
(progn |
294 |
- |
|
294 |
+ |
|
295 | 295 |
(smtp-send-recv (sock (format nil "MAIL from:<~a>" from) msg) |
296 | 296 |
(2 ;; cool |
297 | 297 |
nil |
298 | 298 |
) |
299 | 299 |
(t (smtp-transaction-error))) |
300 |
- |
|
301 |
- (let ((tos (if* (stringp to) |
|
302 |
- then (list to) |
|
300 |
+ |
|
301 |
+ (let ((tos (if* (stringp to) |
|
302 |
+ then (list to) |
|
303 | 303 |
elseif (consp to) |
304 | 304 |
then to |
305 | 305 |
else (error "to should be a string or list, not ~s" |
... | ... |
@@ -310,24 +310,24 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s" |
310 | 310 |
nil |
311 | 311 |
) |
312 | 312 |
(t (smtp-transaction-error))))) |
313 |
- |
|
313 |
+ |
|
314 | 314 |
(smtp-send-recv (sock "DATA" msg) |
315 | 315 |
(3 ;; cool |
316 | 316 |
nil) |
317 | 317 |
(t (smtp-transaction-error))) |
318 |
- |
|
319 |
- |
|
320 |
- |
|
321 |
- (let ((at-bol t) |
|
318 |
+ |
|
319 |
+ |
|
320 |
+ |
|
321 |
+ (let ((at-bol t) |
|
322 | 322 |
(prev-ch nil) |
323 | 323 |
ch stream) |
324 | 324 |
(dolist (message messages) |
325 | 325 |
(when message |
326 | 326 |
(setf stream (if* (streamp message) |
327 |
- then message |
|
327 |
+ then message |
|
328 | 328 |
else (make-buffer-input-stream |
329 |
- (string-to-octets |
|
330 |
- message |
|
329 |
+ (string-to-octets |
|
330 |
+ message |
|
331 | 331 |
:null-terminate nil |
332 | 332 |
:external-format external-format)))) |
333 | 333 |
|
... | ... |
@@ -346,11 +346,11 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s" |
346 | 346 |
(write-char #\return sock) (write-char #\linefeed sock) |
347 | 347 |
(write-char #\. sock) |
348 | 348 |
(write-char #\return sock) (write-char #\linefeed sock) |
349 |
- |
|
349 |
+ |
|
350 | 350 |
(response-case (sock msg) |
351 | 351 |
(2 nil ; (format t "Message sent to ~a~%" to) |
352 | 352 |
) |
353 |
- |
|
353 |
+ |
|
354 | 354 |
(t (error "message not sent: ~s" msg))) |
355 | 355 |
|
356 | 356 |
(smtp-send-recv (sock "QUIT" msg) |
... | ... |
@@ -362,9 +362,9 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s" |
362 | 362 |
|
363 | 363 |
(defun connect-to-mail-server (server login password) |
364 | 364 |
;; make that initial connection to the mail server |
365 |
- ;; returning a socket connected to it and |
|
365 |
+ ;; returning a socket connected to it and |
|
366 | 366 |
;; signaling an error if it can't be made. |
367 |
- |
|
367 |
+ |
|
368 | 368 |
(let ((use-port 25) ;; standard SMTP port |
369 | 369 |
ssl-args |
370 | 370 |
ssl |
... | ... |
@@ -391,20 +391,20 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s" |
391 | 391 |
(if* match |
392 | 392 |
then (setf server m1) |
393 | 393 |
(setf use-port (parse-integer m2))))) |
394 |
- |
|
394 |
+ |
|
395 | 395 |
(let ((ipaddr (determine-mail-server server)) |
396 | 396 |
(sock) |
397 | 397 |
(ok)) |
398 |
- |
|
398 |
+ |
|
399 | 399 |
(if* (null ipaddr) |
400 | 400 |
then (error "Can't determine ip address for mail server ~s" server)) |
401 |
- |
|
401 |
+ |
|
402 | 402 |
(setq sock (socket:make-socket :remote-host ipaddr |
403 | 403 |
:remote-port use-port |
404 | 404 |
)) |
405 | 405 |
(when ssl |
406 | 406 |
(setq sock (apply #'acl-socket:make-ssl-client-stream sock ssl-args))) |
407 |
- |
|
407 |
+ |
|
408 | 408 |
(unwind-protect |
409 | 409 |
(tagbody |
410 | 410 |
(response-case (sock msg) |
... | ... |
@@ -430,21 +430,21 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s" |
430 | 430 |
elseif (and mechs login password |
431 | 431 |
(setq auth-mechs (car (member "LOGIN" mechs |
432 | 432 |
:test #'(lambda (x y) (search x y)))))) |
433 |
- then (setf sock |
|
433 |
+ then (setf sock |
|
434 | 434 |
(smtp-authenticate sock server auth-mechs login password))))) |
435 |
- |
|
435 |
+ |
|
436 | 436 |
;; all is good |
437 | 437 |
(setq ok t)) |
438 |
- |
|
438 |
+ |
|
439 | 439 |
;; cleanup: |
440 |
- (if* (null ok) |
|
440 |
+ (if* (null ok) |
|
441 | 441 |
then (close sock :abort t) |
442 | 442 |
(setq sock nil))) |
443 |
- |
|
443 |
+ |
|
444 | 444 |
;; return: |
445 | 445 |
sock |
446 | 446 |
))) |
447 |
- |
|
447 |
+ |
|
448 | 448 |
|
449 | 449 |
;; Returns string with mechanisms, or nil if none. |
450 | 450 |
;; This may need to be expanded in the future as we support |
... | ... |
@@ -482,29 +482,29 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s" |
482 | 482 |
(response-case (sock msg) |
483 | 483 |
(3 ;; need more interaction |
484 | 484 |
(multiple-value-setq (res response) |
485 |
- (net.sasl:sasl-step |
|
486 |
- ctx |
|
485 |
+ (net.sasl:sasl-step |
|
486 |
+ ctx |
|
487 | 487 |
(base64-string-to-usb8-array (subseq msg 4)))) |
488 |
- (smtp-command sock "~a" |
|
488 |
+ (smtp-command sock "~a" |
|
489 | 489 |
(usb8-array-to-base64-string response nil))) |
490 | 490 |
(2 ;; server is satisfied. |
491 | 491 |
;; Make sure the auth process really completed |
492 | 492 |
(if (not (net.sasl:sasl-conn-auth-complete-p ctx)) |
493 | 493 |
(error "SMTP server indicated authentication complete before mechanisms was satisfied")) |
494 |
- ;; It's all good. |
|
494 |
+ ;; It's all good. |
|
495 | 495 |
(return)) ;; break from loop |
496 | 496 |
(t |
497 | 497 |
(error "SMTP authentication failed: ~a" msg))))) |
498 |
- |
|
498 |
+ |
|
499 | 499 |
;; Reach here if authentication completed. |
500 | 500 |
;; If a security layer was negotiated, return an encapsulated sock, |
501 | 501 |
;; otherwise just return the original sock. |
502 | 502 |
(if (net.sasl:sasl-conn-security-layer-p ctx) |
503 | 503 |
(net.sasl:sasl-make-stream ctx sock :close-base t) |
504 | 504 |
sock))) |
505 |
- |
|
506 | 505 |
|
507 |
- |
|
506 |
+ |
|
507 |
+ |
|
508 | 508 |
(defun test-email-address (address) |
509 | 509 |
;; test to see if we can determine if the address is valid |
510 | 510 |
;; return nil if the address is bogus |
... | ... |
@@ -512,7 +512,7 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s" |
512 | 512 |
(if* (or (not (stringp address)) |
513 | 513 |
(zerop (length address))) |
514 | 514 |
then (error "mail address should be a non-empty string: ~s" address)) |
515 |
- |
|
515 |
+ |
|
516 | 516 |
; split on the @ sign |
517 | 517 |
(let (name hostname) |
518 | 518 |
(let ((pos (position #\@ address))) |
... | ... |
@@ -525,10 +525,10 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s" |
525 | 525 |
(return-from test-email-address nil) |
526 | 526 |
else (setq name (subseq address 0 pos) |
527 | 527 |
hostname (subseq address (1+ pos))))) |
528 |
- |
|
528 |
+ |
|
529 | 529 |
(let ((sock (ignore-errors (connect-to-mail-server hostname nil nil)))) |
530 | 530 |
(if* (null sock) then (return-from test-email-address nil)) |
531 |
- |
|
531 |
+ |
|
532 | 532 |
(unwind-protect |
533 | 533 |
(progn |
534 | 534 |
(smtp-send-recv (sock (format nil "VRFY ~a" name) msg code) |
... | ... |
@@ -549,21 +549,21 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s" |
549 | 549 |
else t)) |
550 | 550 |
(t t))) |
551 | 551 |
(close sock :abort t))))) |
552 |
- |
|
553 |
- |
|
554 |
- |
|
555 |
- |
|
556 |
- |
|
557 |
- |
|
558 |
- |
|
559 |
- |
|
560 | 552 |
|
561 | 553 |
|
562 | 554 |
|
563 | 555 |
|
564 | 556 |
|
565 |
- |
|
566 |
- |
|
557 |
+ |
|
558 |
+ |
|
559 |
+ |
|
560 |
+ |
|
561 |
+ |
|
562 |
+ |
|
563 |
+ |
|
564 |
+ |
|
565 |
+ |
|
566 |
+ |
|
567 | 567 |
(defun wait-for-response (stream) |
568 | 568 |
;; read the response of the smtp server. |
569 | 569 |
;; collect it all in a string. |
... | ... |
@@ -676,13 +676,13 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s" |
676 | 676 |
) |
677 | 677 |
|
678 | 678 |
(defun determine-mail-server (name) |
679 |
- ;; return the ipaddress to be used to connect to the |
|
679 |
+ ;; return the ipaddress to be used to connect to the |
|
680 | 680 |
;; the mail server. |
681 | 681 |
;; name is any method for naming a machine: |
682 | 682 |
;; ip address (binary) |
683 | 683 |
;; string with dotted ip address |
684 | 684 |
;; string naming a domain |
685 |
- ;; we can only do the mx lookup for the third case, the rest |
|
685 |
+ ;; we can only do the mx lookup for the third case, the rest |
|
686 | 686 |
;; we just return the ipaddress for what we were given |
687 | 687 |
;; |
688 | 688 |
(let (ipaddr) |
... | ... |
@@ -700,16 +700,16 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s" |
700 | 700 |
else (dolist (suffix socket::*domain-search-list* |
701 | 701 |
(socket:dns-lookup-hostname name)) |
702 | 702 |
(declare (special socket:*domain-search-list*)) |
703 |
- (let ((name |
|
703 |
+ (let ((name |
|
704 | 704 |
(concatenate 'string name "." suffix))) |
705 | 705 |
(setq res (socket:dns-query name :type :mx)) |
706 | 706 |
(if* (and res (cadr res)) |
707 | 707 |
then (return (cadr res))))))) |
708 |
- |
|
709 |
- |
|
708 |
+ |
|
709 |
+ |
|
710 | 710 |
else ; just do a hostname lookup |
711 | 711 |
(ignore-errors (socket:lookup-hostname name)))))) |
712 |
- |
|
713 |
- |
|
714 |
- |
|
712 |
+ |
|
713 |
+ |
|
714 |
+ |
|
715 | 715 |
(provide :smtp) |