2001-09-29 Simon Josefsson <jas@extundo.com>
[gnus] / lisp / imap.el
index 70712fd..a4fecd0 100644 (file)
@@ -1,5 +1,5 @@
 ;;; imap.el --- imap library
-;; Copyright (C) 1998, 1999, 2000
+;; Copyright (C) 1998, 1999, 2000, 2001
 ;;        Free Software Foundation, Inc.
 
 ;; Author: Simon Josefsson <jas@pdc.kth.se>
@@ -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
@@ -188,10 +188,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
@@ -214,14 +214,38 @@ until a successful connection is made."
   :group 'imap
   :type '(repeat string))
 
-(defvar imap-shell-host "gateway"
-  "Hostname of rlogin proxy.")
+(defcustom imap-process-connection-type nil
+  "*Value for `process-connection-type' to use for Kerberos4 and GSSAPI."
+  :group 'imap
+  :type 'boolean)
+
+(defcustom imap-use-utf7 t
+  "If non-nil, do utf7 encoding/decoding of mailbox names.
+Since the UTF7 decoding currently only decodes into ISO-8859-1
+characters, you may disable this decoding if you need to access UTF7
+encoded mailboxes which doesn't translate into ISO-8859-1."
+  :group 'imap
+  :type 'boolean)
 
-(defvar imap-default-user (user-login-name)
-  "Default username to use.")
+(defcustom imap-log nil
+  "If non-nil, a imap session trace is placed in *imap-log* buffer."
+  :group 'imap
+  :type 'boolean)
 
-(defvar imap-error nil
-  "Error codes from the last command.")
+(defcustom imap-debug nil
+  "If non-nil, random debug spews are placed in *imap-debug* buffer."
+  :group 'imap
+  :type 'boolean)
+
+(defcustom imap-shell-host "gateway"
+  "Hostname of rlogin proxy."
+  :group 'imap
+  :type 'string)
+
+(defcustom imap-default-user (user-login-name)
+  "Default username to use."
+  :group 'imap
+  :type 'string)
 
 ;; Various variables.
 
@@ -246,7 +270,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
@@ -254,7 +278,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)
@@ -269,11 +293,8 @@ NAME names the authenticator.  CHECK is a function returning non-nil if
 the server support the authenticator and AUTHENTICATE is a function
 for doing the actuall authentification.")
 
-(defvar imap-use-utf7 t
-  "If non-nil, do utf7 encoding/decoding of mailbox names.
-Since the UTF7 decoding currently only decodes into ISO-8859-1
-characters, you may disable this decoding if you need to access UTF7
-encoded mailboxes which doesn't translate into ISO-8859-1.")
+(defvar imap-error nil
+  "Error codes from the last command.")
 
 ;; Internal constants.  Change theese and die.
 
@@ -302,6 +323,8 @@ encoded mailboxes which doesn't translate into ISO-8859-1.")
                                 imap-process
                                 imap-calculate-literal-size-first
                                 imap-mailbox-data))
+(defconst imap-log-buffer "*imap-log*")
+(defconst imap-debug-buffer "*imap-debug*")
 
 ;; Internal variables.
 
@@ -312,7 +335,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'.")
@@ -353,7 +376,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
@@ -369,14 +392,6 @@ human readable response text (a string).")
   "Non-nil indicates that the server emitted a continuation request.
 The actually value is really the text on the continuation line.")
 
-(defvar imap-log nil
-  "Name of buffer for imap session trace.
-For example: (setq imap-log \"*imap-log*\")")
-
-(defvar imap-debug nil                 ;"*imap-debug*"
-  "Name of buffer for random debug spew.
-For example: (setq imap-debug \"*imap-debug*\")")
-
 \f
 ;; Utility functions:
 
@@ -406,7 +421,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)))
@@ -448,7 +463,8 @@ If ARGS, PROMPT is used as an argument to `format'."
       (let* ((port (or port imap-default-port))
             (coding-system-for-read imap-coding-system-for-read)
             (coding-system-for-write imap-coding-system-for-write)
-            (process (start-process 
+            (process-connection-type imap-process-connection-type)
+            (process (start-process
                       name buffer shell-file-name shell-command-switch
                       (format-spec
                        cmd
@@ -464,11 +480,11 @@ If ARGS, PROMPT is used as an argument to `format'."
            (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
+                  ;; 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
+               ;; cyrus 1.6 imtest print "S: " before server greeting
                        (or (not (looking-at "S: "))
                            (forward-char 3)
                            t)
@@ -483,7 +499,7 @@ If ARGS, PROMPT is used as an argument to `format'."
              (accept-process-output process 1)
              (sit-for 1))
            (and imap-log
-                (with-current-buffer (get-buffer-create imap-log)
+                (with-current-buffer (get-buffer-create imap-log-buffer)
                   (imap-disable-multibyte)
                   (buffer-disable-undo)
                   (goto-char (point-max))
@@ -499,7 +515,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))
 
@@ -511,7 +527,8 @@ If ARGS, PROMPT is used as an argument to `format'."
       (let* ((port (or port imap-default-port))
             (coding-system-for-read imap-coding-system-for-read)
             (coding-system-for-write imap-coding-system-for-write)
-            (process (start-process 
+            (process-connection-type imap-process-connection-type)
+            (process (start-process
                       name buffer shell-file-name shell-command-switch
                       (format-spec
                        cmd
@@ -527,11 +544,11 @@ If ARGS, PROMPT is used as an argument to `format'."
            (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
+                  ;; 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
+               ;; cyrus 1.6 imtest print "S: " before server greeting
                        (or (not (looking-at "S: "))
                            (forward-char 3)
                            t)
@@ -543,7 +560,7 @@ If ARGS, PROMPT is used as an argument to `format'."
              (accept-process-output process 1)
              (sit-for 1))
            (and imap-log
-                (with-current-buffer (get-buffer-create imap-log)
+                (with-current-buffer (get-buffer-create imap-log-buffer)
                   (imap-disable-multibyte)
                   (buffer-disable-undo)
                   (goto-char (point-max))
@@ -592,7 +609,7 @@ If ARGS, PROMPT is used as an argument to `format'."
              (accept-process-output process 1)
              (sit-for 1))
            (and imap-log
-                (with-current-buffer (get-buffer-create imap-log)
+                (with-current-buffer (get-buffer-create imap-log-buffer)
                   (imap-disable-multibyte)
                   (buffer-disable-undo)
                   (goto-char (point-max))
@@ -604,7 +621,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)
@@ -623,7 +640,7 @@ If ARGS, PROMPT is used as an argument to `format'."
        (accept-process-output process 1)
        (sit-for 1))
       (and imap-log
-          (with-current-buffer (get-buffer-create imap-log)
+          (with-current-buffer (get-buffer-create imap-log-buffer)
             (imap-disable-multibyte)
             (buffer-disable-undo)
             (goto-char (point-max))
@@ -643,7 +660,7 @@ If ARGS, PROMPT is used as an argument to `format'."
       (let* ((port (or port imap-default-port))
             (coding-system-for-read imap-coding-system-for-read)
             (coding-system-for-write imap-coding-system-for-write)
-            (process (start-process 
+            (process (start-process
                       name buffer shell-file-name shell-command-switch
                       (format-spec
                        cmd
@@ -660,7 +677,7 @@ If ARGS, PROMPT is used as an argument to `format'."
            (accept-process-output process 1)
            (sit-for 1))
          (and imap-log
-              (with-current-buffer (get-buffer-create imap-log)
+              (with-current-buffer (get-buffer-create imap-log-buffer)
                 (imap-disable-multibyte)
                 (buffer-disable-undo)
                 (goto-char (point-max))
@@ -672,7 +689,7 @@ If ARGS, PROMPT is used as an argument to `format'."
        (progn
          (message "imap: Opening IMAP connection with `%s'...done" cmd)
          done)
-         (message "imap: Opening IMAP connection with `%s'...failed" cmd)
+      (message "imap: Opening IMAP connection with `%s'...failed" cmd)
       nil)))
 
 (defun imap-starttls-p (buffer)
@@ -698,7 +715,7 @@ If ARGS, PROMPT is used as an argument to `format'."
        (accept-process-output process 1)
        (sit-for 1))
       (and imap-log
-          (with-current-buffer (get-buffer-create imap-log)
+          (with-current-buffer (get-buffer-create imap-log-buffer)
             (buffer-disable-undo)
             (goto-char (point-max))
             (insert-buffer-substring buffer)))
@@ -718,7 +735,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)
@@ -727,18 +744,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)
@@ -760,7 +777,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"
@@ -768,7 +792,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"
@@ -805,10 +836,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)
@@ -818,7 +849,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)
@@ -833,7 +864,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"
@@ -841,10 +872,10 @@ Returns t if login was successful, nil otherwise."
                (digest-md5-parse-digest-challenge
                 (base64-decode-string challenge))
                (let* ((digest-uri
-                       (digest-md5-digest-uri 
+                       (digest-md5-digest-uri
                         "imap" (digest-md5-challenge 'realm)))
                       (response
-                       (digest-md5-digest-response 
+                       (digest-md5-digest-response
                         user passwd digest-uri)))
                  (base64-encode-string response 'no-line-break))))
             )))
@@ -863,7 +894,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)))
@@ -893,7 +924,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)
     (imap-disable-multibyte)
     (buffer-disable-undo)
     (setq imap-server (or server imap-server))
@@ -910,7 +941,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
@@ -923,7 +954,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)
@@ -931,7 +962,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)))
@@ -963,8 +994,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)
@@ -1034,7 +1065,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))
@@ -1070,7 +1101,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)
@@ -1079,18 +1110,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."
@@ -1098,7 +1129,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
                                                    "\"")))
@@ -1153,7 +1184,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
@@ -1167,7 +1198,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))
                    "%\"")))
@@ -1191,7 +1222,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))
                    "%\"")))
@@ -1205,7 +1236,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)
                                               "\"")))))
 
@@ -1213,7 +1244,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)
                                               "\"")))))
 
@@ -1224,13 +1255,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)
@@ -1289,8 +1320,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))
@@ -1310,7 +1341,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)
@@ -1327,7 +1358,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
@@ -1401,7 +1432,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)
@@ -1475,7 +1508,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)
@@ -1504,11 +1537,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)
@@ -1528,8 +1561,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) ">"))))
 
@@ -1539,7 +1572,7 @@ on failure."
 (defun imap-send-command-1 (cmdstr)
   (setq cmdstr (concat cmdstr imap-client-eol))
   (and imap-log
-       (with-current-buffer (get-buffer-create imap-log)
+       (with-current-buffer (get-buffer-create imap-log-buffer)
         (imap-disable-multibyte)
         (buffer-disable-undo)
         (goto-char (point-max))
@@ -1569,21 +1602,21 @@ on failure."
                       (replace-match eol)))
                   (if (not calcfirst)
                       (setq size (buffer-size))))
-                (setq cmdstr 
+                (setq cmdstr
                       (concat cmdstr (format "{%d}" size))))
               (unwind-protect
                   (progn
                     (imap-send-command-1 cmdstr)
                     (setq cmdstr nil)
                     (if (not (eq (imap-wait-for-tag tag) 'INCOMPLETE))
-                        (setq command nil);; abort command if no cont-req
+                        (setq command nil) ;; abort command if no cont-req
                       (let ((process imap-process)
                             (stream imap-stream)
                             (eol imap-client-eol))
                         (with-current-buffer cmd
                           (and imap-log
                                (with-current-buffer (get-buffer-create
-                                                     imap-log)
+                                                     imap-log-buffer)
                                  (imap-disable-multibyte)
                                  (buffer-disable-undo)
                                  (goto-char (point-max))
@@ -1597,7 +1630,7 @@ on failure."
               (setq cmdstr nil)
               (unwind-protect
                   (if (not (eq (imap-wait-for-tag tag) 'INCOMPLETE))
-                      (setq command nil);; abort command if no cont-req
+                      (setq command nil) ;; abort command if no cont-req
                     (setq command (cons (funcall cmd imap-continuation)
                                         command)))
                 (setq imap-continuation nil)))
@@ -1610,19 +1643,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))
@@ -1646,7 +1679,7 @@ Return nil if no complete line has arrived."
     (goto-char (point-max))
     (insert string)
     (and imap-log
-        (with-current-buffer (get-buffer-create imap-log)
+        (with-current-buffer (get-buffer-create imap-log-buffer)
           (imap-disable-multibyte)
           (buffer-disable-undo)
           (goto-char (point-max))
@@ -1667,7 +1700,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))))))))
 
@@ -1754,7 +1787,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)
@@ -1814,7 +1847,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
@@ -1900,11 +1933,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)))
                                           ")"))))
@@ -1934,7 +1967,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))
@@ -1962,14 +1995,14 @@ Return nil if no complete line has arrived."
 
 ;;   resp-text-code  = "ALERT" /
 ;;                     "BADCHARSET [SP "(" astring *(SP astring) ")" ] /
-;;                     "NEWNAME" SP string SP string / 
+;;                     "NEWNAME" SP string SP string /
 ;;                    "PARSE" /
-;;                     "PERMANENTFLAGS" SP "(" 
+;;                     "PERMANENTFLAGS" SP "("
 ;;                               [flag-perm *(SP flag-perm)] ")" /
-;;                     "READ-ONLY" / 
-;;                    "READ-WRITE" / 
+;;                     "READ-ONLY" /
+;;                    "READ-WRITE" /
 ;;                    "TRYCREATE" /
-;;                     "UIDNEXT" SP nz-number / 
+;;                     "UIDNEXT" SP nz-number /
 ;;                    "UIDVALIDITY" SP nz-number /
 ;;                     "UNSEEN" SP nz-number /
 ;;                     resp-text-atom [SP 1*<any TEXT-CHAR except "]">]
@@ -1988,7 +2021,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
@@ -2089,18 +2122,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 ()
@@ -2113,7 +2146,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
@@ -2123,7 +2156,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)
@@ -2175,7 +2208,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)] ")"
 ;;                      ...
 ;;
@@ -2200,7 +2233,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
@@ -2239,7 +2272,7 @@ 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)
@@ -2248,7 +2281,7 @@ Return nil if no complete line has arrived."
                              (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)))
 
@@ -2279,31 +2312,31 @@ Return nil if no complete line has arrived."
 (defun imap-parse-envelope ()
   (when (eq (char-after) ?\()
     (imap-forward)
-    (vector (prog1 (imap-parse-nstring);; date
+    (vector (prog1 (imap-parse-nstring)        ;; date
              (imap-forward))
-           (prog1 (imap-parse-nstring);; subject
+           (prog1 (imap-parse-nstring) ;; subject
              (imap-forward))
-           (prog1 (imap-parse-address-list);; from
+           (prog1 (imap-parse-address-list) ;; from
              (imap-forward))
-           (prog1 (imap-parse-address-list);; sender
+           (prog1 (imap-parse-address-list) ;; sender
              (imap-forward))
-           (prog1 (imap-parse-address-list);; reply-to
+           (prog1 (imap-parse-address-list) ;; reply-to
              (imap-forward))
-           (prog1 (imap-parse-address-list);; to
+           (prog1 (imap-parse-address-list) ;; to
              (imap-forward))
-           (prog1 (imap-parse-address-list);; cc
+           (prog1 (imap-parse-address-list) ;; cc
              (imap-forward))
-           (prog1 (imap-parse-address-list);; bcc
+           (prog1 (imap-parse-address-list) ;; bcc
              (imap-forward))
-           (prog1 (imap-parse-nstring);; in-reply-to
+           (prog1 (imap-parse-nstring) ;; in-reply-to
              (imap-forward))
-           (prog1 (imap-parse-nstring);; message-id
+           (prog1 (imap-parse-nstring) ;; message-id
              (imap-forward)))))
 
 ;;   body-fld-param  = "(" string SP string *(SP string SP string) ")" / nil
 
 (defsubst imap-parse-string-list ()
-  (cond ((eq (char-after) ?\();; body-fld-param
+  (cond ((eq (char-after) ?\() ;; body-fld-param
         (let (strlist str)
           (imap-forward)
           (while (setq str (imap-parse-string))
@@ -2333,7 +2366,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)
@@ -2351,7 +2384,7 @@ Return nil if no complete line has arrived."
 
 (defsubst imap-parse-body-ext ()
   (let (ext)
-    (when (eq (char-after) ?\ );; body-fld-dsp
+    (when (eq (char-after) ?\ )        ;; body-fld-dsp
       (imap-forward)
       (let (dsp)
        (if (eq (char-after) ?\()
@@ -2361,14 +2394,14 @@ 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
+      (when (eq (char-after) ?\ ) ;; body-fld-lang
        (imap-forward)
        (if (eq (char-after) ?\()
            (push (imap-parse-string-list) ext)
          (push (imap-parse-nstring) ext))
-       (while (eq (char-after) ?\ );; body-extension
+       (while (eq (char-after) ?\ ) ;; body-extension
          (imap-forward)
          (setq ext (append (imap-parse-body-extension) ext)))))
     ext))
@@ -2442,89 +2475,89 @@ Return nil if no complete line has arrived."
          (let (subbody)
            (while (and (eq (char-after) ?\()
                        (setq subbody (imap-parse-body)))
-             ;; buggy stalker communigate pro 3.0 insert a SPC between
+            ;; buggy stalker communigate pro 3.0 insert a SPC between
              ;; parts in multiparts
              (when (and (eq (char-after) ?\ )
                         (eq (char-after (1+ (point))) ?\())
                (imap-forward))
              (push subbody body))
            (imap-forward)
-           (push (imap-parse-string) body);; media-subtype
-           (when (eq (char-after) ?\ );; body-ext-mpart:
+           (push (imap-parse-string) body) ;; media-subtype
+           (when (eq (char-after) ?\ ) ;; body-ext-mpart:
              (imap-forward)
-             (if (eq (char-after) ?\();; body-fld-param
+             (if (eq (char-after) ?\() ;; body-fld-param
                  (push (imap-parse-string-list) body)
                (push (and (imap-parse-nil) nil) body))
              (setq body
-                   (append (imap-parse-body-ext) body)));; body-ext-...
-           (assert (eq (char-after) ?\)))
+                   (append (imap-parse-body-ext) body))) ;; body-ext-...
+           (assert (eq (char-after) ?\)) t "In imap-parse-body")
            (imap-forward)
            (nreverse body))
 
-       (push (imap-parse-string) body);; media-type
+       (push (imap-parse-string) body) ;; media-type
        (imap-forward)
-       (push (imap-parse-string) body);; media-subtype
+       (push (imap-parse-string) body) ;; media-subtype
        (imap-forward)
        ;; next line for Sun SIMS bug
        (and (eq (char-after) ? ) (imap-forward))
-       (if (eq (char-after) ?\();; body-fld-param
+       (if (eq (char-after) ?\() ;; body-fld-param
            (push (imap-parse-string-list) body)
          (push (and (imap-parse-nil) nil) body))
        (imap-forward)
-       (push (imap-parse-nstring) body);; body-fld-id
+       (push (imap-parse-nstring) body) ;; body-fld-id
        (imap-forward)
-       (push (imap-parse-nstring) body);; body-fld-desc
+       (push (imap-parse-nstring) body) ;; body-fld-desc
        (imap-forward)
        ;; next `or' for Sun SIMS bug, it regard body-fld-enc as a
        ;; nstring and return NIL instead of defaulting back to 7BIT
        ;; as the standard says.
-       (push (or (imap-parse-nstring) "7BIT") body);; body-fld-enc
+       (push (or (imap-parse-nstring) "7BIT") body) ;; body-fld-enc
        (imap-forward)
-       (push (imap-parse-number) body);; body-fld-octets
+       (push (imap-parse-number) body) ;; body-fld-octets
 
-       ;; ok, we're done parsing the required parts, what comes now is one
+   ;; ok, we're done parsing the required parts, what comes now is one
        ;; of three things:
        ;;
        ;; envelope       (then we're parsing body-type-msg)
        ;; body-fld-lines (then we're parsing body-type-text)
        ;; body-ext-1part (then we're parsing body-type-basic)
        ;;
-       ;; the problem is that the two first are in turn optionally followed
-       ;; by the third.  So we parse the first two here (if there are any)...
+  ;; the problem is that the two first are in turn optionally followed
+;; by the third.  So we parse the first two here (if there are any)...
 
        (when (eq (char-after) ?\ )
          (imap-forward)
          (let (lines)
-           (cond ((eq (char-after) ?\();; body-type-msg:
-                  (push (imap-parse-envelope) body);; envelope
+           (cond ((eq (char-after) ?\() ;; body-type-msg:
+                  (push (imap-parse-envelope) body) ;; envelope
                   (imap-forward)
-                  (push (imap-parse-body) body);; body
+                  (push (imap-parse-body) body) ;; body
                   ;; buggy stalker communigate pro 3.0 doesn't print
                   ;; number of lines in message/rfc822 attachment
                   (if (eq (char-after) ?\))
                       (push 0 body)
                     (imap-forward)
                     (push (imap-parse-number) body))) ;; body-fld-lines
-                 ((setq lines (imap-parse-number))    ;; body-type-text:
-                  (push lines body))                  ;; body-fld-lines
+                 ((setq lines (imap-parse-number)) ;; body-type-text:
+                  (push lines body)) ;; body-fld-lines
                  (t
-                  (backward-char)))))                 ;; no match...
+                  (backward-char))))) ;; no match...
 
        ;; ...and then parse the third one here...
 
-       (when (eq (char-after) ?\ );; body-ext-1part:
+       (when (eq (char-after) ?\ ) ;; body-ext-1part:
          (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) ?\)))
+         (push (imap-parse-nstring) body) ;; body-fld-md5
+         (setq body (append (imap-parse-body-ext) body))) ;; body-ext-1part..
+
+       (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)) 
+  (buffer-disable-undo (get-buffer-create imap-debug-buffer))
+  (mapcar (lambda (f) (trace-function-background f imap-debug-buffer))
          '(
            imap-read-passwd
            imap-utf7-encode
@@ -2618,7 +2651,7 @@ Return nil if no complete line has arrived."
            imap-parse-body-extension
            imap-parse-body
            )))
-       
+
 (provide 'imap)
 
 ;;; imap.el ends here