git.fiddlerwoaroof.com
Browse code

Merge branch 'master' of /repo/git.fromcvs/imap

Kevin Layer authored on 10/04/2009 03:20:06
Showing 2 changed files
... ...
@@ -1,3 +1,7 @@
1
+2009-03-12  Mikel Bancroft  <mikel@gemini>
2
+
3
+	* rfe8602: add ssl/tls support to imap/pop module.
4
+	
1 5
 2008-11-19  Ahmon Dancy  <dancy@dancy>
2 6
 
3 7
 	* rfe8406: mime-api.cl: Improved performance of
... ...
@@ -10,6 +10,12 @@
10 10
   :type :system
11 11
   :post-loadable t)
12 12
 
13
+#+(version= 8 1)
14
+(sys:defpatch "imap" 1
15
+  "v1: Add ssl/tls support for both imap/pop connections."
16
+  :type :system
17
+  :post-loadable t)
18
+
13 19
 ;; -*- mode: common-lisp; package: net.post-office -*-
14 20
 ;;
15 21
 ;; imap.cl
... ...
@@ -29,7 +35,7 @@
29 35
 ;; merchantability or fitness for a particular purpose.  See the GNU
30 36
 ;; Lesser General Public License for more details.
31 37
 ;;
32
-;; $Id: imap.cl,v 1.31 2007/04/17 22:01:42 layer Exp $
38
+;; $Id: imap.cl,v 1.32 2009/03/25 22:46:02 layer Exp $
33 39
 
34 40
 ;; Description:
35 41
 ;;- This code in this file obeys the Lisp Coding Standard found in
... ...
@@ -373,25 +379,70 @@
373 379
       (setf (aref str 1) #\linefeed)
374 380
       str))
375 381
 
382
+;; returns values: socket starttls
383
+;; server is a cons of the form:
384
+;; (server-name &key (port 25) (ssl nil) (starttls nil) ...ssl-client-keywords...)
385
+(defun connect-to-imap/pop-server (server-info server-type)
386
+  (macrolet ((pop-keyword (k l) `(prog1 (getf ,l ,k) (remf ,l ,k)))
387
+	     (server-port (ssl type) `(cond ((eq ,type :imap) (if ,ssl 993 143))
388
+					    ((eq ,type :pop) (if ,ssl 995 110)))))
389
+    (let* ((server (car server-info))
390
+	   (ssl-args (cdr server-info))
391
+	   ssl port starttls sock)
392
+      (setq ssl (pop-keyword :ssl ssl-args))
393
+      (setq port (or (pop-keyword :port ssl-args) (server-port ssl server-type)))
394
+      (setq starttls (pop-keyword :starttls ssl-args))
395
+      (setq sock (socket:make-socket :remote-host server
396
+				     :remote-port port))
397
+      (when ssl
398
+	(setq sock (apply #'socket:make-ssl-client-stream sock ssl-args)))
399
+      
400
+      (values sock starttls))) )
401
+
376 402
 (defun make-imap-connection (host &key (port 143) 
377 403
 				       user 
378 404
 				       password
379 405
 				       (timeout 30))
380
-  (let* ((sock (socket:make-socket :remote-host host
381
-				   :remote-port port))
382
-	 (imap (make-instance 'imap-mailbox
383
-		 :socket sock
384
-		 :host   host
385
-		 :timeout timeout
386
-		 :state :unauthorized)))
406
+  (multiple-value-bind (sock starttls)
407
+      (if (consp host)
408
+	  (connect-to-imap/pop-server host :imap)
409
+	(socket:make-socket :remote-host host :remote-port port))
410
+    (let ((imap (make-instance 'imap-mailbox
411
+		  :socket sock
412
+		  :host   host
413
+		  :timeout timeout
414
+		  :state :unauthorized)))
387 415
     
388 416
     (multiple-value-bind (tag cmd count extra comment)
389 417
 	(get-and-parse-from-imap-server imap)
390
-      (declare (ignore cmd count extra))
418
+      (declare (ignorable cmd count extra))
391 419
       (if* (not (eq :untagged tag))
392 420
 	 then  (po-error :error-response
393 421
 			 :server-string comment)))
394 422
       
423
+    ; check for starttls negotiation
424
+    (when starttls
425
+      (let (capabilities)
426
+	(send-command-get-results
427
+	 imap "CAPABILITY"
428
+	 #'(lambda (mb cmd count extra comment)
429
+	     (declare (ignorable mb cmd count extra))
430
+	     (setq capabilities comment))
431
+	 #'(lambda (mb cmd count extra comment)
432
+	     (check-for-success mb cmd count extra comment
433
+				"CAPABILITY")))
434
+	(when (and capabilities (match-re "STARTTLS" capabilities :case-fold t
435
+					  :return nil))
436
+	  ;; negotiate starttls
437
+	  (send-command-get-results imap "STARTTLS"
438
+				    #'handle-untagged-response
439
+				    #'(lambda (mb cmd count extra comment)
440
+					(check-for-success mb cmd count extra comment
441
+							   "STARTTLS")
442
+					(setf (post-office-socket mb)
443
+					  (socket:make-ssl-client-stream
444
+					   (post-office-socket mb) :method :tlsv1)))))))
445
+
395 446
     ; now login
396 447
     (send-command-get-results imap 
397 448
 			      (format nil "login ~a ~a" user password)
... ...
@@ -410,7 +461,7 @@
410 461
     
411 462
 				    
412 463
 				    
413
-    imap))
464
+    imap)))
414 465
 
415 466
 
416 467
 (defmethod close-connection ((mb imap-mailbox))
... ...
@@ -452,9 +503,11 @@
452 503
 				      user
453 504
 				      password
454 505
 				      (timeout 30))
455
-  (let* ((sock (socket:make-socket :remote-host host
456
-				   :remote-port port))
457
-	 (pop (make-instance 'pop-mailbox
506
+  (multiple-value-bind (sock starttls)
507
+      (if (consp host)
508
+	  (connect-to-imap/pop-server host :pop)
509
+	(socket:make-socket :remote-host host :remote-port port))
510
+    (let ((pop (make-instance 'pop-mailbox
458 511
 		:socket sock
459 512
 		:host   host
460 513
 		:timeout timeout
... ...
@@ -467,6 +520,15 @@
467 520
 			 :format-control
468 521
 			 "unexpected line from server after connect")))
469 522
       
523
+    ; check for starttls negotiation
524
+    (when starttls
525
+      (let ((capabilities (send-pop-command-get-results pop "capa" t)))
526
+	(when (and capabilities (match-re "STLS" capabilities :case-fold t
527
+					  :return nil))
528
+	  (send-pop-command-get-results pop "STLS")		   
529
+	  (setf (post-office-socket pop) (socket:make-ssl-client-stream 
530
+					  (post-office-socket pop) :method :tlsv1)))))
531
+    
470 532
     ; now login
471 533
     (send-pop-command-get-results pop (format nil "user ~a" user))
472 534
     (send-pop-command-get-results pop (format nil "pass ~a" password))
... ...
@@ -476,7 +538,7 @@
476 538
     
477 539
     			    
478 540
 				    
479
-    pop))
541
+    pop)))
480 542
 			    
481 543
 
482 544
 (defmethod send-command-get-results ((mb imap-mailbox)