git.fiddlerwoaroof.com
Browse code

Untabify smtp.lisp

Orivej Desh authored on 10/02/2012 19:09:02
Showing 1 changed files
... ...
@@ -52,7 +52,7 @@
52 52
 ;; the exported functions:
53 53
 
54 54
 ;; (send-letter "mail-server" "from" "to" "message"
55
-;;		&key cc bcc subject reply-to headers)
55
+;;              &key cc bcc subject reply-to headers)
56 56
 ;;
57 57
 ;;
58 58
 ;;    sends a message to the mail server (which may be a relay server
... ...
@@ -61,12 +61,12 @@
61 61
 ;;    recipients.
62 62
 ;;    "message" is the message to be sent.  It can be a string or a stream.
63 63
 ;;    cc and bcc can be either be a string or a  list of strings
64
-;;	naming recipients.  All cc's and bcc's are sent the message
65
-;;	but the bcc's aren't included in the header created.
64
+;;      naming recipients.  All cc's and bcc's are sent the message
65
+;;      but the bcc's aren't included in the header created.
66 66
 ;;    reply-to's value is a string and in cases a Reply-To header
67
-;;	 to be created.
67
+;;       to be created.
68 68
 ;;    headers is a string or list of stings. These are raw header lines
69
-;;	added to the header build to send out.
69
+;;      added to the header build to send out.
70 70
 ;;
71 71
 ;;    This builds a header and inserts the optional cc, bcc,
72 72
 ;;    subject and reply-to  lines.
... ...
@@ -101,146 +101,146 @@
101 101
   ;;
102 102
   (let ((response-class (gensym)))
103 103
     `(multiple-value-bind (,response-class
104
-			   ,@(if* smtp-response then (list smtp-response))
105
-			   ,@(if* response-code then (list response-code)))
106
-	 (progn (force-output ,smtp-stream)
107
-		(wait-for-response ,smtp-stream))
104
+                           ,@(if* smtp-response then (list smtp-response))
105
+                           ,@(if* response-code then (list response-code)))
106
+         (progn (force-output ,smtp-stream)
107
+                (wait-for-response ,smtp-stream))
108 108
        ;;(declare (ignorable smtp-response))
109 109
        (case ,response-class
110
-	 ,@case-clauses))))
110
+         ,@case-clauses))))
111 111
 
112 112
 (defmacro smtp-send-recv ((smtp-stream cmd smtp-response &optional response-code) &rest case-clauses)
113 113
   (let ((stream (gensym))
114
-	(sent (gensym)))
114
+        (sent (gensym)))
115 115
     `(let ((,stream ,smtp-stream)
116
-	   (,sent ,cmd))
116
+           (,sent ,cmd))
117 117
        (if* *smtp-debug*
118
-	  then (format *smtp-debug* "to smtp command: ~s~%" ,sent)
119
-	       (force-output *smtp-debug*))
118
+          then (format *smtp-debug* "to smtp command: ~s~%" ,sent)
119
+               (force-output *smtp-debug*))
120 120
        (write-string ,sent ,stream)
121 121
        (write-char #\return ,stream)
122 122
        (write-char #\newline ,stream)
123 123
        (force-output ,stream)
124 124
        (macrolet ((smtp-transaction-error ()
125
-		    (list
126
-		     'error
127
-		     "SMTP transaction failed.  We said: ~s, and the server replied: ~s"
128
-		     (quote ,sent)
129
-		     (quote ,smtp-response))))
125
+                    (list
126
+                     'error
127
+                     "SMTP transaction failed.  We said: ~s, and the server replied: ~s"
128
+                     (quote ,sent)
129
+                     (quote ,smtp-response))))
130 130
 
131
-	 (response-case (,stream ,smtp-response ,response-code)
132
-	   ,@case-clauses)))))
131
+         (response-case (,stream ,smtp-response ,response-code)
132
+           ,@case-clauses)))))
133 133
 
134 134
 (defvar *smtp-debug* nil)
135 135
 
136 136
 
137 137
 
138 138
 (defun send-letter (server from to message
139
-		    &key cc bcc subject reply-to headers
140
-			 login password attachments)
139
+                    &key cc bcc subject reply-to headers
140
+                         login password attachments)
141 141
   ;;
142 142
   ;; see documentation at the head of this file
143 143
   ;;
144 144
 
145 145
   (if* (mime-part-constructed-p message)
146 146
      then (if* (and (not (multipart-mixed-p message)) attachments)
147
-	     then (error "~
147
+             then (error "~
148 148
 attachments are not allowed for non-multipart/mixed messages."))
149 149
      else (let ((part
150
-		 (if* (streamp message)
151
-		    then
152
-			 (make-mime-part :file message)
153
-		  elseif (stringp message)
154
-		    then (make-mime-part :text message)
155
-		    else (error "~
150
+                 (if* (streamp message)
151
+                    then
152
+                         (make-mime-part :file message)
153
+                  elseif (stringp message)
154
+                    then (make-mime-part :text message)
155
+                    else (error "~
156 156
 message must be a string, stream, or mime-part-constructed, not ~s" message))))
157 157
 
158
-	    (setf message
159
-	      (if* attachments
160
-		 then (make-mime-part :subparts (list part))
161
-		 else part))))
158
+            (setf message
159
+              (if* attachments
160
+                 then (make-mime-part :subparts (list part))
161
+                 else part))))
162 162
 
163 163
   (let ((hdrs nil)
164
-	(user-headers "")
165
-	(tos (if* (stringp to)
166
-		then (list to)
167
-	      elseif (consp to)
168
-		then to
169
-		else (error "to should be a string or list, not ~s" to)))
170
-	(ccs
171
-	 (if* (null cc)
172
-	    then nil
173
-	  elseif (stringp cc)
174
-	    then (list cc)
175
-	  elseif (consp cc)
176
-	    then cc
177
-	    else (error "cc should be a string or list, not ~s" cc)))
178
-	(bccs (if* (null bcc)
179
-		 then nil
180
-	       elseif (stringp bcc)
181
-		 then (list bcc)
182
-	       elseif (consp bcc)
183
-		 then bcc
184
-		 else (error "bcc should be a string or list, not ~s" bcc))))
164
+        (user-headers "")
165
+        (tos (if* (stringp to)
166
+                then (list to)
167
+              elseif (consp to)
168
+                then to
169
+                else (error "to should be a string or list, not ~s" to)))
170
+        (ccs
171
+         (if* (null cc)
172
+            then nil
173
+          elseif (stringp cc)
174
+            then (list cc)
175
+          elseif (consp cc)
176
+            then cc
177
+            else (error "cc should be a string or list, not ~s" cc)))
178
+        (bccs (if* (null bcc)
179
+                 then nil
180
+               elseif (stringp bcc)
181
+                 then (list bcc)
182
+               elseif (consp bcc)
183
+                 then bcc
184
+                 else (error "bcc should be a string or list, not ~s" bcc))))
185 185
 
186 186
     (setf hdrs
187 187
       (with-output-to-string (hdrs)
188
-	(macrolet ((already-have (name)
189
-		     `(mime-get-header ,name message)))
188
+        (macrolet ((already-have (name)
189
+                     `(mime-get-header ,name message)))
190 190
 
191
-	  ;; Give priority to headers already provided in a mime-part.
192
-	  (if* (not (already-have "From"))
193
-	     then (format hdrs "From: ~a~%" from))
191
+          ;; Give priority to headers already provided in a mime-part.
192
+          (if* (not (already-have "From"))
193
+             then (format hdrs "From: ~a~%" from))
194 194
 
195
-	  (if* (not (already-have "To"))
196
-	     then (format hdrs "To: ~a~%" (list-to-delimited-string tos ", ")))
195
+          (if* (not (already-have "To"))
196
+             then (format hdrs "To: ~a~%" (list-to-delimited-string tos ", ")))
197 197
 
198
-	  (if* (and ccs (not (already-have "Cc")))
199
-	     then (format hdrs "Cc: ~a~%" (list-to-delimited-string ccs ", ")))
198
+          (if* (and ccs (not (already-have "Cc")))
199
+             then (format hdrs "Cc: ~a~%" (list-to-delimited-string ccs ", ")))
200 200
 
201
-	  (if* (and subject (not (already-have "Subject")))
202
-	     then (format hdrs "Subject: ~a~%" subject))
201
+          (if* (and subject (not (already-have "Subject")))
202
+             then (format hdrs "Subject: ~a~%" subject))
203 203
 
204
-	  (if* (and reply-to (not (already-have "Reply-To")))
205
-	     then (format hdrs "Reply-To: ~a~%" reply-to)))))
204
+          (if* (and reply-to (not (already-have "Reply-To")))
205
+             then (format hdrs "Reply-To: ~a~%" reply-to)))))
206 206
 
207 207
     (if* headers
208 208
        then (if* (stringp headers)
209
-	       then (setq headers (list headers))
210
-	     elseif (consp headers)
211
-	       thenret
212
-	       else (error "Unknown headers format: ~s." headers))
213
-	    (setf user-headers
214
-	      (with-output-to-string (header)
215
-		(dolist (h headers)
216
-		  (format header "~a~%" h)))))
209
+               then (setq headers (list headers))
210
+             elseif (consp headers)
211
+               thenret
212
+               else (error "Unknown headers format: ~s." headers))
213
+            (setf user-headers
214
+              (with-output-to-string (header)
215
+                (dolist (h headers)
216
+                  (format header "~a~%" h)))))
217 217
 
218 218
     ;; Temporarily modifies 'message', which may be user-provided.
219 219
     (let ((parts-save (mime-part-parts message)))
220 220
       (if* attachments
221
-	 then (if (not (consp attachments))
222
-		  (setf attachments (list attachments)))
223
-
224
-	      (let (res)
225
-		(dolist (attachment attachments)
226
-		  (if* (mime-part-constructed-p attachment)
227
-		     thenret
228
-		   elseif (or (streamp attachment) (stringp attachment)
229
-			      (pathnamep attachment))
230
-		     then (setf attachment (make-mime-part :file attachment))
231
-		     else (error "~
221
+         then (if (not (consp attachments))
222
+                  (setf attachments (list attachments)))
223
+
224
+              (let (res)
225
+                (dolist (attachment attachments)
226
+                  (if* (mime-part-constructed-p attachment)
227
+                     thenret
228
+                   elseif (or (streamp attachment) (stringp attachment)
229
+                              (pathnamep attachment))
230
+                     then (setf attachment (make-mime-part :file attachment))
231
+                     else (error "~
232 232
 Attachments must be filenames, streams, or mime-part-constructed, not ~s"
233
-				 attachment))
234
-		  (push attachment res))
233
+                                 attachment))
234
+                  (push attachment res))
235 235
 
236
-		(setf (mime-part-parts message) (append parts-save res))))
236
+                (setf (mime-part-parts message) (append parts-save res))))
237 237
 
238 238
       (with-mime-part-constructed-stream (s message)
239
-	(send-smtp-auth server from (append tos ccs bccs)
240
-			login password
241
-			hdrs
242
-			user-headers
243
-			s))
239
+        (send-smtp-auth server from (append tos ccs bccs)
240
+                        login password
241
+                        hdrs
242
+                        user-headers
243
+                        s))
244 244
 
245 245
       (setf (mime-part-parts message) parts-save)
246 246
       t)))
... ...
@@ -253,7 +253,7 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s"
253 253
   (send-smtp-1 server from to login password messages))
254 254
 
255 255
 (defun send-smtp-1 (server from to login password messages
256
-		    &key (external-format :default))
256
+                    &key (external-format :default))
257 257
   ;; send the effective concatenation of the messages via
258 258
   ;; smtp to the mail server
259 259
   ;; Each message should be a string or a stream.
... ...
@@ -265,73 +265,73 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s"
265 265
   (let ((sock (connect-to-mail-server server login password)))
266 266
 
267 267
     (unwind-protect
268
-	(progn
269
-
270
-	  (smtp-send-recv (sock (format nil "MAIL from:<~a>" from) msg)
271
-	    (2 ;; cool
272
-	     nil
273
-	     )
274
-	    (t (smtp-transaction-error)))
275
-
276
-	  (let ((tos (if* (stringp to)
277
-			then (list to)
278
-		      elseif (consp to)
279
-			then to
280
-			else (error "to should be a string or list, not ~s"
281
-				    to))))
282
-	    (dolist (to tos)
283
-	      (smtp-send-recv (sock (format nil "RCPT to:<~a>" to) msg)
284
-		(2 ;; cool
285
-		 nil
286
-		 )
287
-		(t (smtp-transaction-error)))))
288
-
289
-	  (smtp-send-recv (sock "DATA" msg)
290
-	    (3 ;; cool
291
-	     nil)
292
-	    (t (smtp-transaction-error)))
293
-
294
-
295
-
296
-	  (let ((at-bol t)
297
-		(prev-ch nil)
298
-		ch stream)
299
-	    (dolist (message messages)
300
-	      (when message
301
-		(setf stream (if* (streamp message)
302
-				then message
303
-				else (make-buffer-input-stream
304
-				      (string-to-octets
305
-				       message
306
-				       :null-terminate nil
307
-				       :external-format external-format))))
308
-
309
-		(while (setf ch (read-byte stream nil))
310
-		  (if* (and at-bol (eq ch #.(char-code #\.)))
311
-		     then ;; to prevent . from being interpreted as eol
312
-			  (write-char #\. sock))
313
-		  (if* (eq ch #.(char-code #\newline))
314
-		     then (setq at-bol t)
315
-			  (if* (not (eq prev-ch #.(char-code #\return)))
316
-			     then (write-char #\return sock))
317
-		     else (setq at-bol nil))
318
-		  (write-byte ch sock)
319
-		  (setq prev-ch ch)))))
320
-
321
-	  (write-char #\return sock) (write-char #\linefeed sock)
322
-	  (write-char #\. sock)
323
-	  (write-char #\return sock) (write-char #\linefeed sock)
324
-
325
-	  (response-case (sock msg)
326
-	    (2 nil ; (format t "Message sent to ~a~%" to)
327
-	       )
328
-
329
-	    (t (error "message not sent: ~s" msg)))
330
-
331
-	  (smtp-send-recv (sock "QUIT" msg)
332
-	    (2 ;; cool
333
-	     nil)
334
-	    (t (smtp-transaction-error))))
268
+        (progn
269
+
270
+          (smtp-send-recv (sock (format nil "MAIL from:<~a>" from) msg)
271
+            (2 ;; cool
272
+             nil
273
+             )
274
+            (t (smtp-transaction-error)))
275
+
276
+          (let ((tos (if* (stringp to)
277
+                        then (list to)
278
+                      elseif (consp to)
279
+                        then to
280
+                        else (error "to should be a string or list, not ~s"
281
+                                    to))))
282
+            (dolist (to tos)
283
+              (smtp-send-recv (sock (format nil "RCPT to:<~a>" to) msg)
284
+                (2 ;; cool
285
+                 nil
286
+                 )
287
+                (t (smtp-transaction-error)))))
288
+
289
+          (smtp-send-recv (sock "DATA" msg)
290
+            (3 ;; cool
291
+             nil)
292
+            (t (smtp-transaction-error)))
293
+
294
+
295
+
296
+          (let ((at-bol t)
297
+                (prev-ch nil)
298
+                ch stream)
299
+            (dolist (message messages)
300
+              (when message
301
+                (setf stream (if* (streamp message)
302
+                                then message
303
+                                else (make-buffer-input-stream
304
+                                      (string-to-octets
305
+                                       message
306
+                                       :null-terminate nil
307
+                                       :external-format external-format))))
308
+
309
+                (while (setf ch (read-byte stream nil))
310
+                  (if* (and at-bol (eq ch #.(char-code #\.)))
311
+                     then ;; to prevent . from being interpreted as eol
312
+                          (write-char #\. sock))
313
+                  (if* (eq ch #.(char-code #\newline))
314
+                     then (setq at-bol t)
315
+                          (if* (not (eq prev-ch #.(char-code #\return)))
316
+                             then (write-char #\return sock))
317
+                     else (setq at-bol nil))
318
+                  (write-byte ch sock)
319
+                  (setq prev-ch ch)))))
320
+
321
+          (write-char #\return sock) (write-char #\linefeed sock)
322
+          (write-char #\. sock)
323
+          (write-char #\return sock) (write-char #\linefeed sock)
324
+
325
+          (response-case (sock msg)
326
+            (2 nil ; (format t "Message sent to ~a~%" to)
327
+               )
328
+
329
+            (t (error "message not sent: ~s" msg)))
330
+
331
+          (smtp-send-recv (sock "QUIT" msg)
332
+            (2 ;; cool
333
+             nil)
334
+            (t (smtp-transaction-error))))
335 335
       ;; Cleanup
336 336
       (close sock))))
337 337
 
... ...
@@ -341,80 +341,80 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s"
341 341
   ;; signaling an error if it can't be made.
342 342
 
343 343
   (let ((use-port 25) ;; standard SMTP port
344
-	ssl-args
345
-	ssl
346
-	starttls)
344
+        ssl-args
345
+        ssl
346
+        starttls)
347 347
     (if* (consp server)
348 348
        then (if* (consp (cdr server))
349
-	       then ;; long form
350
-		    (setq ssl-args (cdr server))
351
-		    (setf server (car server))
352
-		    (setq ssl (getf ssl-args :ssl))
353
-		    (remf ssl-args :ssl)
354
-		    (setq use-port (or (getf ssl-args :port)
355
-				       (if ssl 465 use-port)))
356
-		    (remf ssl-args :port)
357
-		    (setq starttls (getf ssl-args :starttls))
358
-		    (remf ssl-args :starttls)
359
-	       else ;; short form
360
-		    (setf use-port (cdr server))
361
-		    (setf server (car server)))
349
+               then ;; long form
350
+                    (setq ssl-args (cdr server))
351
+                    (setf server (car server))
352
+                    (setq ssl (getf ssl-args :ssl))
353
+                    (remf ssl-args :ssl)
354
+                    (setq use-port (or (getf ssl-args :port)
355
+                                       (if ssl 465 use-port)))
356
+                    (remf ssl-args :port)
357
+                    (setq starttls (getf ssl-args :starttls))
358
+                    (remf ssl-args :starttls)
359
+               else ;; short form
360
+                    (setf use-port (cdr server))
361
+                    (setf server (car server)))
362 362
      elseif (stringp server)
363 363
        then (multiple-value-bind (match whole m1 m2)
364
-		(match-re "^([^:]+):([0-9]+)$" server)
365
-	      (declare (ignore whole))
366
-	      (if* match
367
-		 then (setf server m1)
368
-		      (setf use-port (parse-integer m2)))))
364
+                (match-re "^([^:]+):([0-9]+)$" server)
365
+              (declare (ignore whole))
366
+              (if* match
367
+                 then (setf server m1)
368
+                      (setf use-port (parse-integer m2)))))
369 369
 
370 370
     (let ((ipaddr (determine-mail-server server))
371
-	  (sock)
372
-	  (ok))
371
+          (sock)
372
+          (ok))
373 373
 
374 374
       (if* (null ipaddr)
375
-	 then (error "Can't determine ip address for mail server ~s" server))
375
+         then (error "Can't determine ip address for mail server ~s" server))
376 376
 
377 377
       (setq sock (socket:make-socket :remote-host ipaddr
378
-				     :remote-port use-port
379
-				     ))
378
+                                     :remote-port use-port
379
+                                     ))
380 380
       (when ssl
381
-	(setq sock (apply #'acl-socket:make-ssl-client-stream sock ssl-args)))
381
+        (setq sock (apply #'acl-socket:make-ssl-client-stream sock ssl-args)))
382 382
 
383 383
       (unwind-protect
384
-	  (tagbody
385
-	    (response-case (sock msg)
386
-			   (2 ;; to the initial connect
387
-			    nil)
388
-			   (t (error "initial connect failed: ~s" msg)))
389
-	    ehlo
390
-	    ;; now that we're connected we can compute our hostname
391
-	    (let ((hostname (socket:ipaddr-to-hostname
392
-			     (socket:local-host sock))))
393
-	      (if* (null hostname)
394
-		 then (setq hostname
395
-			(format nil "[~a]" (socket:ipaddr-to-dotted
396
-					    (socket:local-host sock)))))
397
-	      (let ((mechs (smtp-ehlo sock hostname))
398
-		    auth-mechs)
399
-		(if* (and mechs starttls (member "STARTTLS" mechs :test #'string=))
400
-		   then (smtp-send-recv (sock (format nil "STARTTLS") msg)
401
-					(2 ;; ok
402
-					 (setq sock (acl-socket:make-ssl-client-stream sock :method :tlsv1)))
403
-					(t (smtp-transaction-error)))
404
-			(go ehlo)
405
-		 elseif (and mechs login password
406
-			     (setq auth-mechs (car (member "LOGIN" mechs
407
-						      :test #'(lambda (x y) (search x y))))))
408
-		   then (setf sock
409
-			  (smtp-authenticate sock server auth-mechs login password)))))
410
-
411
-	    ;; all is good
412
-	    (setq ok t))
413
-
414
-	;; cleanup:
415
-	(if* (null ok)
416
-	   then (close sock :abort t)
417
-		(setq sock nil)))
384
+          (tagbody
385
+            (response-case (sock msg)
386
+                           (2 ;; to the initial connect
387
+                            nil)
388
+                           (t (error "initial connect failed: ~s" msg)))
389
+            ehlo
390
+            ;; now that we're connected we can compute our hostname
391
+            (let ((hostname (socket:ipaddr-to-hostname
392
+                             (socket:local-host sock))))
393
+              (if* (null hostname)
394
+                 then (setq hostname
395
+                        (format nil "[~a]" (socket:ipaddr-to-dotted
396
+                                            (socket:local-host sock)))))
397
+              (let ((mechs (smtp-ehlo sock hostname))
398
+                    auth-mechs)
399
+                (if* (and mechs starttls (member "STARTTLS" mechs :test #'string=))
400
+                   then (smtp-send-recv (sock (format nil "STARTTLS") msg)
401
+                                        (2 ;; ok
402
+                                         (setq sock (acl-socket:make-ssl-client-stream sock :method :tlsv1)))
403
+                                        (t (smtp-transaction-error)))
404
+                        (go ehlo)
405
+                 elseif (and mechs login password
406
+                             (setq auth-mechs (car (member "LOGIN" mechs
407
+                                                      :test #'(lambda (x y) (search x y))))))
408
+                   then (setf sock
409
+                          (smtp-authenticate sock server auth-mechs login password)))))
410
+
411
+            ;; all is good
412
+            (setq ok t))
413
+
414
+        ;; cleanup:
415
+        (if* (null ok)
416
+           then (close sock :abort t)
417
+                (setq sock nil)))
418 418
 
419 419
       ;; return:
420 420
       sock
... ...
@@ -430,52 +430,52 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s"
430 430
      ;; Collect the auth mechanisms.
431 431
      (let (mechs)
432 432
        (multiple-value-bind (found whole mech)
433
-	   (match-re "250[- ]AUTH (.*)" msg)
434
-	 (declare (ignore whole))
435
-	 (if found (push mech mechs)))
433
+           (match-re "250[- ]AUTH (.*)" msg)
434
+         (declare (ignore whole))
435
+         (if found (push mech mechs)))
436 436
        (multiple-value-bind (found whole mech)
437
-	   (match-re "250[- ](STARTTLS)" msg)
438
-	 (declare (ignore whole))
439
-	 (if found (push mech mechs)))
437
+           (match-re "250[- ](STARTTLS)" msg)
438
+         (declare (ignore whole))
439
+         (if found (push mech mechs)))
440 440
        mechs))
441 441
     (t
442 442
      (smtp-send-recv (sock (format nil "HELO ~A" our-name) msg)
443 443
        (2 ;; ok
444
-	nil)
444
+        nil)
445 445
        (t (smtp-transaction-error))))))
446 446
 
447 447
 (defun smtp-authenticate (sock server mechs login password)
448 448
   (let ((ctx (net.sasl:sasl-client-new "smtp" server
449
-				       :user login
450
-				       :pass password)))
449
+                                       :user login
450
+                                       :pass password)))
451 451
     (multiple-value-bind (res selected-mech response)
452
-	(net.sasl:sasl-client-start ctx mechs)
452
+        (net.sasl:sasl-client-start ctx mechs)
453 453
       (if (not (eq res :continue))
454
-	  (error "sasl-client-start unexpectedly returned: ~s" res))
454
+          (error "sasl-client-start unexpectedly returned: ~s" res))
455 455
       (smtp-command sock "AUTH ~a" selected-mech)
456 456
       (loop
457
-	(response-case (sock msg)
458
-	  (3  ;; need more interaction
459
-	   (multiple-value-setq (res response)
460
-	     (net.sasl:sasl-step
461
-	      ctx
462
-	      (base64-string-to-usb8-array (subseq msg 4))))
463
-	   (smtp-command sock "~a"
464
-			 (usb8-array-to-base64-string response nil)))
465
-	  (2 ;; server is satisfied.
466
-	   ;; Make sure the auth process really completed
467
-	   (if (not (net.sasl:sasl-conn-auth-complete-p ctx))
468
-	       (error "SMTP server indicated authentication complete before mechanisms was satisfied"))
469
-	   ;; It's all good.
470
-	   (return)) ;; break from loop
471
-	  (t
472
-	   (error "SMTP authentication failed: ~a" msg)))))
457
+        (response-case (sock msg)
458
+          (3  ;; need more interaction
459
+           (multiple-value-setq (res response)
460
+             (net.sasl:sasl-step
461
+              ctx
462
+              (base64-string-to-usb8-array (subseq msg 4))))
463
+           (smtp-command sock "~a"
464
+                         (usb8-array-to-base64-string response nil)))
465
+          (2 ;; server is satisfied.
466
+           ;; Make sure the auth process really completed
467
+           (if (not (net.sasl:sasl-conn-auth-complete-p ctx))
468
+               (error "SMTP server indicated authentication complete before mechanisms was satisfied"))
469
+           ;; It's all good.
470
+           (return)) ;; break from loop
471
+          (t
472
+           (error "SMTP authentication failed: ~a" msg)))))
473 473
 
474 474
     ;; Reach here if authentication completed.
475 475
     ;; If a security layer was negotiated, return an encapsulated sock,
476 476
     ;; otherwise just return the original sock.
477 477
     (if (net.sasl:sasl-conn-security-layer-p ctx)
478
-	(net.sasl:sasl-make-stream ctx sock :close-base t)
478
+        (net.sasl:sasl-make-stream ctx sock :close-base t)
479 479
       sock)))
480 480
 
481 481
 
... ...
@@ -485,45 +485,45 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s"
485 485
   ;; return nil if the address is bogus
486 486
   ;; return t if the address may or may not be bogus
487 487
   (if* (or (not (stringp address))
488
-	   (zerop (length address)))
488
+           (zerop (length address)))
489 489
      then (error "mail address should be a non-empty string: ~s" address))
490 490
 
491 491
   ; split on the @ sign
492 492
   (let (name hostname)
493 493
     (let ((pos (position #\@ address)))
494 494
       (if* (null pos)
495
-	 then (setq name address
496
-		    hostname "localhost")
495
+         then (setq name address
496
+                    hostname "localhost")
497 497
        elseif (or (eql pos 0)
498
-		  (eql pos (1- (length address))))
499
-	 then ; @ at beginning or end, bogus since we don't do route addrs
500
-	      (return-from test-email-address nil)
501
-	 else (setq name (subseq address 0 pos)
502
-		    hostname (subseq address (1+ pos)))))
498
+                  (eql pos (1- (length address))))
499
+         then ; @ at beginning or end, bogus since we don't do route addrs
500
+              (return-from test-email-address nil)
501
+         else (setq name (subseq address 0 pos)
502
+                    hostname (subseq address (1+ pos)))))
503 503
 
504 504
     (let ((sock (ignore-errors (connect-to-mail-server hostname nil nil))))
505 505
       (if* (null sock) then (return-from test-email-address nil))
506 506
 
507 507
       (unwind-protect
508
-	  (progn
509
-	    (smtp-send-recv (sock (format nil "VRFY ~a" name) msg code)
510
-	      (5
511
-	       (if* (eq code 550)
512
-		  then ; no such user
513
-		       msg ; to remove unused warning
514
-		       nil
515
-		  else ;; otherwise we don't know
516
-		       (return-from test-email-address t)))
517
-	      (t (return-from test-email-address t)))
518
-	    (smtp-send-recv (sock (format nil "VRFY ~a" address) msg code)
519
-	      (5
520
-	       (if* (eq code 550)
521
-		  then ; no such user
522
-		       msg ; to remove unused warning
523
-		       nil
524
-		  else t))
525
-	      (t t)))
526
-	(close sock :abort t)))))
508
+          (progn
509
+            (smtp-send-recv (sock (format nil "VRFY ~a" name) msg code)
510
+              (5
511
+               (if* (eq code 550)
512
+                  then ; no such user
513
+                       msg ; to remove unused warning
514
+                       nil
515
+                  else ;; otherwise we don't know
516
+                       (return-from test-email-address t)))
517
+              (t (return-from test-email-address t)))
518
+            (smtp-send-recv (sock (format nil "VRFY ~a" address) msg code)
519
+              (5
520
+               (if* (eq code 550)
521
+                  then ; no such user
522
+                       msg ; to remove unused warning
523
+                       nil
524
+                  else t))
525
+              (t t)))
526
+        (close sock :abort t)))))
527 527
 
528 528
 
529 529
 
... ...
@@ -543,7 +543,7 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s"
543 543
   ;; read the response of the smtp server.
544 544
   ;; collect it all in a string.
545 545
   ;; Return two values:
546
-  ;; 	response class
546
+  ;;    response class
547 547
   ;;    whole string
548 548
   ;; The string should begin with a decimal digit, and that is converted
549 549
   ;; into a number which is returned as the response class.
... ...
@@ -551,18 +551,18 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s"
551 551
   ;; response class is -1.
552 552
   ;;
553 553
   (flet ((match-chars (string pos1 pos2 count)
554
-	   ;; like strncmp
555
-	   (dotimes (i count t)
556
-	     (if* (not (eq (aref string (+ pos1 i))
557
-			   (aref string (+ pos2 i))))
558
-		then (return nil)))))
554
+           ;; like strncmp
555
+           (dotimes (i count t)
556
+             (if* (not (eq (aref string (+ pos1 i))
557
+                           (aref string (+ pos2 i))))
558
+                then (return nil)))))
559 559
 
560 560
     (let ((res (make-array 20 :element-type 'character
561
-			   :adjustable t
562
-			   :fill-pointer 0)))
561
+                           :adjustable t
562
+                           :fill-pointer 0)))
563 563
       (if* (null (read-a-line stream res))
564
-	 then ; eof encountered before end of line
565
-	      (return-from wait-for-response (values -1 res)))
564
+         then ; eof encountered before end of line
565
+              (return-from wait-for-response (values -1 res)))
566 566
 
567 567
       ;; a multi-line response begins with line containing
568 568
       ;; a hyphen in the 4th column:
... ...
@@ -574,40 +574,40 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s"
574 574
       ;;
575 575
 
576 576
       (if* (and (>= (length res) 4) (eq #\- (aref res 3)))
577
-	 then ;; multi line response
578
-	      (let ((old-length (length res))
579
-		    (new-length nil))
580
-		(loop
581
-		  (if* (null (read-a-line stream res))
582
-		     then ; eof encountered before end of line
583
-			  (return-from wait-for-response (values -1 res)))
584
-		  (setq new-length (length res))
585
-		  ;; see if this is the last line
586
-		  (if* (and (>= (- new-length old-length) 4)
587
-			    (eq (aref res (+ old-length 3)) #\space)
588
-			    (match-chars res 0 old-length 3))
589
-		     then (return))
590
-
591
-		  (setq old-length new-length))))
577
+         then ;; multi line response
578
+              (let ((old-length (length res))
579
+                    (new-length nil))
580
+                (loop
581
+                  (if* (null (read-a-line stream res))
582
+                     then ; eof encountered before end of line
583
+                          (return-from wait-for-response (values -1 res)))
584
+                  (setq new-length (length res))
585
+                  ;; see if this is the last line
586
+                  (if* (and (>= (- new-length old-length) 4)
587
+                            (eq (aref res (+ old-length 3)) #\space)
588
+                            (match-chars res 0 old-length 3))
589
+                     then (return))
590
+
591
+                  (setq old-length new-length))))
592 592
 
593 593
       ;; complete response is in res
594 594
       ;; compute class and return the whole thing
595 595
       (let ((class (or (and (> (length res) 0)
596
-			    (digit-char-p (aref res 0)))
597
-		       -1)))
598
-	(values class res
599
-		(if* (>= (length res) 3)
600
-		   then ; compute the whole response value
601
-			(+ (* (or (digit-char-p (aref res 0)) 0) 100)
602
-			   (* (or (digit-char-p (aref res 1)) 0) 10)
603
-			   (or (digit-char-p (aref res 2)) 0))))))))
596
+                            (digit-char-p (aref res 0)))
597
+                       -1)))
598
+        (values class res
599
+                (if* (>= (length res) 3)
600
+                   then ; compute the whole response value
601
+                        (+ (* (or (digit-char-p (aref res 0)) 0) 100)
602
+                           (* (or (digit-char-p (aref res 1)) 0) 10)
603
+                           (or (digit-char-p (aref res 2)) 0))))))))
604 604
 
605 605
 (defun smtp-command (stream &rest format-args)
606 606
   ;; send a command to the smtp server
607 607
   (let ((command (apply #'format nil format-args)))
608 608
     (if* *smtp-debug*
609 609
        then (format *smtp-debug* "to smtp command: ~s~%" command)
610
-	    (force-output *smtp-debug*))
610
+            (force-output *smtp-debug*))
611 611
     (write-string command stream)
612 612
     (write-char #\return stream)
613 613
     (write-char #\newline stream)
... ...
@@ -622,25 +622,25 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s"
622 622
     (loop
623 623
       (setq ch (read-char stream nil nil))
624 624
       (if* (null ch)
625
-	 then ; premature eof
626
-	      (return nil))
625
+         then ; premature eof
626
+              (return nil))
627 627
 
628 628
       (if* *smtp-debug*
629
-	 then (format *smtp-debug* "~c" ch)
630
-	      (force-output *smtp-debug*)
631
-	      )
629
+         then (format *smtp-debug* "~c" ch)
630
+              (force-output *smtp-debug*)
631
+              )
632 632
 
633 633
       (if* (eq last-ch #\return)
634
-	 then (if* (eq ch #\linefeed)
635
-		 then (vector-push-extend #\newline res)
636
-		      (return t)
637
-		 else (vector-push-extend last-ch res))
634
+         then (if* (eq ch #\linefeed)
635
+                 then (vector-push-extend #\newline res)
636
+                      (return t)
637
+                 else (vector-push-extend last-ch res))
638 638
        elseif (eq ch #\linefeed)
639
-	 then ; line ends with just lf, not cr-lf
640
-	      (vector-push-extend #\newline res)
641
-	      (return t)
639
+         then ; line ends with just lf, not cr-lf
640
+              (vector-push-extend #\newline res)
641
+              (return t)
642 642
        elseif (not (eq ch #\return))
643
-	 then (vector-push-extend ch res))
643
+         then (vector-push-extend ch res))
644 644
 
645 645
       (setq last-ch ch))))
646 646
 
... ...
@@ -667,24 +667,24 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s"
667 667
      elseif (ipaddrp (setq ipaddr (socket:dotted-to-ipaddr name :errorp nil)))
668 668
        then ipaddr
669 669
        else ; do mx lookup if acldns is being used
670
-	    (if* (or (eq socket:*dns-mode* :acldns)
671
-		     (and (consp socket:*dns-mode*)
672
-			  (member :acldns socket:*dns-mode* :test #'eq)))
673
-	       then (let ((res (socket:dns-query name :type :mx)))
674
-		      (if* (and (consp res) (cadr res))
675
-			 then (cadr res) ; the ip address
676
-			 else (dolist (suffix socket::*domain-search-list*
677
-					(socket:dns-lookup-hostname name))
678
-				(declare (special socket:*domain-search-list*))
679
-				(let ((name
680
-				       (concatenate 'string name "." suffix)))
681
-				  (setq res (socket:dns-query name :type :mx))
682
-				  (if* (and res (cadr res))
683
-				     then (return (cadr res)))))))
684
-
685
-
686
-	       else ; just do a hostname lookup
687
-		    (ignore-errors (socket:lookup-hostname name))))))
670
+            (if* (or (eq socket:*dns-mode* :acldns)
671
+                     (and (consp socket:*dns-mode*)
672
+                          (member :acldns socket:*dns-mode* :test #'eq)))
673
+               then (let ((res (socket:dns-query name :type :mx)))
674
+                      (if* (and (consp res) (cadr res))
675
+                         then (cadr res) ; the ip address
676
+                         else (dolist (suffix socket::*domain-search-list*
677
+                                        (socket:dns-lookup-hostname name))
678
+                                (declare (special socket:*domain-search-list*))
679
+                                (let ((name
680
+                                       (concatenate 'string name "." suffix)))
681
+                                  (setq res (socket:dns-query name :type :mx))
682
+                                  (if* (and res (cadr res))
683
+                                     then (return (cadr res)))))))
684
+
685
+
686
+               else ; just do a hostname lookup
687
+                    (ignore-errors (socket:lookup-hostname name))))))
688 688
 
689 689
 
690 690