git.fiddlerwoaroof.com
Browse code

2008-09-16 Mikel Bancroft <mikel@gemini>

layer authored on 16/09/2008 23:22:14
Showing 2 changed files
... ...
@@ -1,3 +1,8 @@
1
+2008-09-16  Mikel Bancroft  <mikel@gemini>
2
+
3
+	* rfe8214 - smtp.cl: Add support for SSL connections to secure
4
+          SMTP Servers. Also add support for STARTTLS negotiation.
5
+
1 6
 2008-05-21  Ahmon Dancy  <dancy@dancy>
2 7
 
3 8
 	* bug17849: Fix parse-mime-structure behavior when it
... ...
@@ -1,4 +1,10 @@
1
-#+(version= 8 0)
1
+#+(version= 8 1)
2
+(sys:defpatch "smtp" 1
3
+  "v1: add smtp support for ssl connections and STARTTLS negotiation."
4
+  :type :system
5
+  :post-loadable t)
6
+
7
+#+(version= 8 0) ;; not current with latest sources
2 8
 (sys:defpatch "smtp" 5
3 9
   "v1: send-letter w/attachments; send-smtp* can take streams;
4 10
 v2: add :port argument to send-letter, send-smtp, send-smtp-auth;
... ...
@@ -8,7 +14,7 @@ v5: send-smtp-1: New external-format keyword arg."
8 14
   :type :system
9 15
   :post-loadable t)
10 16
 
11
-#+(version= 7 0)
17
+#+(version= 7 0) ;; not current with latest sources
12 18
 (sys:defpatch "smtp" 5
13 19
   "v2: send-letter w/attachments; send-smtp* can take streams;
14 20
 v3: add :port argument to send-letter, send-smtp, send-smtp-auth;
... ...
@@ -22,7 +28,7 @@ v5: rm stray force-output of t; send-smtp-1: New external-format keyword arg."
22 28
 ;; smtp.cl
23 29
 ;;
24 30
 ;; copyright (c) 1986-2002 Franz Inc, Berkeley, CA  - All rights reserved.
25
-;; copyright (c) 2002-2007 Franz Inc, Oakland, CA - All rights reserved.
31
+;; copyright (c) 2002-2008 Franz Inc, Oakland, CA - All rights reserved.
26 32
 ;;
27 33
 ;; This code is free software; you can redistribute it and/or
28 34
 ;; modify it under the terms of the version 2.1 of
... ...
@@ -43,7 +49,7 @@ v5: rm stray force-output of t; send-smtp-1: New external-format keyword arg."
43 49
 ;; Suite 330, Boston, MA  02111-1307  USA
44 50
 ;;
45 51
 ;;
46
-;; $Id: smtp.cl,v 1.23 2007/04/17 22:01:42 layer Exp $
52
+;; $Id: smtp.cl,v 1.24 2008/09/16 23:22:14 layer Exp $
47 53
 
48 54
 ;; Description:
49 55
 ;;   send mail to an smtp server.  See rfc821 for the spec.
... ...
@@ -282,7 +288,7 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s"
282 288
   ;;
283 289
 
284 290
   (let ((sock (connect-to-mail-server server login password)))
285
-  
291
+
286 292
     (unwind-protect
287 293
 	(progn
288 294
 	  
... ...
@@ -359,17 +365,32 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s"
359 365
   ;; returning a socket connected to it and 
360 366
   ;; signaling an error if it can't be made.
361 367
   
362
-  (let ((port 25)) ;; standard SMTP port
368
+  (let ((use-port 25) ;; standard SMTP port
369
+	ssl-args
370
+	ssl
371
+	starttls)
363 372
     (if* (consp server)
364
-       then (setf port (cdr server))
365
-	    (setf server (car server))
373
+       then (if* (consp (cdr server))
374
+	       then ;; long form
375
+		    (setq ssl-args (cdr server))
376
+		    (setf server (car server))
377
+		    (setq ssl (getf ssl-args :ssl))
378
+		    (remf ssl-args :ssl)
379
+		    (setq use-port (or (getf ssl-args :port)
380
+				       (if ssl 465 use-port)))
381
+		    (remf ssl-args :port)
382
+		    (setq starttls (getf ssl-args :starttls))
383
+		    (remf ssl-args :starttls)
384
+	       else ;; short form
385
+		    (setf use-port (cdr server))
386
+		    (setf server (car server)))
366 387
      elseif (stringp server)
367 388
        then (multiple-value-bind (match whole m1 m2)
368 389
 		(match-re "^([^:]+):([0-9]+)$" server)
369 390
 	      (declare (ignore whole))
370 391
 	      (if* match
371 392
 		 then (setf server m1)
372
-		      (setf port (parse-integer m2)))))
393
+		      (setf use-port (parse-integer m2)))))
373 394
     
374 395
     (let ((ipaddr (determine-mail-server server))
375 396
 	  (sock)
... ...
@@ -379,15 +400,18 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s"
379 400
 	 then (error "Can't determine ip address for mail server ~s" server))
380 401
       
381 402
       (setq sock (socket:make-socket :remote-host ipaddr
382
-				     :remote-port port
403
+				     :remote-port use-port
383 404
 				     ))
405
+      (when ssl
406
+	(setq sock (apply #'acl-socket:make-ssl-client-stream sock ssl-args)))
407
+      
384 408
       (unwind-protect
385
-	  (progn
409
+	  (tagbody
386 410
 	    (response-case (sock msg)
387 411
 			   (2 ;; to the initial connect
388 412
 			    nil)
389 413
 			   (t (error "initial connect failed: ~s" msg)))
390
-	  
414
+	    ehlo
391 415
 	    ;; now that we're connected we can compute our hostname
392 416
 	    (let ((hostname (socket:ipaddr-to-hostname
393 417
 			     (socket:local-host sock))))
... ...
@@ -395,10 +419,19 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s"
395 419
 		 then (setq hostname
396 420
 			(format nil "[~a]" (socket:ipaddr-to-dotted
397 421
 					    (socket:local-host sock)))))
398
-	      (let ((mechs (smtp-ehlo sock hostname)))
399
-		(if (and mechs login password)
400
-		    (setf sock 
401
-		      (smtp-authenticate sock server mechs login password)))))
422
+	      (let ((mechs (smtp-ehlo sock hostname))
423
+		    auth-mechs)
424
+		(if* (and mechs starttls (member "STARTTLS" mechs :test #'string=))
425
+		   then (smtp-send-recv (sock (format nil "STARTTLS") msg)
426
+					(2 ;; ok
427
+					 (setq sock (acl-socket:make-ssl-client-stream sock :method :tlsv1)))
428
+					(t (smtp-transaction-error)))
429
+			(go ehlo)
430
+		 elseif (and mechs login password
431
+			     (setq auth-mechs (car (member "LOGIN" mechs
432
+						      :test #'(lambda (x y) (search x y))))))
433
+		   then (setf sock 
434
+			  (smtp-authenticate sock server auth-mechs login password)))))
402 435
 	  
403 436
 	    ;; all is good
404 437
 	    (setq ok t))
... ...
@@ -420,11 +453,16 @@ Attachments must be filenames, streams, or mime-part-constructed, not ~s"
420 453
   (smtp-send-recv (sock (format nil "EHLO ~A" our-name) msg)
421 454
     (2 ;; ok
422 455
      ;; Collect the auth mechanisms.
423
-     (multiple-value-bind (found whole mechs)
424
-	 (match-regexp "250[- ]AUTH \\(.*\\)" msg)
425
-       (declare (ignore whole))
426
-       (if found
427
-	   mechs)))
456
+     (let (mechs)
457
+       (multiple-value-bind (found whole mech)
458
+	   (match-re "250[- ]AUTH (.*)" msg)
459
+	 (declare (ignore whole))
460
+	 (if found (push mech mechs)))
461
+       (multiple-value-bind (found whole mech)
462
+	   (match-re "250[- ](STARTTLS)" msg)
463
+	 (declare (ignore whole))
464
+	 (if found (push mech mechs)))
465
+       mechs))
428 466
     (t
429 467
      (smtp-send-recv (sock (format nil "HELO ~A" our-name) msg)
430 468
        (2 ;; ok