git.fiddlerwoaroof.com
Browse code

2007-04-12 Ahmon Dancy <dancy@dancy>

layer authored on 12/04/2007 23:58:15
Showing 2 changed files
... ...
@@ -1,3 +1,7 @@
1
+2007-04-12  Ahmon Dancy  <dancy@dancy>
2
+
3
+	* rfe7016: Increased verbosity of smtp transaction failures.
4
+
1 5
 2007-03-14  Duane Rettig  <duane@franz.com>
2 6
 
3 7
 	* mime-parse.cl: Remove bogus declarations
... ...
@@ -43,7 +43,7 @@ v5: rm stray force-output of t; send-smtp-1: New external-format keyword arg."
43 43
 ;; Suite 330, Boston, MA  02111-1307  USA
44 44
 ;;
45 45
 ;;
46
-;; $Id: smtp.cl,v 1.21 2006/11/17 00:32:07 layer Exp $
46
+;; $Id: smtp.cl,v 1.22 2007/04/12 23:58:15 layer Exp $
47 47
 
48 48
 ;; Description:
49 49
 ;;   send mail to an smtp server.  See rfc821 for the spec.
... ...
@@ -128,6 +128,28 @@ v5: rm stray force-output of t; send-smtp-1: New external-format keyword arg."
128 128
        (case ,response-class
129 129
 	 ,@case-clauses))))
130 130
 
131
+(defmacro smtp-send-recv ((smtp-stream cmd smtp-response &optional response-code) &rest case-clauses)
132
+  (let ((stream (gensym))
133
+	(sent (gensym)))
134
+    `(let ((,stream ,smtp-stream)
135
+	   (,sent ,cmd))
136
+       (if* *smtp-debug*
137
+	  then (format *smtp-debug* "to smtp command: ~s~%" ,sent)
138
+	       (force-output *smtp-debug*))
139
+       (write-string ,sent ,stream)
140
+       (write-char #\return ,stream)
141
+       (write-char #\newline ,stream)
142
+       (force-output ,stream)
143
+       (macrolet ((smtp-transaction-error ()
144
+		    (list
145
+		     'error
146
+		     "SMTP transaction failed.  We said: ~s, and the server replied: ~s"
147
+		     (quote ,sent)
148
+		     (quote ,smtp-response))))
149
+	 
150
+	 (response-case (,stream ,smtp-response ,response-code)
151
+	   ,@case-clauses)))))
152
+
131 153
 (defvar *smtp-debug* nil)
132 154
 
133 155
 
... ...
@@ -264,13 +286,12 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s"
264 286
     (unwind-protect
265 287
 	(progn
266 288
 	  
267
-	  (smtp-command sock "MAIL from:<~a>" from)
268
-	  (response-case (sock msg)
289
+	  (smtp-send-recv (sock (format nil "MAIL from:<~a>" from) msg)
269 290
 	    (2 ;; cool
270 291
 	     nil
271 292
 	     )
272
-	    (t (error "Mail from command failed: ~s" msg)))
273
-
293
+	    (t (smtp-transaction-error)))
294
+	  
274 295
 	  (let ((tos (if* (stringp to) 
275 296
 			then (list to) 
276 297
 		      elseif (consp to)
... ...
@@ -278,18 +299,16 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s"
278 299
 			else (error "to should be a string or list, not ~s"
279 300
 				    to))))
280 301
 	    (dolist (to tos)
281
-	      (smtp-command sock "RCPT to:<~a>" to)
282
-	      (response-case (sock msg)
302
+	      (smtp-send-recv (sock (format nil "RCPT to:<~a>" to) msg)
283 303
 		(2 ;; cool
284 304
 		 nil
285 305
 		 )
286
-		(t (error "rcpt to command failed: ~s" msg)))))
306
+		(t (smtp-transaction-error)))))
287 307
 	
288
-	  (smtp-command sock "DATA")
289
-	  (response-case (sock msg)
308
+	  (smtp-send-recv (sock "DATA" msg)
290 309
 	    (3 ;; cool
291 310
 	     nil)
292
-	    (t (error "Data command failed: ~s" msg)))
311
+	    (t (smtp-transaction-error)))
293 312
 	  
294 313
 	  
295 314
 	  
... ...
@@ -328,16 +347,11 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s"
328 347
 			 
329 348
 	    (t (error "message not sent: ~s" msg)))
330 349
 
331
-	  ;; Hmmmm, this is not good.  Perhaps force-output on
332
-	  ;; *error-output* is what was intended?  I'm pretty sure that's
333
-	  ;; *not needed.
334
-	  #+ignore (force-output t)
335
-	  
336
-	  (smtp-command sock "QUIT")
337
-	  (response-case (sock msg)
350
+	  (smtp-send-recv (sock "QUIT" msg)
338 351
 	    (2 ;; cool
339 352
 	     nil)
340
-	    (t (error "quit failed: ~s" msg))))
353
+	    (t (smtp-transaction-error))))
354
+      ;; Cleanup
341 355
       (close sock))))
342 356
 
343 357
 (defun connect-to-mail-server (server login password)
... ...
@@ -403,8 +417,7 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s"
403 417
 ;; This may need to be expanded in the future as we support
404 418
 ;; more of the features that EHLO responds with.
405 419
 (defun smtp-ehlo (sock our-name)
406
-  (smtp-command sock "EHLO ~A" our-name)
407
-  (response-case (sock msg)
420
+  (smtp-send-recv (sock (format nil "EHLO ~A" our-name) msg)
408 421
     (2 ;; ok
409 422
      ;; Collect the auth mechanisms.
410 423
      (multiple-value-bind (found whole mechs)
... ...
@@ -413,11 +426,10 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s"
413 426
        (if found
414 427
 	   mechs)))
415 428
     (t
416
-     (smtp-command sock "HELO ~A" our-name)
417
-     (response-case (sock msg)
429
+     (smtp-send-recv (sock (format nil "HELO ~A" our-name) msg)
418 430
        (2 ;; ok
419 431
 	nil)
420
-       (t (error "hello greeting failed: ~s" msg))))))
432
+       (t (smtp-transaction-error))))))
421 433
 
422 434
 (defun smtp-authenticate (sock server mechs login password)
423 435
   (let ((ctx (net.sasl:sasl-client-new "smtp" server
... ...
@@ -440,11 +452,11 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s"
440 452
 	  (2 ;; server is satisfied.
441 453
 	   ;; Make sure the auth process really completed
442 454
 	   (if (not (net.sasl:sasl-conn-auth-complete-p ctx))
443
-	       (error "SMTP server indicated authentication complete  before mechanisms was satisfied"))
455
+	       (error "SMTP server indicated authentication complete before mechanisms was satisfied"))
444 456
 	   ;; It's all good.  
445 457
 	   (return)) ;; break from loop
446 458
 	  (t
447
-	   (error "SMTP authentication failed")))))
459
+	   (error "SMTP authentication failed: ~a" msg)))))
448 460
     
449 461
     ;; Reach here if authentication completed.
450 462
     ;; If a security layer was negotiated, return an encapsulated sock,
... ...
@@ -481,8 +493,7 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s"
481 493
     
482 494
       (unwind-protect
483 495
 	  (progn
484
-	    (smtp-command sock "VRFY ~a" name)
485
-	    (response-case (sock msg code)
496
+	    (smtp-send-recv (sock (format nil "VRFY ~a" name) msg code)
486 497
 	      (5
487 498
 	       (if* (eq code 550)
488 499
 		  then ; no such user
... ...
@@ -491,8 +502,7 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s"
491 502
 		  else ;; otherwise we don't know
492 503
 		       (return-from test-email-address t)))
493 504
 	      (t (return-from test-email-address t)))
494
-	    (smtp-command sock "VRFY ~a" address)
495
-	    (response-case (sock msg code)
505
+	    (smtp-send-recv (sock (format nil "VRFY ~a" address) msg code)
496 506
 	      (5
497 507
 	       (if* (eq code 550)
498 508
 		  then ; no such user