Browse code
join from acl7 to trunk
layer authored on 03/08/2005 05:17:29
Showing 3 changed files
Showing 3 changed files
... | ... |
@@ -1,3 +1,18 @@ |
1 |
+2005-02-15 Kevin Layer <layer@gemini> |
|
2 |
+ |
|
3 |
+ * smtp.cl: bug15190: from jkf: fix nameserver lookup if *dns-mode* |
|
4 |
+ is just :clib |
|
5 |
+ |
|
6 |
+2004-09-28 Kevin Layer <layer@gemini> |
|
7 |
+ |
|
8 |
+ * imap.cl: fix copyright notice |
|
9 |
+ |
|
10 |
+2004-09-14 Kevin Layer <layer@gemini> |
|
11 |
+ |
|
12 |
+ * smtp.cl: |
|
13 |
+ - add new exported `send-smtp-auth' (from dancy) |
|
14 |
+ - add `login' and `password' keywords to send-letter |
|
15 |
+ |
|
1 | 16 |
2004-08-13 Kevin Layer <layer@gemini> |
2 | 17 |
imap 1.13 |
3 | 18 |
|
... | ... |
@@ -6,25 +6,20 @@ |
6 | 6 |
;; copyright (c) 1999 Franz Inc, Berkeley, CA - All rights reserved. |
7 | 7 |
;; copyright (c) 1999-2004 Franz Inc, Oakland, CA - All rights reserved. |
8 | 8 |
;; |
9 |
-;; The software, data and information contained herein are proprietary |
|
10 |
-;; to, and comprise valuable trade secrets of, Franz, Inc. They are |
|
11 |
-;; given in confidence by Franz, Inc. pursuant to a written license |
|
12 |
-;; agreement, and may be stored and used only in accordance with the terms |
|
13 |
-;; of such license. |
|
9 |
+;; This code is free software; you can redistribute it and/or |
|
10 |
+;; modify it under the terms of the version 2.1 of |
|
11 |
+;; the GNU Lesser General Public License as published by |
|
12 |
+;; the Free Software Foundation, as clarified by the AllegroServe |
|
13 |
+;; prequel found in license-allegroserve.txt. |
|
14 | 14 |
;; |
15 |
-;; Restricted Rights Legend |
|
16 |
-;; ------------------------ |
|
17 |
-;; Use, duplication, and disclosure of the software, data and information |
|
18 |
-;; contained herein by any agency, department or entity of the U.S. |
|
19 |
-;; Government are subject to restrictions of Restricted Rights for |
|
20 |
-;; Commercial Software developed at private expense as specified in |
|
21 |
-;; DOD FAR Supplement 52.227-7013 (c) (1) (ii), as applicable. |
|
15 |
+;; This code is distributed in the hope that it will be useful, |
|
16 |
+;; but without any warranty; without even the implied warranty of |
|
17 |
+;; merchantability or fitness for a particular purpose. See the GNU |
|
18 |
+;; Lesser General Public License for more details. |
|
22 | 19 |
;; |
23 |
-;; $Id: imap.cl,v 1.26 2004/08/27 18:06:31 layer Exp $ |
|
20 |
+;; $Id: imap.cl,v 1.27 2005/08/03 05:17:29 layer Exp $ |
|
24 | 21 |
|
25 | 22 |
;; Description: |
26 |
-;; |
|
27 |
-;; |
|
28 | 23 |
;;- This code in this file obeys the Lisp Coding Standard found in |
29 | 24 |
;;- http://www.franz.com/~jkf/coding_standards.html |
30 | 25 |
;;- |
... | ... |
@@ -24,7 +24,7 @@ |
24 | 24 |
;; Suite 330, Boston, MA 02111-1307 USA |
25 | 25 |
;; |
26 | 26 |
;; |
27 |
-;; $Id: smtp.cl,v 1.8 2004/01/16 19:31:52 layer Exp $ |
|
27 |
+;; $Id: smtp.cl,v 1.9 2005/08/03 05:17:29 layer Exp $ |
|
28 | 28 |
|
29 | 29 |
;; Description: |
30 | 30 |
;; send mail to an smtp server. See rfc821 for the spec. |
... | ... |
@@ -39,10 +39,13 @@ |
39 | 39 |
(:export |
40 | 40 |
#:send-letter |
41 | 41 |
#:send-smtp |
42 |
+ #:send-smtp-auth |
|
42 | 43 |
#:test-email-address)) |
43 | 44 |
|
44 | 45 |
(in-package :net.post-office) |
45 | 46 |
|
47 |
+(eval-when (compile load eval) |
|
48 |
+ (require :sasl)) |
|
46 | 49 |
|
47 | 50 |
;; the exported functions: |
48 | 51 |
|
... | ... |
@@ -109,7 +112,8 @@ |
109 | 112 |
|
110 | 113 |
|
111 | 114 |
(defun send-letter (server from to message |
112 |
- &key cc bcc subject reply-to headers) |
|
115 |
+ &key cc bcc subject reply-to headers |
|
116 |
+ login password) |
|
113 | 117 |
;; |
114 | 118 |
;; see documentation at the head of this file |
115 | 119 |
;; |
... | ... |
@@ -159,15 +163,19 @@ |
159 | 163 |
|
160 | 164 |
(format header "~c~c" #\return #\linefeed) |
161 | 165 |
|
162 |
- (send-smtp server from (append tos ccs bccs) |
|
166 |
+ (send-smtp-auth server from (append tos ccs bccs) |
|
167 |
+ login password |
|
163 | 168 |
(get-output-stream-string header) |
164 | 169 |
message))) |
165 | 170 |
|
166 | 171 |
|
172 |
+(defun send-smtp(server from to &rest messages) |
|
173 |
+ (send-smtp-1 server from to nil nil messages)) |
|
167 | 174 |
|
175 |
+(defun send-smtp-auth (server from to login password &rest messages) |
|
176 |
+ (send-smtp-1 server from to login password messages)) |
|
168 | 177 |
|
169 |
- |
|
170 |
-(defun send-smtp (server from to &rest messages) |
|
178 |
+(defun send-smtp-1 (server from to login password messages) |
|
171 | 179 |
;; send the effective concatenation of the messages via |
172 | 180 |
;; smtp to the mail server |
173 | 181 |
;; Each message should be a string |
... | ... |
@@ -176,7 +184,7 @@ |
176 | 184 |
;; each string should be in the official rfc822 format "foo@bar.com" |
177 | 185 |
;; |
178 | 186 |
|
179 |
- (let ((sock (connect-to-mail-server server))) |
|
187 |
+ (let ((sock (connect-to-mail-server server login password))) |
|
180 | 188 |
|
181 | 189 |
(unwind-protect |
182 | 190 |
(progn |
... | ... |
@@ -245,7 +253,7 @@ |
245 | 253 |
(t (error "quit failed: ~s" msg)))) |
246 | 254 |
(close sock)))) |
247 | 255 |
|
248 |
-(defun connect-to-mail-server (server) |
|
256 |
+(defun connect-to-mail-server (server login password) |
|
249 | 257 |
;; make that initial connection to the mail server |
250 | 258 |
;; returning a socket connected to it and |
251 | 259 |
;; signaling an error if it can't be made. |
... | ... |
@@ -273,11 +281,10 @@ |
273 | 281 |
then (setq hostname |
274 | 282 |
(format nil "[~a]" (socket:ipaddr-to-dotted |
275 | 283 |
(socket:local-host sock))))) |
276 |
- (smtp-command sock "HELO ~a" hostname) |
|
277 |
- (response-case (sock msg) |
|
278 |
- (2 ;; ok |
|
279 |
- nil) |
|
280 |
- (t (error "hello greeting failed: ~s" msg)))) |
|
284 |
+ (let ((mechs (smtp-ehlo sock hostname))) |
|
285 |
+ (if (and mechs login password) |
|
286 |
+ (setf sock |
|
287 |
+ (smtp-authenticate sock server mechs login password))))) |
|
281 | 288 |
|
282 | 289 |
; all is good |
283 | 290 |
(setq ok t)) |
... | ... |
@@ -292,6 +299,61 @@ |
292 | 299 |
)) |
293 | 300 |
|
294 | 301 |
|
302 |
+;; Returns string with mechanisms, or nil if none. |
|
303 |
+;; This may need to be expanded in the future as we support |
|
304 |
+;; more of the features that EHLO responds with. |
|
305 |
+(defun smtp-ehlo (sock our-name) |
|
306 |
+ (smtp-command sock "EHLO ~A" our-name) |
|
307 |
+ (response-case (sock msg) |
|
308 |
+ (2 ;; ok |
|
309 |
+ ;; Collect the auth mechanisms. |
|
310 |
+ (multiple-value-bind (found whole mechs) |
|
311 |
+ (match-regexp "250[- ]AUTH \\(.*\\)" msg) |
|
312 |
+ (declare (ignore whole)) |
|
313 |
+ (if found |
|
314 |
+ mechs))) |
|
315 |
+ (t |
|
316 |
+ (smtp-command sock "HELO ~A" our-name) |
|
317 |
+ (response-case (sock msg) |
|
318 |
+ (2 ;; ok |
|
319 |
+ nil) |
|
320 |
+ (t (error "hello greeting failed: ~s" msg)))))) |
|
321 |
+ |
|
322 |
+(defun smtp-authenticate (sock server mechs login password) |
|
323 |
+ (let ((ctx (net.sasl:sasl-client-new "smtp" server |
|
324 |
+ :user login |
|
325 |
+ :pass password))) |
|
326 |
+ (multiple-value-bind (res selected-mech response) |
|
327 |
+ (net.sasl:sasl-client-start ctx mechs) |
|
328 |
+ (if (not (eq res :continue)) |
|
329 |
+ (error "sasl-client-start unexpectedly returned: ~s" res)) |
|
330 |
+ (smtp-command sock "AUTH ~a" selected-mech) |
|
331 |
+ (loop |
|
332 |
+ (response-case (sock msg) |
|
333 |
+ (3 ;; need more interaction |
|
334 |
+ (multiple-value-setq (res response) |
|
335 |
+ (net.sasl:sasl-step |
|
336 |
+ ctx |
|
337 |
+ (base64-string-to-usb8-array (subseq msg 4)))) |
|
338 |
+ (smtp-command sock "~a" |
|
339 |
+ (usb8-array-to-base64-string response nil))) |
|
340 |
+ (2 ;; server is satisfied. |
|
341 |
+ ;; Make sure the auth process really completed |
|
342 |
+ (if (not (net.sasl:sasl-conn-auth-complete-p ctx)) |
|
343 |
+ (error "SMTP server indicated authentication complete before mechanisms was satisfied")) |
|
344 |
+ ;; It's all good. |
|
345 |
+ (return)) ;; break from loop |
|
346 |
+ (t |
|
347 |
+ (error "SMTP authentication failed"))))) |
|
348 |
+ |
|
349 |
+ ;; Reach here if authentication completed. |
|
350 |
+ ;; If a security layer was negotiated, return an encapsulated sock, |
|
351 |
+ ;; otherwise just return the original sock. |
|
352 |
+ (if (net.sasl:sasl-conn-security-layer-p ctx) |
|
353 |
+ (net.sasl:sasl-make-stream ctx sock :close-base t) |
|
354 |
+ sock))) |
|
355 |
+ |
|
356 |
+ |
|
295 | 357 |
|
296 | 358 |
(defun test-email-address (address) |
297 | 359 |
;; test to see if we can determine if the address is valid |
... | ... |
@@ -314,7 +376,7 @@ |
314 | 376 |
else (setq name (subseq address 0 pos) |
315 | 377 |
hostname (subseq address (1+ pos))))) |
316 | 378 |
|
317 |
- (let ((sock (ignore-errors (connect-to-mail-server hostname)))) |
|
379 |
+ (let ((sock (ignore-errors (connect-to-mail-server hostname nil nil)))) |
|
318 | 380 |
(if* (null sock) then (return-from test-email-address nil)) |
319 | 381 |
|
320 | 382 |
(unwind-protect |
... | ... |
@@ -478,7 +540,8 @@ |
478 | 540 |
then ipaddr |
479 | 541 |
else ; do mx lookup if acldns is being used |
480 | 542 |
(if* (or (eq socket:*dns-mode* :acldns) |
481 |
- (member :acldns socket:*dns-mode* :test #'eq)) |
|
543 |
+ (and (consp socket:*dns-mode*) |
|
544 |
+ (member :acldns socket:*dns-mode* :test #'eq))) |
|
482 | 545 |
then (let ((res (socket:dns-query name :type :mx))) |
483 | 546 |
(if* (and (consp res) (cadr res)) |
484 | 547 |
then (cadr res) ; the ip address |