Browse code
version 1.2
jkf authored on 27/10/1999 19:16:31
Showing 4 changed files
Showing 4 changed files
... | ... |
@@ -19,7 +19,7 @@ |
19 | 19 |
;; Commercial Software developed at private expense as specified in |
20 | 20 |
;; DOD FAR Supplement 52.227-7013 (c) (1) (ii), as applicable. |
21 | 21 |
;; |
22 |
-;; $Id: imap.cl,v 1.5 1999/09/29 16:25:23 jkf Exp $ |
|
22 |
+;; $Id: imap.cl,v 1.6 1999/10/27 19:16:31 jkf Exp $ |
|
23 | 23 |
|
24 | 24 |
;; Description: |
25 | 25 |
;; |
... | ... |
@@ -75,6 +75,12 @@ |
75 | 75 |
#:make-imap-connection |
76 | 76 |
#:make-pop-connection |
77 | 77 |
#:noop |
78 |
+ |
|
79 |
+ #:po-condition |
|
80 |
+ #:po-condition-indentifier |
|
81 |
+ #:po-condition-server-string |
|
82 |
+ #:po-error |
|
83 |
+ |
|
78 | 84 |
#:rename-mailbox |
79 | 85 |
#:search-mailbox |
80 | 86 |
#:select-mailbox |
... | ... |
@@ -83,8 +89,9 @@ |
83 | 89 |
|
84 | 90 |
(in-package :post-office) |
85 | 91 |
|
92 |
+(provide :imap) |
|
86 | 93 |
|
87 |
-(defparameter *imap-version-number* '(:major 1 :minor 1)) ; major.minor |
|
94 |
+(defparameter *imap-version-number* '(:major 1 :minor 2)) ; major.minor |
|
88 | 95 |
|
89 | 96 |
(defvar *debug-imap* nil) |
90 | 97 |
|
... | ... |
@@ -194,6 +201,125 @@ |
194 | 201 |
) |
195 | 202 |
|
196 | 203 |
|
204 |
+ |
|
205 |
+;-------------------------------- |
|
206 |
+; conditions |
|
207 |
+; |
|
208 |
+; We define a set of conditions that are signalled due to events |
|
209 |
+; in the imap interface. |
|
210 |
+; Each condition has an indentifier which is a keyword. That can |
|
211 |
+; be used in the handling code to identify the class of error. |
|
212 |
+; All our conditions are po-condition or po-error (which is a subclass of |
|
213 |
+; po-condition). |
|
214 |
+; |
|
215 |
+; A condition will have a server-string value if it as initiated by |
|
216 |
+; something returned by the server. |
|
217 |
+; A condition will have a format-control value if we want to display |
|
218 |
+; something we generated in response to |
|
219 |
+; |
|
220 |
+; |
|
221 |
+; |
|
222 |
+;; identifiers used in conditions/errors |
|
223 |
+ |
|
224 |
+; :problem condition |
|
225 |
+; the server responded with 'no' followed by an explanation. |
|
226 |
+; this mean that something unusual happend and doesn't necessarily |
|
227 |
+; mean that the command has completely failed (but it might). |
|
228 |
+; |
|
229 |
+; :unknown-ok condition |
|
230 |
+; the server responded with an 'ok' followed by something |
|
231 |
+; we don't recognize. It's probably safe to ignore this. |
|
232 |
+; |
|
233 |
+; :unknown-untagged condition |
|
234 |
+; the server responded with some untagged command we don't |
|
235 |
+; recognize. it's probaby ok to ignore this. |
|
236 |
+; |
|
237 |
+; :error-response error |
|
238 |
+; the command failed. |
|
239 |
+; |
|
240 |
+; :syntax-error error |
|
241 |
+; the data passed to a function in this interface was malformed |
|
242 |
+; |
|
243 |
+; :unexpected error |
|
244 |
+; the server responded an unexpected way. |
|
245 |
+; |
|
246 |
+; :server-shutdown-connection error |
|
247 |
+; the server has shut down the connection, don't attempt to |
|
248 |
+; send any more commands to this connection, or even close it. |
|
249 |
+; |
|
250 |
+; :timeout error |
|
251 |
+; server failed to respond within the timeout period |
|
252 |
+ |
|
253 |
+ |
|
254 |
+ |
|
255 |
+;; conditions |
|
256 |
+(define-condition po-condition () |
|
257 |
+ ;; used to notify user of things that shouldn't necessarily stop |
|
258 |
+ ;; program flow |
|
259 |
+ ((identifier |
|
260 |
+ ;; keyword identifying the error (or :unknown) |
|
261 |
+ :reader po-condition-identifier |
|
262 |
+ :initform :unknown |
|
263 |
+ :initarg :identifier |
|
264 |
+ ) |
|
265 |
+ (server-string |
|
266 |
+ ;; message from the imap server |
|
267 |
+ :reader po-condition-server-string |
|
268 |
+ :initform "" |
|
269 |
+ :initarg :server-string |
|
270 |
+ )) |
|
271 |
+ (:report |
|
272 |
+ (lambda (con stream) |
|
273 |
+ (with-slots (identifier server-string) con |
|
274 |
+ ;; a condition either has a server-string or it has a |
|
275 |
+ ;; format-control string |
|
276 |
+ (format stream "Post Office condition: ~s~%" identifier) |
|
277 |
+ (if* (and (slot-boundp con 'excl::format-control) |
|
278 |
+ (excl::simple-condition-format-control con)) |
|
279 |
+ then (apply #'format stream |
|
280 |
+ (excl::simple-condition-format-control con) |
|
281 |
+ (excl::simple-condition-format-arguments con))) |
|
282 |
+ (if* server-string |
|
283 |
+ then (format stream |
|
284 |
+ "~&Message from server: ~s" |
|
285 |
+ (string-left-trim " " server-string))))))) |
|
286 |
+ |
|
287 |
+ |
|
288 |
+ |
|
289 |
+(define-condition po-error (po-condition error) |
|
290 |
+ ;; used to denote things that should stop program flow |
|
291 |
+ ()) |
|
292 |
+ |
|
293 |
+ |
|
294 |
+ |
|
295 |
+;; aignalling the conditions |
|
296 |
+ |
|
297 |
+(defun po-condition (identifier &key server-string format-control |
|
298 |
+ format-arguments) |
|
299 |
+ (signal (make-instance 'po-condition |
|
300 |
+ :identifier identifier |
|
301 |
+ :server-string server-string |
|
302 |
+ :format-control format-control |
|
303 |
+ :format-arguments format-arguments |
|
304 |
+ ))) |
|
305 |
+ |
|
306 |
+(defun po-error (identifier &key server-string |
|
307 |
+ format-control format-arguments) |
|
308 |
+ (error (make-instance 'po-error |
|
309 |
+ :identifier identifier |
|
310 |
+ :server-string server-string |
|
311 |
+ :format-control format-control |
|
312 |
+ :format-arguments format-arguments))) |
|
313 |
+ |
|
314 |
+ |
|
315 |
+ |
|
316 |
+;---------------------------------------------- |
|
317 |
+ |
|
318 |
+ |
|
319 |
+ |
|
320 |
+ |
|
321 |
+ |
|
322 |
+ |
|
197 | 323 |
(defparameter *imap-tags* '("t01" "t02" "t03" "t04" "t05" "t06" "t07")) |
198 | 324 |
(defvar *cur-imap-tags* nil) |
199 | 325 |
|
... | ... |
@@ -215,17 +341,20 @@ |
215 | 341 |
:timeout timeout |
216 | 342 |
:state :unauthorized))) |
217 | 343 |
|
218 |
- (multiple-value-bind (tag) |
|
344 |
+ (multiple-value-bind (tag cmd count extra comment) |
|
219 | 345 |
(get-and-parse-from-imap-server imap) |
346 |
+ (declare (ignore cmd count extra)) |
|
220 | 347 |
(if* (not (eq :untagged tag)) |
221 |
- then (error "unexpected line from server after connect"))) |
|
348 |
+ then (po-error :error-response |
|
349 |
+ :server-string comment))) |
|
222 | 350 |
|
223 | 351 |
; now login |
224 | 352 |
(send-command-get-results imap |
225 | 353 |
(format nil "login ~a ~a" user password) |
226 | 354 |
#'handle-untagged-response |
227 |
- #'(lambda (mb command count extra) |
|
355 |
+ #'(lambda (mb command count extra comment) |
|
228 | 356 |
(check-for-success mb command count extra |
357 |
+ comment |
|
229 | 358 |
"login"))) |
230 | 359 |
|
231 | 360 |
; find the separator character |
... | ... |
@@ -253,8 +382,9 @@ |
253 | 382 |
#'(lambda (mb command count extra) |
254 | 383 |
(declare (ignore mb command count extra)) |
255 | 384 |
nil) |
256 |
- #'(lambda (mb command count extra) |
|
385 |
+ #'(lambda (mb command count extra comment) |
|
257 | 386 |
(check-for-success mb command count extra |
387 |
+ comment |
|
258 | 388 |
"logout"))))) |
259 | 389 |
(setf (post-office-socket mb) nil) |
260 | 390 |
(if* sock then (ignore-errors (close sock))) |
... | ... |
@@ -289,7 +419,9 @@ |
289 | 419 |
(multiple-value-bind (result) |
290 | 420 |
(get-and-parse-from-pop-server pop) |
291 | 421 |
(if* (not (eq :ok result)) |
292 |
- then (error "unexpected line from server after connect"))) |
|
422 |
+ then (po-error :error-response |
|
423 |
+ :format-control |
|
424 |
+ "unexpected line from server after connect"))) |
|
293 | 425 |
|
294 | 426 |
; now login |
295 | 427 |
(send-pop-command-get-results pop (format nil "user ~a" user)) |
... | ... |
@@ -318,12 +450,12 @@ |
318 | 450 |
"~a ~a~a" tag command *crlf*) |
319 | 451 |
(force-output)) |
320 | 452 |
(loop |
321 |
- (multiple-value-bind (got-tag cmd count extra) |
|
453 |
+ (multiple-value-bind (got-tag cmd count extra comment) |
|
322 | 454 |
(get-and-parse-from-imap-server mb) |
323 | 455 |
(if* (eq got-tag :untagged) |
324 |
- then (funcall untagged-handler mb cmd count extra) |
|
456 |
+ then (funcall untagged-handler mb cmd count extra comment) |
|
325 | 457 |
elseif (equal tag got-tag) |
326 |
- then (funcall tagged-handler mb cmd count extra) |
|
458 |
+ then (funcall tagged-handler mb cmd count extra comment) |
|
327 | 459 |
(return) |
328 | 460 |
else (warn "received tag ~s out of order" got-tag)))))) |
329 | 461 |
|
... | ... |
@@ -335,7 +467,7 @@ |
335 | 467 |
else (setq *cur-imap-tags* *imap-tags*) |
336 | 468 |
(pop *cur-imap-tags*)))) |
337 | 469 |
|
338 |
-(defun handle-untagged-response (mb command count extra) |
|
470 |
+(defun handle-untagged-response (mb command count extra comment) |
|
339 | 471 |
;; default function to handle untagged responses, which are |
340 | 472 |
;; really just returning general state information about |
341 | 473 |
;; the mailbox |
... | ... |
@@ -345,9 +477,10 @@ |
345 | 477 |
(:flags (setf (mailbox-flags mb) (mapcar #'kwd-intern extra))) |
346 | 478 |
(:bye ; occurs when connection times out or mailbox lock is stolen |
347 | 479 |
(ignore-errors (close (post-office-socket mb))) |
348 |
- (error "connection to the imap server was closed by the server")) |
|
480 |
+ (po-error :server-shutdown-connection |
|
481 |
+ :server-string "server shut down the connection")) |
|
349 | 482 |
(:no ; used when grabbing a lock from another process |
350 |
- (warn "grabbing mailbox lock from another process")) |
|
483 |
+ (po-condition :problem :server-string comment)) |
|
351 | 484 |
(:ok ; a whole variety of things |
352 | 485 |
(if* extra |
353 | 486 |
then (if* (equalp (car extra) "unseen") |
... | ... |
@@ -359,8 +492,8 @@ |
359 | 492 |
elseif (equalp (car extra) "permanentflags") |
360 | 493 |
then (setf (mailbox-permanent-flags mb) |
361 | 494 |
(mapcar #'kwd-intern (cadr extra))) |
362 |
- else (warn "unknown ok response ~s" extra)))) |
|
363 |
- (t (warn "unknown untagged response ~a ~a" command extra))) |
|
495 |
+ else (po-condition :unknown-ok :server-string comment)))) |
|
496 |
+ (t (po-condition :unknown-untagged :server-string comment))) |
|
364 | 497 |
|
365 | 498 |
) |
366 | 499 |
|
... | ... |
@@ -378,7 +511,8 @@ |
378 | 511 |
(multiple-value-bind (result parsed line) |
379 | 512 |
(get-and-parse-from-pop-server pop) |
380 | 513 |
(if* (not (eq result :ok)) |
381 |
- then (error "error from pop server: ~a" line)) |
|
514 |
+ then (po-error :error-response |
|
515 |
+ :server-string line)) |
|
382 | 516 |
|
383 | 517 |
(if* extrap |
384 | 518 |
then ; get the rest of the data |
... | ... |
@@ -393,13 +527,17 @@ |
393 | 527 |
(sock (post-office-socket pop))) |
394 | 528 |
(flet ((add-to-buffer (ch) |
395 | 529 |
(if* (>= pos (length buf)) |
396 |
- then (error "missinfomation from pop") |
|
530 |
+ then (po-error :unexpected |
|
531 |
+ :format-control |
|
532 |
+ "missinfomation from pop" |
|
533 |
+ :server-string line) |
|
397 | 534 |
else (setf (schar buf pos) ch) |
398 | 535 |
(incf pos)))) |
399 | 536 |
(loop |
400 | 537 |
(let ((ch (read-char sock nil nil))) |
401 | 538 |
(if* (null ch) |
402 |
- then (error "premature end of file from server")) |
|
539 |
+ then (po-error :unexpected |
|
540 |
+ :format-control "premature end of file from server")) |
|
403 | 541 |
(if* (eq ch #\return) |
404 | 542 |
thenret ; ignore crs |
405 | 543 |
else (case state |
... | ... |
@@ -441,10 +579,14 @@ |
441 | 579 |
(send-command-get-results mb |
442 | 580 |
(format nil "select ~a" name) |
443 | 581 |
#'handle-untagged-response |
444 |
- #'(lambda (mb command count extra) |
|
582 |
+ #'(lambda (mb command count extra comment) |
|
445 | 583 |
(declare (ignore mb count extra)) |
446 | 584 |
(if* (not (eq command :ok)) |
447 |
- then (error "imap mailbox select failed")))) |
|
585 |
+ then (po-error |
|
586 |
+ :problem |
|
587 |
+ :format-control |
|
588 |
+ "imap mailbox select failed" |
|
589 |
+ :server-string comment)))) |
|
448 | 590 |
(setf (mailbox-name mb) name) |
449 | 591 |
t |
450 | 592 |
) |
... | ... |
@@ -473,15 +615,17 @@ |
473 | 615 |
(message-set-string number) |
474 | 616 |
(or parts "body[]") |
475 | 617 |
) |
476 |
- #'(lambda (mb command count extra) |
|
618 |
+ #'(lambda (mb command count extra comment) |
|
477 | 619 |
(if* (eq command :fetch) |
478 | 620 |
then (push (list count (internalize-flags extra)) res) |
479 | 621 |
else (handle-untagged-response |
480 |
- mb command count extra))) |
|
481 |
- #'(lambda (mb command count extra) |
|
622 |
+ mb command count extra comment))) |
|
623 |
+ #'(lambda (mb command count extra comment) |
|
482 | 624 |
(declare (ignore mb count extra)) |
483 | 625 |
(if* (not (eq command :ok)) |
484 |
- then (error "imap mailbox fetch failed")))) |
|
626 |
+ then (po-error :problem |
|
627 |
+ :format-control "imap mailbox fetch failed" |
|
628 |
+ :server-string comment)))) |
|
485 | 629 |
res)) |
486 | 630 |
|
487 | 631 |
|
... | ... |
@@ -546,8 +690,9 @@ |
546 | 690 |
then (setq messages (list messages))) |
547 | 691 |
|
548 | 692 |
(if* (not (consp messages)) |
549 |
- then (error "expect a mesage number or list of messages, not ~s" |
|
550 |
- messages)) |
|
693 |
+ then (po-error :syntax-error |
|
694 |
+ :format-control "expect a mesage number or list of messages, not ~s" |
|
695 |
+ :format-arguments (list messages))) |
|
551 | 696 |
|
552 | 697 |
(dolist (message messages) |
553 | 698 |
(if* (numberp message) |
... | ... |
@@ -559,7 +704,9 @@ |
559 | 704 |
((> start end)) |
560 | 705 |
(send-pop-command-get-results pb |
561 | 706 |
(format nil "DELE ~d" start))) |
562 |
- else (error "bad message number ~s" message)))) |
|
707 |
+ else (po-error :syntax-error |
|
708 |
+ :format-control "bad message number ~s" |
|
709 |
+ :format-arguments (list message))))) |
|
563 | 710 |
|
564 | 711 |
|
565 | 712 |
|
... | ... |
@@ -571,9 +718,10 @@ |
571 | 718 |
(send-command-get-results mb |
572 | 719 |
"noop" |
573 | 720 |
#'handle-untagged-response |
574 |
- #'(lambda (mb command count extra) |
|
721 |
+ #'(lambda (mb command count extra comment) |
|
575 | 722 |
(check-for-success |
576 | 723 |
mb command count extra |
724 |
+ comment |
|
577 | 725 |
"noop")))) |
578 | 726 |
|
579 | 727 |
|
... | ... |
@@ -584,10 +732,13 @@ |
584 | 732 |
) |
585 | 733 |
|
586 | 734 |
|
587 |
-(defun check-for-success (mb command count extra command-string) |
|
735 |
+(defun check-for-success (mb command count extra comment command-string ) |
|
588 | 736 |
(declare (ignore mb count extra)) |
589 | 737 |
(if* (not (eq command :ok)) |
590 |
- then (error "imap ~a failed" command-string))) |
|
738 |
+ then (po-error :error-response |
|
739 |
+ :format-control "imap ~a failed" |
|
740 |
+ :format-arguments (list command-string) |
|
741 |
+ :server-string comment))) |
|
591 | 742 |
|
592 | 743 |
|
593 | 744 |
|
... | ... |
@@ -598,14 +749,16 @@ |
598 | 749 |
(let (res) |
599 | 750 |
(send-command-get-results mb |
600 | 751 |
(format nil "list ~s ~s" reference pattern) |
601 |
- #'(lambda (mb command count extra) |
|
752 |
+ #'(lambda (mb command count extra comment) |
|
602 | 753 |
(if* (eq command :list) |
603 | 754 |
then (push extra res) |
604 | 755 |
else (handle-untagged-response |
605 |
- mb command count extra))) |
|
606 |
- #'(lambda (mb command count extra) |
|
756 |
+ mb command count extra |
|
757 |
+ comment))) |
|
758 |
+ #'(lambda (mb command count extra comment) |
|
607 | 759 |
(check-for-success |
608 |
- mb command count extra "list"))) |
|
760 |
+ mb command count extra |
|
761 |
+ comment "list"))) |
|
609 | 762 |
|
610 | 763 |
;; the car of each list is a set of keywords, make that so |
611 | 764 |
(dolist (rr res) |
... | ... |
@@ -623,9 +776,10 @@ |
623 | 776 |
(send-command-get-results mb |
624 | 777 |
(format nil "create ~s" mailbox-name) |
625 | 778 |
#'handle-untagged-response |
626 |
- #'(lambda (mb command count extra) |
|
779 |
+ #'(lambda (mb command count extra comment) |
|
627 | 780 |
(check-for-success |
628 |
- mb command count extra "create"))) |
|
781 |
+ mb command count extra |
|
782 |
+ comment "create"))) |
|
629 | 783 |
t) |
630 | 784 |
|
631 | 785 |
|
... | ... |
@@ -635,9 +789,10 @@ |
635 | 789 |
(send-command-get-results mb |
636 | 790 |
(format nil "delete ~s" mailbox-name) |
637 | 791 |
#'handle-untagged-response |
638 |
- #'(lambda (mb command count extra) |
|
792 |
+ #'(lambda (mb command count extra comment) |
|
639 | 793 |
(check-for-success |
640 |
- mb command count extra "delete")))) |
|
794 |
+ mb command count extra |
|
795 |
+ comment "delete")))) |
|
641 | 796 |
|
642 | 797 |
(defmethod rename-mailbox ((mb imap-mailbox) old-mailbox-name new-mailbox-name) |
643 | 798 |
;; create a mailbox name of the given name. |
... | ... |
@@ -647,9 +802,11 @@ |
647 | 802 |
old-mailbox-name |
648 | 803 |
new-mailbox-name) |
649 | 804 |
#'handle-untagged-response |
650 |
- #'(lambda (mb command count extra) |
|
805 |
+ #'(lambda (mb command count extra comment) |
|
651 | 806 |
(check-for-success |
652 |
- mb command count extra "rename")))) |
|
807 |
+ mb command count extra |
|
808 |
+ comment |
|
809 |
+ "rename")))) |
|
653 | 810 |
|
654 | 811 |
|
655 | 812 |
|
... | ... |
@@ -682,18 +839,20 @@ |
682 | 839 |
(if* val |
683 | 840 |
thenret |
684 | 841 |
else "()")) |
685 |
- #'(lambda (mb command count extra) |
|
842 |
+ #'(lambda (mb command count extra comment) |
|
686 | 843 |
(if* (eq command :fetch) |
687 | 844 |
then (push (list count |
688 | 845 |
(convert-flags-plist |
689 | 846 |
extra)) |
690 | 847 |
res) |
691 | 848 |
else (handle-untagged-response |
692 |
- mb command count extra))) |
|
849 |
+ mb command count extra |
|
850 |
+ comment))) |
|
693 | 851 |
|
694 |
- #'(lambda (mb command count extra) |
|
852 |
+ #'(lambda (mb command count extra comment) |
|
695 | 853 |
(check-for-success |
696 |
- mb command count extra "store"))) |
|
854 |
+ mb command count extra |
|
855 |
+ comment "store"))) |
|
697 | 856 |
res)) |
698 | 857 |
|
699 | 858 |
|
... | ... |
@@ -715,7 +874,9 @@ |
715 | 874 |
elseif (eq :seq (car msg)) |
716 | 875 |
then (format str |
717 | 876 |
"~a:~a" (cadr msg) (caddr msg)) |
718 |
- else (error "bad message list ~s" msg)) |
|
877 |
+ else (po-error :syntax-error |
|
878 |
+ :format-control "bad message list ~s" |
|
879 |
+ :format-arguments (list msg))) |
|
719 | 880 |
(setq precomma t)) |
720 | 881 |
(get-output-stream-string str))))) |
721 | 882 |
|
... | ... |
@@ -729,14 +890,17 @@ |
729 | 890 |
(let (res) |
730 | 891 |
(send-command-get-results mb |
731 | 892 |
"expunge" |
732 |
- #'(lambda (mb command count extra) |
|
893 |
+ #'(lambda (mb command count extra |
|
894 |
+ comment) |
|
733 | 895 |
(if* (eq command :expunge) |
734 | 896 |
then (push count res) |
735 | 897 |
else (handle-untagged-response |
736 |
- mb command count extra))) |
|
737 |
- #'(lambda (mb command count extra) |
|
898 |
+ mb command count extra |
|
899 |
+ comment))) |
|
900 |
+ #'(lambda (mb command count extra comment) |
|
738 | 901 |
(check-for-success |
739 |
- mb command count extra "expunge"))) |
|
902 |
+ mb command count extra |
|
903 |
+ comment "expunge"))) |
|
740 | 904 |
(nreverse res))) |
741 | 905 |
|
742 | 906 |
|
... | ... |
@@ -747,9 +911,10 @@ |
747 | 911 |
"close" |
748 | 912 |
#'handle-untagged-response |
749 | 913 |
|
750 |
- #'(lambda (mb command count extra) |
|
914 |
+ #'(lambda (mb command count extra comment) |
|
751 | 915 |
(check-for-success |
752 |
- mb command count extra "close"))) |
|
916 |
+ mb command count extra |
|
917 |
+ comment "close"))) |
|
753 | 918 |
t) |
754 | 919 |
|
755 | 920 |
|
... | ... |
@@ -762,9 +927,10 @@ |
762 | 927 |
(message-set-string message-list) |
763 | 928 |
destination) |
764 | 929 |
#'handle-untagged-response |
765 |
- #'(lambda (mb command count extra) |
|
930 |
+ #'(lambda (mb command count extra comment) |
|
766 | 931 |
(check-for-success |
767 |
- mb command count extra "copy"))) |
|
932 |
+ mb command count extra |
|
933 |
+ comment "copy"))) |
|
768 | 934 |
t) |
769 | 935 |
|
770 | 936 |
|
... | ... |
@@ -776,14 +942,16 @@ |
776 | 942 |
(format nil "~asearch ~a" |
777 | 943 |
(if* uid then "uid " else "") |
778 | 944 |
(build-search-string search-expression)) |
779 |
- #'(lambda (mb command count extra) |
|
945 |
+ #'(lambda (mb command count extra comment) |
|
780 | 946 |
(if* (eq command :search) |
781 | 947 |
then (setq res (append res extra)) |
782 | 948 |
else (handle-untagged-response |
783 |
- mb command count extra))) |
|
784 |
- #'(lambda (mb command count extra) |
|
949 |
+ mb command count extra |
|
950 |
+ comment))) |
|
951 |
+ #'(lambda (mb command count extra comment) |
|
785 | 952 |
(check-for-success |
786 |
- mb command count extra "search"))) |
|
953 |
+ mb command count extra |
|
954 |
+ comment "search"))) |
|
787 | 955 |
res)) |
788 | 956 |
|
789 | 957 |
|
... | ... |
@@ -877,7 +1045,9 @@ |
877 | 1045 |
(eq :seq (car val)) |
878 | 1046 |
(eq 3 (length val))) |
879 | 1047 |
then (format str "~s:~s" (cadr val) (caddr val)) |
880 |
- else (error "illegal set format ~s" val)) |
|
1048 |
+ else (po-error :syntax-error |
|
1049 |
+ :format-control "illegal set format ~s" |
|
1050 |
+ :format-arguments (list val))) |
|
881 | 1051 |
(if* (cdr xsrch) then (format str ",")))) |
882 | 1052 |
(arg-process (str args arginfo) |
883 | 1053 |
;; process and print each arg to str |
... | ... |
@@ -896,14 +1066,17 @@ |
896 | 1066 |
then (setq val (universal-time-to-rfc822-date |
897 | 1067 |
val)) |
898 | 1068 |
elseif (not (stringp val)) |
899 |
- then (error "illegal value for date search ~s" |
|
900 |
- val)) |
|
1069 |
+ then (po-error :syntax-error |
|
1070 |
+ :format-control "illegal value for date search ~s" |
|
1071 |
+ :format-arguments (list val))) |
|
901 | 1072 |
;; val is now a string |
902 | 1073 |
(format str " ~s" val)) |
903 | 1074 |
(:number |
904 | 1075 |
|
905 | 1076 |
(if* (not (integerp val)) |
906 |
- then (error "illegal value for number in search ~s" val)) |
|
1077 |
+ then (po-error :syntax-error |
|
1078 |
+ :format-control "illegal value for number in search ~s" |
|
1079 |
+ :format-arguments (list val))) |
|
907 | 1080 |
(format str " ~s" val)) |
908 | 1081 |
(:flag |
909 | 1082 |
|
... | ... |
@@ -915,15 +1088,19 @@ |
915 | 1088 |
then (format str " ~s" val) |
916 | 1089 |
elseif (consp val) |
917 | 1090 |
then (set-ify val str) |
918 |
- else (error "illegal message set ~s" val))) |
|
1091 |
+ else (po-error :syntax-error |
|
1092 |
+ :format-control "illegal message set ~s" |
|
1093 |
+ :format-arguments (list val)))) |
|
919 | 1094 |
|
920 | 1095 |
)))) |
921 | 1096 |
|
922 | 1097 |
(if* (symbolp search) |
923 | 1098 |
then (if* (get search 'imap-search-no-args) |
924 | 1099 |
then (format str "~a" (string-upcase |
925 |
- (string search))) |
|
926 |
- else (error "illegal search word: ~s" search)) |
|
1100 |
+ (string search))) |
|
1101 |
+ else (po-error :syntax-error |
|
1102 |
+ :format-control "illegal search word: ~s" |
|
1103 |
+ :format-arguments (list search))) |
|
927 | 1104 |
elseif (consp search) |
928 | 1105 |
then (case (car search) |
929 | 1106 |
(and (if* (null (cdr search)) |
... | ... |
@@ -937,7 +1114,9 @@ |
937 | 1114 |
then (bss-int (cadr search) str) |
938 | 1115 |
else (or-ify (cdr search) str))) |
939 | 1116 |
(not (if* (not (eql (length search) 2)) |
940 |
- then (error "not takes one argument: ~s" search)) |
|
1117 |
+ then (po-error :syntax-error |
|
1118 |
+ :format-control "not takes one argument: ~s" |
|
1119 |
+ :format-arguments (list search))) |
|
941 | 1120 |
(format str "not (" ) |
942 | 1121 |
(bss-int (cadr search) str) |
943 | 1122 |
(format str ")")) |
... | ... |
@@ -949,20 +1128,26 @@ |
949 | 1128 |
'imap-search-args))) |
950 | 1129 |
then |
951 | 1130 |
(format str "~a" (string-upcase |
952 |
- (string (car search)))) |
|
1131 |
+ (string (car search)))) |
|
953 | 1132 |
(if* (not (equal (length (cdr search)) |
954 | 1133 |
(length arginfo))) |
955 |
- then (error "wrong number of arguments to ~s" search)) |
|
1134 |
+ then (po-error :syntax-error |
|
1135 |
+ :format-control "wrong number of arguments to ~s" |
|
1136 |
+ :format-arguments search)) |
|
956 | 1137 |
|
957 | 1138 |
(arg-process str (cdr search) arginfo) |
958 | 1139 |
|
959 | 1140 |
elseif (integerp (car search)) |
960 | 1141 |
then (set-ify search str) |
961 |
- else (error "Illegal form ~s in search string" search))))) |
|
1142 |
+ else (po-error :syntax-error |
|
1143 |
+ :format-control "Illegal form ~s in search string" |
|
1144 |
+ :format-arguments (list search)))))) |
|
962 | 1145 |
elseif (integerp search) |
963 | 1146 |
then ; a message number |
964 | 1147 |
(format str "~s" search) |
965 |
- else (error "Illegal form ~s in search string" search)))) |
|
1148 |
+ else (po-error :syntax-error |
|
1149 |
+ :format-control "Illegal form ~s in search string" |
|
1150 |
+ :format-arguments (list search))))) |
|
966 | 1151 |
|
967 | 1152 |
|
968 | 1153 |
|
... | ... |
@@ -1013,10 +1198,12 @@ |
1013 | 1198 |
;; bracketted - a list of objects found in []'s after the command |
1014 | 1199 |
;; or in ()'s after the command or sometimes just |
1015 | 1200 |
;; out in the open after the command (like the search) |
1201 |
+;; comment -- the whole of the part after the command |
|
1016 | 1202 |
;; |
1017 | 1203 |
(defun parse-imap-response (line end) |
1018 | 1204 |
(let (kind value next |
1019 |
- tag count command extra-data) |
|
1205 |
+ tag count command extra-data |
|
1206 |
+ comment) |
|
1020 | 1207 |
|
1021 | 1208 |
;; get tag |
1022 | 1209 |
(multiple-value-setq (kind value next) |
... | ... |
@@ -1026,7 +1213,11 @@ |
1026 | 1213 |
(:string (setq tag (if* (equal value "*") |
1027 | 1214 |
then :untagged |
1028 | 1215 |
else value))) |
1029 |
- (t (error "Illegal tag on response: ~s" (subseq line 0 count)))) |
|
1216 |
+ (t (po-error :unexpected |
|
1217 |
+ :format-control "Illegal tag on response: ~s" |
|
1218 |
+ :format-arguments (list (subseq line 0 count)) |
|
1219 |
+ :server-string (subseq line 0 end) |
|
1220 |
+ ))) |
|
1030 | 1221 |
|
1031 | 1222 |
;; get command |
1032 | 1223 |
(multiple-value-setq (kind value next) |
... | ... |
@@ -1039,8 +1230,13 @@ |
1039 | 1230 |
(get-next-token line next end)) |
1040 | 1231 |
(go again)) |
1041 | 1232 |
(:string (setq command (kwd-intern value))) |
1042 |
- (t (error "Illegal command on response: ~s" (subseq line 0 count))))) |
|
1043 |
- |
|
1233 |
+ (t (po-error :unexpected |
|
1234 |
+ :format-control "Illegal command on response: ~s" |
|
1235 |
+ :format-arguments (list (subseq line 0 count)) |
|
1236 |
+ :server-string (subseq line 0 end))))) |
|
1237 |
+ |
|
1238 |
+ (setq comment (subseq line next end)) |
|
1239 |
+ |
|
1044 | 1240 |
;; now the part after the command... this gets tricky |
1045 | 1241 |
(loop |
1046 | 1242 |
(multiple-value-setq (kind value next) |
... | ... |
@@ -1052,7 +1248,7 @@ |
1052 | 1248 |
(get-next-sexpr line (1- next) end)) |
1053 | 1249 |
(case kind |
1054 | 1250 |
(:sexpr (push value extra-data)) |
1055 |
- (t (error "bad sexpr form")))) |
|
1251 |
+ (t (po-error :syntax-error :format-control "bad sexpr form")))) |
|
1056 | 1252 |
(:eof (return nil)) |
1057 | 1253 |
((:number :string :nil) (push value extra-data)) |
1058 | 1254 |
(t ; should never happen |
... | ... |
@@ -1067,7 +1263,7 @@ |
1067 | 1263 |
then (setq extra-data (nreverse extra-data))) |
1068 | 1264 |
|
1069 | 1265 |
|
1070 |
- (values tag command count extra-data))) |
|
1266 |
+ (values tag command count extra-data comment))) |
|
1071 | 1267 |
|
1072 | 1268 |
|
1073 | 1269 |
|
... | ... |
@@ -1083,8 +1279,9 @@ |
1083 | 1279 |
|
1084 | 1280 |
(case kind |
1085 | 1281 |
((:string :number :nil) |
1086 |
- (values :sexpr value next)) |
|
1087 |
- (:eof (error "eof inside sexpr")) |
|
1282 |
+ (values :sexpr value next)) |
|
1283 |
+ (:eof (po-error :syntax-error |
|
1284 |
+ :format-control "eof inside sexpr")) |
|
1088 | 1285 |
((:lbracket :lparen) |
1089 | 1286 |
(let (res) |
1090 | 1287 |
(loop |
... | ... |
@@ -1094,10 +1291,12 @@ |
1094 | 1291 |
(:sexpr (push value res)) |
1095 | 1292 |
((:rparen :rbracket) |
1096 | 1293 |
(return (values :sexpr (nreverse res) next))) |
1097 |
- (t (error "bad sexpression")))))) |
|
1294 |
+ (t (po-error :syntax-error |
|
1295 |
+ :format-control "bad sexpression")))))) |
|
1098 | 1296 |
((:rbracket :rparen) |
1099 | 1297 |
(values kind nil next)) |
1100 |
- (t (error "bad sexpression"))))) |
|
1298 |
+ (t (po-error :syntax-error |
|
1299 |
+ :format-control "bad sexpression"))))) |
|
1101 | 1300 |
|
1102 | 1301 |
|
1103 | 1302 |
(defun parse-pop-response (line end) |
... | ... |
@@ -1114,7 +1313,9 @@ |
1114 | 1313 |
(:string (setq result (if* (equal "+OK" value) |
1115 | 1314 |
then :ok |
1116 | 1315 |
else :error))) |
1117 |
- (t (error "bad response from server: ~s" (subseq line 0 end)))) |
|
1316 |
+ (t (po-error :unexpected |
|
1317 |
+ :format-control "bad response from server" |
|
1318 |
+ :server-string (subseq line 0 end)))) |
|
1118 | 1319 |
|
1119 | 1320 |
(setq lineres (subseq line next end)) |
1120 | 1321 |
|
... | ... |
@@ -1238,13 +1439,15 @@ |
1238 | 1439 |
then ; escaping the next character |
1239 | 1440 |
(incf start) |
1240 | 1441 |
(if* (>= start end) |
1241 |
- then (error "eof in string returned")) |
|
1442 |
+ then (po-error :unexpected |
|
1443 |
+ :format-control "eof in string returned")) |
|
1242 | 1444 |
(setq ch (schar line start))) |
1243 | 1445 |
(vector-push-extend ch collector) |
1244 | 1446 |
|
1245 | 1447 |
(if* (>= start end) |
1246 | 1448 |
then ; we overran the end of the input |
1247 |
- (error "eof in string returned"))))) |
|
1449 |
+ (po-error :unexpected |
|
1450 |
+ :format-control "eof in string returned"))))) |
|
1248 | 1451 |
(:big-string |
1249 | 1452 |
;; super string... just a block of data |
1250 | 1453 |
; (format t "start is ~s kind is ~s~%" start chkind) |
... | ... |
@@ -1302,99 +1505,108 @@ |
1302 | 1505 |
(whole-count) |
1303 | 1506 |
) |
1304 | 1507 |
|
1305 |
- (flet ((grow-buffer (size) |
|
1306 |
- (let ((newbuff (get-line-buffer size))) |
|
1307 |
- (dotimes (j i) |
|
1308 |
- (setf (schar newbuff j) (schar buff j))) |
|
1309 |
- (free-line-buffer buff) |
|
1310 |
- (setq buff newbuff) |
|
1311 |
- (setq len (length buff))))) |
|
1508 |
+ (handler-case |
|
1509 |
+ (flet ((grow-buffer (size) |
|
1510 |
+ (let ((newbuff (get-line-buffer size))) |
|
1511 |
+ (dotimes (j i) |
|
1512 |
+ (setf (schar newbuff j) (schar buff j))) |
|
1513 |
+ (free-line-buffer buff) |
|
1514 |
+ (setq buff newbuff) |
|
1515 |
+ (setq len (length buff))))) |
|
1312 | 1516 |
|
1313 |
- ;; increase the buffer to at least size |
|
1314 |
- ;; this is somewhat complex to ensure that we aren't doing |
|
1315 |
- ;; buffer allocation within the with-timeout form, since |
|
1316 |
- ;; that could trigger a gc which could then cause the |
|
1317 |
- ;; with-timeout form to expire. |
|
1318 |
- (loop |
|
1517 |
+ ;; increase the buffer to at least size |
|
1518 |
+ ;; this is somewhat complex to ensure that we aren't doing |
|
1519 |
+ ;; buffer allocation within the with-timeout form, since |
|
1520 |
+ ;; that could trigger a gc which could then cause the |
|
1521 |
+ ;; with-timeout form to expire. |
|
1522 |
+ (loop |
|
1319 | 1523 |
|
1320 |
- (if* whole-count |
|
1321 |
- then ; we should now read in this may bytes and |
|
1322 |
- ; append it to this buffer |
|
1323 |
- (multiple-value-bind (ans this-count) |
|
1324 |
- (get-block-of-data-from-server mailbox whole-count) |
|
1325 |
- ; now put this data in the current buffer |
|
1326 |
- (if* (> (+ i whole-count 5) len) |
|
1327 |
- then ; grow the initial buffer |
|
1328 |
- (grow-buffer (+ i whole-count 100))) |
|
1524 |
+ (if* whole-count |
|
1525 |
+ then ; we should now read in this may bytes and |
|
1526 |
+ ; append it to this buffer |
|
1527 |
+ (multiple-value-bind (ans this-count) |
|
1528 |
+ (get-block-of-data-from-server mailbox whole-count) |
|
1529 |
+ ; now put this data in the current buffer |
|
1530 |
+ (if* (> (+ i whole-count 5) len) |
|
1531 |
+ then ; grow the initial buffer |
|
1532 |
+ (grow-buffer (+ i whole-count 100))) |
|
1329 | 1533 |
|
1330 |
- (dotimes (ind this-count) |
|
1331 |
- (setf (schar buff i) (schar ans ind)) |
|
1534 |
+ (dotimes (ind this-count) |
|
1535 |
+ (setf (schar buff i) (schar ans ind)) |
|
1536 |
+ (incf i)) |
|
1537 |
+ (setf (schar buff i) #\^b) ; end of inset string |
|
1538 |
+ (incf i) |
|
1539 |
+ (free-line-buffer ans) |
|
1540 |
+ ) |
|
1541 |
+ elseif ch |
|
1542 |
+ then ; we're growing the buffer holding the line data |
|
1543 |
+ (grow-buffer (+ len 200)) |
|
1544 |
+ (setf (schar buff i) ch) |
|
1332 | 1545 |
(incf i)) |
1333 |
- (setf (schar buff i) #\^b) ; end of inset string |
|
1334 |
- (incf i) |
|
1335 |
- (free-line-buffer ans) |
|
1336 |
- ) |
|
1337 |
- elseif ch |
|
1338 |
- then ; we're growing the buffer holding the line data |
|
1339 |
- (grow-buffer (+ len 200)) |
|
1340 |
- (setf (schar buff i) ch) |
|
1341 |
- (incf i)) |
|
1342 |
- |
|
1343 |
- (block timeout |
|
1344 |
- (mp:with-timeout ((timeout mailbox) |
|
1345 |
- (error "imap server failed to respond")) |
|
1346 |
- ;; read up to lf (lf most likely preceeded by cr) |
|
1347 |
- (loop |
|
1348 |
- (setq ch (read-char p)) |
|
1349 |
- (if* (eq #\linefeed ch) |
|
1350 |
- then ; end of line. Don't save the return |
|
1351 |
- (if* (and (> i 0) |
|
1352 |
- (eq (schar buff (1- i)) #\return)) |
|
1353 |
- then ; remove #\return, replace with newline |
|
1354 |
- (decf i) |
|
1355 |
- (setf (schar buff i) #\newline) |
|
1356 |
- ) |
|
1357 |
- ;; must check for an extended return value which |
|
1358 |
- ;; is indicated by a {nnn} at the end of the line |
|
1359 |
- (block count-check |
|
1360 |
- (let ((ind (1- i))) |
|
1361 |
- (if* (and (>= i 0) (eq (schar buff ind) #\})) |
|
1362 |
- then (let ((count 0) |
|
1363 |
- (mult 1)) |
|
1364 |
- (loop |
|
1365 |
- (decf ind) |
|
1366 |
- (if* (< ind 0) |
|
1367 |
- then ; no of the form {nnn} |
|
1368 |
- (return-from count-check)) |
|
1369 |
- (setf ch (schar buff ind)) |
|
1370 |
- (if* (eq ch #\{) |
|
1371 |
- then ; must now read that many bytes |
|
1372 |
- (setf (schar buff ind) #\^b) |
|
1373 |
- (setq whole-count count) |
|
1374 |
- (setq i (1+ ind)) |
|
1375 |
- (return-from timeout) |
|
1376 |
- elseif (<= #.(char-code #\0) |
|
1377 |
- (char-code ch) |
|
1378 |
- #.(char-code #\9)) |
|
1379 |
- then ; is a digit |
|
1380 |
- (setq count |
|
1381 |
- (+ count |
|
1382 |
- (* mult |
|
1383 |
- (- (char-code ch) |
|
1384 |
- #.(char-code #\0))))) |
|
1385 |
- (setq mult (* 10 mult)) |
|
1386 |
- else ; invalid form, get out |
|
1387 |
- (return-from count-check))))))) |
|
1546 |
+ |
|
1547 |
+ (block timeout |
|
1548 |
+ (mp:with-timeout ((timeout mailbox) |
|
1549 |
+ (po-error :timeout |
|
1550 |
+ :format-control "imap server failed to respond")) |
|
1551 |
+ ;; read up to lf (lf most likely preceeded by cr) |
|
1552 |
+ (loop |
|
1553 |
+ (setq ch (read-char p)) |
|
1554 |
+ (if* (eq #\linefeed ch) |
|
1555 |
+ then ; end of line. Don't save the return |
|
1556 |
+ (if* (and (> i 0) |
|
1557 |
+ (eq (schar buff (1- i)) #\return)) |
|
1558 |
+ then ; remove #\return, replace with newline |
|
1559 |
+ (decf i) |
|
1560 |
+ (setf (schar buff i) #\newline) |
|
1561 |
+ ) |
|
1562 |
+ ;; must check for an extended return value which |
|
1563 |
+ ;; is indicated by a {nnn} at the end of the line |
|
1564 |
+ (block count-check |
|
1565 |
+ (let ((ind (1- i))) |
|
1566 |
+ (if* (and (>= i 0) (eq (schar buff ind) #\})) |
|
1567 |
+ then (let ((count 0) |
|
1568 |
+ (mult 1)) |
|
1569 |
+ (loop |
|
1570 |
+ (decf ind) |
|
1571 |
+ (if* (< ind 0) |
|
1572 |
+ then ; no of the form {nnn} |
|
1573 |
+ (return-from count-check)) |
|
1574 |
+ (setf ch (schar buff ind)) |
|
1575 |
+ (if* (eq ch #\{) |
|
1576 |
+ then ; must now read that many bytes |
|
1577 |
+ (setf (schar buff ind) #\^b) |
|
1578 |
+ (setq whole-count count) |
|
1579 |
+ (setq i (1+ ind)) |
|
1580 |
+ (return-from timeout) |
|
1581 |
+ elseif (<= #.(char-code #\0) |
|
1582 |
+ (char-code ch) |
|
1583 |
+ #.(char-code #\9)) |
|
1584 |
+ then ; is a digit |
|
1585 |
+ (setq count |
|
1586 |
+ (+ count |
|
1587 |
+ (* mult |
|
1588 |
+ (- (char-code ch) |
|
1589 |
+ #.(char-code #\0))))) |
|
1590 |
+ (setq mult (* 10 mult)) |
|
1591 |
+ else ; invalid form, get out |
|
1592 |
+ (return-from count-check))))))) |
|
1388 | 1593 |
|
1389 | 1594 |
|
1390 |
- (return-from get-line-from-server |
|
1391 |
- (values buff i)) |
|
1392 |
- else ; save character |
|
1393 |
- (if* (>= i len) |
|
1394 |
- then ; need bigger buffer |
|
1395 |
- (return)) |
|
1396 |
- (setf (schar buff i) ch) |
|
1397 |
- (incf i))))))))) |
|
1595 |
+ (return-from get-line-from-server |
|
1596 |
+ (values buff i)) |
|
1597 |
+ else ; save character |
|
1598 |
+ (if* (>= i len) |
|
1599 |
+ then ; need bigger buffer |
|
1600 |
+ (return)) |
|
1601 |
+ (setf (schar buff i) ch) |
|
1602 |
+ (incf i))))))) |
|
1603 |
+ (error (con) |
|
1604 |
+ ;; most likely error is that the server went away |
|
1605 |
+ (ignore-errors (close p)) |
|
1606 |
+ (po-error :server-shutdown-connection |
|
1607 |
+ :format-control "condition signalled: ~a~%most likely server shut down the connection." |
|
1608 |
+ :format-arguments (list con))) |
|
1609 |
+ ))) |
|
1398 | 1610 |
|
1399 | 1611 |
|
1400 | 1612 |
(defun get-block-of-data-from-server (mb count &key save-returns) |
... | ... |
@@ -1407,7 +1619,8 @@ |
1407 | 1619 |
(p (post-office-socket mb)) |
1408 | 1620 |
(ind 0)) |
1409 | 1621 |
(mp:with-timeout ((timeout mb) |
1410 |
- (error "imap server timed out")) |
|
1622 |
+ (po-error :timeout |
|
1623 |
+ :format-control "imap server timed out")) |
|
1411 | 1624 |
|
1412 | 1625 |
(dotimes (i count) |
1413 | 1626 |
(if* (eq #\return (setf (schar buff ind) (read-char p))) |
... | ... |
@@ -27,6 +27,9 @@ interface.</p> |
27 | 27 |
</li> |
28 | 28 |
<li><p align="left"><a href="#pop">the <strong>pop</strong> interface</a></p> |
29 | 29 |
</li> |
30 |
+ <li><p align="left"><a href="#conditions">the <strong>conditions</strong> signaled by the <strong>imap</strong> |
|
31 |
+ and <strong>pop</strong> interfaces.</a></p> |
|
32 |
+ </li> |
|
30 | 33 |
<li><p align="left"><a href="#smtp">the <strong>smtp</strong> interface</a> (used for |
31 | 34 |
sending mail)</p> |
32 | 35 |
</li> |
... | ... |
@@ -314,6 +317,18 @@ this command has finished there is no currently selected mailbox.</p> |
314 | 317 |
|
315 | 318 |
<p align="left"> </p> |
316 | 319 |
|
320 |
+<p align="left"><strong><font face="Courier New">(copy-to-mailbox mailbox messages |
|
321 |
+destination &key uid)</font></strong></p> |
|
322 |
+ |
|
323 |
+<p align="left">copies the specified <strong>messages </strong>from the currently selected |
|
324 |
+mailbox to the mailbox named <strong>destination</strong> (given as a string). The |
|
325 |
+flags are copied as well. The destination mailbox must already exist. The messages |
|
326 |
+are <strong>not</strong> removed from the selected mailbox after the copy .If <strong>uid</strong> |
|
327 |
+is true then the <strong>messages</strong> are considered to be unique ids rather than |
|
328 |
+message sequence numbers. </p> |
|
329 |
+ |
|
330 |
+<p align="left"> </p> |
|
331 |
+ |
|
317 | 332 |
<p align="left"><font face="Courier New"><strong>(delete-letter mailbox messages &key |
318 | 333 |
expunge uid</strong></font>)</p> |
319 | 334 |
|
... | ... |
@@ -408,7 +423,7 @@ this can be check using <strong>mailbox-message-count</strong>.   |
408 | 423 |
|
409 | 424 |
<p align="left"> </p> |
410 | 425 |
|
411 |
-<p align="left"><font face="Courier New"><strong>(search-mailbox search-expression |
|
426 |
+<p align="left"><font face="Courier New"><strong>(search-mailbox mailbox search-expression |
|
412 | 427 |
&key uid)</strong></font></p> |
413 | 428 |
|
414 | 429 |
<p align="left">return a list of messages in the mailbox that satisfy the<strong> |
... | ... |
@@ -830,7 +845,7 @@ t |
830 | 845 |
|
831 | 846 |
<h1><a name="pop"></a>The Pop interface</h1> |
832 | 847 |
|
833 |
-<p>The <strong>pop</strong> protocol is a very simple means for retreiving messages from a |
|
848 |
+<p>The <strong>pop</strong> protocol is a very simple means for retrieving messages from a |
|
834 | 849 |
single mailbox. The functions in the interface are:</p> |
835 | 850 |
|
836 | 851 |
<p> </p> |
... | ... |
@@ -897,6 +912,109 @@ will contain the current count of messages in the mailbox.</p> |
897 | 912 |
|
898 | 913 |
<p> </p> |
899 | 914 |
|
915 |
+<h1>Cond<a name="conditions"></a>itions</h1> |
|
916 |
+ |
|
917 |
+<p>When an unexpected event occurs a condition is signaled. This applies to |
|
918 |
+both the <strong>imap</strong> and <strong>pop</strong> interfaces. There are two |
|
919 |
+classes of conditions signaled by this package: |
|
920 |
+ |
|
921 |
+<ul> |
|
922 |
+ <li><strong>po-condition</strong> - this class denotes conditions that need not and in fact |
|
923 |
+ should not interrupt program flow. When the mailbox server is responding to a |
|
924 |
+ command it sometimes sends informational warning messages and we turn them into |
|
925 |
+ conditions. It's important for all messages from the server to be read |
|
926 |
+ and processed otherwise the next command issued will see messages in response to the |
|
927 |
+ previous command. Therefore the user code should never do a non-local-transfer |
|
928 |
+ in response to a <strong>po-condition.</strong></li> |
|
929 |
+ <li><strong>po-error - </strong> this class denotes conditions that will prevent execution |
|
930 |
+ from continuing. If one of these errors is not caught, the interactive debugger will |
|
931 |
+ be entered.</li> |
|
932 |
+</ul> |
|
933 |
+ |
|
934 |
+<p>Instances of both of these condition classes have these slots in addition to the |
|
935 |
+standard condition slots: </p> |
|
936 |
+ |
|
937 |
+<table border="1" width="100%"> |
|
938 |
+ <tr> |
|
939 |
+ <td width="16%">Name</td> |
|
940 |
+ <td width="24%">Accessor</td> |
|
941 |
+ <td width="60%">Value</td> |
|
942 |
+ </tr> |
|
943 |
+ <tr> |
|
944 |
+ <td width="16%">identifier</td> |
|
945 |
+ <td width="24%">po-condition-identifier</td> |
|
946 |
+ <td width="60%">keyword describing the kind of condition being signaled. See the |
|
947 |
+ table below for the possible values.</td> |
|
948 |
+ </tr> |
|
949 |
+ <tr> |
|
950 |
+ <td width="16%">server-string</td> |
|
951 |
+ <td width="24%">po-condition-server-string</td> |
|
952 |
+ <td width="60%">If the condition was created because of a messages sent from the mailbox |
|
953 |
+ server then this is that message.</td> |
|
954 |
+ </tr> |
|
955 |
+</table> |
|
956 |
+ |
|
957 |
+<p>The meaning of the identifier value is as follows</p> |
|
958 |
+ |
|
959 |
+<table border="1" width="100%"> |
|
960 |
+ <tr> |
|
961 |
+ <td width="11%"><strong>Identifier</strong></td> |
|
962 |
+ <td width="13%">Kind</td> |
|
963 |
+ <td width="76%">Meaning</td> |
|
964 |
+ </tr> |
|
965 |
+ <tr> |
|
966 |
+ <td width="11%"><strong>:problem</strong></td> |
|
967 |
+ <td width="13%">po-condition</td> |
|
968 |
+ <td width="76%">The server has responded with a warning message. The most |
|
969 |
+ likely warning is that the mailbox can only be opened in read-only mode due to another |
|
970 |
+ processing using it.</td> |
|
971 |
+ </tr> |
|
972 |
+ <tr> |
|
973 |
+ <td width="11%"><strong>:unknown-ok</strong></td> |
|
974 |
+ <td width="13%">po-condition</td> |
|
975 |
+ <td width="76%">The server has sent an informative message that we don't understand. |
|
976 |
+ It's probably safe to ignore this.</td> |
|
977 |
+ </tr> |
|
978 |
+ <tr> |
|
979 |
+ <td width="11%"><strong>:unknown-untagged</strong></td> |
|
980 |
+ <td width="13%">po-condition</td> |
|
981 |
+ <td width="76%">The server has sent an informative message that we don't understand. |
|
982 |
+ It's probably safe to ignore this.</td> |
|
983 |
+ </tr> |
|
984 |
+ <tr> |
|
985 |
+ <td width="11%"><strong>:error-response</strong></td> |
|
986 |
+ <td width="13%">po-error</td> |
|
987 |
+ <td width="76%">The server cannot execute the requested command.</td> |
|
988 |
+ </tr> |
|
989 |
+ <tr> |
|
990 |
+ <td width="11%"><strong>:syntax-error</strong></td> |
|
991 |
+ <td width="13%">po-error</td> |
|
992 |
+ <td width="76%">The arguments to a function in this package are malformed.</td> |
|
993 |
+ </tr> |
|
994 |
+ <tr> |
|
995 |
+ <td width="11%"><strong>:unexpected</strong></td> |
|
996 |
+ <td width="13%">po-error</td> |
|
997 |
+ <td width="76%">The server has responded a way we don't understand and which prevents us |
|
998 |
+ from continuing</td> |
|
999 |
+ </tr> |
|
1000 |
+ <tr> |
|
1001 |
+ <td width="11%"><strong>:server-shutdown-connection</strong></td> |
|
1002 |
+ <td width="13%">po-error</td> |
|
1003 |
+ <td width="76%">The connection to the server has been broken. This usually occurs |
|
1004 |
+ when the connection has been idle for too long and the server intentionally disconnects. |
|
1005 |
+ Just before this condition is signaled we close down the socket connection to |
|
1006 |
+ free up the socket resource on our side. When this condition is signaled the user |
|
1007 |
+ program should not use the mailbox object again (even to call <strong>close-connection</strong> |
|
1008 |
+ on it).</td> |
|
1009 |
+ </tr> |
|
1010 |
+ <tr> |
|
1011 |
+ <td width="11%"><strong>:timeout</strong></td> |
|
1012 |
+ <td width="13%">po-error</td> |
|
1013 |
+ <td width="76%">The server did not respond quickly enough. The timeout value |
|
1014 |
+ is set in the call to <strong>make-imap-connection.</strong></td> |
|
1015 |
+ </tr> |
|
1016 |
+</table> |
|
1017 |
+ |
|
900 | 1018 |
<h1><a name="smtp"></a>The smtp interface</h1> |
901 | 1019 |
|
902 | 1020 |
<p>With the smtp interface, a Lisp program can contact a mail server and send electronic |
... | ... |
@@ -184,10 +184,10 @@ |
184 | 184 |
|
185 | 185 |
(test-eql 2 (and :third (po:mailbox-message-count pb))) |
186 | 186 |
|
187 |
- (po:fetch-letter mb 1) |
|
188 |
- (test-err (po:fetch-letter mb 2)) |
|
189 |
- (test-err (po:fetch-letter mb 3)) |
|
190 |
- (po:fetch-letter mb 4) |
|
187 |
+ (po:fetch-letter pb 1) |
|
188 |
+ (test-err (po:fetch-letter pb 2)) |
|
189 |
+ (test-err (po:fetch-letter pb 3)) |
|
190 |
+ (po:fetch-letter pb 4) |
|
191 | 191 |
|
192 | 192 |
(po:close-connection pb) |
193 | 193 |
|
... | ... |
@@ -204,18 +204,22 @@ |
204 | 204 |
|
205 | 205 |
|
206 | 206 |
(defun test-imap () |
207 |
- (test-connect) |
|
207 |
+ (handler-bind ((po:po-condition |
|
208 |
+ #'(lambda (con) |
|
209 |
+ (format t "Got imap condition: ~a~%" con)))) |
|
210 |
+ |
|
211 |
+ (test-connect) |
|
208 | 212 |
|
209 |
- (test-sends) |
|
213 |
+ (test-sends) |
|
210 | 214 |
|
211 |
- (test-flags) |
|
215 |
+ (test-flags) |
|
212 | 216 |
|
213 |
- (test-mailboxes) |
|
217 |
+ (test-mailboxes) |
|
214 | 218 |
|
215 |
- (test-pop) |
|
219 |
+ (test-pop) |
|
216 | 220 |
|
217 | 221 |
|
218 |
- ) |
|
222 |
+ )) |
|
219 | 223 |
|
220 | 224 |
|
221 | 225 |
(if* *do-test* then (do-test :imap #'test-imap)) |