+;;; IMAP parser.
+
+(defvar elmo-imap4-server-eol "\r\n"
+ "The EOL string sent from the server.")
+
+(defvar elmo-imap4-client-eol "\r\n"
+ "The EOL string we send to the server.")
+
+(defun elmo-imap4-find-next-line ()
+ "Return point at end of current line, taking into account literals.
+Return nil if no complete line has arrived."
+ (when (re-search-forward (concat elmo-imap4-server-eol "\\|{\\([0-9]+\\)}"
+ elmo-imap4-server-eol)
+ nil t)
+ (if (match-string 1)
+ (if (< (point-max) (+ (point) (string-to-number (match-string 1))))
+ nil
+ (goto-char (+ (point) (string-to-number (match-string 1))))
+ (elmo-imap4-find-next-line))
+ (point))))
+
+(defun elmo-imap4-sentinel (process string)
+ (delete-process process))
+
+(defun elmo-imap4-arrival-filter (proc string)
+ "IMAP process filter."
+ (when (buffer-live-p (process-buffer proc))
+ (with-current-buffer (process-buffer proc)
+ (elmo-imap4-debug "-> %s" string)
+ (goto-char (point-max))
+ (insert string)
+ (let (end)
+ (goto-char (point-min))
+ (while (setq end (elmo-imap4-find-next-line))
+ (save-restriction
+ (narrow-to-region (point-min) end)
+ (delete-backward-char (length elmo-imap4-server-eol))
+ (goto-char (point-min))
+ (unwind-protect
+ (cond ((eq elmo-imap4-status 'initial)
+ (setq elmo-imap4-current-response
+ (list
+ (list 'greeting (elmo-imap4-parse-greeting)))))
+ ((or (eq elmo-imap4-status 'auth)
+ (eq elmo-imap4-status 'nonauth)
+ (eq elmo-imap4-status 'selected)
+ (eq elmo-imap4-status 'examine))
+ (setq elmo-imap4-current-response
+ (cons
+ (elmo-imap4-parse-response)
+ elmo-imap4-current-response)))
+ (t
+ (message "Unknown state %s in arrival filter"
+ elmo-imap4-status))))
+ (delete-region (point-min) (point-max))))))))
+
+;; IMAP parser.
+
+(defsubst elmo-imap4-forward ()
+ (or (eobp) (forward-char 1)))
+
+(defsubst elmo-imap4-parse-number ()
+ (when (looking-at "[0-9]+")
+ (prog1
+ (string-to-number (match-string 0))
+ (goto-char (match-end 0)))))
+
+(defsubst elmo-imap4-parse-literal ()
+ (when (looking-at "{\\([0-9]+\\)}\r\n")
+ (let ((pos (match-end 0))
+ (len (string-to-number (match-string 1))))
+ (if (< (point-max) (+ pos len))
+ nil
+ (goto-char (+ pos len))
+ (buffer-substring pos (+ pos len))))))
+;;; (list ' pos (+ pos len))))))
+
+(defsubst elmo-imap4-parse-string ()
+ (cond ((eq (char-after (point)) ?\")
+ (forward-char 1)
+ (let ((p (point)) (name ""))
+ (skip-chars-forward "^\"\\\\")
+ (setq name (buffer-substring p (point)))
+ (while (eq (char-after (point)) ?\\)
+ (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 (point)) ?{)
+ (elmo-imap4-parse-literal))))
+
+(defsubst elmo-imap4-parse-nil ()
+ (if (looking-at "NIL")
+ (goto-char (match-end 0))))
+
+(defsubst elmo-imap4-parse-nstring ()
+ (or (elmo-imap4-parse-string)
+ (and (elmo-imap4-parse-nil)
+ nil)))
+
+(defsubst elmo-imap4-parse-astring ()
+ (or (elmo-imap4-parse-string)
+ (buffer-substring (point)
+ (if (re-search-forward "[(){ \r\n%*\"\\]" nil t)
+ (goto-char (1- (match-end 0)))
+ (end-of-line)
+ (point)))))
+
+(defsubst elmo-imap4-parse-address ()
+ (let (address)
+ (when (eq (char-after (point)) ?\()
+ (elmo-imap4-forward)
+ (setq address (vector (prog1 (elmo-imap4-parse-nstring)
+ (elmo-imap4-forward))
+ (prog1 (elmo-imap4-parse-nstring)
+ (elmo-imap4-forward))
+ (prog1 (elmo-imap4-parse-nstring)
+ (elmo-imap4-forward))
+ (elmo-imap4-parse-nstring)))
+ (when (eq (char-after (point)) ?\))
+ (elmo-imap4-forward)
+ address))))
+
+(defsubst elmo-imap4-parse-address-list ()
+ (if (eq (char-after (point)) ?\()
+ (let (address addresses)
+ (elmo-imap4-forward)
+ (while (and (not (eq (char-after (point)) ?\)))
+ ;; next line for MS Exchange bug
+ (progn (and (eq (char-after (point)) ? ) (elmo-imap4-forward)) t)
+ (setq address (elmo-imap4-parse-address)))
+ (setq addresses (cons address addresses)))
+ (when (eq (char-after (point)) ?\))
+ (elmo-imap4-forward)
+ (nreverse addresses)))
+ (assert (elmo-imap4-parse-nil))))
+
+(defsubst elmo-imap4-parse-mailbox ()
+ (let ((mailbox (elmo-imap4-parse-astring)))
+ (if (string-equal "INBOX" (upcase mailbox))
+ "INBOX"
+ mailbox)))
+
+(defun elmo-imap4-parse-greeting ()
+ "Parse a IMAP greeting."
+ (cond ((looking-at "\\* OK ")
+ (setq elmo-imap4-status 'nonauth))
+ ((looking-at "\\* PREAUTH ")
+ (setq elmo-imap4-status 'auth))
+ ((looking-at "\\* BYE ")
+ (setq elmo-imap4-status 'closed))))
+
+(defun elmo-imap4-parse-response ()
+ "Parse a IMAP command response."
+ (let (token)
+ (case (setq token (elmo-read (current-buffer)))
+ (+ (progn
+ (skip-chars-forward " ")
+ (list 'continue-req (buffer-substring (point) (point-max)))))
+ (* (case (prog1 (setq token (elmo-read (current-buffer)))
+ (elmo-imap4-forward))
+ (OK (elmo-imap4-parse-resp-text-code))
+ (NO (elmo-imap4-parse-resp-text-code))
+ (BAD (elmo-imap4-parse-resp-text-code))
+ (BYE (elmo-imap4-parse-bye))
+ (FLAGS (list 'flags
+ (elmo-imap4-parse-flag-list)))
+ (LIST (list 'list (elmo-imap4-parse-data-list)))
+ (LSUB (list 'lsub (elmo-imap4-parse-data-list)))
+ (SEARCH (list
+ 'search
+ (elmo-read (concat "("
+ (buffer-substring (point) (point-max))
+ ")"))))
+ (STATUS (elmo-imap4-parse-status))
+ ;; Added
+ (NAMESPACE (elmo-imap4-parse-namespace))
+ (CAPABILITY (list 'capability
+ (elmo-read
+ (concat "(" (downcase (buffer-substring
+ (point) (point-max)))
+ ")"))))
+ (ACL (elmo-imap4-parse-acl))
+ (t (case (prog1 (elmo-read (current-buffer))
+ (elmo-imap4-forward))
+ (EXISTS (list 'exists token))
+ (RECENT (list 'recent token))
+ (EXPUNGE (list 'expunge token))
+ (FETCH (elmo-imap4-parse-fetch token))
+ (t (list 'garbage (buffer-string)))))))
+ (t (if (not (string-match elmo-imap4-seq-prefix (symbol-name token)))
+ (list 'garbage (buffer-string))
+ (case (prog1 (elmo-read (current-buffer))
+ (elmo-imap4-forward))
+ (OK (progn
+ (setq elmo-imap4-parsing nil)
+ (setq token (symbol-name token))
+ (elmo-unintern token)
+ (elmo-imap4-debug "*%s* OK arrived" token)
+ (setq elmo-imap4-reached-tag token)
+ (list 'ok (elmo-imap4-parse-resp-text-code))))
+ (NO (progn
+ (setq elmo-imap4-parsing nil)
+ (setq token (symbol-name token))
+ (elmo-unintern token)
+ (elmo-imap4-debug "*%s* NO arrived" token)
+ (setq elmo-imap4-reached-tag token)
+ (let (code text)
+ (when (eq (char-after (point)) ?\[)
+ (setq code (buffer-substring (point)
+ (search-forward "]")))
+ (elmo-imap4-forward))
+ (setq text (buffer-substring (point) (point-max)))
+ (list 'no (list code text)))))
+ (BAD (progn
+ (setq elmo-imap4-parsing nil)
+ (elmo-imap4-debug "*%s* BAD arrived" token)
+ (setq token (symbol-name token))
+ (elmo-unintern token)
+ (setq elmo-imap4-reached-tag token)
+ (let (code text)
+ (when (eq (char-after (point)) ?\[)
+ (setq code (buffer-substring (point)
+ (search-forward "]")))
+ (elmo-imap4-forward))
+ (setq text (buffer-substring (point) (point-max)))
+ (list 'bad (list code text)))))
+ (t (list 'garbage (buffer-string)))))))))
+
+(defun elmo-imap4-parse-bye ()
+ (let (code text)
+ (when (eq (char-after (point)) ?\[)
+ (setq code (buffer-substring (point)
+ (search-forward "]")))
+ (elmo-imap4-forward))
+ (setq text (buffer-substring (point) (point-max)))
+ (list 'bye (list code text))))
+
+(defun elmo-imap4-parse-text ()
+ (goto-char (point-min))
+ (when (search-forward "[" nil t)
+ (search-forward "]")
+ (elmo-imap4-forward))
+ (list 'text (buffer-substring (point) (point-max))))
+
+(defun elmo-imap4-parse-resp-text-code ()
+ (when (eq (char-after (point)) ?\[)
+ (elmo-imap4-forward)
+ (cond ((search-forward "PERMANENTFLAGS " nil t)
+ (list 'permanentflags (elmo-imap4-parse-flag-list)))
+ ((search-forward "UIDNEXT " nil t)
+ (list 'uidnext (elmo-read (current-buffer))))
+ ((search-forward "UNSEEN " nil t)
+ (list 'unseen (elmo-read (current-buffer))))
+ ((looking-at "UIDVALIDITY \\([0-9]+\\)")
+ (list 'uidvalidity (match-string 1)))
+ ((search-forward "READ-ONLY" nil t)
+ (list 'read-only t))
+ ((search-forward "READ-WRITE" nil t)
+ (list 'read-write t))
+ ((search-forward "NEWNAME " nil t)
+ (let (oldname newname)
+ (setq oldname (elmo-imap4-parse-string))
+ (elmo-imap4-forward)
+ (setq newname (elmo-imap4-parse-string))
+ (list 'newname newname oldname)))
+ ((search-forward "TRYCREATE" nil t)
+ (list 'trycreate t))
+ ((looking-at "APPENDUID \\([0-9]+\\) \\([0-9]+\\)")
+ (list 'appenduid
+ (list (match-string 1)
+ (string-to-number (match-string 2)))))
+ ((looking-at "COPYUID \\([0-9]+\\) \\([0-9,:]+\\) \\([0-9,:]+\\)")
+ (list 'copyuid (list (match-string 1)
+ (match-string 2)
+ (match-string 3))))
+ ((search-forward "ALERT] " nil t)
+ (message "IMAP server information: %s"
+ (buffer-substring (point) (point-max))))
+ (t (list 'unknown)))))
+
+(defun elmo-imap4-parse-data-list ()
+ (let (flags delimiter mailbox)
+ (setq flags (elmo-imap4-parse-flag-list))
+ (when (looking-at " NIL\\| \"\\\\?\\(.\\)\"")
+ (setq delimiter (match-string 1))
+ (goto-char (1+ (match-end 0)))
+ (when (setq mailbox (elmo-imap4-parse-mailbox))
+ (list mailbox flags delimiter)))))
+
+(defsubst elmo-imap4-parse-header-list ()
+ (when (eq (char-after (point)) ?\()
+ (let (strlist)
+ (while (not (eq (char-after (point)) ?\)))
+ (elmo-imap4-forward)
+ (push (elmo-imap4-parse-astring) strlist))
+ (elmo-imap4-forward)
+ (nreverse strlist))))
+
+(defsubst elmo-imap4-parse-fetch-body-section ()
+ (let ((section
+ (buffer-substring (point)
+ (1-
+ (progn (re-search-forward "[] ]" nil t)
+ (point))))))
+ (if (eq (char-before) ? )
+ (prog1
+ (mapconcat 'identity
+ (cons section (elmo-imap4-parse-header-list)) " ")
+ (search-forward "]" nil t))
+ section)))
+
+(defun elmo-imap4-parse-fetch (response)
+ (when (eq (char-after (point)) ?\()
+ (let (element list)
+ (while (not (eq (char-after (point)) ?\)))
+ (elmo-imap4-forward)
+ (let ((token (elmo-imap4-fetch-read (current-buffer))))
+ (elmo-imap4-forward)
+ (setq element
+ (cond ((eq token 'UID)
+ (list 'uid (condition-case nil
+ (elmo-read (current-buffer))
+ (error nil))))
+ ((eq token 'FLAGS)
+ (list 'flags (elmo-imap4-parse-flag-list)))
+ ((eq token 'ENVELOPE)
+ (list 'envelope (elmo-imap4-parse-envelope)))
+ ((eq token 'INTERNALDATE)
+ (list 'internaldate (elmo-imap4-parse-string)))
+ ((eq token 'RFC822)
+ (list 'rfc822 (elmo-imap4-parse-nstring)))
+ ((eq token (intern elmo-imap4-rfc822-header))
+ (list 'rfc822header (elmo-imap4-parse-nstring)))
+ ((eq token (intern elmo-imap4-rfc822-text))
+ (list 'rfc822text (elmo-imap4-parse-nstring)))
+ ((eq token (intern elmo-imap4-rfc822-size))
+ (list 'rfc822size (elmo-read (current-buffer))))
+ ((eq token 'BODY)
+ (if (eq (char-before) ?\[)
+ (list
+ 'bodydetail
+ (upcase (elmo-imap4-parse-fetch-body-section))
+ (and
+ (eq (char-after (point)) ?<)
+ (buffer-substring (1+ (point))
+ (progn
+ (search-forward ">" nil t)
+ (point))))
+ (progn (elmo-imap4-forward)
+ (elmo-imap4-parse-nstring)))
+ (list 'body (elmo-imap4-parse-body))))
+ ((eq token 'BODYSTRUCTURE)
+ (list 'bodystructure (elmo-imap4-parse-body)))))
+ (setq list (cons element list))))
+ (and elmo-imap4-fetch-callback
+ (elmo-imap4-fetch-callback list elmo-imap4-fetch-callback-data))
+ (list 'fetch list))))
+
+(defun elmo-imap4-parse-status ()
+ (let ((mailbox (elmo-imap4-parse-mailbox))
+ status)
+ (when (and mailbox (search-forward "(" nil t))
+ (while (not (eq (char-after (point)) ?\)))
+ (setq status
+ (cons
+ (let ((token (elmo-read (current-buffer))))
+ (cond ((eq token 'MESSAGES)
+ (list 'messages (elmo-read (current-buffer))))
+ ((eq token 'RECENT)
+ (list 'recent (elmo-read (current-buffer))))
+ ((eq token 'UIDNEXT)
+ (list 'uidnext (elmo-read (current-buffer))))
+ ((eq token 'UIDVALIDITY)
+ (and (looking-at " \\([0-9]+\\)")
+ (prog1 (list 'uidvalidity (match-string 1))
+ (goto-char (match-end 1)))))
+ ((eq token 'UNSEEN)
+ (list 'unseen (elmo-read (current-buffer))))
+ (t
+ (message
+ "Unknown status data %s in mailbox %s ignored"
+ token mailbox))))
+ status))))
+ (and elmo-imap4-status-callback
+ (funcall elmo-imap4-status-callback
+ status
+ elmo-imap4-status-callback-data))
+ (list 'status status)))
+
+
+(defmacro elmo-imap4-value (value)
+ (` (if (eq (, value) 'NIL) nil
+ (, value))))
+
+(defmacro elmo-imap4-nth (pos list)
+ (` (let ((value (nth (, pos) (, list))))
+ (elmo-imap4-value value))))
+
+(defun elmo-imap4-parse-namespace ()
+ (list 'namespace
+ (nconc
+ (copy-sequence elmo-imap4-extra-namespace-alist)
+ (elmo-imap4-parse-namespace-subr
+ (elmo-read (concat "(" (buffer-substring
+ (point) (point-max))
+ ")"))))))
+
+(defun elmo-imap4-parse-namespace-subr (ns)
+ (let (prefix delim namespace-alist default-delim)
+ ;; 0: personal, 1: other, 2: shared
+ (dotimes (i 3)
+ (setq namespace-alist
+ (nconc namespace-alist
+ (delq nil
+ (mapcar
+ (lambda (namespace)
+ (setq prefix (elmo-imap4-nth 0 namespace)
+ delim (elmo-imap4-nth 1 namespace))
+ (if (and prefix delim
+ (string-match
+ (concat (regexp-quote delim) "\\'")
+ prefix))
+ (setq prefix (substring prefix 0
+ (match-beginning 0))))
+ (if (eq (length prefix) 0)
+ (progn (setq default-delim delim) nil)
+ (cons
+ (concat "^"
+ (if (string= (downcase prefix) "inbox")
+ "[Ii][Nn][Bb][Oo][Xx]"
+ (regexp-quote prefix))
+ ".*$")
+ delim)))
+ (elmo-imap4-nth i ns))))))
+ (if default-delim
+ (setq namespace-alist
+ (nconc namespace-alist
+ (list (cons "^.*$" default-delim)))))
+ namespace-alist))
+
+(defun elmo-imap4-parse-acl ()
+ (let ((mailbox (elmo-imap4-parse-mailbox))
+ identifier rights acl)
+ (while (eq (char-after (point)) ?\ )
+ (elmo-imap4-forward)
+ (setq identifier (elmo-imap4-parse-astring))
+ (elmo-imap4-forward)
+ (setq rights (elmo-imap4-parse-astring))
+ (setq acl (append acl (list (cons identifier rights)))))
+ (list 'acl acl mailbox)))
+
+(defun elmo-imap4-parse-flag-list ()
+ (let ((str (buffer-substring (+ (point) 1)
+ (progn (search-forward ")" nil t)
+ (- (point) 1)))))
+ (unless (eq (length str) 0)
+ (split-string str))))
+
+(defun elmo-imap4-parse-envelope ()
+ (when (eq (char-after (point)) ?\()
+ (elmo-imap4-forward)
+ (vector (prog1 (elmo-imap4-parse-nstring);; date
+ (elmo-imap4-forward))
+ (prog1 (elmo-imap4-parse-nstring);; subject
+ (elmo-imap4-forward))
+ (prog1 (elmo-imap4-parse-address-list);; from
+ (elmo-imap4-forward))
+ (prog1 (elmo-imap4-parse-address-list);; sender
+ (elmo-imap4-forward))
+ (prog1 (elmo-imap4-parse-address-list);; reply-to
+ (elmo-imap4-forward))
+ (prog1 (elmo-imap4-parse-address-list);; to
+ (elmo-imap4-forward))
+ (prog1 (elmo-imap4-parse-address-list);; cc
+ (elmo-imap4-forward))
+ (prog1 (elmo-imap4-parse-address-list);; bcc
+ (elmo-imap4-forward))
+ (prog1 (elmo-imap4-parse-nstring);; in-reply-to
+ (elmo-imap4-forward))
+ (prog1 (elmo-imap4-parse-nstring);; message-id
+ (elmo-imap4-forward)))))
+
+(defsubst elmo-imap4-parse-string-list ()
+ (cond ((eq (char-after (point)) ?\();; body-fld-param
+ (let (strlist str)
+ (elmo-imap4-forward)
+ (while (setq str (elmo-imap4-parse-string))
+ (push str strlist)
+ (elmo-imap4-forward))
+ (nreverse strlist)))
+ ((elmo-imap4-parse-nil)
+ nil)))
+
+(defun elmo-imap4-parse-body-extension ()
+ (if (eq (char-after (point)) ?\()
+ (let (b-e)
+ (elmo-imap4-forward)
+ (push (elmo-imap4-parse-body-extension) b-e)
+ (while (eq (char-after (point)) ?\ )
+ (elmo-imap4-forward)
+ (push (elmo-imap4-parse-body-extension) b-e))
+ (assert (eq (char-after (point)) ?\)))
+ (elmo-imap4-forward)
+ (nreverse b-e))
+ (or (elmo-imap4-parse-number)
+ (elmo-imap4-parse-nstring))))
+
+(defsubst elmo-imap4-parse-body-ext ()
+ (let (ext)
+ (when (eq (char-after (point)) ?\ );; body-fld-dsp
+ (elmo-imap4-forward)
+ (let (dsp)
+ (if (eq (char-after (point)) ?\()
+ (progn
+ (elmo-imap4-forward)
+ (push (elmo-imap4-parse-string) dsp)
+ (elmo-imap4-forward)
+ (push (elmo-imap4-parse-string-list) dsp)
+ (elmo-imap4-forward))
+ (assert (elmo-imap4-parse-nil)))
+ (push (nreverse dsp) ext))
+ (when (eq (char-after (point)) ?\ );; body-fld-lang
+ (elmo-imap4-forward)
+ (if (eq (char-after (point)) ?\()
+ (push (elmo-imap4-parse-string-list) ext)
+ (push (elmo-imap4-parse-nstring) ext))
+ (while (eq (char-after (point)) ?\ );; body-extension
+ (elmo-imap4-forward)
+ (setq ext (append (elmo-imap4-parse-body-extension) ext)))))
+ ext))
+
+(defun elmo-imap4-parse-body ()
+ (let (body)
+ (when (eq (char-after (point)) ?\()
+ (elmo-imap4-forward)
+ (if (eq (char-after (point)) ?\()
+ (let (subbody)
+ (while (and (eq (char-after (point)) ?\()
+ (setq subbody (elmo-imap4-parse-body)))
+ (push subbody body))
+ (elmo-imap4-forward)
+ (push (elmo-imap4-parse-string) body);; media-subtype
+ (when (eq (char-after (point)) ?\ );; body-ext-mpart:
+ (elmo-imap4-forward)
+ (if (eq (char-after (point)) ?\();; body-fld-param
+ (push (elmo-imap4-parse-string-list) body)
+ (push (and (elmo-imap4-parse-nil) nil) body))
+ (setq body
+ (append (elmo-imap4-parse-body-ext) body)));; body-ext-...
+ (assert (eq (char-after (point)) ?\)))
+ (elmo-imap4-forward)
+ (nreverse body))
+
+ (push (elmo-imap4-parse-string) body);; media-type
+ (elmo-imap4-forward)
+ (push (elmo-imap4-parse-string) body);; media-subtype
+ (elmo-imap4-forward)
+ ;; next line for Sun SIMS bug
+ (and (eq (char-after (point)) ? ) (elmo-imap4-forward))
+ (if (eq (char-after (point)) ?\();; body-fld-param
+ (push (elmo-imap4-parse-string-list) body)
+ (push (and (elmo-imap4-parse-nil) nil) body))
+ (elmo-imap4-forward)
+ (push (elmo-imap4-parse-nstring) body);; body-fld-id
+ (elmo-imap4-forward)
+ (push (elmo-imap4-parse-nstring) body);; body-fld-desc
+ (elmo-imap4-forward)
+ (push (elmo-imap4-parse-string) body);; body-fld-enc
+ (elmo-imap4-forward)
+ (push (elmo-imap4-parse-number) body);; body-fld-octets
+
+ ;; ok, we're done parsing the required parts, what comes now is one
+ ;; of three things:
+ ;;
+ ;; envelope (then we're parsing body-type-msg)
+ ;; body-fld-lines (then we're parsing body-type-text)
+ ;; body-ext-1part (then we're parsing body-type-basic)
+ ;;
+ ;; the problem is that the two first are in turn optionally followed
+ ;; by the third. So we parse the first two here (if there are any)...
+
+ (when (eq (char-after (point)) ?\ )
+ (elmo-imap4-forward)
+ (let (lines)
+ (cond ((eq (char-after (point)) ?\();; body-type-msg:
+ (push (elmo-imap4-parse-envelope) body);; envelope
+ (elmo-imap4-forward)
+ (push (elmo-imap4-parse-body) body);; body
+ (elmo-imap4-forward)
+ (push (elmo-imap4-parse-number) body));; body-fld-lines
+ ((setq lines (elmo-imap4-parse-number));; body-type-text:
+ (push lines body));; body-fld-lines
+ (t
+ (backward-char)))));; no match...
+
+ ;; ...and then parse the third one here...
+
+ (when (eq (char-after (point)) ?\ );; body-ext-1part:
+ (elmo-imap4-forward)
+ (push (elmo-imap4-parse-nstring) body);; body-fld-md5
+ (setq body
+ (append (elmo-imap4-parse-body-ext) body)));; body-ext-1part..
+
+ (assert (eq (char-after (point)) ?\)))
+ (elmo-imap4-forward)
+ (nreverse body)))))
+
+(require 'product)
+(product-provide (provide 'elmo-imap4) (require 'elmo-version))