Importing Oort Gnus v0.06.
[elisp/gnus.git-] / lisp / imap.el
index 661dd0a..082c83c 100644 (file)
@@ -1,5 +1,6 @@
 ;;; imap.el --- imap library
 ;;; imap.el --- imap library
-;; Copyright (C) 1998,1999 Free Software Foundation, Inc.
+;; Copyright (C) 1998, 1999, 2000, 2001, 2002
+;;        Free Software Foundation, Inc.
 
 ;; Author: Simon Josefsson <jas@pdc.kth.se>
 ;; Keywords: mail
 
 ;; Author: Simon Josefsson <jas@pdc.kth.se>
 ;; Keywords: mail
@@ -29,7 +30,7 @@
 ;; imap.el is roughly divided in two parts, one that parses IMAP
 ;; responses from the server and storing data into buffer-local
 ;; variables, and one for utility functions which send commands to
 ;; imap.el is roughly divided in two parts, one that parses IMAP
 ;; responses from the server and storing data into buffer-local
 ;; variables, and one for utility functions which send commands to
-;; server, waits for an answer, and return information. The latter
+;; server, waits for an answer, and return information.  The latter
 ;; part is layered on top of the previous.
 ;;
 ;; The imap.el API consist of the following functions, other functions
 ;; part is layered on top of the previous.
 ;;
 ;; The imap.el API consist of the following functions, other functions
@@ -43,7 +44,7 @@
 ;;
 ;; Mailbox commands:
 ;;
 ;;
 ;; 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
 ;; 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
@@ -56,7 +57,7 @@
 ;; imap-fetch-asynch,                 imap-fetch,
 ;; imap-current-message,              imap-list-to-message-set,
 ;; imap-message-get,                  imap-message-map
 ;; 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
 ;; 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
 ;; imap-body-lines
 ;;
 ;; It is my hope that theese commands should be pretty self
 ;; imap-body-lines
 ;;
 ;; It is my hope that theese commands should be pretty self
-;; explanatory for someone that know IMAP. All functions have
+;; explanatory for someone that know IMAP.  All functions have
 ;; additional documentation on how to invoke them.
 ;;
 ;; imap.el support RFC1730/2060 (IMAP4/IMAP4rev1), implemented IMAP
 ;; extensions are RFC2195 (CRAM-MD5), RFC2086 (ACL), RFC2342
 ;; additional documentation on how to invoke them.
 ;;
 ;; imap.el support RFC1730/2060 (IMAP4/IMAP4rev1), implemented IMAP
 ;; extensions are RFC2195 (CRAM-MD5), RFC2086 (ACL), RFC2342
-;; (NAMESPACE), RFC2359 (UIDPLUS), and the kerberos V4 part of RFC1731
+;; (NAMESPACE), RFC2359 (UIDPLUS), the IMAP-part of RFC2595 (STARTTLS,
+;; LOGINDISABLED) (with use of external library starttls.el and
+;; program starttls) and the GSSAPI / kerberos V4 sections of RFC1731
 ;; (with use of external program `imtest').  It also take advantage
 ;; the UNSELECT extension in Cyrus IMAPD.
 ;;
 ;; Without the work of John McClary Prevost and Jim Radford this library
 ;; (with use of external program `imtest').  It also take advantage
 ;; the UNSELECT extension in Cyrus IMAPD.
 ;;
 ;; Without the work of John McClary Prevost and Jim Radford this library
-;; would not have seen the light of day. Many thanks.
+;; would not have seen the light of day.  Many thanks.
 ;;
 ;; This is a transcript of short interactive session for demonstration
 ;; purposes.
 ;;
 ;; This is a transcript of short interactive session for demonstration
 ;; purposes.
@@ -88,7 +91,7 @@
 ;; => " *imap* my.mail.server:0"
 ;;
 ;; The rest are invoked with current buffer as the buffer returned by
 ;; => " *imap* my.mail.server:0"
 ;;
 ;; The rest are invoked with current buffer as the buffer returned by
-;; `imap-open'. It is possible to do all without this, but it would
+;; `imap-open'.  It is possible to do all without this, but it would
 ;; look ugly here since `buffer' is always the last argument for all
 ;; imap.el API functions.
 ;;
 ;; look ugly here since `buffer' is always the last argument for all
 ;; imap.el API functions.
 ;;
 ;; => "X-Sieve: cmu-sieve 1.3^M\nX-Username: <jas@pdc.kth.se>^M\r...."
 ;;
 ;; Todo:
 ;; => "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
 ;;   imap-message-* functions.
 ;; 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
 ;;   imap-message-* functions.
-;; o Cyrus IMAPd 1.6.x `imtest' support in the imtest wrapper
-;; o Format-spec'ify the ssl horror
 ;;
 ;; Revision history:
 ;;
 ;;
 ;; Revision history:
 ;;
-;;  - this is unreleased software
+;;  - 19991218 added starttls/digest-md5 patch,
+;;             by Daiki Ueno <ueno@ueda.info.waseda.ac.jp>
+;;             NB! you need SLIM for starttls.el and digest-md5.el
+;;  - 19991023 commited to pgnus
 ;;
 
 ;;; Code:
 
 ;;
 
 ;;; Code:
 
+(eval-when-compile (require 'cl))
 (eval-and-compile
 (eval-and-compile
-  (require 'cl)
   (autoload 'open-ssl-stream "ssl")
   (autoload 'base64-decode-string "base64")
   (autoload 'open-ssl-stream "ssl")
   (autoload 'base64-decode-string "base64")
+  (autoload 'base64-encode-string "base64")
+  (autoload 'starttls-open-stream "starttls")
+  (autoload 'starttls-negotiate "starttls")
+  (autoload 'digest-md5-parse-digest-challenge "digest-md5")
+  (autoload 'digest-md5-digest-response "digest-md5")
+  (autoload 'digest-md5-digest-uri "digest-md5")
+  (autoload 'digest-md5-challenge "digest-md5")
   (autoload 'rfc2104-hash "rfc2104")
   (autoload 'md5 "md5")
   (autoload 'utf7-encode "utf7")
   (autoload 'utf7-decode "utf7")
   (autoload 'format-spec "format-spec")
   (autoload 'rfc2104-hash "rfc2104")
   (autoload 'md5 "md5")
   (autoload 'utf7-encode "utf7")
   (autoload 'utf7-decode "utf7")
   (autoload 'format-spec "format-spec")
-  (autoload 'format-spec-make "format-spec"))
+  (autoload 'format-spec-make "format-spec")
+  ;; Avoid use gnus-point-at-eol so we're independent of Gnus.  These
+  ;; days we have point-at-eol anyhow.
+  (if (fboundp 'point-at-eol)
+      (defalias 'imap-point-at-eol 'point-at-eol)
+    (defun imap-point-at-eol ()
+      (save-excursion
+       (end-of-line)
+       (point)))))
 
 ;; User variables.
 
 
 ;; User variables.
 
-(defvar imap-imtest-program "imtest -kp %s %p"
-  "How to call program for Kerberos 4 authentication.
-%s is replaced with server and %p with port to connect to.  The
-program should accept IMAP commands on stdin and return responses to
-stdout.")
-
-(defvar imap-ssl-program 'auto
-  "Program to use for SSL connections. It is called like this
-
-`imap-ssl-program' `imap-ssl-arguments' -ssl2 -connect host:port
-
-where -ssl2 can also be -ssl3 to indicate which ssl version to use. It
-should accept IMAP commands on stdin and return responses to stdout.
-
-For SSLeay set this to \"s_client\" and `imap-ssl-arguments' to nil,
-for OpenSSL set this to \"openssl\" and `imap-ssl-arguments' to
-\"s_client\".
-
-If 'auto it tries s_client first and then openssl.")
-
-(defvar imap-ssl-arguments nil
-  "Arguments to pass to `imap-ssl-program'.
-
-For SSLeay set this to nil, for OpenSSL to \"s_client\".
-
-If `imap-ssl-program' is 'auto this variable has no effect.")
-
-(defvar imap-default-user (user-login-name)
-  "Default username to use.")
-
-(defvar imap-error nil
-  "Error codes from the last command.")
+(defgroup imap nil
+  "Low-level IMAP issues."
+  :version "21.1"
+  :group 'mail)
+
+(defcustom imap-kerberos4-program '("imtest -m kerberos_v4 -u %l -p %p %s"
+                                   "imtest -kp %s %p")
+  "List of strings containing commands for Kerberos 4 authentication.
+%s is replaced with server hostname, %p with port to connect to, and
+%l with the value of `imap-default-user'.  The program should accept
+IMAP commands on stdin and return responses to stdout.  Each entry in
+the list is tried until a successful connection is made."
+  :group 'imap
+  :type '(repeat string))
+
+(defcustom imap-gssapi-program '("imtest -m gssapi -u %l -p %p %s")
+  "List of strings containing commands for GSSAPI (krb5) authentication.
+%s is replaced with server hostname, %p with port to connect to, and
+%l with the value of `imap-default-user'.  The program should accept
+IMAP commands on stdin and return responses to stdout.  Each entry in
+the list is tried until a successful connection is made."
+  :group 'imap
+  :type '(repeat string))
+
+(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
+stdin and return responses to stdout.  Each entry in the list is tried
+until a successful connection is made."
+  :group 'imap
+  :type '(choice string
+                (repeat string)))
+
+(defcustom imap-shell-program '("ssh %s imapd"
+                               "rsh %s imapd"
+                               "ssh %g ssh %s imapd"
+                               "rsh %g rsh %s imapd")
+  "A list of strings, containing commands for IMAP connection.
+Within a string, %s is replaced with the server address, %p with port
+number on server, %g with `imap-shell-host', and %l with
+`imap-default-user'.  The program should read IMAP commands from stdin
+and write IMAP response to stdout. Each entry in the list is tried
+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)
+
+(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)
+
+(defcustom imap-log nil
+  "If non-nil, a imap session trace is placed in *imap-log* buffer."
+  :group 'imap
+  :type 'boolean)
+
+(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.
 
 (defvar imap-fetch-data-hook nil
   "Hooks called after receiving each FETCH response.")
 
 
 ;; Various variables.
 
 (defvar imap-fetch-data-hook nil
   "Hooks called after receiving each FETCH response.")
 
-(defvar imap-streams '(kerberos4 ssl network)
-  "Priority of streams to consider when opening connection to
-server.")
+(defvar imap-streams '(gssapi kerberos4 starttls ssl network shell)
+  "Priority of streams to consider when opening connection to server.")
 
 (defvar imap-stream-alist
 
 (defvar imap-stream-alist
-  '((kerberos4 imap-kerberos4s-p imap-kerberos4-open)
-    (ssl       imap-ssl-p        imap-ssl-open)
-    (network   imap-network-p    imap-network-open))
+  '((gssapi    imap-gssapi-stream-p    imap-gssapi-open)
+    (kerberos4 imap-kerberos4-stream-p imap-kerberos4-open)
+    (ssl       imap-ssl-p              imap-ssl-open)
+    (network   imap-network-p          imap-network-open)
+    (shell     imap-shell-p            imap-shell-open)
+    (starttls  imap-starttls-p         imap-starttls-open))
   "Definition of network streams.
 
   "Definition of network streams.
 
-(NAME CHECK OPEN)
+\(NAME CHECK OPEN)
 
 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.")
 
 
 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 '(kerberos4 cram-md5 login anonymous)
-  "Priority of authenticators to consider when authenticating to
-server.")
-
-(defvar imap-authenticator-alist 
-  '((kerberos4 imap-kerberos4a-p imap-kerberos4-auth)
-    (cram-md5  imap-cram-md5-p   imap-cram-md5-auth)
-    (login     imap-login-p      imap-login-auth)
-    (anonymous imap-anonymous-p  imap-anonymous-auth))
+(defvar imap-authenticators '(gssapi
+                             kerberos4
+                             digest-md5
+                             cram-md5
+                             login
+                             anonymous)
+  "Priority of authenticators to consider when authenticating to server.")
+
+(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)
+    (login      imap-login-p          imap-login-auth)
+    (anonymous  imap-anonymous-p      imap-anonymous-auth)
+    (digest-md5 imap-digest-md5-p     imap-digest-md5-auth))
   "Definition of authenticators.
 
   "Definition of authenticators.
 
-(NAME CHECK AUTHENTICATE)
+\(NAME CHECK AUTHENTICATE)
 
 
-NAME names the authenticator. CHECK is a function returning non-nil if
+NAME names the authenticator.  CHECK is a function returning non-nil if
 the server support the authenticator and AUTHENTICATE is a function
 the server support the authenticator and AUTHENTICATE is a function
-for doing the actuall authentification.")
+for doing the actual authentication.")
 
 
-(defvar imap-utf7-p nil
-  "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.
+;; Internal constants.  Change theese and die.
 
 (defconst imap-default-port 143)
 (defconst imap-default-ssl-port 993)
 
 (defconst imap-default-port 143)
 (defconst imap-default-ssl-port 993)
@@ -247,7 +321,10 @@ encoded mailboxes which doesn't translate into ISO-8859-1.")
                                 imap-failed-tags
                                 imap-tag
                                 imap-process
                                 imap-failed-tags
                                 imap-tag
                                 imap-process
+                                imap-calculate-literal-size-first
                                 imap-mailbox-data))
                                 imap-mailbox-data))
+(defconst imap-log-buffer "*imap-log*")
+(defconst imap-debug-buffer "*imap-debug*")
 
 ;; Internal variables.
 
 
 ;; Internal variables.
 
@@ -257,9 +334,11 @@ encoded mailboxes which doesn't translate into ISO-8859-1.")
 (defvar imap-port nil)
 (defvar imap-username nil)
 (defvar imap-password nil)
 (defvar imap-port nil)
 (defvar imap-username nil)
 (defvar imap-password nil)
-(defvar imap-state 'closed 
-  "IMAP state. Valid states are `closed', `initial', `nonauth',
-`auth', `selected' and `examine'.")
+(defvar imap-calculate-literal-size-first nil)
+(defvar imap-state 'closed
+  "IMAP state.
+Valid states are `closed', `initial', `nonauth', `auth', `selected'
+and `examine'.")
 
 (defvar imap-server-eol "\r\n"
   "The EOL string sent from the server.")
 
 (defvar imap-server-eol "\r\n"
   "The EOL string sent from the server.")
@@ -297,11 +376,11 @@ encoded mailboxes which doesn't translate into ISO-8859-1.")
 (defvar imap-reached-tag 0
   "Lower limit on command tags that have been parsed.")
 
 (defvar imap-reached-tag 0
   "Lower limit on command tags that have been parsed.")
 
-(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 human readable response text (a
-string).")
+(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
+human readable response text (a string).")
 
 (defvar imap-tag 0
   "Command tag number.")
 
 (defvar imap-tag 0
   "Command tag number.")
@@ -310,26 +389,37 @@ string).")
   "Process.")
 
 (defvar imap-continuation nil
   "Process.")
 
 (defvar imap-continuation nil
-  "Non-nil indicates that the server emitted a continuation request. The
-actually value is really the text on the continuation line.")
+  "Non-nil indicates that the server emitted a continuation request.
+The actually value is really the text on the continuation line.")
 
 
-(defvar imap-log "*imap-log*"
-  "Imap session trace.")
-
-(defvar imap-debug nil;"*imap-debug*"
-  "Random debug spew.")
+(defvar imap-callbacks nil
+  "List of response tags and callbacks, on the form `(number . function)'.
+The function should take two arguments, the first the IMAP tag and the
+second the status (OK, NO, BAD etc) of the command.")
 
 \f
 ;; Utility functions:
 
 
 \f
 ;; Utility functions:
 
+(defun imap-remassoc (key alist)
+  "Delete by side effect any elements of LIST whose car is `equal' to KEY.
+The modified LIST is returned.  If the first member
+of LIST has a car that is `equal' to KEY, there is no way to remove it
+by side effect; therefore, write `(setq foo (remassoc key foo))' to be
+sure of changing the value of `foo'."
+  (when alist
+    (if (equal key (caar alist))
+       (cdr alist)
+      (setcdr alist (imap-remassoc key (cdr alist)))
+      alist)))
+
 (defsubst imap-disable-multibyte ()
   "Enable multibyte in the current buffer."
   (when (fboundp 'set-buffer-multibyte)
     (set-buffer-multibyte nil)))
 
 (defun imap-read-passwd (prompt &rest args)
 (defsubst imap-disable-multibyte ()
   "Enable multibyte in the current buffer."
   (when (fboundp 'set-buffer-multibyte)
     (set-buffer-multibyte nil)))
 
 (defun imap-read-passwd (prompt &rest args)
-  "Read a password using PROMPT. If ARGS, PROMPT is used as an
-argument to `format'."
+  "Read a password using PROMPT.
+If ARGS, PROMPT is used as an argument to `format'."
   (let ((prompt (if args
                    (apply 'format prompt args)
                  prompt)))
   (let ((prompt (if args
                    (apply 'format prompt args)
                  prompt)))
@@ -344,18 +434,18 @@ argument to `format'."
             prompt)))
 
 (defsubst imap-utf7-encode (string)
             prompt)))
 
 (defsubst imap-utf7-encode (string)
-  (if imap-utf7-p
+  (if imap-use-utf7
       (and string
           (condition-case ()
               (utf7-encode string t)
       (and string
           (condition-case ()
               (utf7-encode string t)
-            (error (message 
+            (error (message
                     "imap: Could not UTF7 encode `%s', using it unencoded..."
                     string)
                    string)))
     string))
 
 (defsubst imap-utf7-decode (string)
                     "imap: Could not UTF7 encode `%s', using it unencoded..."
                     string)
                    string)))
     string))
 
 (defsubst imap-utf7-decode (string)
-  (if imap-utf7-p
+  (if imap-use-utf7
       (and string
           (condition-case ()
               (utf7-decode string t)
       (and string
           (condition-case ()
               (utf7-decode string t)
@@ -378,98 +468,181 @@ argument to `format'."
 \f
 ;; Server functions; stream stuff:
 
 \f
 ;; Server functions; stream stuff:
 
-(defun imap-kerberos4s-p (buffer)
+(defun imap-kerberos4-stream-p (buffer)
   (imap-capability 'AUTH=KERBEROS_V4 buffer))
 
 (defun imap-kerberos4-open (name buffer server port)
   (imap-capability 'AUTH=KERBEROS_V4 buffer))
 
 (defun imap-kerberos4-open (name buffer server port)
-  (message "Opening Kerberized IMAP connection...")
-  (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 
-                  name buffer shell-file-name shell-command-switch
-                  (format-spec
-                   imap-imtest-program
-                   (format-spec-make ?s server ?p (number-to-string port))))))
-    (when process
-      (with-current-buffer buffer
-       (setq imap-client-eol "\n")
-       ;; Result of authentication is a string: __Full privacy protection__
-       (while (and (memq (process-status process) '(open run))
-                   (goto-char (point-min))
-                   (not (and (imap-parse-greeting)
-                             (re-search-forward "__\\(.*\\)__\n" nil t))))
-         (accept-process-output process 1)
-         (sit-for 1))
-       (and imap-log
-            (with-current-buffer (get-buffer-create imap-log)
-              (imap-disable-multibyte)
-              (buffer-disable-undo)
-              (goto-char (point-max))
-              (insert-buffer-substring buffer)))
-      (let ((response (match-string 1)))
-       (erase-buffer)
-       (message "Kerberized IMAP connection: %s" response)
-       (if (and response (let ((case-fold-search nil))
-                           (not (string-match "failed" response))))
-           process
-         (if (memq (process-status process) '(open run))
-             (imap-send-command-wait "LOGOUT"))
-         (delete-process process)
-         nil))))))
-  
+  (let ((cmds imap-kerberos4-program)
+       cmd done)
+    (while (and (not done) (setq cmd (pop cmds)))
+      (message "Opening Kerberos 4 IMAP connection with `%s'..." cmd)
+      (erase-buffer)
+      (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-connection-type imap-process-connection-type)
+            (process (start-process
+                      name buffer shell-file-name shell-command-switch
+                      (format-spec
+                       cmd
+                       (format-spec-make
+                        ?s server
+                        ?p (number-to-string port)
+                        ?l imap-default-user))))
+            response)
+       (when process
+         (with-current-buffer buffer
+           (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:")
+                             (forward-line))
+                           t)
+                       ;; cyrus 1.6 imtest print "S: " before server greeting
+                       (or (not (looking-at "S: "))
+                           (forward-char 3)
+                           t)
+                       (not (and (imap-parse-greeting)
+                                 ;; success in imtest < 1.6:
+                                 (or (re-search-forward
+                                      "^__\\(.*\\)__\n" nil t)
+                                     ;; success in imtest 1.6:
+                                     (re-search-forward
+                                      "^\\(Authenticat.*\\)" nil t))
+                                 (setq response (match-string 1)))))
+             (accept-process-output process 1)
+             (sit-for 1))
+           (and imap-log
+                (with-current-buffer (get-buffer-create imap-log-buffer)
+                  (imap-disable-multibyte)
+                  (buffer-disable-undo)
+                  (goto-char (point-max))
+                  (insert-buffer-substring buffer)))
+           (erase-buffer)
+           (message "Opening Kerberos 4 IMAP connection with `%s'...%s" cmd
+                    (if response (concat "done, " response) "failed"))
+           (if (and response (let ((case-fold-search nil))
+                               (not (string-match "failed" response))))
+               (setq done process)
+             (if (memq (process-status process) '(open run))
+                 (imap-send-command "LOGOUT"))
+             (delete-process process)
+             nil)))))
+    done))
+
+(defun imap-gssapi-stream-p (buffer)
+  (imap-capability 'AUTH=GSSAPI buffer))
+
+(defun imap-gssapi-open (name buffer server port)
+  (let ((cmds imap-gssapi-program)
+       cmd done)
+    (while (and (not done) (setq cmd (pop cmds)))
+      (message "Opening GSSAPI IMAP connection with `%s'..." cmd)
+      (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-connection-type imap-process-connection-type)
+            (process (start-process
+                      name buffer shell-file-name shell-command-switch
+                      (format-spec
+                       cmd
+                       (format-spec-make
+                        ?s server
+                        ?p (number-to-string port)
+                        ?l imap-default-user))))
+            response)
+       (when process
+         (with-current-buffer buffer
+           (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:")
+                             (forward-line))
+                           t)
+                       ;; cyrus 1.6 imtest print "S: " before server greeting
+                       (or (not (looking-at "S: "))
+                           (forward-char 3)
+                           t)
+                       (not (and (imap-parse-greeting)
+                                 ;; success in imtest 1.6:
+                                 (re-search-forward
+                                  "^\\(Authenticat.*\\)" nil t)
+                                 (setq response (match-string 1)))))
+             (accept-process-output process 1)
+             (sit-for 1))
+           (and imap-log
+                (with-current-buffer (get-buffer-create imap-log-buffer)
+                  (imap-disable-multibyte)
+                  (buffer-disable-undo)
+                  (goto-char (point-max))
+                  (insert-buffer-substring buffer)))
+           (erase-buffer)
+           (message "GSSAPI IMAP connection: %s" (or response "failed"))
+           (if (and response (let ((case-fold-search nil))
+                               (not (string-match "failed" response))))
+               (setq done process)
+             (if (memq (process-status process) '(open run))
+                 (imap-send-command "LOGOUT"))
+             (delete-process process)
+             nil)))))
+    done))
+
 (defun imap-ssl-p (buffer)
   nil)
 
 (defun imap-ssl-p (buffer)
   nil)
 
-(defun imap-ssl-open-2 (name buffer server port &optional extra-ssl-args)
-  (let* ((port (or port imap-default-ssl-port))
-        (coding-system-for-read imap-coding-system-for-read)
-        (coding-system-for-write imap-coding-system-for-write)
-        (ssl-program-name imap-ssl-program)
-        (ssl-program-arguments (append imap-ssl-arguments extra-ssl-args
-                                       (list "-connect" 
-                                             (format "%s:%d" server port))))
-        (process (ignore-errors (open-ssl-stream name buffer server port))))
-    (when process
-      (with-current-buffer buffer
-       (goto-char (point-min))
-       (while (and (memq (process-status process) '(open run))
-                   (goto-char (point-max))
-                   (forward-line -1)
-                   (not (imap-parse-greeting)))
-         (accept-process-output process 1)
-         (sit-for 1))
-       (and imap-log
-            (with-current-buffer (get-buffer-create imap-log)
-              (imap-disable-multibyte)
-              (buffer-disable-undo)
-              (goto-char (point-max))
-              (insert-buffer-substring buffer)))
-       (erase-buffer))
-      (when (memq (process-status process) '(open run))
-       process))))
-
-(defun imap-ssl-open-1 (name buffer server port &optional extra-ssl-args)
-  (or (and (eq imap-ssl-program 'auto)
-          (let ((imap-ssl-program "s_client")
-                (imap-ssl-arguments nil))
-            (message "imap: Opening IMAP connection with %s %s..."
-                     imap-ssl-program (car-safe extra-ssl-args))
-            (imap-ssl-open-2 name buffer server port extra-ssl-args)))
-      (and (eq imap-ssl-program 'auto)
-          (let ((imap-ssl-program "openssl")
-                (imap-ssl-arguments '("s_client")))
-            (message "imap: Opening IMAP connection with %s %s..."
-                     imap-ssl-program (car-safe extra-ssl-args))
-            (imap-ssl-open-2 name buffer server port extra-ssl-args)))
-      (and (not (eq imap-ssl-program 'auto))
-          (progn (message "imap: Opening IMAP connection with %s %s..."
-                          imap-ssl-program (car-safe extra-ssl-args))
-                 (imap-ssl-open-2 name buffer server port extra-ssl-args)))))
-          
 (defun imap-ssl-open (name buffer server port)
 (defun imap-ssl-open (name buffer server port)
-  (or (imap-ssl-open-1 name buffer server port '("-ssl3"))
-      (imap-ssl-open-1 name buffer server port '("-ssl2"))))
+  "Open a SSL connection to server."
+  (let ((cmds (if (listp imap-ssl-program) imap-ssl-program
+               (list imap-ssl-program)))
+       cmd done)
+    (condition-case ()
+       (require 'ssl)
+      (error))
+    (while (and (not done) (setq cmd (pop cmds)))
+      (message "imap: Opening SSL connection with `%s'..." cmd)
+      (let* ((port (or port imap-default-ssl-port))
+            (coding-system-for-read imap-coding-system-for-read)
+            (coding-system-for-write imap-coding-system-for-write)
+            (ssl-program-name shell-file-name)
+            (ssl-program-arguments
+             (list shell-command-switch
+                   (format-spec cmd (format-spec-make
+                                     ?s server
+                                     ?p (number-to-string port)))))
+            process)
+       (when (setq process (condition-case ()
+                               (open-ssl-stream name buffer server port)
+                             (error)))
+         (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)))
+             (accept-process-output process 1)
+             (sit-for 1))
+           (and imap-log
+                (with-current-buffer (get-buffer-create imap-log-buffer)
+                  (imap-disable-multibyte)
+                  (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
+       (progn
+         (message "imap: Opening SSL connection with `%s'...done" cmd)
+         done)
+      (message "imap: Opening SSL connection with `%s'...failed" cmd)
+      nil)))
 
 (defun imap-network-p (buffer)
   t)
 
 (defun imap-network-p (buffer)
   t)
@@ -481,63 +654,162 @@ argument to `format'."
         (process (open-network-stream name buffer server port)))
     (when process
       (while (and (memq (process-status process) '(open run))
         (process (open-network-stream 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)
        (sit-for 1))
       (and imap-log
                  (goto-char (point-min))
                  (not (imap-parse-greeting)))
        (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))
             (insert-buffer-substring buffer)))
       (when (memq (process-status process) '(open run))
        process))))
             (imap-disable-multibyte)
             (buffer-disable-undo)
             (goto-char (point-max))
             (insert-buffer-substring buffer)))
       (when (memq (process-status process) '(open run))
        process))))
-  
+
+(defun imap-shell-p (buffer)
+  nil)
+
+(defun imap-shell-open (name buffer server port)
+  (let ((cmds imap-shell-program)
+       cmd done)
+    (while (and (not done) (setq cmd (pop cmds)))
+      (message "imap: Opening IMAP connection with `%s'..." cmd)
+      (setq imap-client-eol "\n")
+      (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
+                      name buffer shell-file-name shell-command-switch
+                      (format-spec
+                       cmd
+                       (format-spec-make
+                        ?s server
+                        ?g imap-shell-host
+                        ?p (number-to-string port)
+                        ?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))
+         (and imap-log
+              (with-current-buffer (get-buffer-create imap-log-buffer)
+                (imap-disable-multibyte)
+                (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
+       (progn
+         (message "imap: Opening IMAP connection with `%s'...done" cmd)
+         done)
+      (message "imap: Opening IMAP connection with `%s'...failed" cmd)
+      nil)))
+
+(defun imap-starttls-p (buffer)
+  (imap-capability 'STARTTLS buffer))
+
+(defun imap-starttls-open (name buffer server port)
+  (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 (starttls-open-stream name buffer server port))
+        done)
+    (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)
+       (sit-for 1))
+      (and imap-log
+          (with-current-buffer (get-buffer-create imap-log-buffer)
+            (buffer-disable-undo)
+            (goto-char (point-max))
+            (insert-buffer-substring buffer)))
+      (let ((imap-process process))
+       (unwind-protect
+           (progn
+             (set-process-filter imap-process 'imap-arrival-filter)
+             (when (and (eq imap-stream 'starttls)
+                        (imap-ok-p (imap-send-command-wait "STARTTLS")))
+               (starttls-negotiate imap-process)))
+         (set-process-filter imap-process nil)))
+      (when (memq (process-status process) '(open run))
+       (setq done process)))
+    (if done
+       (progn
+         (message "imap: Connecting with STARTTLS...done")
+         done)
+      (message "imap: Connecting with STARTTLS...failed")
+      nil)))
+
 ;; Server functions; authenticator stuff:
 
 (defun imap-interactive-login (buffer loginfunc)
 ;; Server functions; authenticator stuff:
 
 (defun imap-interactive-login (buffer loginfunc)
-  "Login to server in BUFFER. 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."
+  "Login to server in BUFFER.
+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
   (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)
     (let (user passwd ret)
-;;      (condition-case ()
-         (while (or (not user) (not passwd))
-           (setq user (or imap-username
-                          (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 "@" 
-                                     imap-server ": "))))
-           (when (and user passwd)
-             (if (funcall loginfunc user passwd)
-                 (progn
-                   (setq ret t
-                         imap-username user)
-                   (if (and (not imap-password)
-                            (y-or-n-p "Store password for this session? "))
-                       (setq imap-password passwd)))
-               (message "Login failed...")
-               (setq passwd nil)
-               (sit-for 1))))
-;;     (quit (with-current-buffer buffer
-;;             (setq user nil
-;;                   passwd nil)))
-;;     (error (with-current-buffer buffer
-;;              (setq user nil
-;;                    passwd nil))))
+      ;;      (condition-case ()
+      (while (or (not user) (not passwd))
+       (setq user (or imap-username
+                      (read-from-minibuffer
+                       (concat "IMAP username for " imap-server
+                               " (using stream `" (symbol-name imap-stream)
+                               "'): ")
+                       (or user imap-default-user))))
+       (setq passwd (or imap-password
+                        (imap-read-passwd
+                         (concat "IMAP password for " user "@"
+                                 imap-server " (using authenticator `"
+                                 (symbol-name imap-auth) "'): "))))
+       (when (and user passwd)
+         (if (funcall loginfunc user passwd)
+             (progn
+               (setq ret t
+                     imap-username user)
+               (if (and (not imap-password)
+                        (y-or-n-p "Store password for this session? "))
+                   (setq imap-password passwd)))
+           (message "Login failed...")
+           (setq passwd nil)
+           (sit-for 1))))
+      ;;       (quit (with-current-buffer buffer
+      ;;               (setq user nil
+      ;;                     passwd nil)))
+      ;;       (error (with-current-buffer buffer
+      ;;                (setq user nil
+      ;;                      passwd nil))))
       ret)))
 
       ret)))
 
-(defun imap-kerberos4a-p (buffer)
-  (imap-capability 'AUTH=KERBEROS_V4 buffer))
+(defun imap-gssapi-auth-p (buffer)
+  (and (imap-capability 'AUTH=GSSAPI buffer)
+       (eq imap-stream 'gssapi)))
+
+(defun imap-gssapi-auth (buffer)
+  (message "imap: Authenticating using GSSAPI...%s"
+          (if (eq imap-stream 'gssapi) "done" "failed"))
+  (eq imap-stream 'gssapi))
+
+(defun imap-kerberos4-auth-p (buffer)
+  (and (imap-capability 'AUTH=KERBEROS_V4 buffer)
+       (eq imap-stream 'kerberos4)))
 
 (defun imap-kerberos4-auth (buffer)
 
 (defun imap-kerberos4-auth (buffer)
+  (message "imap: Authenticating using Kerberos 4...%s"
+          (if (eq imap-stream 'kerberos4) "done" "failed"))
   (eq imap-stream 'kerberos4))
 
 (defun imap-cram-md5-p (buffer)
   (eq imap-stream 'kerberos4))
 
 (defun imap-cram-md5-p (buffer)
@@ -545,40 +817,80 @@ successful, nil otherwise."
 
 (defun imap-cram-md5-auth (buffer)
   "Login to server using the AUTH CRAM-MD5 method."
 
 (defun imap-cram-md5-auth (buffer)
   "Login to server using the AUTH CRAM-MD5 method."
-  (imap-interactive-login
-   buffer
-   (lambda (user passwd)
-     (imap-ok-p
-      (imap-send-command-wait
-       (list
-       "AUTHENTICATE CRAM-MD5"
-       (lambda (challenge)
-         (let* ((decoded (base64-decode-string challenge))
-                (hash (rfc2104-hash 'md5 64 16 passwd decoded))
-                (response (concat user " " hash))
-                (encoded (base64-encode-string response)))
-           encoded))))))))
+  (message "imap: Authenticating using CRAM-MD5...")
+  (let ((done (imap-interactive-login
+              buffer
+              (lambda (user passwd)
+                (imap-ok-p
+                 (imap-send-command-wait
+                  (list
+                   "AUTHENTICATE CRAM-MD5"
+                   (lambda (challenge)
+                     (let* ((decoded (base64-decode-string challenge))
+                            (hash (rfc2104-hash 'md5 64 16 passwd decoded))
+                            (response (concat user " " hash))
+                            (encoded (base64-encode-string response)))
+                       encoded)))))))))
+    (if done
+       (message "imap: Authenticating using CRAM-MD5...done")
+      (message "imap: Authenticating using CRAM-MD5...failed"))))
 
 (defun imap-login-p (buffer)
 
 (defun imap-login-p (buffer)
-  (not (imap-capability 'X-LOGIN-CMD-DISABLED buffer)))
+  (and (not (imap-capability 'LOGINDISABLED buffer))
+       (not (imap-capability 'X-LOGIN-CMD-DISABLED buffer))))
 
 (defun imap-login-auth (buffer)
   "Login to server using the LOGIN command."
 
 (defun imap-login-auth (buffer)
   "Login to server using the LOGIN command."
-  (imap-interactive-login buffer 
+  (message "imap: Plaintext authentication...")
+  (imap-interactive-login buffer
                          (lambda (user passwd)
                          (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)
   t)
 
 (defun imap-anonymous-auth (buffer)
                                                passwd "\""))))))
 
 (defun imap-anonymous-p (buffer)
   t)
 
 (defun imap-anonymous-auth (buffer)
+  (message "imap: Logging in anonymously...")
   (with-current-buffer buffer
     (imap-ok-p (imap-send-command-wait
   (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)) "\"")))))
 
                                                     (system-name)) "\"")))))
 
+(defun imap-digest-md5-p (buffer)
+  (and (imap-capability 'AUTH=DIGEST-MD5 buffer)
+       (condition-case ()
+          (require 'digest-md5)
+        (error nil))))
+
+(defun imap-digest-md5-auth (buffer)
+  "Login to server using the AUTH DIGEST-MD5 method."
+  (message "imap: Authenticating using DIGEST-MD5...")
+  (imap-interactive-login
+   buffer
+   (lambda (user passwd)
+     (let ((tag
+           (imap-send-command
+            (list
+             "AUTHENTICATE DIGEST-MD5"
+             (lambda (challenge)
+               (digest-md5-parse-digest-challenge
+                (base64-decode-string challenge))
+               (let* ((digest-uri
+                       (digest-md5-digest-uri
+                        "imap" (digest-md5-challenge 'realm)))
+                      (response
+                       (digest-md5-digest-response
+                        user passwd digest-uri)))
+                 (base64-encode-string response 'no-line-break))))
+            )))
+       (if (not (eq (imap-wait-for-tag tag) 'INCOMPLETE))
+          nil
+        (setq imap-continuation nil)
+        (imap-send-command-1 "")
+        (imap-ok-p (imap-wait-for-tag tag)))))))
+
 ;; Server functions:
 
 (defun imap-open-1 (buffer)
 ;; Server functions:
 
 (defun imap-open-1 (buffer)
@@ -588,7 +900,7 @@ successful, nil otherwise."
          imap-current-message nil
          imap-state 'initial
          imap-process (condition-case ()
          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)))
                                                 imap-stream-alist))
                                    "imap" buffer imap-server imap-port)
                         ((error quit) nil)))
@@ -604,65 +916,79 @@ successful, nil otherwise."
           imap-process))))
 
 (defun imap-open (server &optional port stream auth buffer)
           imap-process))))
 
 (defun imap-open (server &optional port stream auth buffer)
-  "Open a IMAP connection to host SERVER at PORT returning a
-buffer. If PORT is unspecified, a default value is used (143 except
+  "Open a IMAP connection to host SERVER at PORT returning a buffer.
+If PORT is unspecified, a default value is used (143 except
 for SSL which use 993).
 STREAM indicates the stream to use, see `imap-streams' for available
 for SSL which use 993).
 STREAM indicates the stream to use, see `imap-streams' for available
-streams. If nil, it choices the best stream the server is capable of.
+streams.  If nil, it choices the best stream the server is capable of.
 AUTH indicates authenticator to use, see `imap-authenticators' for
 AUTH indicates authenticator to use, see `imap-authenticators' for
-available authenticators. If nil, it choices the best stream the
+available authenticators.  If nil, it choices the best stream the
 server is capable of.
 BUFFER can be a buffer or a name of a buffer, which is created if
 server is capable of.
 BUFFER can be a buffer or a name of a buffer, which is created if
-necessery. If nil, the buffer name is generated."
+necessery.  If nil, the buffer name is generated."
   (setq buffer (or buffer (format " *imap* %s:%d" server (or port 0))))
   (with-current-buffer (get-buffer-create buffer)
     (if (imap-opened buffer)
        (imap-close buffer))
   (setq buffer (or buffer (format " *imap* %s:%d" server (or port 0))))
   (with-current-buffer (get-buffer-create buffer)
     (if (imap-opened buffer)
        (imap-close buffer))
-    (mapc '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))
     (setq imap-port (or port imap-port))
     (setq imap-auth (or auth imap-auth))
     (setq imap-stream (or stream imap-stream))
     (imap-disable-multibyte)
     (buffer-disable-undo)
     (setq imap-server (or server imap-server))
     (setq imap-port (or port imap-port))
     (setq imap-auth (or auth imap-auth))
     (setq imap-stream (or stream imap-stream))
-    (when (let ((imap-stream (or imap-stream imap-default-stream)))
-           (imap-open-1 buffer))
-      ;; Choose stream.
-      (let (stream-changed)
-       (when (null imap-stream)
-         (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 
-                                                   imap-default-stream)
-                                               stream))
-                       imap-stream stream
-                       streams nil)))
-           (unless imap-stream
-             (error "Couldn't figure out a stream for server"))))
-       (when stream-changed
-         (message "Reconnecting with %s..." imap-stream)
-         (imap-close buffer)
-         (imap-open-1 buffer)
-         (setq imap-capability nil)))
-      (if (imap-opened buffer)
-         ;; Choose authenticator
-         (when (null imap-auth)
-           (let ((auths imap-authenticators))
-             (while (setq auth (pop auths))
-               (if (funcall (nth 1 (assq auth imap-authenticator-alist)) 
-                            buffer)
-                   (setq imap-auth auth
-                         auths nil)))
-             (unless imap-auth
-               (error "Couldn't figure out authenticator for server"))))))
-    (when (imap-opened buffer)
-      (setq imap-mailbox-data (make-vector imap-mailbox-prime 0))
-      buffer)))
+    (message "imap: Connecting to %s..." imap-server)
+    (if (null (let ((imap-stream (or imap-stream imap-default-stream)))
+               (imap-open-1 buffer)))
+       (progn
+         (message "imap: Connecting to %s...failed" imap-server)
+         nil)
+      (when (null imap-stream)
+       ;; Need to choose stream.
+       (let ((streams imap-streams))
+         (while (setq stream (pop streams))
+           ;; OK to use this stream?
+           (when (funcall (nth 1 (assq stream imap-stream-alist)) buffer)
+             ;; Stream changed?
+             (if (not (eq imap-default-stream stream))
+                 (with-current-buffer (get-buffer-create
+                                       (generate-new-buffer-name " *temp*"))
+                   (mapcar 'make-local-variable imap-local-variables)
+                   (imap-disable-multibyte)
+                   (buffer-disable-undo)
+                   (setq imap-server (or server imap-server))
+                   (setq imap-port (or port imap-port))
+                   (setq imap-auth (or auth imap-auth))
+                   (message "imap: Reconnecting with stream `%s'..." stream)
+                   (if (null (let ((imap-stream stream))
+                               (imap-open-1 (current-buffer))))
+                       (progn
+                         (kill-buffer (current-buffer))
+                         (message
+                          "imap: Reconnecting with stream `%s'...failed"
+                          stream))
+                     ;; We're done, kill the first connection
+                     (imap-close buffer)
+                     (kill-buffer buffer)
+                     (rename-buffer buffer)
+                     (message "imap: Reconnecting with stream `%s'...done"
+                              stream)
+                     (setq imap-stream stream)
+                     (setq imap-capability nil)
+                     (setq streams nil)))
+               ;; We're done
+               (message "imap: Connecting to %s...done" imap-server)
+               (setq imap-stream stream)
+               (setq imap-capability nil)
+               (setq streams nil))))))
+      (when (imap-opened buffer)
+       (setq imap-mailbox-data (make-vector imap-mailbox-prime 0)))
+      (when imap-stream
+       buffer))))
 
 (defun imap-opened (&optional buffer)
 
 (defun imap-opened (&optional buffer)
-  "Return non-nil if connection to imap server in BUFFER is open. If
-BUFFER is nil then the current buffer is used."
+  "Return non-nil if connection to imap server in BUFFER is open.
+If BUFFER is nil then the current buffer is used."
   (and (setq buffer (get-buffer (or buffer (current-buffer))))
        (buffer-live-p buffer)
        (with-current-buffer buffer
   (and (setq buffer (get-buffer (or buffer (current-buffer))))
        (buffer-live-p buffer)
        (with-current-buffer buffer
@@ -670,28 +996,51 @@ BUFFER is nil then the current buffer is used."
              (memq (process-status imap-process) '(open run))))))
 
 (defun imap-authenticate (&optional user passwd buffer)
              (memq (process-status imap-process) '(open run))))))
 
 (defun imap-authenticate (&optional user passwd buffer)
-  "Authenticate to server in BUFFER, using current buffer if nil. It
-uses the authenticator specified when opening the server. If the
+  "Authenticate to server in BUFFER, using current buffer if nil.
+It uses the authenticator specified when opening the server.  If the
 authenticator requires username/passwords, they are queried from the
 user and optionally stored in the buffer.  If USER and/or PASSWD is
 specified, the user will not be questioned and the username and/or
 password is remembered in the buffer."
   (with-current-buffer (or buffer (current-buffer))
 authenticator requires username/passwords, they are queried from the
 user and optionally stored in the buffer.  If USER and/or PASSWD is
 specified, the user will not be questioned and the username and/or
 password is remembered in the buffer."
   (with-current-buffer (or buffer (current-buffer))
-    (when (eq imap-state 'nonauth)
-      (make-variable-buffer-local 'imap-username)
-      (make-variable-buffer-local 'imap-password)
+    (if (not (eq imap-state 'nonauth))
+       (or (eq imap-state 'auth)
+           (eq imap-state 'select)
+           (eq imap-state 'examine))
+      (make-local-variable 'imap-username)
+      (make-local-variable 'imap-password)
       (if user (setq imap-username user))
       (if passwd (setq imap-password passwd))
       (if user (setq imap-username user))
       (if passwd (setq imap-password passwd))
-      (if (funcall (nth 2 (assq imap-auth imap-authenticator-alist)) buffer)
-         (setq imap-state 'auth)))))
+      (if imap-auth
+         (and (funcall (nth 2 (assq imap-auth
+                                    imap-authenticator-alist)) buffer)
+              (setq imap-state 'auth))
+       ;; Choose authenticator.
+       (let ((auths imap-authenticators)
+             auth)
+         (while (setq auth (pop auths))
+           ;; OK to use authenticator?
+           (when (funcall (nth 1 (assq auth imap-authenticator-alist)) buffer)
+             (message "imap: Authenticating to `%s' using `%s'..."
+                      imap-server auth)
+             (setq imap-auth auth)
+             (if (funcall (nth 2 (assq auth imap-authenticator-alist)) buffer)
+                 (progn
+                   (message "imap: Authenticating to `%s' using `%s'...done"
+                            imap-server auth)
+                   (setq auths nil))
+               (message "imap: Authenticating to `%s' using `%s'...failed"
+                        imap-server auth)))))
+       imap-state))))
 
 (defun imap-close (&optional buffer)
 
 (defun imap-close (&optional buffer)
-  "Close connection to server in BUFFER. If BUFFER is nil, the current
-buffer is used."
+  "Close connection to server in BUFFER.
+If BUFFER is nil, the current buffer is used."
   (with-current-buffer (or buffer (current-buffer))
   (with-current-buffer (or buffer (current-buffer))
-    (and (imap-opened)
-        (not (imap-ok-p (imap-send-command-wait "LOGOUT")))
-        (message "Server %s didn't let me log out" imap-server))
+    (when (imap-opened)
+      (condition-case nil
+         (imap-send-command-wait "LOGOUT")
+       (quit nil)))
     (when (and imap-process
               (memq (process-status imap-process) '(open run)))
       (delete-process imap-process))
     (when (and imap-process
               (memq (process-status imap-process) '(open run)))
       (delete-process imap-process))
@@ -702,9 +1051,9 @@ buffer is used."
     t))
 
 (defun imap-capability (&optional identifier buffer)
     t))
 
 (defun imap-capability (&optional identifier buffer)
-  "Return a list of identifiers which server in BUFFER support. If
-IDENTIFIER, return non-nil if it's among the servers capabilities. If
-BUFFER is nil, the current buffer is assumed."
+  "Return a list of identifiers which server in BUFFER support.
+If IDENTIFIER, return non-nil if it's among the servers capabilities.
+If BUFFER is nil, the current buffer is assumed."
   (with-current-buffer (or buffer (current-buffer))
     (unless imap-capability
       (unless (imap-ok-p (imap-send-command-wait "CAPABILITY"))
   (with-current-buffer (or buffer (current-buffer))
     (unless imap-capability
       (unless (imap-ok-p (imap-send-command-wait "CAPABILITY"))
@@ -714,8 +1063,8 @@ BUFFER is nil, the current buffer is assumed."
       imap-capability)))
 
 (defun imap-namespace (&optional buffer)
       imap-capability)))
 
 (defun imap-namespace (&optional buffer)
-  "Return a namespace hierarchy at server in BUFFER. If BUFFER is nil,
-the current buffer is assumed."
+  "Return a namespace hierarchy at server in BUFFER.
+If BUFFER is nil, the current buffer is assumed."
   (with-current-buffer (or buffer (current-buffer))
     (unless imap-namespace
       (when (imap-capability 'NAMESPACE)
   (with-current-buffer (or buffer (current-buffer))
     (unless imap-namespace
       (when (imap-capability 'NAMESPACE)
@@ -749,7 +1098,7 @@ the current buffer is assumed."
 (defun imap-mailbox-map-1 (func &optional mailbox-decoder buffer)
   (with-current-buffer (or buffer (current-buffer))
     (let (result)
 (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))
        (lambda (s)
         (push (funcall func (if mailbox-decoder
                                 (funcall mailbox-decoder (symbol-name s))
@@ -758,8 +1107,8 @@ the current buffer is assumed."
       result)))
 
 (defun imap-mailbox-map (func &optional buffer)
       result)))
 
 (defun imap-mailbox-map (func &optional buffer)
-  "Map a function across each mailbox in `imap-mailbox-data',
-returning a list. Function should take a mailbox name (a string) as
+  "Map a function across each mailbox in `imap-mailbox-data', returning a list.
+Function should take a mailbox name (a string) as
 the only argument."
   (imap-mailbox-map-1 func 'imap-utf7-decode buffer))
 
 the only argument."
   (imap-mailbox-map-1 func 'imap-utf7-decode buffer))
 
@@ -779,13 +1128,13 @@ the only argument."
     (imap-current-mailbox-p-1 (imap-utf7-encode mailbox) examine)))
 
 (defun imap-mailbox-select-1 (mailbox &optional examine)
     (imap-current-mailbox-p-1 (imap-utf7-encode mailbox) examine)))
 
 (defun imap-mailbox-select-1 (mailbox &optional examine)
-  "Select MAILBOX on server in BUFFER. If EXAMINE is non-nil, do a
-read-only select."
+  "Select MAILBOX on server in BUFFER.
+If EXAMINE is non-nil, do a read-only select."
   (if (imap-current-mailbox-p-1 mailbox examine)
       imap-current-mailbox
     (setq imap-current-mailbox mailbox)
     (if (imap-ok-p (imap-send-command-wait
   (if (imap-current-mailbox-p-1 mailbox examine)
       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)
                            mailbox "\"")))
        (progn
          (setq imap-message-data (make-vector imap-message-prime 0)
@@ -794,14 +1143,18 @@ read-only select."
       ;; Failed SELECT/EXAMINE unselects current mailbox
       (setq imap-current-mailbox nil))))
 
       ;; 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))
   (with-current-buffer (or buffer (current-buffer))
-    (imap-utf7-decode 
+    (imap-utf7-decode
      (imap-mailbox-select-1 (imap-utf7-encode mailbox) examine))))
 
      (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 'examine)))
+
 (defun imap-mailbox-examine (mailbox &optional buffer)
 (defun imap-mailbox-examine (mailbox &optional buffer)
-  "Examine MAILBOX on server in BUFFER"
-  (imap-mailbox-select mailbox 'exmine buffer))
+  "Examine MAILBOX on server in BUFFER."
+  (imap-mailbox-select mailbox 'examine buffer))
 
 (defun imap-mailbox-unselect (&optional buffer)
   "Close current folder in BUFFER, without expunging articles."
 
 (defun imap-mailbox-unselect (&optional buffer)
   "Close current folder in BUFFER, without expunging articles."
@@ -809,7 +1162,7 @@ read-only select."
     (when (or (eq imap-state 'auth)
              (and (imap-capability 'UNSELECT)
                   (imap-ok-p (imap-send-command-wait "UNSELECT")))
     (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
                                                    "\"")))
                    (imap-send-command-wait (concat "EXAMINE \""
                                                    imap-current-mailbox
                                                    "\"")))
@@ -819,44 +1172,60 @@ read-only select."
            imap-state 'auth)
       t)))
 
            imap-state 'auth)
       t)))
 
-(defun imap-mailbox-expunge (&optional buffer)
-  "Expunge articles in current folder in BUFFER. If BUFFER is
-nil the current buffer is assumed."
+(defun imap-mailbox-expunge (&optional asynch buffer)
+  "Expunge articles in current folder in BUFFER.
+If ASYNCH, do not wait for succesful completion of the command.
+If BUFFER is nil the current buffer is assumed."
   (with-current-buffer (or buffer (current-buffer))
     (when (and imap-current-mailbox (not (eq imap-state 'examine)))
   (with-current-buffer (or buffer (current-buffer))
     (when (and imap-current-mailbox (not (eq imap-state 'examine)))
-      (imap-ok-p (imap-send-command-wait "EXPUNGE")))))
-
-(defun imap-mailbox-close (&optional buffer)
-  "Expunge articles and close current folder in BUFFER. If BUFFER is
-nil the current buffer is assumed."
+      (if asynch
+         (imap-send-command "EXPUNGE")
+      (imap-ok-p (imap-send-command-wait "EXPUNGE"))))))
+
+(defun imap-mailbox-close (&optional asynch buffer)
+  "Expunge articles and close current folder in BUFFER.
+If ASYNCH, do not wait for succesful completion of the command.
+If BUFFER is nil the current buffer is assumed."
   (with-current-buffer (or buffer (current-buffer))
   (with-current-buffer (or buffer (current-buffer))
-    (when (and imap-current-mailbox
-              (imap-ok-p (imap-send-command-wait "CLOSE")))
-       (setq imap-current-mailbox nil
-             imap-message-data nil
-             imap-state 'auth)
-       t)))
+    (when imap-current-mailbox
+      (if asynch
+         (imap-add-callback (imap-send-command "CLOSE")
+                            `(lambda (tag status)
+                               (message "IMAP mailbox `%s' closed... %s"
+                                        imap-current-mailbox status)
+                               (when (eq ,imap-current-mailbox
+                                         imap-current-mailbox)
+                                 ;; Don't wipe out data if another mailbox
+                                 ;; was selected...
+                                 (setq imap-current-mailbox nil
+                                       imap-message-data nil
+                                       imap-state 'auth))))
+       (when (imap-ok-p (imap-send-command-wait "CLOSE"))
+         (setq imap-current-mailbox nil
+               imap-message-data nil
+               imap-state 'auth)))
+      t)))
 
 (defun imap-mailbox-create-1 (mailbox)
   (imap-ok-p (imap-send-command-wait (list "CREATE \"" mailbox "\""))))
 
 (defun imap-mailbox-create (mailbox &optional buffer)
 
 (defun imap-mailbox-create-1 (mailbox)
   (imap-ok-p (imap-send-command-wait (list "CREATE \"" mailbox "\""))))
 
 (defun imap-mailbox-create (mailbox &optional buffer)
-  "Create MAILBOX on server in BUFFER. If BUFFER is nil the current
-buffer is assumed."
+  "Create MAILBOX on server in BUFFER.
+If BUFFER is nil the current buffer is assumed."
   (with-current-buffer (or buffer (current-buffer))
     (imap-mailbox-create-1 (imap-utf7-encode mailbox))))
 
 (defun imap-mailbox-delete (mailbox &optional buffer)
   (with-current-buffer (or buffer (current-buffer))
     (imap-mailbox-create-1 (imap-utf7-encode mailbox))))
 
 (defun imap-mailbox-delete (mailbox &optional buffer)
-  "Delete MAILBOX on server in BUFFER. If BUFFER is nil the current
-buffer is assumed."
+  "Delete MAILBOX on server in BUFFER.
+If BUFFER is nil the current buffer is assumed."
   (let ((mailbox (imap-utf7-encode mailbox)))
     (with-current-buffer (or buffer (current-buffer))
       (imap-ok-p
        (imap-send-command-wait (list "DELETE \"" mailbox "\""))))))
 
 (defun imap-mailbox-rename (oldname newname &optional buffer)
   (let ((mailbox (imap-utf7-encode mailbox)))
     (with-current-buffer (or buffer (current-buffer))
       (imap-ok-p
        (imap-send-command-wait (list "DELETE \"" mailbox "\""))))))
 
 (defun imap-mailbox-rename (oldname newname &optional buffer)
-  "Rename mailbox OLDNAME to NEWNAME on server in BUFFER. If BUFFER is
-nil the current buffer is assumed."
+  "Rename mailbox OLDNAME to NEWNAME on server in BUFFER.
+If BUFFER is nil the current buffer is assumed."
   (let ((oldname (imap-utf7-encode oldname))
        (newname (imap-utf7-encode newname)))
     (with-current-buffer (or buffer (current-buffer))
   (let ((oldname (imap-utf7-encode oldname))
        (newname (imap-utf7-encode newname)))
     (with-current-buffer (or buffer (current-buffer))
@@ -864,10 +1233,10 @@ nil the current buffer is assumed."
        (imap-send-command-wait (list "RENAME \"" oldname "\" "
                                     "\"" newname "\""))))))
 
        (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
   "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
+non-nil, a hierarchy delimiter is added to root.  REFERENCE is a
 implementation-specific string that has to be passed to lsub command."
   (with-current-buffer (or buffer (current-buffer))
     ;; Make sure we know the hierarchy separator for root's hierarchy
 implementation-specific string that has to be passed to lsub command."
   (with-current-buffer (or buffer (current-buffer))
     ;; Make sure we know the hierarchy separator for root's hierarchy
@@ -878,7 +1247,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-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))
                    "%\"")))
            (concat "LSUB \"" reference "\" \"" (imap-utf7-encode root)
                    (and add-delimiter (imap-mailbox-get-1 'delimiter root))
                    "%\"")))
@@ -891,7 +1260,7 @@ implementation-specific string that has to be passed to lsub command."
 (defun imap-mailbox-list (root &optional reference add-delimiter buffer)
   "Return a list of mailboxes matching ROOT on server in BUFFER.
 If ADD-DELIMITER is non-nil, a hierarchy delimiter is added to
 (defun imap-mailbox-list (root &optional reference add-delimiter buffer)
   "Return a list of mailboxes matching ROOT on server in BUFFER.
 If ADD-DELIMITER is non-nil, a hierarchy delimiter is added to
-root. REFERENCE is a implementation-specific string that has to be
+root.  REFERENCE is a implementation-specific string that has to be
 passed to list command."
   (with-current-buffer (or buffer (current-buffer))
     ;; Make sure we know the hierarchy separator for root's hierarchy
 passed to list command."
   (with-current-buffer (or buffer (current-buffer))
     ;; Make sure we know the hierarchy separator for root's hierarchy
@@ -902,7 +1271,7 @@ passed to list command."
     (imap-mailbox-map-1 (lambda (mailbox)
                          (imap-mailbox-put 'list nil mailbox)))
     (when (imap-ok-p
     (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))
                    "%\"")))
            (concat "LIST \"" reference "\" \"" (imap-utf7-encode root)
                    (and add-delimiter (imap-mailbox-get-1 'delimiter root))
                    "%\"")))
@@ -913,41 +1282,55 @@ passed to list command."
        (nreverse out)))))
 
 (defun imap-mailbox-subscribe (mailbox &optional buffer)
        (nreverse out)))))
 
 (defun imap-mailbox-subscribe (mailbox &optional buffer)
-  "Send the SUBSCRIBE command on the mailbox to server in
-BUFFER. 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))
   (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)
                                               "\"")))))
 
 (defun imap-mailbox-unsubscribe (mailbox &optional buffer)
                                               (imap-utf7-encode mailbox)
                                               "\"")))))
 
 (defun imap-mailbox-unsubscribe (mailbox &optional buffer)
-  "Send the SUBSCRIBE command on the mailbox to server in
-BUFFER. 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))
   (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)
                                               "\"")))))
 
 (defun imap-mailbox-status (mailbox items &optional buffer)
                                               (imap-utf7-encode mailbox)
                                               "\"")))))
 
 (defun imap-mailbox-status (mailbox items &optional buffer)
-  "Get status items ITEM in MAILBOX from server in BUFFER. ITEMS can
-be a symbol or a list of symbols, valid symbols are one of 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."
+  "Get status items ITEM in MAILBOX from server in BUFFER.
+ITEMS can be a symbol or a list of symbols, valid symbols are one of
+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))
   (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)
           (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)
                                                   (list items))))))
       (if (listp items)
          (mapcar (lambda (item)
-                   (imap-mailbox-get-1 item mailbox))
+                   (imap-mailbox-get item mailbox))
                  items)
                  items)
-       (imap-mailbox-get-1 items mailbox)))))
+       (imap-mailbox-get items mailbox)))))
+
+(defun imap-mailbox-status-asynch (mailbox items &optional buffer)
+  "Send status item request ITEM on MAILBOX to server in BUFFER.
+ITEMS can be a symbol or a list of symbols, valid symbols are one of
+the STATUS data items -- ie 'messages, 'recent, 'uidnext, 'uidvalidity
+or 'unseen.  The IMAP command tag is returned."
+  (with-current-buffer (or buffer (current-buffer))
+    (imap-send-command (list "STATUS \""
+                            (imap-utf7-encode mailbox)
+                            "\" "
+                            (format "%s"
+                                    (if (listp items)
+                                        items
+                                      (list items)))))))
 
 (defun imap-mailbox-acl-get (&optional mailbox buffer)
   "Get ACL on mailbox from server in BUFFER."
 
 (defun imap-mailbox-acl-get (&optional mailbox buffer)
   "Get ACL on mailbox from server in BUFFER."
@@ -957,11 +1340,10 @@ if ITEMS is a symbol only it's value is returned."
             (imap-send-command-wait (list "GETACL \""
                                           (or mailbox imap-current-mailbox)
                                           "\"")))
             (imap-send-command-wait (list "GETACL \""
                                           (or mailbox imap-current-mailbox)
                                           "\"")))
-      (imap-mailbox-get-1 'acl (or mailbox imap-current-mailbox))))))
+       (imap-mailbox-get-1 'acl (or mailbox imap-current-mailbox))))))
 
 (defun imap-mailbox-acl-set (identifier rights &optional mailbox buffer)
 
 (defun imap-mailbox-acl-set (identifier rights &optional mailbox buffer)
-  "Change/set ACL for IDENTIFIER to RIGHTS in MAILBOX from server in
-BUFFER."
+  "Change/set ACL for IDENTIFIER to RIGHTS in MAILBOX from server in BUFFER."
   (let ((mailbox (imap-utf7-encode mailbox)))
     (with-current-buffer (or buffer (current-buffer))
       (imap-ok-p
   (let ((mailbox (imap-utf7-encode mailbox)))
     (with-current-buffer (or buffer (current-buffer))
       (imap-ok-p
@@ -973,8 +1355,7 @@ BUFFER."
                                     rights))))))
 
 (defun imap-mailbox-acl-delete (identifier &optional mailbox buffer)
                                     rights))))))
 
 (defun imap-mailbox-acl-delete (identifier &optional mailbox buffer)
-  "Removes any <identifier,rights> pair for IDENTIFIER in MAILBOX from
-server in BUFFER."
+  "Removes any <identifier,rights> pair for IDENTIFIER in MAILBOX from server in BUFFER."
   (let ((mailbox (imap-utf7-encode mailbox)))
     (with-current-buffer (or buffer (current-buffer))
       (imap-ok-p
   (let ((mailbox (imap-utf7-encode mailbox)))
     (with-current-buffer (or buffer (current-buffer))
       (imap-ok-p
@@ -998,6 +1379,18 @@ server in BUFFER."
               (list list))
             ","))
 
               (list list))
             ","))
 
+(defun imap-range-to-message-set (range)
+  (mapconcat
+   (lambda (item)
+     (if (consp 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))
+     range)
+   ","))
+
 (defun imap-fetch-asynch (uids props &optional nouidfetch buffer)
   (with-current-buffer (or buffer (current-buffer))
     (imap-send-command (format "%sFETCH %s %s" (if nouidfetch "" "UID ")
 (defun imap-fetch-asynch (uids props &optional nouidfetch buffer)
   (with-current-buffer (or buffer (current-buffer))
     (imap-send-command (format "%sFETCH %s %s" (if nouidfetch "" "UID ")
@@ -1007,11 +1400,11 @@ server in BUFFER."
                               props))))
 
 (defun imap-fetch (uids props &optional receive nouidfetch buffer)
                               props))))
 
 (defun imap-fetch (uids props &optional receive nouidfetch buffer)
-  "Fetch properties PROPS from message set UIDS from server in
-BUFFER. UIDS can be a string, number or a list of numbers. If RECEIVE
+  "Fetch properties PROPS from message set UIDS from server in BUFFER.
+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))
 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)
                      (format "%sFETCH %s %s" (if nouidfetch "" "UID ")
                              (if (listp uids)
                                  (imap-list-to-message-set uids)
@@ -1028,7 +1421,7 @@ is non-nil return theese properties."
                        (imap-message-get uid receive)))
                    uids)
          (imap-message-get uids receive))))))
                        (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
 (defun imap-message-put (uid propname value &optional buffer)
   (with-current-buffer (or buffer (current-buffer))
     (if imap-message-data
@@ -1044,8 +1437,7 @@ is non-nil return theese properties."
         propname)))
 
 (defun imap-message-map (func propname &optional buffer)
         propname)))
 
 (defun imap-message-map (func propname &optional buffer)
-  "Map a function across each mailbox in `imap-message-data',
-returning a list."
+  "Map a function across each mailbox in `imap-message-data', returning a list."
   (with-current-buffer (or buffer (current-buffer))
     (let (result)
       (mapatoms
   (with-current-buffer (or buffer (current-buffer))
     (let (result)
       (mapatoms
@@ -1103,12 +1495,13 @@ returning a list."
     (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)
     (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)
        (imap-mailbox-get-1 'search imap-current-mailbox)))))
 
 (defun imap-message-flag-permanent-p (flag &optional mailbox buffer)
-  "Return t iff FLAG can be permanently (between IMAP sessions) saved
-on articles, in MAILBOX on server in BUFFER."
+  "Return t iff FLAG can be permanently (between IMAP sessions) saved on articles, in MAILBOX on server in BUFFER."
   (with-current-buffer (or buffer (current-buffer))
     (or (member "\\*" (imap-mailbox-get 'permanentflags mailbox))
        (member flag (imap-mailbox-get 'permanentflags mailbox)))))
   (with-current-buffer (or buffer (current-buffer))
     (or (member "\\*" (imap-mailbox-get 'permanentflags mailbox))
        (member flag (imap-mailbox-get 'permanentflags mailbox)))))
@@ -1141,7 +1534,7 @@ on articles, in MAILBOX on server in BUFFER."
     (let ((old-mailbox imap-current-mailbox)
          (state imap-state)
          (imap-message-data (make-vector 2 0)))
     (let ((old-mailbox imap-current-mailbox)
          (state imap-state)
          (imap-message-data (make-vector 2 0)))
-      (when (imap-mailbox-examine mailbox)
+      (when (imap-mailbox-examine-1 mailbox)
        (prog1
            (and (imap-fetch "*" "UID")
                 (list (imap-mailbox-get-1 'uidvalidity mailbox)
        (prog1
            (and (imap-fetch "*" "UID")
                 (list (imap-mailbox-get-1 'uidvalidity mailbox)
@@ -1158,8 +1551,8 @@ on articles, in MAILBOX on server in BUFFER."
 (defun imap-message-copy (articles mailbox
                                   &optional dont-create no-copyuid buffer)
   "Copy ARTICLES (a string message set) to MAILBOX on server in
 (defun imap-message-copy (articles mailbox
                                   &optional dont-create no-copyuid buffer)
   "Copy ARTICLES (a string message set) to MAILBOX on server in
-BUFFER, creating mailbox if it doesn't exist. If dont-create is
-non-nil, it will not create a mailbox. On success, return a list with
+BUFFER, creating mailbox if it doesn't exist.  If dont-create is
+non-nil, it will not create a mailbox.  On success, return a list with
 the UIDVALIDITY of the mailbox the article(s) was copied to as the
 first element, rest of list contain the saved articles' UIDs."
   (when articles
 the UIDVALIDITY of the mailbox the article(s) was copied to as the
 first element, rest of list contain the saved articles' UIDs."
   (when articles
@@ -1170,19 +1563,22 @@ first element, rest of list contain the saved articles' UIDs."
              (if (imap-ok-p (imap-send-command-wait cmd))
                  t
                (when (and (not dont-create)
              (if (imap-ok-p (imap-send-command-wait cmd))
                  t
                (when (and (not dont-create)
-                          (imap-mailbox-get-1 'trycreate mailbox))
-                 (imap-mailbox-create-1 mailbox)
+                          ;; removed because of buggy Oracle server
+                          ;; that doesn't send TRYCREATE tags (which
+                          ;; is a MUST according to specifications):
+                          ;;(imap-mailbox-get-1 'trycreate mailbox)
+                          (imap-mailbox-create-1 mailbox))
                  (imap-ok-p (imap-send-command-wait cmd)))))
            (or no-copyuid
                (imap-message-copyuid-1 mailbox)))))))
                  (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)
     (let ((old-mailbox imap-current-mailbox)
          (state imap-state)
          (imap-message-data (make-vector 2 0)))
 (defun imap-message-appenduid-1 (mailbox)
   (if (imap-capability 'UIDPLUS)
       (imap-mailbox-get-1 'appenduid mailbox)
     (let ((old-mailbox imap-current-mailbox)
          (state imap-state)
          (imap-message-data (make-vector 2 0)))
-      (when (imap-mailbox-examine mailbox)
+      (when (imap-mailbox-examine-1 mailbox)
        (prog1
            (and (imap-fetch "*" "UID")
                 (list (imap-mailbox-get-1 'uidvalidity mailbox)
        (prog1
            (and (imap-fetch "*" "UID")
                 (list (imap-mailbox-get-1 'uidvalidity mailbox)
@@ -1197,26 +1593,26 @@ first element, rest of list contain the saved articles' UIDs."
     (imap-message-appenduid-1 (imap-utf7-encode mailbox))))
 
 (defun imap-message-append (mailbox article &optional flags date-time buffer)
     (imap-message-appenduid-1 (imap-utf7-encode mailbox))))
 
 (defun imap-message-append (mailbox article &optional flags date-time buffer)
-  "Append ARTICLE (a buffer) to MAILBOX on server in BUFFER. FLAGS and
-DATE-TIME is currently not used. Return a cons holding uidvalidity of
-MAILBOX and UID the newly created article got, or nil on failure."
+  "Append ARTICLE (a buffer) to MAILBOX on server in BUFFER.
+FLAGS and DATE-TIME is currently not used.  Return a cons holding
+uidvalidity of MAILBOX and UID the newly created article got, or nil
+on failure."
   (let ((mailbox (imap-utf7-encode mailbox)))
     (with-current-buffer (or buffer (current-buffer))
       (and (let ((imap-current-target-mailbox mailbox))
   (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)))))
               (list "APPEND \"" mailbox "\" "  article))))
           (imap-message-appenduid-1 mailbox)))))
-  
+
 (defun imap-body-lines (body)
 (defun imap-body-lines (body)
-  "Return number of lines in article by looking at the mime bodystructure
-BODY."
+  "Return number of lines in article by looking at the mime bodystructure BODY."
   (if (listp body)
       (if (stringp (car body))
   (if (listp body)
       (if (stringp (car body))
-         (cond ((and (string= (car body) "TEXT")
+         (cond ((and (string= (upcase (car body)) "TEXT")
                      (numberp (nth 7 body)))
                 (nth 7 body))
                      (numberp (nth 7 body)))
                 (nth 7 body))
-               ((and (string= (car body) "MESSAGE")
+               ((and (string= (upcase (car body)) "MESSAGE")
                      (numberp (nth 9 body)))
                 (nth 9 body))
                (t 0))
                      (numberp (nth 9 body)))
                 (nth 9 body))
                (t 0))
@@ -1228,18 +1624,21 @@ BODY."
   (and from
        (concat (aref from 0)
               (if (aref from 0) " <")
   (and from
        (concat (aref from 0)
               (if (aref from 0) " <")
-              (aref from 2) 
-              "@" 
+              (aref from 2)
+              "@"
               (aref from 3)
               (if (aref from 0) ">"))))
 
 \f
 ;; Internal functions.
 
               (aref from 3)
               (if (aref from 0) ">"))))
 
 \f
 ;; Internal functions.
 
+(defun imap-add-callback (tag func)
+  (setq imap-callbacks (append (list (cons tag func)) imap-callbacks)))
+
 (defun imap-send-command-1 (cmdstr)
   (setq cmdstr (concat cmdstr imap-client-eol))
   (and imap-log
 (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))
         (imap-disable-multibyte)
         (buffer-disable-undo)
         (goto-char (point-max))
@@ -1256,9 +1655,21 @@ BODY."
        (cond ((stringp cmd)
               (setq cmdstr (concat cmdstr cmd)))
              ((bufferp cmd)
        (cond ((stringp cmd)
               (setq cmdstr (concat cmdstr cmd)))
              ((bufferp cmd)
-              (setq cmdstr 
-                    (concat cmdstr (format "{%d}" (with-current-buffer cmd
-                                                    (buffer-size)))))
+              (let ((eol imap-client-eol)
+                    (calcfirst imap-calculate-literal-size-first)
+                    size)
+                (with-current-buffer cmd
+                  (if calcfirst
+                      (setq size (buffer-size)))
+                  (when (not (equal eol "\r\n"))
+                    ;; XXX modifies buffer!
+                    (goto-char (point-min))
+                    (while (search-forward "\r\n" nil t)
+                      (replace-match eol)))
+                  (if (not calcfirst)
+                      (setq size (buffer-size))))
+                (setq cmdstr
+                      (concat cmdstr (format "{%d}" size))))
               (unwind-protect
                   (progn
                     (imap-send-command-1 cmdstr)
               (unwind-protect
                   (progn
                     (imap-send-command-1 cmdstr)
@@ -1266,16 +1677,12 @@ BODY."
                     (if (not (eq (imap-wait-for-tag tag) 'INCOMPLETE))
                         (setq command nil) ;; abort command if no cont-req
                       (let ((process imap-process)
                     (if (not (eq (imap-wait-for-tag tag) 'INCOMPLETE))
                         (setq command nil) ;; abort command if no cont-req
                       (let ((process imap-process)
-                            (stream imap-stream))
+                            (stream imap-stream)
+                            (eol imap-client-eol))
                         (with-current-buffer cmd
                         (with-current-buffer cmd
-                          (when (eq stream 'kerberos4)
-                            ;; XXX modifies buffer!
-                            (goto-char (point-min))
-                            (while (search-forward "\r\n" nil t)
-                              (replace-match "\n")))
                           (and imap-log
                                (with-current-buffer (get-buffer-create
                           (and imap-log
                                (with-current-buffer (get-buffer-create
-                                                     imap-log)
+                                                     imap-log-buffer)
                                  (imap-disable-multibyte)
                                  (buffer-disable-undo)
                                  (goto-char (point-max))
                                  (imap-disable-multibyte)
                                  (buffer-disable-undo)
                                  (goto-char (point-max))
@@ -1301,22 +1708,30 @@ BODY."
 
 (defun imap-wait-for-tag (tag &optional buffer)
   (with-current-buffer (or buffer (current-buffer))
 
 (defun imap-wait-for-tag (tag &optional buffer)
   (with-current-buffer (or buffer (current-buffer))
-    (while (and (null imap-continuation)
-               (< imap-reached-tag tag))
-      (or (and (not (memq (process-status imap-process) '(open run)))
-              (sit-for 1))
+    (let (imap-have-messaged)
+      (while (and (null imap-continuation)
+                 (memq (process-status imap-process) '(open run))
+                 (< imap-reached-tag tag))
+       (let ((len (/ (point-max) 1024))
+             message-log-max)
+         (unless (< len 10)
+           (setq imap-have-messaged t)
+           (message "imap read: %dk" len))
          (accept-process-output imap-process 1)))
          (accept-process-output imap-process 1)))
-    (or (assq tag imap-failed-tags)
-       (if imap-continuation
-           'INCOMPLETE
-         'OK))))
+      (when imap-have-messaged
+       (message ""))
+      (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))
 
 (defun imap-find-next-line ()
 
 (defun imap-sentinel (process string)
   (delete-process process))
 
 (defun imap-find-next-line ()
-  "Return point at end of current line, taking into account
-literals. Return nil if no complete line has arrived."
+  "Return point at end of current line, taking into account literals.
+Return nil if no complete line has arrived."
   (when (re-search-forward (concat imap-server-eol "\\|{\\([0-9]+\\)}"
                                   imap-server-eol)
                           nil t)
   (when (re-search-forward (concat imap-server-eol "\\|{\\([0-9]+\\)}"
                                   imap-server-eol)
                           nil t)
@@ -1333,7 +1748,7 @@ literals. Return nil if no complete line has arrived."
     (goto-char (point-max))
     (insert string)
     (and imap-log
     (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))
           (imap-disable-multibyte)
           (buffer-disable-undo)
           (goto-char (point-max))
@@ -1354,7 +1769,7 @@ literals. Return nil if no complete line has arrived."
                         (eq imap-state 'examine))
                     (imap-parse-response))
                    (t
                         (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))))))))
 
                              imap-state)))
            (delete-region (point-min) (point-max))))))))
 
@@ -1384,7 +1799,7 @@ literals. Return nil if no complete line has arrived."
       (if (< (point-max) (+ pos len))
          nil
        (goto-char (+ pos len))
       (if (< (point-max) (+ pos len))
          nil
        (goto-char (+ pos len))
-       (buffer-substring-no-properties pos (+ pos len))))))
+       (buffer-substring pos (+ pos len))))))
 
 ;;   string          = quoted / literal
 ;;
 
 ;;   string          = quoted / literal
 ;;
@@ -1398,13 +1813,20 @@ literals. Return nil if no complete line has arrived."
 ;;   TEXT-CHAR       = <any CHAR except CR and LF>
 
 (defsubst imap-parse-string ()
 ;;   TEXT-CHAR       = <any CHAR except CR and LF>
 
 (defsubst imap-parse-string ()
-  (let (strstart strend)
-    (cond ((and (eq (char-after) ?\")
-               (setq strstart (point))
-               (setq strend (search-forward "\"" nil t 2)))
-          (buffer-substring-no-properties (1+ strstart) (1- strend)))
-         ((eq (char-after) ?{)
-          (imap-parse-literal)))))
+  (cond ((eq (char-after) ?\")
+        (forward-char 1)
+        (let ((p (point)) (name ""))
+          (skip-chars-forward "^\"\\\\")
+          (setq name (buffer-substring p (point)))
+          (while (eq (char-after) ?\\)
+            (setq p (1+ (point)))
+            (forward-char 2)
+            (skip-chars-forward "^\"\\\\")
+            (setq name (concat name (buffer-substring p (point)))))
+          (forward-char 1)
+          name))
+       ((eq (char-after) ?{)
+        (imap-parse-literal))))
 
 ;;   nil             = "NIL"
 
 
 ;;   nil             = "NIL"
 
@@ -1434,7 +1856,7 @@ literals. Return nil if no complete line has arrived."
 
 (defsubst imap-parse-astring ()
   (or (imap-parse-string)
 
 (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)
                        (if (re-search-forward "[(){ \r\n%*\"\\]" nil t)
                            (goto-char (1- (match-end 0)))
                          (end-of-line)
@@ -1445,21 +1867,21 @@ literals. Return nil if no complete line has arrived."
 ;;
 ;;   addr-adl        = nstring
 ;;                       ; Holds route from [RFC-822] route-addr if
 ;;
 ;;   addr-adl        = nstring
 ;;                       ; Holds route from [RFC-822] route-addr if
-;;                       ; non-NIL
+;;                       ; non-nil
 ;;
 ;;   addr-host       = nstring
 ;;
 ;;   addr-host       = nstring
-;;                       ; NIL indicates [RFC-822] group syntax.
+;;                       ; nil indicates [RFC-822] group syntax.
 ;;                       ; Otherwise, holds [RFC-822] domain name
 ;;
 ;;   addr-mailbox    = nstring
 ;;                       ; Otherwise, holds [RFC-822] domain name
 ;;
 ;;   addr-mailbox    = nstring
-;;                       ; NIL indicates end of [RFC-822] group; if
-;;                       ; non-NIL and addr-host is NIL, holds
+;;                       ; nil indicates end of [RFC-822] group; if
+;;                       ; non-nil and addr-host is nil, holds
 ;;                       ; [RFC-822] group name.
 ;;                       ; Otherwise, holds [RFC-822] local-part
 ;;                       ; after removing [RFC-822] quoting
 ;;
 ;;   addr-name       = nstring
 ;;                       ; [RFC-822] group name.
 ;;                       ; Otherwise, holds [RFC-822] local-part
 ;;                       ; after removing [RFC-822] quoting
 ;;
 ;;   addr-name       = nstring
-;;                       ; If non-NIL, holds phrase from [RFC-822]
+;;                       ; If non-nil, holds phrase from [RFC-822]
 ;;                       ; mailbox after removing [RFC-822] quoting
 ;;
 
 ;;                       ; mailbox after removing [RFC-822] quoting
 ;;
 
@@ -1494,7 +1916,7 @@ literals. Return nil if no complete line has arrived."
        (when (eq (char-after) ?\))
          (imap-forward)
          (nreverse addresses)))
        (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
 
 ;;   mailbox         = "INBOX" / astring
 ;;                       ; INBOX is case-insensitive.  All case variants of
@@ -1547,7 +1969,7 @@ literals. Return nil if no complete line has arrived."
 ;;   resp-cond-bye   = "BYE" SP resp-text
 ;;
 ;;   mailbox-data    =  "FLAGS" SP flag-list /
 ;;   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) /
 ;;                      "STATUS" SP mailbox SP "("
 ;;                      "LSUB" SP mailbox-list /
 ;;                     "SEARCH" *(SP nz-number) /
 ;;                      "STATUS" SP mailbox SP "("
@@ -1580,14 +2002,14 @@ literals. 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))
           (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))
                        (read (concat "(" (buffer-substring (point) (point-max)) ")"))))
           (STATUS     (imap-parse-status))
-          (CAPABILITY (setq imap-capability 
-                            (read (concat "(" (upcase (buffer-substring
-                                                       (point) (point-max)))
-                                          ")"))))
+          (CAPABILITY (setq imap-capability
+                              (read (concat "(" (upcase (buffer-substring
+                                                         (point) (point-max)))
+                                            ")"))))
           (ACL        (imap-parse-acl))
           (t       (case (prog1 (read (current-buffer))
                            (imap-forward))
           (ACL        (imap-parse-acl))
           (t       (case (prog1 (read (current-buffer))
                            (imap-forward))
@@ -1614,7 +2036,7 @@ literals. Return nil if no complete line has arrived."
                                                       (search-forward "]")))
                          (imap-forward))
                        (setq text (buffer-substring (point) (point-max)))
                                                       (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))
                              imap-failed-tags))))
               (BAD (progn
                      (setq imap-reached-tag (max imap-reached-tag token))
@@ -1629,7 +2051,11 @@ literals. Return nil if no complete line has arrived."
                        (push (list token status code text) imap-failed-tags)
                        (error "Internal error, tag %s status %s code %s text %s"
                               token status code text))))
                        (push (list token status code text) imap-failed-tags)
                        (error "Internal error, tag %s status %s code %s text %s"
                               token status code text))))
-              (t   (message "Garbage: %s" (buffer-string))))))))))
+              (t   (message "Garbage: %s" (buffer-string))))
+            (when (assq token imap-callbacks)
+              (funcall (cdr (assq token imap-callbacks)) token status)
+              (setq imap-callbacks
+                    (imap-remassoc token imap-callbacks)))))))))
 
 ;;   resp-text       = ["[" resp-text-code "]" SP] text
 ;;
 
 ;;   resp-text       = ["[" resp-text-code "]" SP] text
 ;;
@@ -1642,14 +2068,14 @@ literals. Return nil if no complete line has arrived."
 
 ;;   resp-text-code  = "ALERT" /
 ;;                     "BADCHARSET [SP "(" astring *(SP astring) ")" ] /
 
 ;;   resp-text-code  = "ALERT" /
 ;;                     "BADCHARSET [SP "(" astring *(SP astring) ")" ] /
-;;                     "NEWNAME" SP string SP string / 
+;;                     "NEWNAME" SP string SP string /
 ;;                    "PARSE" /
 ;;                    "PARSE" /
-;;                     "PERMANENTFLAGS" SP "(" 
+;;                     "PERMANENTFLAGS" SP "("
 ;;                               [flag-perm *(SP flag-perm)] ")" /
 ;;                               [flag-perm *(SP flag-perm)] ")" /
-;;                     "READ-ONLY" / 
-;;                    "READ-WRITE" / 
-;;                    "TRYCREATE" /
-;;                     "UIDNEXT" 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 "]">]
 ;;                    "UIDVALIDITY" SP nz-number /
 ;;                     "UNSEEN" SP nz-number /
 ;;                     resp-text-atom [SP 1*<any TEXT-CHAR except "]">]
@@ -1668,7 +2094,7 @@ literals. 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.
 ;;                          ; 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
 ;;   sequence-num    = nz-number / "*"
 ;;                          ; * is the largest number in use.  For message
 ;;                          ; sequence numbers, it is the number of messages
@@ -1695,12 +2121,15 @@ literals. Return nil if no complete line has arrived."
 ;;   resp-text-atom  = 1*<any ATOM-CHAR except "]">
 
 (defun imap-parse-resp-text-code ()
 ;;   resp-text-atom  = 1*<any ATOM-CHAR except "]">
 
 (defun imap-parse-resp-text-code ()
+  ;; xxx next line for stalker communigate pro 3.3.1 bug
+  (when (looking-at " \\[")
+    (imap-forward))
   (when (eq (char-after) ?\[)
     (imap-forward)
     (cond ((search-forward "PERMANENTFLAGS " nil t)
           (imap-mailbox-put 'permanentflags (imap-parse-flag-list)))
   (when (eq (char-after) ?\[)
     (imap-forward)
     (cond ((search-forward "PERMANENTFLAGS " nil t)
           (imap-mailbox-put 'permanentflags (imap-parse-flag-list)))
-         ((search-forward "UIDNEXT " nil t)
-          (imap-mailbox-put 'uidnext (read (current-buffer))))
+         ((search-forward "UIDNEXT \\([0-9]+\\)" nil t)
+          (imap-mailbox-put 'uidnext (match-string 1)))
          ((search-forward "UNSEEN " nil t)
           (imap-mailbox-put 'unseen (read (current-buffer))))
          ((looking-at "UIDVALIDITY \\([0-9]+\\)")
          ((search-forward "UNSEEN " nil t)
           (imap-mailbox-put 'unseen (read (current-buffer))))
          ((looking-at "UIDVALIDITY \\([0-9]+\\)")
@@ -1766,18 +2195,18 @@ literals. Return nil if no complete line has arrived."
 ;;                      "BODY" ["STRUCTURE"] SPACE body /
 ;;                      "BODY" section ["<" number ">"] SPACE nstring /
 ;;                      "UID" SPACE uniqueid) ")"
 ;;                      "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 <">
 ;;  date_time       ::= <"> date_day_fixed "-" date_month "-" date_year
 ;;                      SPACE time SPACE zone <">
-;;  
+;;
 ;;  section         ::= "[" [section_text / (nz_number *["." nz_number]
 ;;                      ["." (section_text / "MIME")])] "]"
 ;;  section         ::= "[" [section_text / (nz_number *["." nz_number]
 ;;                      ["." (section_text / "MIME")])] "]"
-;;  
+;;
 ;;  section_text    ::= "HEADER" / "HEADER.FIELDS" [".NOT"]
 ;;                      SPACE header_list / "TEXT"
 ;;  section_text    ::= "HEADER" / "HEADER.FIELDS" [".NOT"]
 ;;                      SPACE header_list / "TEXT"
-;;  
+;;
 ;;  header_fld_name ::= astring
 ;;  header_fld_name ::= astring
-;;  
+;;
 ;;  header_list     ::= "(" 1#header_fld_name ")"
 
 (defsubst imap-parse-header-list ()
 ;;  header_list     ::= "(" 1#header_fld_name ")"
 
 (defsubst imap-parse-header-list ()
@@ -1790,7 +2219,7 @@ literals. Return nil if no complete line has arrived."
       (nreverse strlist))))
 
 (defsubst imap-parse-fetch-body-section ()
       (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
         (buffer-substring (point) (1- (re-search-forward "[] ]" nil t)))))
     (if (eq (char-before) ? )
        (prog1
@@ -1800,16 +2229,20 @@ literals. Return nil if no complete line has arrived."
 
 (defun imap-parse-fetch (response)
   (when (eq (char-after) ?\()
 
 (defun imap-parse-fetch (response)
   (when (eq (char-after) ?\()
-    (let (uid flags envelope internaldate rfc822 rfc822header rfc822text 
-             rfc822size body bodydetail bodystructure)
+    (let (uid flags envelope internaldate rfc822 rfc822header rfc822text
+             rfc822size body bodydetail bodystructure flags-empty)
       (while (not (eq (char-after) ?\)))
        (imap-forward)
        (let ((token (read (current-buffer))))
          (imap-forward)
          (cond ((eq token 'UID)
       (while (not (eq (char-after) ?\)))
        (imap-forward)
        (let ((token (read (current-buffer))))
          (imap-forward)
          (cond ((eq token 'UID)
-                (setq uid (ignore-errors (read (current-buffer)))))
+                (setq uid (condition-case ()
+                              (read (current-buffer))
+                            (error))))
                ((eq token 'FLAGS)
                ((eq token 'FLAGS)
-                (setq flags (imap-parse-flag-list)))
+                (setq flags (imap-parse-flag-list))
+                (if (not flags)
+                    (setq flags-empty 't)))
                ((eq token 'ENVELOPE)
                 (setq envelope (imap-parse-envelope)))
                ((eq token 'INTERNALDATE)
                ((eq token 'ENVELOPE)
                 (setq envelope (imap-parse-envelope)))
                ((eq token 'INTERNALDATE)
@@ -1838,7 +2271,7 @@ literals. Return nil if no complete line has arrived."
       (when uid
        (setq imap-current-message uid)
        (imap-message-put uid 'UID uid)
       (when uid
        (setq imap-current-message uid)
        (imap-message-put uid 'UID uid)
-       (and flags (imap-message-put uid 'FLAGS flags))
+       (and (or flags flags-empty) (imap-message-put uid 'FLAGS flags))
        (and envelope (imap-message-put uid 'ENVELOPE envelope))
        (and internaldate (imap-message-put uid 'INTERNALDATE internaldate))
        (and rfc822 (imap-message-put uid 'RFC822 rfc822))
        (and envelope (imap-message-put uid 'ENVELOPE envelope))
        (and internaldate (imap-message-put uid 'INTERNALDATE internaldate))
        (and rfc822 (imap-message-put uid 'RFC822 rfc822))
@@ -1852,7 +2285,7 @@ literals. Return nil if no complete line has arrived."
 
 ;;   mailbox-data    =  ...
 ;;                      "STATUS" SP mailbox SP "("
 
 ;;   mailbox-data    =  ...
 ;;                      "STATUS" SP mailbox SP "("
-;;                           [status-att SP number 
+;;                           [status-att SP number
 ;;                            *(SP status-att SP number)] ")"
 ;;                      ...
 ;;
 ;;                            *(SP status-att SP number)] ")"
 ;;                      ...
 ;;
@@ -1869,7 +2302,9 @@ literals. Return nil if no complete line has arrived."
                ((eq token 'RECENT)
                 (imap-mailbox-put 'recent (read (current-buffer)) mailbox))
                ((eq token 'UIDNEXT)
                ((eq token 'RECENT)
                 (imap-mailbox-put 'recent (read (current-buffer)) mailbox))
                ((eq token 'UIDNEXT)
-                (imap-mailbox-put 'uidnext (read (current-buffer)) mailbox))
+                (and (looking-at " \\([0-9]+\\)")
+                     (imap-mailbox-put 'uidnext (match-string 1) mailbox)
+                     (goto-char (match-end 1))))
                ((eq token 'UIDVALIDITY)
                 (and (looking-at " \\([0-9]+\\)")
                      (imap-mailbox-put 'uidvalidity (match-string 1) mailbox)
                ((eq token 'UIDVALIDITY)
                 (and (looking-at " \\([0-9]+\\)")
                      (imap-mailbox-put 'uidvalidity (match-string 1) mailbox)
@@ -1877,7 +2312,7 @@ literals. Return nil if no complete line has arrived."
                ((eq token 'UNSEEN)
                 (imap-mailbox-put 'unseen (read (current-buffer)) mailbox))
                (t
                ((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
                          token mailbox))))))))
 
 ;;   acl_data        ::= "ACL" SPACE mailbox *(SPACE identifier SPACE
@@ -1915,12 +2350,19 @@ literals. Return nil if no complete line has arrived."
 ;;                       ; revisions of this specification.
 
 (defun imap-parse-flag-list ()
 ;;                       ; revisions of this specification.
 
 (defun imap-parse-flag-list ()
-  (let ((str (buffer-substring-no-properties
-             (point) (search-forward ")" nil t)))
-       pos)
-    (while (setq pos (string-match "\\\\" str (and pos (+ 2 pos))))
-      (setq str (replace-match "\\\\" nil t str)))
-    (mapcar 'symbol-name (read str))))
+  (let (flag-list start)
+    (assert (eq (char-after) ?\() t "In imap-parse-flag-list")
+    (while (and (not (eq (char-after) ?\)))
+               (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) ?\)) t "In imap-parse-flag-list")
+    (imap-forward)
+    (nreverse flag-list)))
 
 ;;   envelope        = "(" env-date SP env-subject SP env-from SP env-sender SP
 ;;                     env-reply-to SP env-to SP env-cc SP env-bcc SP
 
 ;;   envelope        = "(" env-date SP env-subject SP env-from SP env-sender SP
 ;;                     env-reply-to SP env-to SP env-cc SP env-bcc SP
@@ -1949,9 +2391,9 @@ literals. Return nil if no complete line has arrived."
 (defun imap-parse-envelope ()
   (when (eq (char-after) ?\()
     (imap-forward)
 (defun imap-parse-envelope ()
   (when (eq (char-after) ?\()
     (imap-forward)
-    (vector (prog1 (imap-parse-nstring)      ;; date
+    (vector (prog1 (imap-parse-nstring)        ;; date
              (imap-forward))
              (imap-forward))
-           (prog1 (imap-parse-nstring)      ;; subject
+           (prog1 (imap-parse-nstring) ;; subject
              (imap-forward))
            (prog1 (imap-parse-address-list) ;; from
              (imap-forward))
              (imap-forward))
            (prog1 (imap-parse-address-list) ;; from
              (imap-forward))
@@ -1965,20 +2407,23 @@ literals. Return nil if no complete line has arrived."
              (imap-forward))
            (prog1 (imap-parse-address-list) ;; bcc
              (imap-forward))
              (imap-forward))
            (prog1 (imap-parse-address-list) ;; bcc
              (imap-forward))
-           (prog1 (imap-parse-nstring)      ;; in-reply-to
+           (prog1 (imap-parse-nstring) ;; in-reply-to
              (imap-forward))
              (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 ()
              (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))
             (push str strlist)
         (let (strlist str)
           (imap-forward)
           (while (setq str (imap-parse-string))
             (push str strlist)
-            (imap-forward))
+            ;; buggy stalker communigate pro 3.0 doesn't print SPC
+            ;; between body-fld-param's sometimes
+            (or (eq (char-after) ?\")
+                (imap-forward)))
           (nreverse strlist)))
        ((imap-parse-nil)
         nil)))
           (nreverse strlist)))
        ((imap-parse-nil)
         nil)))
@@ -2000,7 +2445,7 @@ literals. Return nil if no complete line has arrived."
        (while (eq (char-after) ?\ )
          (imap-forward)
          (push (imap-parse-body-extension) b-e))
        (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)
        (imap-forward)
        (nreverse b-e))
     (or (imap-parse-number)
@@ -2018,7 +2463,7 @@ literals. Return nil if no complete line has arrived."
 
 (defsubst imap-parse-body-ext ()
   (let (ext)
 
 (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) ?\()
       (imap-forward)
       (let (dsp)
        (if (eq (char-after) ?\()
@@ -2028,14 +2473,14 @@ literals. Return nil if no complete line has arrived."
              (imap-forward)
              (push (imap-parse-string-list) dsp)
              (imap-forward))
              (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))
        (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))
        (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))
          (imap-forward)
          (setq ext (append (imap-parse-body-extension) ext)))))
     ext))
@@ -2109,172 +2554,183 @@ literals. Return nil if no complete line has arrived."
          (let (subbody)
            (while (and (eq (char-after) ?\()
                        (setq subbody (imap-parse-body)))
          (let (subbody)
            (while (and (eq (char-after) ?\()
                        (setq subbody (imap-parse-body)))
+            ;; 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 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)
              (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-...
                  (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) ?\)))
+           (assert (eq (char-after) ?\)) t "In imap-parse-body")
            (imap-forward)
            (nreverse body))
 
            (imap-forward)
            (nreverse body))
 
-       (push (imap-parse-string) body)                   ;; media-type
+       (push (imap-parse-string) body) ;; media-type
        (imap-forward)
        (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))
        (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-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)
        (imap-forward)
-       (push (imap-parse-nstring) body)                  ;; body-fld-desc
+       (push (imap-parse-nstring) body) ;; body-fld-desc
        (imap-forward)
        (imap-forward)
-       (push (imap-parse-string) body)                   ;; body-fld-enc
+       ;; 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
        (imap-forward)
        (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)
        ;;
        ;; 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)
 
        (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)
                   (imap-forward)
-                  (push (imap-parse-body) body)          ;; 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
+                  (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
                  (t
                  (t
-                  (backward-char)))))                    ;; no match...
+                  (backward-char))))) ;; no match...
 
        ;; ...and then parse the third one here...
 
 
        ;; ...and then parse the third one here...
 
-       (when (eq (char-after) ?\ )                       ;; body-ext-1part:
+       (when (eq (char-after) ?\ ) ;; body-ext-1part:
          (imap-forward)
          (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)))))
 
        (imap-forward)
        (nreverse body)))))
 
-(when imap-debug ; (untrace-all)
+(when imap-debug                       ; (untrace-all)
   (require 'trace)
   (require 'trace)
-  (buffer-disable-undo (get-buffer-create imap-debug))
-  (mapc (lambda (f) (trace-function-background f imap-debug)) 
-        '(
-imap-read-passwd
-imap-utf7-encode
-imap-utf7-decode
-imap-error-text
-imap-kerberos4s-p
-imap-kerberos4-open
-imap-ssl-p
-imap-ssl-open-2
-imap-ssl-open-1
-imap-ssl-open
-imap-network-p
-imap-network-open
-imap-interactive-login
-imap-kerberos4a-p
-imap-kerberos4-auth
-imap-cram-md5-p
-imap-cram-md5-auth
-imap-login-p
-imap-login-auth
-imap-anonymous-p
-imap-anonymous-auth
-imap-open-1
-imap-open
-imap-opened
-imap-authenticate
-imap-close
-imap-capability
-imap-namespace
-imap-send-command-wait
-imap-mailbox-put
-imap-mailbox-get
-imap-mailbox-map-1
-imap-mailbox-map
-imap-current-mailbox
-imap-current-mailbox-p-1
-imap-current-mailbox-p
-imap-mailbox-select-1
-imap-mailbox-select
-imap-mailbox-examine
-imap-mailbox-unselect
-imap-mailbox-expunge
-imap-mailbox-close
-imap-mailbox-create-1
-imap-mailbox-create
-imap-mailbox-delete
-imap-mailbox-rename
-imap-mailbox-lsub
-imap-mailbox-list
-imap-mailbox-subscribe
-imap-mailbox-unsubscribe
-imap-mailbox-status
-imap-mailbox-acl-get
-imap-mailbox-acl-set
-imap-mailbox-acl-delete
-imap-current-message
-imap-list-to-message-set
-imap-fetch-asynch
-imap-fetch
-imap-message-put
-imap-message-get
-imap-message-map
-imap-search
-imap-message-flag-permanent-p
-imap-message-flags-set
-imap-message-flags-del
-imap-message-flags-add
-imap-message-copyuid-1
-imap-message-copyuid
-imap-message-copy
-imap-message-appenduid-1
-imap-message-appenduid
-imap-message-append
-imap-body-lines
-imap-envelope-from
-imap-send-command-1
-imap-send-command
-imap-wait-for-tag
-imap-sentinel
-imap-find-next-line
-imap-arrival-filter
-imap-parse-greeting
-imap-parse-response
-imap-parse-resp-text
-imap-parse-resp-text-code
-imap-parse-data-list
-imap-parse-fetch
-imap-parse-status
-imap-parse-acl
-imap-parse-flag-list
-imap-parse-envelope
-imap-parse-body-extension
-imap-parse-body
-         )))
-       
+  (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
+           imap-utf7-decode
+           imap-error-text
+           imap-kerberos4s-p
+           imap-kerberos4-open
+           imap-ssl-p
+           imap-ssl-open
+           imap-network-p
+           imap-network-open
+           imap-interactive-login
+           imap-kerberos4a-p
+           imap-kerberos4-auth
+           imap-cram-md5-p
+           imap-cram-md5-auth
+           imap-login-p
+           imap-login-auth
+           imap-anonymous-p
+           imap-anonymous-auth
+           imap-open-1
+           imap-open
+           imap-opened
+           imap-authenticate
+           imap-close
+           imap-capability
+           imap-namespace
+           imap-send-command-wait
+           imap-mailbox-put
+           imap-mailbox-get
+           imap-mailbox-map-1
+           imap-mailbox-map
+           imap-current-mailbox
+           imap-current-mailbox-p-1
+           imap-current-mailbox-p
+           imap-mailbox-select-1
+           imap-mailbox-select
+           imap-mailbox-examine-1
+           imap-mailbox-examine
+           imap-mailbox-unselect
+           imap-mailbox-expunge
+           imap-mailbox-close
+           imap-mailbox-create-1
+           imap-mailbox-create
+           imap-mailbox-delete
+           imap-mailbox-rename
+           imap-mailbox-lsub
+           imap-mailbox-list
+           imap-mailbox-subscribe
+           imap-mailbox-unsubscribe
+           imap-mailbox-status
+           imap-mailbox-acl-get
+           imap-mailbox-acl-set
+           imap-mailbox-acl-delete
+           imap-current-message
+           imap-list-to-message-set
+           imap-fetch-asynch
+           imap-fetch
+           imap-message-put
+           imap-message-get
+           imap-message-map
+           imap-search
+           imap-message-flag-permanent-p
+           imap-message-flags-set
+           imap-message-flags-del
+           imap-message-flags-add
+           imap-message-copyuid-1
+           imap-message-copyuid
+           imap-message-copy
+           imap-message-appenduid-1
+           imap-message-appenduid
+           imap-message-append
+           imap-body-lines
+           imap-envelope-from
+           imap-send-command-1
+           imap-send-command
+           imap-wait-for-tag
+           imap-sentinel
+           imap-find-next-line
+           imap-arrival-filter
+           imap-parse-greeting
+           imap-parse-response
+           imap-parse-resp-text
+           imap-parse-resp-text-code
+           imap-parse-data-list
+           imap-parse-fetch
+           imap-parse-status
+           imap-parse-acl
+           imap-parse-flag-list
+           imap-parse-envelope
+           imap-parse-body-extension
+           imap-parse-body
+           )))
+
 (provide 'imap)
 
 ;;; imap.el ends here
 (provide 'imap)
 
 ;;; imap.el ends here