Sync with Oort Gnus (Translating gnus-ja.texi has not been done yet).
[elisp/gnus.git-] / lisp / imap.el
index ec2585b..1079cd2 100644 (file)
@@ -44,7 +44,7 @@
 ;;
 ;; Mailbox commands:
 ;;
-;; imap-mailbox-get,       imap-mailbox-map,         imap-current-mailbox, 
+;; imap-mailbox-get,       imap-mailbox-map,         imap-current-mailbox,
 ;; imap-current-mailbox-p, imap-search,              imap-mailbox-select,
 ;; imap-mailbox-examine,   imap-mailbox-unselect,    imap-mailbox-expunge
 ;; imap-mailbox-close,     imap-mailbox-create,      imap-mailbox-delete
@@ -57,7 +57,7 @@
 ;; imap-fetch-asynch,                 imap-fetch,
 ;; imap-current-message,              imap-list-to-message-set,
 ;; imap-message-get,                  imap-message-map
-;; imap-message-envelope-date,        imap-message-envelope-subject, 
+;; imap-message-envelope-date,        imap-message-envelope-subject,
 ;; imap-message-envelope-from,        imap-message-envelope-sender,
 ;; imap-message-envelope-reply-to,    imap-message-envelope-to,
 ;; imap-message-envelope-cc,          imap-message-envelope-bcc
 ;; => "X-Sieve: cmu-sieve 1.3^M\nX-Username: <jas@pdc.kth.se>^M\r...."
 ;;
 ;; Todo:
-;; 
+;;
 ;; o Parse UIDs as strings? We need to overcome the 28 bit limit somehow.
 ;; o Don't use `read' at all (important places already fixed)
 ;; o Accept list of articles instead of message set string in most
@@ -187,10 +187,10 @@ the list is tried until a successful connection is made."
   :group 'imap
   :type '(repeat string))
 
-(defcustom imap-ssl-program '("openssl s_client -ssl3 -connect %s:%p"
-                             "openssl s_client -ssl2 -connect %s:%p"
-                             "s_client -ssl3 -connect %s:%p"
-                             "s_client -ssl2 -connect %s:%p")
+(defcustom imap-ssl-program '("openssl s_client -quiet -ssl3 -connect %s:%p"
+                             "openssl s_client -quiet -ssl2 -connect %s:%p"
+                             "s_client -quiet -ssl3 -connect %s:%p"
+                             "s_client -quiet -ssl2 -connect %s:%p")
   "A string, or list of strings, containing commands for SSL connections.
 Within a string, %s is replaced with the server address and %p with
 port number on server.  The program should accept IMAP commands on
@@ -213,6 +213,11 @@ until a successful connection is made."
   :group 'imap
   :type '(repeat string))
 
+(defcustom imap-process-connection-type nil
+  "*Value for `process-connection-type' to use for Kerberos4 and GSSAPI."
+  :group 'imap
+  :type 'boolean)
+
 (defvar imap-shell-host "gateway"
   "Hostname of rlogin proxy.")
 
@@ -245,7 +250,7 @@ NAME names the stream, CHECK is a function returning non-nil if the
 server support the stream and OPEN is a function for opening the
 stream.")
 
-(defvar imap-authenticators '(gssapi 
+(defvar imap-authenticators '(gssapi
                              kerberos4
                              digest-md5
                              cram-md5
@@ -253,7 +258,7 @@ stream.")
                              anonymous)
   "Priority of authenticators to consider when authenticating to server.")
 
-(defvar imap-authenticator-alist 
+(defvar imap-authenticator-alist
   '((gssapi     imap-gssapi-auth-p    imap-gssapi-auth)
     (kerberos4  imap-kerberos4-auth-p imap-kerberos4-auth)
     (cram-md5   imap-cram-md5-p       imap-cram-md5-auth)
@@ -309,7 +314,7 @@ encoded mailboxes which doesn't translate into ISO-8859-1.")
 (defvar imap-username nil)
 (defvar imap-password nil)
 (defvar imap-calculate-literal-size-first nil)
-(defvar imap-state 'closed 
+(defvar imap-state 'closed
   "IMAP state.
 Valid states are `closed', `initial', `nonauth', `auth', `selected'
 and `examine'.")
@@ -350,7 +355,7 @@ and `examine'.")
 (defvar imap-reached-tag 0
   "Lower limit on command tags that have been parsed.")
 
-(defvar imap-failed-tags nil 
+(defvar imap-failed-tags nil
   "Alist of tags that failed.
 Each element is a list with four elements; tag (a integer), response
 state (a symbol, `OK', `NO' or `BAD'), response code (a string), and
@@ -398,7 +403,7 @@ If ARGS, PROMPT is used as an argument to `format'."
       (and string
           (condition-case ()
               (utf7-encode string t)
-            (error (message 
+            (error (message
                     "imap: Could not UTF7 encode `%s', using it unencoded..."
                     string)
                    string)))
@@ -438,6 +443,7 @@ If ARGS, PROMPT is used as an argument to `format'."
       (message "Opening Kerberos 4 IMAP connection with `%s'..." cmd)
       (erase-buffer)
       (let* ((port (or port imap-default-port))
+            (process-connection-type imap-process-connection-type)
             (process (as-binary-process
                       (start-process
                        name buffer shell-file-name shell-command-switch
@@ -453,9 +459,10 @@ If ARGS, PROMPT is used as an argument to `format'."
            (setq imap-client-eol "\n"
                  imap-calculate-literal-size-first t)
            (while (and (memq (process-status process) '(open run))
+                       (set-buffer buffer) ;; XXX "blue moon" nntp.el bug
                        (goto-char (point-min))
-                        ;; cyrus 1.6.x (13? < x <= 22) queries capabilities
-                       (or (while (looking-at "^C:")
+                       ;; cyrus 1.6.x (13? < x <= 22) queries capabilities
+                       (or (while (looking-at "^C:")
                              (forward-line))
                            t)
                        ;; cyrus 1.6 imtest print "S: " before server greeting
@@ -488,7 +495,7 @@ If ARGS, PROMPT is used as an argument to `format'."
              (delete-process process)
              nil)))))
     done))
-  
+
 (defun imap-gssapi-stream-p (buffer)
   (imap-capability 'AUTH=GSSAPI buffer))
 
@@ -498,6 +505,7 @@ If ARGS, PROMPT is used as an argument to `format'."
     (while (and (not done) (setq cmd (pop cmds)))
       (message "Opening GSSAPI IMAP connection with `%s'..." cmd)
       (let* ((port (or port imap-default-port))
+            (process-connection-type imap-process-connection-type)
             (process (as-binary-process
                       (start-process
                        name buffer shell-file-name shell-command-switch
@@ -513,9 +521,10 @@ If ARGS, PROMPT is used as an argument to `format'."
            (setq imap-client-eol "\n"
                  imap-calculate-literal-size-first t)
            (while (and (memq (process-status process) '(open run))
+                       (set-buffer buffer) ;; XXX "blue moon" nntp.el bug
                        (goto-char (point-min))
-                        ;; cyrus 1.6.x (13? < x <= 22) queries capabilities
-                       (or (while (looking-at "^C:")
+                       ;; cyrus 1.6.x (13? < x <= 22) queries capabilities
+                       (or (while (looking-at "^C:")
                              (forward-line))
                            t)
                        ;; cyrus 1.6 imtest print "S: " before server greeting
@@ -553,6 +562,7 @@ If ARGS, PROMPT is used as an argument to `format'."
   (let ((cmds (if (listp imap-ssl-program) imap-ssl-program
                (list imap-ssl-program)))
        cmd done)
+    (ignore-errors (require 'ssl))
     (while (and (not done) (setq cmd (pop cmds)))
       (message "imap: Opening SSL connection with `%s'..." cmd)
       (let* ((port (or port imap-default-ssl-port))
@@ -578,6 +588,7 @@ If ARGS, PROMPT is used as an argument to `format'."
          (with-current-buffer buffer
            (goto-char (point-min))
            (while (and (memq (process-status process) '(open run))
+                       (set-buffer buffer) ;; XXX "blue moon" nntp.el bug
                        (goto-char (point-max))
                        (forward-line -1)
                        (not (imap-parse-greeting)))
@@ -595,7 +606,7 @@ If ARGS, PROMPT is used as an argument to `format'."
        (progn
          (message "imap: Opening SSL connection with `%s'...done" cmd)
          done)
-         (message "imap: Opening SSL connection with `%s'...failed" cmd)
+      (message "imap: Opening SSL connection with `%s'...failed" cmd)
       nil)))
 
 (defun imap-network-p (buffer)
@@ -606,6 +617,7 @@ If ARGS, PROMPT is used as an argument to `format'."
         (process (open-network-stream-as-binary name buffer server port)))
     (when process
       (while (and (memq (process-status process) '(open run))
+                 (set-buffer buffer) ;; XXX "blue moon" nntp.el bug
                  (goto-char (point-min))
                  (not (imap-parse-greeting)))
        (accept-process-output process 1)
@@ -640,16 +652,17 @@ If ARGS, PROMPT is used as an argument to `format'."
                          ?l imap-default-user))))))
        (when process
          (while (and (memq (process-status process) '(open run))
+                     (set-buffer buffer) ;; XXX "blue moon" nntp.el bug
                      (goto-char (point-min))
                      (not (imap-parse-greeting)))
            (accept-process-output process 1)
            (sit-for 1))
-         (erase-buffer)
          (and imap-log
               (with-current-buffer (get-buffer-create imap-log)
                 (buffer-disable-undo)
                 (goto-char (point-max))
                 (insert-buffer-substring buffer)))
+         (erase-buffer)
          (when (memq (process-status process) '(open run))
            (setq done process)))))
     (if done
@@ -675,6 +688,7 @@ If ARGS, PROMPT is used as an argument to `format'."
     (message "imap: Connecting with STARTTLS...")
     (when process
       (while (and (memq (process-status process) '(open run))
+                 (set-buffer buffer) ;; XXX "blue moon" nntp.el bug
                  (goto-char (point-min))
                  (not (imap-parse-greeting)))
        (accept-process-output process 1)
@@ -700,7 +714,7 @@ If ARGS, PROMPT is used as an argument to `format'."
          done)
       (message "imap: Connecting with STARTTLS...failed")
       nil)))
-  
+
 ;; Server functions; authenticator stuff:
 
 (defun imap-interactive-login (buffer loginfunc)
@@ -709,18 +723,18 @@ LOGINFUNC is passed a username and a password, it should return t if
 it where sucessful authenticating itself to the server, nil otherwise.
 Returns t if login was successful, nil otherwise."
   (with-current-buffer buffer
-    (make-variable-buffer-local 'imap-username)
-    (make-variable-buffer-local 'imap-password)
+    (make-local-variable 'imap-username)
+    (make-local-variable 'imap-password)
     (let (user passwd ret)
       ;;      (condition-case ()
       (while (or (not user) (not passwd))
        (setq user (or imap-username
-                      (read-from-minibuffer 
+                      (read-from-minibuffer
                        (concat "IMAP username for " imap-server ": ")
                        (or user imap-default-user))))
        (setq passwd (or imap-password
                         (imap-read-passwd
-                         (concat "IMAP password for " user "@" 
+                         (concat "IMAP password for " user "@"
                                  imap-server ": "))))
        (when (and user passwd)
          (if (funcall loginfunc user passwd)
@@ -742,7 +756,14 @@ Returns t if login was successful, nil otherwise."
       ret)))
 
 (defun imap-gssapi-auth-p (buffer)
-  (imap-capability 'AUTH=GSSAPI buffer))
+  (and (imap-capability 'AUTH=GSSAPI buffer)
+       (catch 'imtest-found
+        (let (prg (prgs imap-gssapi-program))
+          (while (setq prg (pop prgs))
+            (condition-case ()
+                (and (call-process (substring prg 0 (string-match " " prg)))
+                     (throw 'imtest-found t))
+              (error nil)))))))
 
 (defun imap-gssapi-auth (buffer)
   (message "imap: Authenticating using GSSAPI...%s"
@@ -750,7 +771,14 @@ Returns t if login was successful, nil otherwise."
   (eq imap-stream 'gssapi))
 
 (defun imap-kerberos4-auth-p (buffer)
-  (imap-capability 'AUTH=KERBEROS_V4 buffer))
+  (and (imap-capability 'AUTH=KERBEROS_V4 buffer)
+       (catch 'imtest-found
+        (let (prg (prgs imap-kerberos4-program))
+          (while (setq prg (pop prgs))
+            (condition-case ()
+                (and (call-process (substring prg 0 (string-match " " prg)))
+                     (throw 'imtest-found t))
+              (error nil)))))))
 
 (defun imap-kerberos4-auth (buffer)
   (message "imap: Authenticating using Kerberos 4...%s"
@@ -794,10 +822,10 @@ Returns t if login was successful, nil otherwise."
 (defun imap-login-auth (buffer)
   "Login to server using the LOGIN command."
   (message "imap: Plaintext authentication...")
-  (imap-interactive-login buffer 
+  (imap-interactive-login buffer
                          (lambda (user passwd)
-                           (imap-ok-p (imap-send-command-wait 
-                                       (concat "LOGIN \"" user "\" \"" 
+                           (imap-ok-p (imap-send-command-wait
+                                       (concat "LOGIN \"" user "\" \""
                                                passwd "\""))))))
 
 (defun imap-anonymous-p (buffer)
@@ -807,7 +835,7 @@ Returns t if login was successful, nil otherwise."
   (message "imap: Loging in anonymously...")
   (with-current-buffer buffer
     (imap-ok-p (imap-send-command-wait
-               (concat "LOGIN anonymous \"" (concat (user-login-name) "@" 
+               (concat "LOGIN anonymous \"" (concat (user-login-name) "@"
                                                     (system-name)) "\"")))))
 
 (defun imap-digest-md5-p (buffer)
@@ -822,7 +850,7 @@ Returns t if login was successful, nil otherwise."
   (imap-interactive-login
    buffer
    (lambda (user passwd)
-     (let ((tag 
+     (let ((tag
            (imap-send-command
             (list
              "AUTHENTICATE DIGEST-MD5"
@@ -847,7 +875,7 @@ Returns t if login was successful, nil otherwise."
          imap-current-message nil
          imap-state 'initial
          imap-process (condition-case ()
-                          (funcall (nth 2 (assq imap-stream 
+                          (funcall (nth 2 (assq imap-stream
                                                 imap-stream-alist))
                                    "imap" buffer imap-server imap-port)
                         ((error quit) nil)))
@@ -877,7 +905,7 @@ necessery.  If nil, the buffer name is generated."
   (with-current-buffer (get-buffer-create buffer)
     (if (imap-opened buffer)
        (imap-close buffer))
-    (mapcar 'make-variable-buffer-local imap-local-variables)
+    (mapcar 'make-local-variable imap-local-variables)
     (set-buffer-multibyte nil)
     (buffer-disable-undo)
     (setq imap-server (or server imap-server))
@@ -894,7 +922,7 @@ necessery.  If nil, the buffer name is generated."
            (let ((streams imap-streams))
              (while (setq stream (pop streams))
                (if (funcall (nth 1 (assq stream imap-stream-alist)) buffer)
-                   (setq stream-changed (not (eq (or imap-stream 
+                   (setq stream-changed (not (eq (or imap-stream
                                                      imap-default-stream)
                                                  stream))
                          imap-stream stream
@@ -907,7 +935,7 @@ necessery.  If nil, the buffer name is generated."
            (if (imap-open-1 buffer)
                (message "imap: Reconnecting with stream `%s'...done"
                         imap-stream)
-             (message "imap: Reconnecting with stream `%s'...failed" 
+             (message "imap: Reconnecting with stream `%s'...failed"
                       imap-stream))
            (setq imap-capability nil))
          (if (imap-opened buffer)
@@ -915,7 +943,7 @@ necessery.  If nil, the buffer name is generated."
              (when (and (null imap-auth) (not (eq imap-state 'auth)))
                (let ((auths imap-authenticators))
                  (while (setq auth (pop auths))
-                   (if (funcall (nth 1 (assq auth imap-authenticator-alist)) 
+                   (if (funcall (nth 1 (assq auth imap-authenticator-alist))
                                 buffer)
                        (setq imap-auth auth
                              auths nil)))
@@ -947,8 +975,8 @@ password is remembered in the buffer."
        (or (eq imap-state 'auth)
            (eq imap-state 'select)
            (eq imap-state 'examine))
-      (make-variable-buffer-local 'imap-username)
-      (make-variable-buffer-local 'imap-password)
+      (make-local-variable 'imap-username)
+      (make-local-variable 'imap-password)
       (if user (setq imap-username user))
       (if passwd (setq imap-password passwd))
       (if (funcall (nth 2 (assq imap-auth imap-authenticator-alist)) buffer)
@@ -1018,7 +1046,7 @@ If BUFFER is nil, the current buffer is assumed."
 (defun imap-mailbox-map-1 (func &optional mailbox-decoder buffer)
   (with-current-buffer (or buffer (current-buffer))
     (let (result)
-      (mapatoms 
+      (mapatoms
        (lambda (s)
         (push (funcall func (if mailbox-decoder
                                 (funcall mailbox-decoder (symbol-name s))
@@ -1054,7 +1082,7 @@ If EXAMINE is non-nil, do a read-only select."
       imap-current-mailbox
     (setq imap-current-mailbox mailbox)
     (if (imap-ok-p (imap-send-command-wait
-                   (concat (if examine "EXAMINE" "SELECT") " \"" 
+                   (concat (if examine "EXAMINE" "SELECT") " \""
                            mailbox "\"")))
        (progn
          (setq imap-message-data (make-vector imap-message-prime 0)
@@ -1063,18 +1091,18 @@ If EXAMINE is non-nil, do a read-only select."
       ;; Failed SELECT/EXAMINE unselects current mailbox
       (setq imap-current-mailbox nil))))
 
-(defun imap-mailbox-select (mailbox &optional examine buffer)  
+(defun imap-mailbox-select (mailbox &optional examine buffer)
   (with-current-buffer (or buffer (current-buffer))
-    (imap-utf7-decode 
+    (imap-utf7-decode
      (imap-mailbox-select-1 (imap-utf7-encode mailbox) examine))))
 
 (defun imap-mailbox-examine-1 (mailbox &optional buffer)
   (with-current-buffer (or buffer (current-buffer))
-    (imap-mailbox-select-1 mailbox 'exmine)))
+    (imap-mailbox-select-1 mailbox 'examine)))
 
 (defun imap-mailbox-examine (mailbox &optional buffer)
   "Examine MAILBOX on server in BUFFER."
-  (imap-mailbox-select mailbox 'exmine buffer))
+  (imap-mailbox-select mailbox 'examine buffer))
 
 (defun imap-mailbox-unselect (&optional buffer)
   "Close current folder in BUFFER, without expunging articles."
@@ -1082,7 +1110,7 @@ If EXAMINE is non-nil, do a read-only select."
     (when (or (eq imap-state 'auth)
              (and (imap-capability 'UNSELECT)
                   (imap-ok-p (imap-send-command-wait "UNSELECT")))
-             (and (imap-ok-p 
+             (and (imap-ok-p
                    (imap-send-command-wait (concat "EXAMINE \""
                                                    imap-current-mailbox
                                                    "\"")))
@@ -1137,7 +1165,7 @@ If BUFFER is nil the current buffer is assumed."
        (imap-send-command-wait (list "RENAME \"" oldname "\" "
                                     "\"" newname "\""))))))
 
-(defun imap-mailbox-lsub (&optional root reference add-delimiter buffer) 
+(defun imap-mailbox-lsub (&optional root reference add-delimiter buffer)
   "Return a list of subscribed mailboxes on server in BUFFER.
 If ROOT is non-nil, only list matching mailboxes.  If ADD-DELIMITER is
 non-nil, a hierarchy delimiter is added to root.  REFERENCE is a
@@ -1151,7 +1179,7 @@ implementation-specific string that has to be passed to lsub command."
     (imap-mailbox-map-1 (lambda (mailbox)
                          (imap-mailbox-put 'lsub nil mailbox)))
     (when (imap-ok-p
-          (imap-send-command-wait 
+          (imap-send-command-wait
            (concat "LSUB \"" reference "\" \"" (imap-utf7-encode root)
                    (and add-delimiter (imap-mailbox-get-1 'delimiter root))
                    "%\"")))
@@ -1175,7 +1203,7 @@ passed to list command."
     (imap-mailbox-map-1 (lambda (mailbox)
                          (imap-mailbox-put 'list nil mailbox)))
     (when (imap-ok-p
-          (imap-send-command-wait 
+          (imap-send-command-wait
            (concat "LIST \"" reference "\" \"" (imap-utf7-encode root)
                    (and add-delimiter (imap-mailbox-get-1 'delimiter root))
                    "%\"")))
@@ -1189,7 +1217,7 @@ passed to list command."
   "Send the SUBSCRIBE command on the mailbox to server in BUFFER.
 Returns non-nil if successful."
   (with-current-buffer (or buffer (current-buffer))
-    (imap-ok-p (imap-send-command-wait (concat "SUBSCRIBE \"" 
+    (imap-ok-p (imap-send-command-wait (concat "SUBSCRIBE \""
                                               (imap-utf7-encode mailbox)
                                               "\"")))))
 
@@ -1197,7 +1225,7 @@ Returns non-nil if successful."
   "Send the SUBSCRIBE command on the mailbox to server in BUFFER.
 Returns non-nil if successful."
   (with-current-buffer (or buffer (current-buffer))
-    (imap-ok-p (imap-send-command-wait (concat "UNSUBSCRIBE " 
+    (imap-ok-p (imap-send-command-wait (concat "UNSUBSCRIBE "
                                               (imap-utf7-encode mailbox)
                                               "\"")))))
 
@@ -1208,13 +1236,13 @@ the STATUS data items -- ie 'messages, 'recent, 'uidnext, 'uidvalidity
 or 'unseen.  If ITEMS is a list of symbols, a list of values is
 returned, if ITEMS is a symbol only it's value is returned."
   (with-current-buffer (or buffer (current-buffer))
-    (when (imap-ok-p 
+    (when (imap-ok-p
           (imap-send-command-wait (list "STATUS \""
                                         (imap-utf7-encode mailbox)
                                         "\" "
                                         (format "%s"
                                                 (if (listp items)
-                                                    items 
+                                                    items
                                                   (list items))))))
       (if (listp items)
          (mapcar (lambda (item)
@@ -1273,8 +1301,8 @@ returned, if ITEMS is a symbol only it's value is returned."
   (mapconcat
    (lambda (item)
      (if (consp item)
-         (format "%d:%d"
-                 (car item) (cdr item))
+        (format "%d:%d"
+                (car item) (cdr item))
        (format "%d" item)))
    (if (and (listp range) (not (listp (cdr range))))
        (list range) ;; make (1 . 2) into ((1 . 2))
@@ -1294,7 +1322,7 @@ returned, if ITEMS is a symbol only it's value is returned."
 UIDS can be a string, number or a list of numbers.  If RECEIVE
 is non-nil return theese properties."
   (with-current-buffer (or buffer (current-buffer))
-    (when (imap-ok-p (imap-send-command-wait 
+    (when (imap-ok-p (imap-send-command-wait
                      (format "%sFETCH %s %s" (if nouidfetch "" "UID ")
                              (if (listp uids)
                                  (imap-list-to-message-set uids)
@@ -1311,7 +1339,7 @@ is non-nil return theese properties."
                        (imap-message-get uid receive)))
                    uids)
          (imap-message-get uids receive))))))
-    
+
 (defun imap-message-put (uid propname value &optional buffer)
   (with-current-buffer (or buffer (current-buffer))
     (if imap-message-data
@@ -1385,7 +1413,9 @@ is non-nil return theese properties."
     (imap-mailbox-put 'search 'dummy)
     (when (imap-ok-p (imap-send-command-wait (concat "UID SEARCH " predicate)))
       (if (eq (imap-mailbox-get-1 'search imap-current-mailbox) 'dummy)
-         (error "Missing SEARCH response to a SEARCH command")
+         (progn
+           (message "Missing SEARCH response to a SEARCH command (server not RFC compliant)...")
+           nil)
        (imap-mailbox-get-1 'search imap-current-mailbox)))))
 
 (defun imap-message-flag-permanent-p (flag &optional mailbox buffer)
@@ -1459,7 +1489,7 @@ first element, rest of list contain the saved articles' UIDs."
                  (imap-ok-p (imap-send-command-wait cmd)))))
            (or no-copyuid
                (imap-message-copyuid-1 mailbox)))))))
-      
+
 (defun imap-message-appenduid-1 (mailbox)
   (if (imap-capability 'UIDPLUS)
       (imap-mailbox-get-1 'appenduid mailbox)
@@ -1488,11 +1518,11 @@ on failure."
   (let ((mailbox (imap-utf7-encode mailbox)))
     (with-current-buffer (or buffer (current-buffer))
       (and (let ((imap-current-target-mailbox mailbox))
-            (imap-ok-p 
-             (imap-send-command-wait 
+            (imap-ok-p
+             (imap-send-command-wait
               (list "APPEND \"" mailbox "\" "  article))))
           (imap-message-appenduid-1 mailbox)))))
-  
+
 (defun imap-body-lines (body)
   "Return number of lines in article by looking at the mime bodystructure BODY."
   (if (listp body)
@@ -1512,8 +1542,8 @@ on failure."
   (and from
        (concat (aref from 0)
               (if (aref from 0) " <")
-              (aref from 2) 
-              "@" 
+              (aref from 2)
+              "@"
               (aref from 3)
               (if (aref from 0) ">"))))
 
@@ -1552,7 +1582,7 @@ on failure."
                       (replace-match eol)))
                   (if (not calcfirst)
                       (setq size (buffer-size))))
-                (setq cmdstr 
+                (setq cmdstr
                       (concat cmdstr (format "{%d}" size))))
               (unwind-protect
                   (progn
@@ -1592,19 +1622,19 @@ on failure."
 (defun imap-wait-for-tag (tag &optional buffer)
   (with-current-buffer (or buffer (current-buffer))
     (while (and (null imap-continuation)
+               (memq (process-status imap-process) '(open run))
                (< imap-reached-tag tag))
-      (or (and (not (memq (process-status imap-process) '(open run)))
-              (sit-for 1))
-         (let ((len (/ (point-max) 1024))
-               message-log-max)
-           (unless (< len 10)
-             (message "imap read: %dk" len))
-           (accept-process-output imap-process 1))))
+      (let ((len (/ (point-max) 1024))
+           message-log-max)
+       (unless (< len 10)
+         (message "imap read: %dk" len))
+       (accept-process-output imap-process 1)))
     (message "")
-    (or (assq tag imap-failed-tags)
-       (if imap-continuation
-           'INCOMPLETE
-         'OK))))
+    (and (memq (process-status imap-process) '(open run))
+        (or (assq tag imap-failed-tags)
+            (if imap-continuation
+                'INCOMPLETE
+              'OK)))))
 
 (defun imap-sentinel (process string)
   (delete-process process))
@@ -1648,7 +1678,7 @@ Return nil if no complete line has arrived."
                         (eq imap-state 'examine))
                     (imap-parse-response))
                    (t
-                    (message "Unknown state %s in arrival filter" 
+                    (message "Unknown state %s in arrival filter"
                              imap-state)))
            (delete-region (point-min) (point-max))))))))
 
@@ -1735,7 +1765,7 @@ Return nil if no complete line has arrived."
 
 (defsubst imap-parse-astring ()
   (or (imap-parse-string)
-      (buffer-substring (point) 
+      (buffer-substring (point)
                        (if (re-search-forward "[(){ \r\n%*\"\\]" nil t)
                            (goto-char (1- (match-end 0)))
                          (end-of-line)
@@ -1795,7 +1825,7 @@ Return nil if no complete line has arrived."
        (when (eq (char-after) ?\))
          (imap-forward)
          (nreverse addresses)))
-    (assert (imap-parse-nil))))
+    (assert (imap-parse-nil) t "In imap-parse-address-list")))
 
 ;;   mailbox         = "INBOX" / astring
 ;;                       ; INBOX is case-insensitive.  All case variants of
@@ -1848,13 +1878,13 @@ Return nil if no complete line has arrived."
 ;;   resp-cond-bye   = "BYE" SP resp-text
 ;;
 ;;   mailbox-data    =  "FLAGS" SP flag-list /
-;;                     "LIST" SP mailbox-list /
+;;                      "LIST" SP mailbox-list /
 ;;                      "LSUB" SP mailbox-list /
-;;                     "SEARCH" *(SP nz-number) /
+;;                      "SEARCH" *(SP nz-number) /
 ;;                      "STATUS" SP mailbox SP "("
-;;                           [status-att SP number *(SP status-att SP number)] ")" /
+;;                            [status-att SP number *(SP status-att SP number)] ")" /
 ;;                      number SP "EXISTS" /
-;;                     number SP "RECENT"
+;;                      number SP "RECENT"
 ;;
 ;;   message-data    = nz-number SP ("EXPUNGE" / ("FETCH" SP msg-att))
 ;;
@@ -1881,11 +1911,11 @@ Return nil if no complete line has arrived."
           (FLAGS      (imap-mailbox-put 'flags (imap-parse-flag-list)))
           (LIST       (imap-parse-data-list 'list))
           (LSUB       (imap-parse-data-list 'lsub))
-          (SEARCH     (imap-mailbox-put 
-                       'search 
+          (SEARCH     (imap-mailbox-put
+                       'search
                        (read (concat "(" (buffer-substring (point) (point-max)) ")"))))
           (STATUS     (imap-parse-status))
-          (CAPABILITY (setq imap-capability 
+          (CAPABILITY (setq imap-capability
                             (read (concat "(" (upcase (buffer-substring
                                                        (point) (point-max)))
                                           ")"))))
@@ -1915,7 +1945,7 @@ Return nil if no complete line has arrived."
                                                       (search-forward "]")))
                          (imap-forward))
                        (setq text (buffer-substring (point) (point-max)))
-                       (push (list token status code text) 
+                       (push (list token status code text)
                              imap-failed-tags))))
               (BAD (progn
                      (setq imap-reached-tag (max imap-reached-tag token))
@@ -1943,15 +1973,15 @@ Return nil if no complete line has arrived."
 
 ;;   resp-text-code  = "ALERT" /
 ;;                     "BADCHARSET [SP "(" astring *(SP astring) ")" ] /
-;;                     "NEWNAME" SP string SP string / 
-;;                    "PARSE" /
-;;                     "PERMANENTFLAGS" SP "(" 
+;;                     "NEWNAME" SP string SP string /
+;;                     "PARSE" /
+;;                     "PERMANENTFLAGS" SP "("
 ;;                               [flag-perm *(SP flag-perm)] ")" /
-;;                     "READ-ONLY" / 
-;;                    "READ-WRITE" / 
-;;                    "TRYCREATE" /
-;;                     "UIDNEXT" SP nz-number / 
-;;                    "UIDVALIDITY" SP nz-number /
+;;                     "READ-ONLY" /
+;;                     "READ-WRITE" /
+;;                     "TRYCREATE" /
+;;                     "UIDNEXT" SP nz-number /
+;;                     "UIDVALIDITY" SP nz-number /
 ;;                     "UNSEEN" SP nz-number /
 ;;                     resp-text-atom [SP 1*<any TEXT-CHAR except "]">]
 ;;
@@ -1969,7 +1999,7 @@ Return nil if no complete line has arrived."
 ;;                          ; delimits between two numbers inclusive.
 ;;                          ; Example: 2,4:7,9,12:* is 2,4,5,6,7,9,12,13,
 ;;                          ; 14,15 for a mailbox with 15 messages.
-;; 
+;;
 ;;   sequence-num    = nz-number / "*"
 ;;                          ; * is the largest number in use.  For message
 ;;                          ; sequence numbers, it is the number of messages
@@ -2070,18 +2100,18 @@ Return nil if no complete line has arrived."
 ;;                      "BODY" ["STRUCTURE"] SPACE body /
 ;;                      "BODY" section ["<" number ">"] SPACE nstring /
 ;;                      "UID" SPACE uniqueid) ")"
-;;  
+;;
 ;;  date_time       ::= <"> date_day_fixed "-" date_month "-" date_year
 ;;                      SPACE time SPACE zone <">
-;;  
+;;
 ;;  section         ::= "[" [section_text / (nz_number *["." nz_number]
 ;;                      ["." (section_text / "MIME")])] "]"
-;;  
+;;
 ;;  section_text    ::= "HEADER" / "HEADER.FIELDS" [".NOT"]
 ;;                      SPACE header_list / "TEXT"
-;;  
+;;
 ;;  header_fld_name ::= astring
-;;  
+;;
 ;;  header_list     ::= "(" 1#header_fld_name ")"
 
 (defsubst imap-parse-header-list ()
@@ -2094,7 +2124,7 @@ Return nil if no complete line has arrived."
       (nreverse strlist))))
 
 (defsubst imap-parse-fetch-body-section ()
-  (let ((section 
+  (let ((section
         (buffer-substring (point) (1- (re-search-forward "[] ]" nil t)))))
     (if (eq (char-before) ? )
        (prog1
@@ -2104,7 +2134,7 @@ Return nil if no complete line has arrived."
 
 (defun imap-parse-fetch (response)
   (when (eq (char-after) ?\()
-    (let (uid flags envelope internaldate rfc822 rfc822header rfc822text 
+    (let (uid flags envelope internaldate rfc822 rfc822header rfc822text
              rfc822size body bodydetail bodystructure)
       (while (not (eq (char-after) ?\)))
        (imap-forward)
@@ -2156,7 +2186,7 @@ Return nil if no complete line has arrived."
 
 ;;   mailbox-data    =  ...
 ;;                      "STATUS" SP mailbox SP "("
-;;                           [status-att SP number 
+;;                            [status-att SP number
 ;;                            *(SP status-att SP number)] ")"
 ;;                      ...
 ;;
@@ -2181,7 +2211,7 @@ Return nil if no complete line has arrived."
                ((eq token 'UNSEEN)
                 (imap-mailbox-put 'unseen (read (current-buffer)) mailbox))
                (t
-                (message "Unknown status data %s in mailbox %s ignored" 
+                (message "Unknown status data %s in mailbox %s ignored"
                          token mailbox))))))))
 
 ;;   acl_data        ::= "ACL" SPACE mailbox *(SPACE identifier SPACE
@@ -2220,12 +2250,16 @@ Return nil if no complete line has arrived."
 
 (defun imap-parse-flag-list ()
   (let (flag-list start)
-    (assert (eq (char-after) ?\())
+    (assert (eq (char-after) ?\() t "In imap-parse-flag-list")
     (while (and (not (eq (char-after) ?\)))
-               (setq start (progn (imap-forward) (point)))
+               (setq start (progn
+                             (imap-forward)
+                             ;; next line for Courier IMAP bug.
+                             (skip-chars-forward " ")
+                             (point)))
                (> (skip-chars-forward "^ )" (imap-point-at-eol)) 0))
       (push (buffer-substring start (point)) flag-list))
-    (assert (eq (char-after) ?\)))
+    (assert (eq (char-after) ?\)) t "In imap-parse-flag-list")
     (imap-forward)
     (nreverse flag-list)))
 
@@ -2310,7 +2344,7 @@ Return nil if no complete line has arrived."
        (while (eq (char-after) ?\ )
          (imap-forward)
          (push (imap-parse-body-extension) b-e))
-       (assert (eq (char-after) ?\)))
+       (assert (eq (char-after) ?\)) t "In imap-parse-body-extension")
        (imap-forward)
        (nreverse b-e))
     (or (imap-parse-number)
@@ -2338,7 +2372,7 @@ Return nil if no complete line has arrived."
              (imap-forward)
              (push (imap-parse-string-list) dsp)
              (imap-forward))
-         (assert (imap-parse-nil)))
+         (assert (imap-parse-nil) t "In imap-parse-body-ext"))
        (push (nreverse dsp) ext))
       (when (eq (char-after) ?\ );; body-fld-lang
        (imap-forward)
@@ -2434,7 +2468,7 @@ Return nil if no complete line has arrived."
                (push (and (imap-parse-nil) nil) body))
              (setq body
                    (append (imap-parse-body-ext) body)));; body-ext-...
-           (assert (eq (char-after) ?\)))
+           (assert (eq (char-after) ?\)) t "In imap-parse-body")
            (imap-forward)
            (nreverse body))
 
@@ -2493,15 +2527,15 @@ Return nil if no complete line has arrived."
          (imap-forward)
          (push (imap-parse-nstring) body);; body-fld-md5
          (setq body (append (imap-parse-body-ext) body)));; body-ext-1part..
-    
-       (assert (eq (char-after) ?\)))
+
+       (assert (eq (char-after) ?\)) t "In imap-parse-body 2")
        (imap-forward)
        (nreverse body)))))
 
 (when imap-debug                       ; (untrace-all)
   (require 'trace)
   (buffer-disable-undo (get-buffer-create imap-debug))
-  (mapcar (lambda (f) (trace-function-background f imap-debug)) 
+  (mapcar (lambda (f) (trace-function-background f imap-debug))
          '(
            imap-read-passwd
            imap-utf7-encode
@@ -2595,7 +2629,7 @@ Return nil if no complete line has arrived."
            imap-parse-body-extension
            imap-parse-body
            )))
-       
+
 (provide 'imap)
 
 ;;; imap.el ends here