1 ;;; elmo-imap4.el -- IMAP4 Interface for ELMO.
3 ;; Copyright (C) 1998,1999,2000 Yuuichi Teranishi <teranisi@gohome.org>
4 ;; Copyright (C) 1999,2000 Kenichi OKADA <okada@opaopa.org>
5 ;; Copyright (C) 2000 OKAZAKI Tetsurou <okazaki@be.to>
6 ;; Copyright (C) 2000 Daiki Ueno <ueno@unixuser.org>
8 ;; Author: Yuuichi Teranishi <teranisi@gohome.org>
9 ;; Kenichi OKADA <okada@opaopa.org>
10 ;; OKAZAKI Tetsurou <okazaki@be.to>
11 ;; Daiki Ueno <ueno@unixuser.org>
12 ;; Keywords: mail, net news
14 ;; This file is part of ELMO (Elisp Library for Message Orchestration).
16 ;; This program is free software; you can redistribute it and/or modify
17 ;; it under the terms of the GNU General Public License as published by
18 ;; the Free Software Foundation; either version 2, or (at your option)
21 ;; This program is distributed in the hope that it will be useful,
22 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
23 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 ;; GNU General Public License for more details.
26 ;; You should have received a copy of the GNU General Public License
27 ;; along with GNU Emacs; see the file COPYING. If not, write to the
28 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
29 ;; Boston, MA 02111-1307, USA.
34 ;; Origin of IMAP parser part is imap.el, included in Gnus.
36 ;; Copyright (C) 1998, 1999, 2000
37 ;; Free Software Foundation, Inc.
38 ;; Author: Simon Josefsson <jas@pdc.kth.se>
51 ;; silence byte compiler.
54 (defun-maybe elmo-generic-list-folder-unread (spec number-alist mark-alist unread-marks))
55 (defun-maybe elmo-generic-folder-diff (spec folder number-list))
56 (defsubst-maybe utf7-decode-string (string &optional imap) string))
59 (autoload 'starttls-open-stream "starttls")
60 (autoload 'starttls-negotiate "starttls"))
62 (defvar elmo-imap4-use-lock t
63 "USE IMAP4 with locking process.")
65 ;;; internal variables
67 (defvar elmo-imap4-seq-prefix "elmo-imap4")
68 (defvar elmo-imap4-seqno 0)
69 (defvar elmo-imap4-use-uid t
70 "Use UID as message number.")
72 (defvar elmo-imap4-current-response nil)
73 (defvar elmo-imap4-status nil)
74 (defvar elmo-imap4-reached-tag "elmo-imap40")
76 ;;; buffer local variables
78 (defvar elmo-imap4-extra-namespace-alist
79 '(("^{.*/nntp}.*$" . ".")) ; Default is for UW's remote nntp mailbox...
80 "Extra namespace alist. A list of cons cell like: (REGEXP . DELIMITER).")
81 (defvar elmo-imap4-default-hierarchy-delimiter "/")
83 (defvar elmo-imap4-server-capability nil)
84 (defvar elmo-imap4-server-namespace nil)
86 (defvar elmo-imap4-parsing nil) ; indicates parsing.
88 (defvar elmo-imap4-fetch-callback nil)
89 (defvar elmo-imap4-fetch-callback-data nil)
90 (defvar elmo-imap4-status-callback nil)
91 (defvar elmo-imap4-status-callback-data nil)
93 (defvar elmo-imap4-server-diff-async-callback nil)
94 (defvar elmo-imap4-server-diff-async-callback-data nil)
96 ;;; progress...(no use?)
97 (defvar elmo-imap4-count-progress nil)
98 (defvar elmo-imap4-count-progress-message nil)
99 (defvar elmo-imap4-progress-count nil)
101 ;;; XXX Temporal implementation
102 (defvar elmo-imap4-current-msgdb nil)
104 (defvar elmo-imap4-local-variables
106 elmo-imap4-current-response
109 elmo-imap4-reached-tag
110 elmo-imap4-count-progress
111 elmo-imap4-count-progress-message
112 elmo-imap4-progress-count
113 elmo-imap4-fetch-callback
114 elmo-imap4-fetch-callback-data
115 elmo-imap4-status-callback
116 elmo-imap4-status-callback-data
117 elmo-imap4-current-msgdb))
121 (defconst elmo-imap4-quoted-specials-list '(?\\ ?\"))
123 (defconst elmo-imap4-non-atom-char-regex
125 (concat "[^" "]!#$&'+,./0-9:;<=>?@A-Z[^_`a-z|}~-" "]")))
127 (defconst elmo-imap4-non-text-char-regex
130 "]\x01-\x09\x0b\x0c\x0e-\x1f\x7f !\"#$%&'()*+,./0-9:;<=>?@A-Z[\\^_`a-z{|}~-"
133 (defconst elmo-imap4-literal-threshold 1024
134 "Limitation of characters that can be used in a quoted string.")
137 (defvar elmo-imap4-debug nil
138 "Non-nil forces IMAP4 folder as debug mode.
139 Debug information is inserted in the buffer \"*IMAP4 DEBUG*\"")
141 (defvar elmo-imap4-debug-inhibit-logging nil)
146 (luna-define-class elmo-imap4-session (elmo-network-session)
147 (capability current-mailbox read-only))
148 (luna-define-internal-accessors 'elmo-imap4-session))
152 (defsubst elmo-imap4-spec-mailbox (spec)
155 (defsubst elmo-imap4-spec-username (spec)
158 (defsubst elmo-imap4-spec-auth (spec)
161 (defsubst elmo-imap4-spec-hostname (spec)
164 (defsubst elmo-imap4-spec-port (spec)
167 (defsubst elmo-imap4-spec-stream-type (spec)
173 (defsubst elmo-imap4-debug (message &rest args)
175 (with-current-buffer (get-buffer-create "*IMAP4 DEBUG*")
176 (goto-char (point-max))
177 (if elmo-imap4-debug-inhibit-logging
178 (insert "NO LOGGING\n")
179 (insert (apply 'format message args) "\n")))))
183 (defmacro elmo-imap4-response-continue-req-p (response)
184 "Returns non-nil if RESPONSE is '+' response."
185 (` (assq 'continue-req (, response))))
187 (defmacro elmo-imap4-response-ok-p (response)
188 "Returns non-nil if RESPONSE is an 'OK' response."
189 (` (assq 'ok (, response))))
191 (defmacro elmo-imap4-response-bye-p (response)
192 "Returns non-nil if RESPONSE is an 'BYE' response."
193 (` (assq 'bye (, response))))
195 (defmacro elmo-imap4-response-value (response symbol)
196 "Get value of the SYMBOL from RESPONSE."
197 (` (nth 1 (assq (, symbol) (, response)))))
199 (defsubst elmo-imap4-response-value-all (response symbol)
200 "Get all value of the SYMBOL from RESPONSE."
203 (if (eq (car (car response)) symbol)
204 (setq matched (nconc matched (nth 1 (car response)))))
205 (setq response (cdr response)))
208 (defmacro elmo-imap4-response-error-text (response)
209 "Returns text of NO, BAD, BYE response."
210 (` (nth 1 (or (elmo-imap4-response-value (, response) 'no)
211 (elmo-imap4-response-value (, response) 'bad)
212 (elmo-imap4-response-value (, response) 'bye)))))
214 (defmacro elmo-imap4-response-bodydetail-text (response)
215 "Returns text of BODY[section]<partial>."
216 (` (nth 3 (assq 'bodydetail (, response)))))
218 ;;; Session commands.
220 ; (defun elmo-imap4-send-command-wait (session command)
221 ; "Send COMMAND to the SESSION and wait for response.
222 ; Returns RESPONSE (parsed lisp object) of IMAP session."
223 ; (elmo-imap4-read-response session
224 ; (elmo-imap4-send-command
228 (defun elmo-imap4-send-command-wait (session command)
229 "Send COMMAND to the SESSION.
230 Returns RESPONSE (parsed lisp object) of IMAP session.
231 If response is not `OK', causes error with IMAP response text."
232 (elmo-imap4-accept-ok session
233 (elmo-imap4-send-command
237 (defun elmo-imap4-send-command (session command)
238 "Send COMMAND to the SESSION.
239 Returns a TAG string which is assigned to the COMAND."
240 (let* ((command-args (if (listp command)
243 (process (elmo-network-session-process-internal session))
244 cmdstr tag token kind)
245 (with-current-buffer (process-buffer process)
246 (setq tag (concat elmo-imap4-seq-prefix
248 (setq elmo-imap4-seqno (+ 1 elmo-imap4-seqno)))))
249 (setq cmdstr (concat tag " "))
250 ;; (erase-buffer) No need.
251 (goto-char (point-min))
252 (if (elmo-imap4-response-bye-p elmo-imap4-current-response)
253 (signal 'elmo-imap4-bye-error
254 (list (elmo-imap4-response-error-text
255 elmo-imap4-current-response))))
256 (setq elmo-imap4-current-response nil)
257 (if elmo-imap4-parsing
258 (error "IMAP process is running. Please wait (or plug again.)"))
259 (setq elmo-imap4-parsing t)
260 (elmo-imap4-debug "<-(%s)- %s" tag command)
261 (while (setq token (car command-args))
262 (cond ((stringp token) ; formatted
263 (setq cmdstr (concat cmdstr token)))
264 ((listp token) ; unformatted
265 (setq kind (car token))
266 (cond ((eq kind 'atom)
267 (setq cmdstr (concat cmdstr (nth 1 token))))
271 (elmo-imap4-format-quoted (nth 1 token)))))
273 (setq cmdstr (concat cmdstr
274 (format "{%d}" (nth 2 token))))
275 (process-send-string process cmdstr)
276 (process-send-string process "\r\n")
278 (elmo-imap4-accept-continue-req session)
279 (cond ((stringp (nth 1 token))
280 (setq cmdstr (nth 1 token)))
281 ((bufferp (nth 1 token))
282 (with-current-buffer (nth 1 token)
286 (+ (point-min) (nth 2 token)))))
288 (error "Wrong argument for literal"))))
290 (error "Unknown token kind %s" kind))))
292 (error "Invalid argument")))
293 (setq command-args (cdr command-args)))
295 (process-send-string process cmdstr))
296 (process-send-string process "\r\n")
299 (defun elmo-imap4-send-string (session string)
300 "Send STRING to the SESSION."
301 (with-current-buffer (process-buffer
302 (elmo-network-session-process-internal session))
303 (setq elmo-imap4-current-response nil)
304 (goto-char (point-min))
305 (elmo-imap4-debug "<-- %s" string)
306 (process-send-string (elmo-network-session-process-internal session)
308 (process-send-string (elmo-network-session-process-internal session)
311 (defun elmo-imap4-read-response (session tag)
312 "Read parsed response from SESSION.
313 TAG is the tag of the command"
314 (with-current-buffer (process-buffer
315 (elmo-network-session-process-internal session))
316 (while (not (or (string= tag elmo-imap4-reached-tag)
317 (elmo-imap4-response-bye-p elmo-imap4-current-response)))
318 (when (memq (process-status
319 (elmo-network-session-process-internal session))
321 (accept-process-output (elmo-network-session-process-internal session)
323 (elmo-imap4-debug "=>%s" (prin1-to-string elmo-imap4-current-response))
324 (setq elmo-imap4-parsing nil)
325 elmo-imap4-current-response))
327 (defsubst elmo-imap4-read-untagged (process)
328 (with-current-buffer (process-buffer process)
329 (while (not elmo-imap4-current-response)
330 (accept-process-output process 1))
331 (elmo-imap4-debug "=>%s" (prin1-to-string elmo-imap4-current-response))
332 elmo-imap4-current-response))
334 (defun elmo-imap4-read-continue-req (session)
335 "Returns a text following to continue-req in SESSION.
336 If response is not `+' response, returns nil."
337 (elmo-imap4-response-value
338 (elmo-imap4-read-untagged
339 (elmo-network-session-process-internal session))
342 (defun elmo-imap4-accept-continue-req (session)
343 "Returns non-nil if `+' (continue-req) response is arrived in SESSION.
344 If response is not `+' response, cause an error."
347 (elmo-imap4-read-untagged
348 (elmo-network-session-process-internal session)))
349 (or (elmo-imap4-response-continue-req-p response)
350 (error "IMAP error: %s"
351 (or (elmo-imap4-response-error-text response)
352 "No continut-req from server.")))))
354 (defun elmo-imap4-read-ok (session tag)
355 "Returns non-nil if `OK' response of the command with TAG is arrived
356 in SESSION. If response is not `OK' response, returns nil."
357 (elmo-imap4-response-ok-p
358 (elmo-imap4-read-response session tag)))
360 (defun elmo-imap4-accept-ok (session tag)
361 "Accept only `OK' response from SESSION.
362 If response is not `OK' response, causes error with IMAP response text."
363 (let ((response (elmo-imap4-read-response session tag)))
364 (if (elmo-imap4-response-ok-p response)
366 (if (elmo-imap4-response-bye-p response)
367 (signal 'elmo-imap4-bye-error
368 (list (elmo-imap4-response-error-text response)))
369 (error "IMAP error: %s"
370 (or (elmo-imap4-response-error-text response)
371 "No `OK' response from server."))))))
374 (defun elmo-imap4-session-check (session)
375 (elmo-imap4-send-command-wait session "check"))
377 (defun elmo-imap4-atom-p (string)
378 "Return t if STRING is an atom defined in rfc2060."
379 (if (string= string "")
382 (not (string-match elmo-imap4-non-atom-char-regex string)))))
384 (defun elmo-imap4-quotable-p (string)
385 "Return t if STRING can be formatted as a quoted defined in rfc2060."
387 (not (string-match elmo-imap4-non-text-char-regex string))))
389 (defun elmo-imap4-nil (string)
390 "Return a list represents the special atom \"NIL\" defined in rfc2060, \
392 Otherwise return nil."
396 (defun elmo-imap4-atom (string)
397 "Return a list represents STRING as an atom defined in rfc2060.
398 Return nil if STRING is not an atom. See `elmo-imap4-atom-p'."
399 (if (elmo-imap4-atom-p string)
400 (list 'atom string)))
402 (defun elmo-imap4-quoted (string)
403 "Return a list represents STRING as a quoted defined in rfc2060.
404 Return nil if STRING can not be formatted as a quoted. See `elmo-imap4-quotable-p'."
405 (if (elmo-imap4-quotable-p string)
406 (list 'quoted string)))
408 (defun elmo-imap4-literal-1 (string-or-buffer length)
409 "Internal function for `elmo-imap4-literal' and `elmo-imap4-buffer-literal'.
410 Return a list represents STRING-OR-BUFFER as a literal defined in rfc2060.
411 STRING-OR-BUFFER must be an encoded string or a single-byte string or a single-byte buffer.
412 LENGTH must be the number of octets for STRING-OR-BUFFER."
413 (list 'literal string-or-buffer length))
415 (defun elmo-imap4-literal (string)
416 "Return a list represents STRING as a literal defined in rfc2060.
417 STRING must be an encoded or a single-byte string."
418 (elmo-imap4-literal-1 string (length string)))
420 (defun elmo-imap4-buffer-literal (buffer)
421 "Return a list represents BUFFER as a literal defined in rfc2060.
422 BUFFER must be a single-byte buffer."
423 (elmo-imap4-literal-1 buffer (with-current-buffer buffer
426 (defun elmo-imap4-string-1 (string length)
427 "Internal function for `elmo-imap4-string' and `elmo-imap4-buffer-string'.
428 Return a list represents STRING as a string defined in rfc2060.
429 STRING must be an encoded or a single-byte string.
430 LENGTH must be the number of octets for STRING."
431 (or (elmo-imap4-quoted string)
432 (elmo-imap4-literal-1 string length)))
434 (defun elmo-imap4-string (string)
435 "Return a list represents STRING as a string defined in rfc2060.
436 STRING must be an encoded or a single-byte string."
437 (let ((length (length string)))
438 (if (< elmo-imap4-literal-threshold length)
439 (elmo-imap4-literal-1 string length)
440 (elmo-imap4-string-1 string length))))
442 (defun elmo-imap4-buffer-string (buffer)
443 "Return a list represents BUFFER as a string defined in rfc2060.
444 BUFFER must be a single-byte buffer."
445 (let ((length (with-current-buffer buffer
447 (if (< elmo-imap4-literal-threshold length)
448 (elmo-imap4-literal-1 buffer length)
449 (elmo-imap4-string-1 (with-current-buffer buffer
453 (defun elmo-imap4-astring-1 (string length)
454 "Internal function for `elmo-imap4-astring' and `elmo-imap4-buffer-astring'.
455 Return a list represents STRING as an astring defined in rfc2060.
456 STRING must be an encoded or a single-byte string.
457 LENGTH must be the number of octets for STRING."
458 (or (elmo-imap4-atom string)
459 (elmo-imap4-string-1 string length)))
461 (defun elmo-imap4-astring (string)
462 "Return a list represents STRING as an astring defined in rfc2060.
463 STRING must be an encoded or a single-byte string."
464 (let ((length (length string)))
465 (if (< elmo-imap4-literal-threshold length)
466 (elmo-imap4-literal-1 string length)
467 (elmo-imap4-astring-1 string length))))
469 (defun elmo-imap4-buffer-astring (buffer)
470 "Return a list represents BUFFER as an astring defined in rfc2060.
471 BUFFER must be a single-byte buffer."
472 (let ((length (with-current-buffer buffer
474 (if (< elmo-imap4-literal-threshold length)
475 (elmo-imap4-literal-1 buffer length)
476 (elmo-imap4-astring-1 (with-current-buffer buffer
480 (defun elmo-imap4-nstring (string)
481 "Return a list represents STRING as a nstring defined in rfc2060.
482 STRING must be an encoded or a single-byte string."
483 (or (elmo-imap4-nil string)
484 (elmo-imap4-string string)))
486 (defun elmo-imap4-buffer-nstring (buffer)
487 "Return a list represents BUFFER as a nstring defined in rfc2060.
488 BUFFER must be a single-byte buffer."
489 (or (elmo-imap4-nil buffer)
490 (elmo-imap4-buffer-string buffer)))
492 (defalias 'elmo-imap4-mailbox 'elmo-imap4-astring)
493 (defalias 'elmo-imap4-field-body 'elmo-imap4-astring)
494 (defalias 'elmo-imap4-userid 'elmo-imap4-astring)
495 (defalias 'elmo-imap4-password 'elmo-imap4-astring)
497 (defun elmo-imap4-format-quoted (string)
498 "Return STRING in a form of the quoted-string defined in rfc2060."
500 (std11-wrap-as-quoted-pairs string elmo-imap4-quoted-specials-list)
503 (defsubst elmo-imap4-response-get-selectable-mailbox-list (response)
507 (if (and (eq 'list (car entry))
508 (not (member "\\NoSelect" (nth 1 (nth 1 entry)))))
509 (car (nth 1 entry))))
513 (defun elmo-imap4-list-folders (spec &optional hierarchy)
514 (let* ((root (elmo-imap4-spec-mailbox spec))
515 (session (elmo-imap4-get-session spec))
518 (elmo-string-matched-assoc
520 (with-current-buffer (elmo-network-session-buffer session)
521 elmo-imap4-server-namespace)))
522 elmo-imap4-default-hierarchy-delimiter))
523 result append-serv type)
526 (not (string= root ""))
527 (not (string-match (concat "\\(.*\\)"
531 (setq root (concat root delim)))
532 (setq result (elmo-imap4-response-get-selectable-mailbox-list
533 (elmo-imap4-send-command-wait
535 (list "list " (elmo-imap4-mailbox root) " *"))))
536 (unless (string= (elmo-imap4-spec-username spec)
537 elmo-default-imap4-user)
538 (setq append-serv (concat ":" (elmo-imap4-spec-username spec))))
539 (unless (eq (elmo-imap4-spec-auth spec)
540 elmo-default-imap4-authenticate-type)
542 (concat append-serv "/" (symbol-name (elmo-imap4-spec-auth spec)))))
543 (unless (string= (elmo-imap4-spec-hostname spec)
544 elmo-default-imap4-server)
545 (setq append-serv (concat append-serv "@" (elmo-imap4-spec-hostname
547 (unless (eq (elmo-imap4-spec-port spec)
548 elmo-default-imap4-port)
549 (setq append-serv (concat append-serv ":"
551 (elmo-imap4-spec-port spec)))))
552 (setq type (elmo-imap4-spec-stream-type spec))
553 (unless (eq (elmo-network-stream-type-symbol type)
554 elmo-default-imap4-stream-type)
556 (setq append-serv (concat append-serv
557 (elmo-network-stream-type-spec-string
560 (let (folder folders ret)
561 (while (setq folders (car result))
564 (concat "^\\(" root "[^" delim "]" "+\\)" delim)
566 (setq folder (match-string 1 folders)))
569 (append ret (list (list
570 (concat "%" (elmo-imap4-decode-folder-string folder)
572 (eval append-serv)))))))
575 (mapcar '(lambda (fld)
578 (concat "^" (regexp-quote folder))
582 (setq ret (append ret (list
583 (concat "%" (elmo-imap4-decode-folder-string folders)
585 (eval append-serv))))))
586 (setq result (cdr result))))
588 (mapcar (lambda (fld)
589 (concat "%" (elmo-imap4-decode-folder-string fld)
591 (eval append-serv))))
594 (defun elmo-imap4-folder-exists-p (spec)
595 (let ((session (elmo-imap4-get-session spec)))
597 (elmo-imap4-session-current-mailbox-internal session)
598 (elmo-imap4-spec-mailbox spec))
600 (elmo-imap4-session-select-mailbox
602 (elmo-imap4-spec-mailbox spec)
605 (defun elmo-imap4-folder-creatable-p (spec)
608 (defun elmo-imap4-create-folder-maybe (spec dummy)
609 (unless (elmo-imap4-folder-exists-p spec)
610 (elmo-imap4-create-folder spec)))
612 (defun elmo-imap4-create-folder (spec)
613 (elmo-imap4-send-command-wait
614 (elmo-imap4-get-session spec)
615 (list "create " (elmo-imap4-mailbox
616 (elmo-imap4-spec-mailbox spec)))))
618 (defun elmo-imap4-delete-folder (spec)
619 (let ((session (elmo-imap4-get-session spec))
621 (when (elmo-imap4-spec-mailbox spec)
622 (when (setq msgs (elmo-imap4-list-folder spec))
623 (elmo-imap4-delete-msgs spec msgs))
624 ;; (elmo-imap4-send-command-wait session "close")
625 (elmo-imap4-send-command-wait
628 (elmo-imap4-mailbox (elmo-imap4-spec-mailbox spec)))))))
630 (defun elmo-imap4-rename-folder (old-spec new-spec)
631 ;;;(elmo-imap4-send-command-wait session "close")
632 (elmo-imap4-send-command-wait
633 (elmo-imap4-get-session old-spec)
636 (elmo-imap4-spec-mailbox old-spec))
639 (elmo-imap4-spec-mailbox new-spec)))))
641 (defun elmo-imap4-max-of-folder (spec)
642 (let ((session (elmo-imap4-get-session spec))
643 (killed (and elmo-use-killed-list
644 (elmo-msgdb-killed-list-load
645 (elmo-msgdb-expand-path spec))))
647 (with-current-buffer (elmo-network-session-buffer session)
648 (setq elmo-imap4-status-callback nil)
649 (setq elmo-imap4-status-callback-data nil))
650 (setq status (elmo-imap4-response-value
651 (elmo-imap4-send-command-wait
655 (elmo-imap4-spec-mailbox spec))
656 " (uidnext messages)"))
659 (- (elmo-imap4-response-value status 'uidnext) 1)
662 (elmo-imap4-response-value status 'messages)
663 (elmo-msgdb-killed-list-length killed))
664 (elmo-imap4-response-value status 'messages)))))
666 (defun elmo-imap4-folder-diff (spec folder &optional number-list)
667 (if elmo-use-server-diff
668 (elmo-imap4-server-diff spec)
669 (elmo-generic-folder-diff spec folder number-list)))
671 (defun elmo-imap4-get-session (spec &optional if-exists)
672 (elmo-network-get-session
675 (elmo-imap4-spec-hostname spec)
676 (elmo-imap4-spec-port spec)
677 (elmo-imap4-spec-username spec)
678 (elmo-imap4-spec-auth spec)
679 (elmo-imap4-spec-stream-type spec)
682 (defun elmo-imap4-commit (spec)
683 (if (elmo-imap4-plugged-p spec)
684 (let ((session (elmo-imap4-get-session spec 'if-exists)))
687 (elmo-imap4-session-current-mailbox-internal session)
688 (elmo-imap4-spec-mailbox spec))
689 (if elmo-imap4-use-select-to-update-status
690 (elmo-imap4-session-select-mailbox
692 (elmo-imap4-spec-mailbox spec)
694 (elmo-imap4-session-check session)))))))
696 (defun elmo-imap4-session-select-mailbox (session mailbox
697 &optional force no-error)
698 "Select MAILBOX in SESSION.
699 If optional argument FORCE is non-nil, select mailbox even if current mailbox
701 If second optional argument NO-ERROR is non-nil, don't cause an error when
702 selecting folder was failed.
703 Returns response value if selecting folder succeed. "
706 (elmo-imap4-session-current-mailbox-internal session)
708 (let (response result)
711 (elmo-imap4-read-response
713 (elmo-imap4-send-command
717 (elmo-imap4-mailbox mailbox)))))
718 (if (setq result (elmo-imap4-response-ok-p response))
720 (elmo-imap4-session-set-current-mailbox-internal session mailbox)
721 (elmo-imap4-session-set-read-only-internal
723 (nth 1 (assq 'read-only (assq 'ok response)))))
724 (elmo-imap4-session-set-current-mailbox-internal session nil)
727 (elmo-imap4-response-error-text response)
728 (format "Select %s failed" mailbox))))))
729 (and result response))))
731 (defun elmo-imap4-check-validity (spec validity-file)
733 ;;;(elmo-imap4-send-command-wait
734 ;;;(elmo-imap4-get-session spec)
736 ;;; (elmo-imap4-mailbox
737 ;;; (elmo-imap4-spec-mailbox spec))
738 ;;; " (uidvalidity)")))
741 (defun elmo-imap4-sync-validity (spec validity-file)
745 (defun elmo-imap4-list (spec flag)
746 (let ((session (elmo-imap4-get-session spec)))
747 (elmo-imap4-session-select-mailbox session
748 (elmo-imap4-spec-mailbox spec))
749 (elmo-imap4-response-value
750 (elmo-imap4-send-command-wait
752 (format (if elmo-imap4-use-uid "uid search %s"
756 (defun elmo-imap4-list-folder (spec)
757 (let ((killed (and elmo-use-killed-list
758 (elmo-msgdb-killed-list-load
759 (elmo-msgdb-expand-path spec))))
761 (setq numbers (elmo-imap4-list spec "all"))
762 (elmo-living-messages numbers killed)))
764 (defun elmo-imap4-list-folder-unread (spec number-alist mark-alist
766 (if (and (elmo-imap4-plugged-p spec)
767 (elmo-imap4-use-flag-p spec))
768 (elmo-imap4-list spec "unseen")
769 (elmo-generic-list-folder-unread spec number-alist mark-alist
772 (defun elmo-imap4-list-folder-important (spec number-alist)
773 (if (and (elmo-imap4-plugged-p spec)
774 (elmo-imap4-use-flag-p spec))
775 (elmo-imap4-list spec "flagged")))
777 (defmacro elmo-imap4-detect-search-charset (string)
780 (detect-mime-charset-region (point-min) (point-max)))))
782 (defun elmo-imap4-search-internal-primitive (spec session filter from-msgs)
783 (let ((search-key (elmo-filter-key filter))
784 (imap-search-keys '("bcc" "body" "cc" "from" "subject" "to"))
787 ((string= "last" search-key)
788 (let ((numbers (or from-msgs (elmo-imap4-list-folder spec))))
789 (nthcdr (max (- (length numbers)
790 (string-to-int (elmo-filter-value filter)))
793 ((string= "first" search-key)
794 (let* ((numbers (or from-msgs (elmo-imap4-list-folder spec)))
795 (rest (nthcdr (string-to-int (elmo-filter-value filter) )
797 (mapcar '(lambda (x) (delete x numbers)) rest)
799 ((or (string= "since" search-key)
800 (string= "before" search-key))
801 (setq search-key (concat "sent" search-key))
802 (elmo-imap4-response-value
803 (elmo-imap4-send-command-wait session
805 (if elmo-imap4-use-uid
806 "uid search %s%s%s %s"
810 (if elmo-imap4-use-uid "uid ")
813 (elmo-imap4-make-number-set-list
817 (if (eq (elmo-filter-type filter)
821 (elmo-date-get-description
822 (elmo-date-get-datevec
823 (elmo-filter-value filter)))))
827 (if (eq (length (elmo-filter-value filter)) 0)
828 (setq charset 'us-ascii)
829 (elmo-imap4-detect-search-charset
830 (elmo-filter-value filter))))
831 (elmo-imap4-response-value
832 (elmo-imap4-send-command-wait session
834 (if elmo-imap4-use-uid "uid ")
838 (symbol-name charset))
842 (if elmo-imap4-use-uid "uid ")
845 (elmo-imap4-make-number-set-list
849 (if (eq (elmo-filter-type filter)
854 (elmo-filter-key filter)
858 (elmo-filter-key filter))
860 (encode-mime-charset-string
861 (elmo-filter-value filter) charset))))
864 (defun elmo-imap4-search-internal (spec session condition from-msgs)
868 (setq result (elmo-imap4-search-internal-primitive
869 spec session condition from-msgs)))
870 ((eq (car condition) 'and)
871 (setq result (elmo-imap4-search-internal spec session (nth 1 condition)
873 result (elmo-list-filter result
874 (elmo-imap4-search-internal
875 spec session (nth 2 condition)
877 ((eq (car condition) 'or)
878 (setq result (elmo-imap4-search-internal
879 spec session (nth 1 condition) from-msgs)
880 result (elmo-uniq-list
882 (elmo-imap4-search-internal
883 spec session (nth 2 condition) from-msgs)))
884 result (sort result '<))))))
887 (defun elmo-imap4-search (spec condition &optional from-msgs)
889 (let ((session (elmo-imap4-get-session spec)))
890 (elmo-imap4-session-select-mailbox
892 (elmo-imap4-spec-mailbox spec))
893 (elmo-imap4-search-internal spec session condition from-msgs))))
895 (defun elmo-imap4-use-flag-p (spec)
896 (not (string-match elmo-imap4-disuse-server-flag-mailbox-regexp
897 (elmo-imap4-spec-mailbox spec))))
901 ;; Emacs can parse dot symbol.
902 (defvar elmo-imap4-rfc822-size "RFC822\.SIZE")
903 (defvar elmo-imap4-rfc822-text "RFC822\.TEXT")
904 (defvar elmo-imap4-rfc822-header "RFC822\.HEADER")
905 (defvar elmo-imap4-rfc822-size "RFC822\.SIZE")
906 (defvar elmo-imap4-header-fields "HEADER\.FIELDS")
907 (defmacro elmo-imap4-replace-dot-symbols ()) ;; noop
908 (defalias 'elmo-imap4-fetch-read 'read)
912 ;; Cannot parse dot symbol.
913 (defvar elmo-imap4-rfc822-size "RFC822_SIZE")
914 (defvar elmo-imap4-header-fields "HEADER_FIELDS")
915 (defvar elmo-imap4-rfc822-size "RFC822_SIZE")
916 (defvar elmo-imap4-rfc822-text "RFC822_TEXT")
917 (defvar elmo-imap4-rfc822-header "RFC822_HEADER")
918 (defvar elmo-imap4-header-fields "HEADER_FIELDS")
919 (defun elmo-imap4-fetch-read (buffer)
920 (with-current-buffer buffer
923 (when (re-search-forward "[[ ]" nil t)
924 (goto-char (match-beginning 0))
925 (setq token (buffer-substring beg (point)))
926 (cond ((string= token "RFC822.SIZE")
927 (intern elmo-imap4-rfc822-size))
928 ((string= token "RFC822.HEADER")
929 (intern elmo-imap4-rfc822-header))
930 ((string= token "RFC822.TEXT")
931 (intern elmo-imap4-rfc822-text))
932 ((string= token "HEADER\.FIELDS")
933 (intern elmo-imap4-header-fields))
935 (elmo-read (current-buffer))))))))))
937 (defun elmo-imap4-make-number-set-list (msg-list &optional chop-length)
938 "Make RFC2060's message set specifier from MSG-LIST.
939 Returns a list of (NUMBER . SET-STRING).
940 SET-STRING is the message set specifier described in RFC2060.
941 NUMBER is contained message number in SET-STRING.
942 Every SET-STRING does not contain number of messages longer than CHOP-LENGTH.
943 If CHOP-LENGTH is not specified, message set is not chopped."
944 (let (count cont-list set-list)
945 (setq msg-list (sort (copy-sequence msg-list) '<))
950 (setq chop-length (length msg-list)))
951 (while (and (not (null msg-list))
952 (< count chop-length))
954 (elmo-number-set-append
955 cont-list (car msg-list)))
957 (setq msg-list (cdr msg-list)))
965 (format "%s:%s" (car x) (cdr x)))
971 (nreverse set-list)))
975 ;; read-mark -> "\\Seen"
976 ;; important -> "\\Flagged"
978 ;; (delete -> \\Deleted)
979 (defun elmo-imap4-mark-set-on-msgs (spec msgs mark &optional unmark no-expunge)
980 "SET flag of MSGS as MARK.
981 If optional argument UNMARK is non-nil, unmark."
982 (let ((session (elmo-imap4-get-session spec))
984 (elmo-imap4-session-select-mailbox session
985 (elmo-imap4-spec-mailbox spec))
986 (setq set-list (elmo-imap4-make-number-set-list msgs))
988 (with-current-buffer (elmo-network-session-buffer session)
989 (setq elmo-imap4-fetch-callback nil)
990 (setq elmo-imap4-fetch-callback-data nil))
991 (elmo-imap4-send-command-wait
994 (if elmo-imap4-use-uid
995 "uid store %s %sflags.silent (%s)"
996 "store %s %sflags.silent (%s)")
1001 (elmo-imap4-send-command-wait session "expunge")))
1004 (defun elmo-imap4-mark-as-important (spec msgs)
1005 (and (elmo-imap4-use-flag-p spec)
1006 (elmo-imap4-mark-set-on-msgs spec msgs "\\Flagged" nil 'no-expunge)))
1008 (defun elmo-imap4-mark-as-read (spec msgs)
1009 (and (elmo-imap4-use-flag-p spec)
1010 (elmo-imap4-mark-set-on-msgs spec msgs "\\Seen" nil 'no-expunge)))
1012 (defun elmo-imap4-unmark-important (spec msgs)
1013 (and (elmo-imap4-use-flag-p spec)
1014 (elmo-imap4-mark-set-on-msgs spec msgs "\\Flagged" 'unmark
1017 (defun elmo-imap4-mark-as-unread (spec msgs)
1018 (and (elmo-imap4-use-flag-p spec)
1019 (elmo-imap4-mark-set-on-msgs spec msgs "\\Seen" 'unmark 'no-expunge)))
1021 (defun elmo-imap4-delete-msgs (spec msgs)
1022 (elmo-imap4-mark-set-on-msgs spec msgs "\\Deleted"))
1024 (defun elmo-imap4-delete-msgs-no-expunge (spec msgs)
1025 (elmo-imap4-mark-set-on-msgs spec msgs "\\Deleted" nil 'no-expunge))
1027 (defun elmo-imap4-msgdb-create-as-numlist (spec numlist new-mark already-mark
1028 seen-mark important-mark
1030 "Create msgdb for SPEC for NUMLIST."
1031 (elmo-imap4-msgdb-create spec numlist new-mark already-mark
1032 seen-mark important-mark seen-list t))
1034 ;; Current buffer is process buffer.
1035 (defun elmo-imap4-fetch-callback (element app-data)
1036 (funcall elmo-imap4-fetch-callback
1038 (insert (or (elmo-imap4-response-bodydetail-text element)
1041 (goto-char (point-min))
1042 (while (search-forward "\r\n" nil t)
1043 (replace-match "\n"))
1044 (elmo-msgdb-create-overview-from-buffer
1045 (elmo-imap4-response-value element 'uid)
1046 (elmo-imap4-response-value element 'rfc822size)))
1047 (elmo-imap4-response-value element 'flags)
1052 ;; 0: new-mark 1: already-mark 2: seen-mark 3: important-mark
1053 ;; 4: seen-list 5: as-number
1054 (defun elmo-imap4-fetch-callback-1 (entity flags app-data)
1055 "A msgdb entity callback function."
1056 (let ((seen (member (car entity) (nth 4 app-data)))
1058 (if (member "\\Flagged" flags)
1059 (elmo-msgdb-global-mark-set (car entity) (nth 3 app-data)))
1060 (setq mark (or (elmo-msgdb-global-mark-get (car entity))
1061 (if (elmo-cache-exists-p (car entity)) ;; XXX
1062 (if (or (member "\\Seen" flags) seen)
1065 (if (or (member "\\Seen" flags) seen)
1066 (if elmo-imap4-use-cache
1068 (nth 0 app-data)))))
1069 (setq elmo-imap4-current-msgdb
1071 elmo-imap4-current-msgdb
1073 (list (cons (elmo-msgdb-overview-entity-get-number entity)
1077 (list (elmo-msgdb-overview-entity-get-number entity)
1080 (defun elmo-imap4-msgdb-create (spec numlist &rest args)
1081 "Create msgdb for SPEC."
1083 (let ((session (elmo-imap4-get-session spec))
1086 '("Subject" "From" "To" "Cc" "Date"
1087 "Message-Id" "References" "In-Reply-To")
1088 elmo-msgdb-extra-fields))
1090 (length (length numlist))
1092 (setq rfc2060 (memq 'imap4rev1
1093 (elmo-imap4-session-capability-internal
1095 (message "Getting overview...")
1096 (elmo-imap4-session-select-mailbox session
1097 (elmo-imap4-spec-mailbox spec))
1098 (setq set-list (elmo-imap4-make-number-set-list
1100 elmo-imap4-overview-fetch-chop-length))
1102 (with-current-buffer (elmo-network-session-buffer session)
1103 (setq elmo-imap4-current-msgdb nil
1104 elmo-imap4-fetch-callback 'elmo-imap4-fetch-callback-1
1105 elmo-imap4-fetch-callback-data args)
1107 (elmo-imap4-send-command-wait
1109 ;; get overview entity from IMAP4
1110 (format "%sfetch %s (%s rfc822.size flags)"
1111 (if elmo-imap4-use-uid "uid " "")
1112 (cdr (car set-list))
1114 (format "body.peek[header.fields %s]" headers)
1115 (format "%s" headers))))
1116 (when (> length elmo-display-progress-threshold)
1117 (setq total (+ total (car (car set-list))))
1118 (elmo-display-progress
1119 'elmo-imap4-msgdb-create "Getting overview..."
1120 (/ (* total 100) length)))
1121 (setq set-list (cdr set-list)))
1122 (message "Getting overview...done")
1123 elmo-imap4-current-msgdb))))
1125 (defun elmo-imap4-parse-capability (string)
1126 (if (string-match "^\\*\\(.*\\)$" string)
1128 (concat "(" (downcase (elmo-match-string 1 string)) ")"))))
1130 (defun elmo-imap4-login (session)
1131 (let ((elmo-imap4-debug-inhibit-logging t))
1135 (elmo-imap4-send-command
1138 (elmo-imap4-userid (elmo-network-session-user-internal session))
1140 (elmo-imap4-password
1141 (elmo-get-passwd (elmo-network-session-password-key session))))))
1142 (signal 'elmo-authenticate-error '(login)))))
1145 elmo-network-initialize-session-buffer :after ((session
1146 elmo-imap4-session) buffer)
1147 (with-current-buffer buffer
1148 (mapcar 'make-variable-buffer-local elmo-imap4-local-variables)
1149 (setq elmo-imap4-seqno 0)
1150 (setq elmo-imap4-status 'initial)))
1152 (luna-define-method elmo-network-initialize-session ((session
1153 elmo-imap4-session))
1154 (let ((process (elmo-network-session-process-internal session)))
1155 (with-current-buffer (process-buffer process)
1156 ;; Skip garbage output from process before greeting.
1157 (while (and (memq (process-status process) '(open run))
1158 (goto-char (point-max))
1160 (not (elmo-imap4-parse-greeting)))
1161 (accept-process-output process 1))
1162 (set-process-filter process 'elmo-imap4-arrival-filter)
1163 (set-process-sentinel process 'elmo-imap4-sentinel)
1164 ;;; (while (and (memq (process-status process) '(open run))
1165 ;;; (eq elmo-imap4-status 'initial))
1166 ;;; (message "Waiting for server response...")
1167 ;;; (accept-process-output process 1))
1169 (unless (memq elmo-imap4-status '(nonauth auth))
1170 (signal 'elmo-open-error
1171 (list 'elmo-network-initialize-session)))
1172 (elmo-imap4-session-set-capability-internal
1174 (elmo-imap4-response-value
1175 (elmo-imap4-send-command-wait session "capability")
1177 (when (eq (elmo-network-stream-type-symbol
1178 (elmo-network-session-stream-type-internal session))
1181 (elmo-imap4-session-capability-internal session))
1182 (signal 'elmo-open-error
1183 '(elmo-imap4-starttls-error)))
1184 (elmo-imap4-send-command-wait session "starttls")
1185 (starttls-negotiate process)))))
1187 (luna-define-method elmo-network-authenticate-session ((session
1188 elmo-imap4-session))
1189 (with-current-buffer (process-buffer
1190 (elmo-network-session-process-internal session))
1191 (let* ((auth (elmo-network-session-auth-internal session))
1192 (auth (if (listp auth) auth (list auth))))
1193 (unless (or (eq elmo-imap4-status 'auth)
1195 (if (eq 'plain (car auth))
1196 (elmo-imap4-login session)
1197 (let* ((elmo-imap4-debug-inhibit-logging t)
1200 (mapcar '(lambda (cap)
1201 (if (string-match "^auth=\\(.*\\)$"
1203 (match-string 1 (upcase (symbol-name cap)))))
1204 (elmo-imap4-session-capability-internal session))))
1206 (sasl-find-mechanism
1208 (mapcar '(lambda (cap) (upcase (symbol-name cap)))
1212 client name step response tag
1213 sasl-read-passphrase)
1215 (if (or elmo-imap4-force-login
1218 "There's no %s capability in server. continue?"
1219 (elmo-list-to-string
1220 (elmo-network-session-auth-internal session)))))
1221 (setq mechanism (sasl-find-mechanism
1223 (signal 'elmo-authenticate-error '(elmo-imap4-auth-no-mechanisms))))
1227 (elmo-network-session-user-internal session)
1229 (elmo-network-session-host-internal session)))
1230 ;;; (if elmo-imap4-auth-user-realm
1231 ;;; (sasl-client-set-property client 'realm elmo-imap4-auth-user-realm))
1232 (setq name (sasl-mechanism-name mechanism)
1233 step (sasl-next-step client nil))
1234 (elmo-network-session-set-auth-internal session
1235 (intern (downcase name)))
1236 (setq sasl-read-passphrase
1240 (elmo-network-session-password-key session)))))
1242 (elmo-imap4-send-command
1244 (concat "AUTHENTICATE " name
1245 (and (sasl-step-data step)
1248 (elmo-base64-encode-string
1249 (sasl-step-data step)
1250 'no-lin-break)))))) ;)
1253 (setq response (elmo-imap4-read-untagged
1254 (elmo-network-session-process-internal session)))
1256 (null (elmo-imap4-response-continue-req-p response))
1257 (elmo-imap4-response-ok-p response)
1258 (or (sasl-next-step client step)
1260 (signal 'elmo-authenticate-error
1262 (concat "elmo-imap4-auth-"
1263 (downcase name))))))
1266 (elmo-base64-decode-string
1267 (elmo-imap4-response-value response 'continue-req)))
1268 (setq step (sasl-next-step client step))
1270 (elmo-imap4-send-string
1272 (if (sasl-step-data step)
1273 (elmo-base64-encode-string (sasl-step-data step)
1277 (luna-define-method elmo-network-setup-session ((session
1278 elmo-imap4-session))
1279 (with-current-buffer (elmo-network-session-buffer session)
1280 (when (memq 'namespace (elmo-imap4-session-capability-internal session))
1281 (setq elmo-imap4-server-namespace
1282 (elmo-imap4-response-value
1283 (elmo-imap4-send-command-wait session "namespace")
1286 (defun elmo-imap4-setup-send-buffer (string)
1287 (let ((tmp-buf (get-buffer-create " *elmo-imap4-setup-send-buffer*")))
1290 (set-buffer tmp-buf)
1292 (elmo-set-buffer-multibyte nil)
1294 (goto-char (point-min))
1295 (if (eq (re-search-forward "^$" nil t)
1298 (goto-char (point-min))
1299 (while (search-forward "\n" nil t)
1300 (replace-match "\r\n"))))
1303 (defun elmo-imap4-read-part (folder msg part)
1304 (let* ((spec (elmo-folder-get-spec folder))
1305 (session (elmo-imap4-get-session spec)))
1306 (elmo-imap4-session-select-mailbox session
1307 (elmo-imap4-spec-mailbox spec))
1308 (with-current-buffer (elmo-network-session-buffer session)
1309 (setq elmo-imap4-fetch-callback nil)
1310 (setq elmo-imap4-fetch-callback-data nil))
1312 (elmo-imap4-response-bodydetail-text
1313 (elmo-imap4-response-value-all
1314 (elmo-imap4-send-command-wait session
1316 (if elmo-imap4-use-uid
1317 "uid fetch %s body.peek[%s]"
1318 "fetch %s body.peek[%s]")
1322 (defun elmo-imap4-prefetch-msg (spec msg outbuf)
1323 (elmo-imap4-read-msg spec msg outbuf 'unseen))
1325 (defun elmo-imap4-read-msg (spec msg outbuf
1326 &optional leave-seen-flag-untouched)
1327 (let ((session (elmo-imap4-get-session spec))
1329 (elmo-imap4-session-select-mailbox session
1330 (elmo-imap4-spec-mailbox spec))
1331 (with-current-buffer (elmo-network-session-buffer session)
1332 (setq elmo-imap4-fetch-callback nil)
1333 (setq elmo-imap4-fetch-callback-data nil))
1335 (elmo-imap4-send-command-wait session
1337 (if elmo-imap4-use-uid
1338 "uid fetch %s rfc822%s"
1339 "fetch %s rfc822%s")
1341 (if leave-seen-flag-untouched
1343 (and (setq response (elmo-imap4-response-value
1344 (elmo-imap4-response-value-all
1347 (with-current-buffer outbuf
1350 (elmo-delete-cr-get-content-type)))))
1352 (defun elmo-imap4-setup-send-buffer-from-file (file)
1353 (let ((tmp-buf (get-buffer-create
1354 " *elmo-imap4-setup-send-buffer-from-file*")))
1357 (set-buffer tmp-buf)
1359 (as-binary-input-file
1360 (insert-file-contents file))
1361 (goto-char (point-min))
1362 (if (eq (re-search-forward "^$" nil t)
1365 (goto-char (point-min))
1366 (while (search-forward "\n" nil t)
1367 (replace-match "\r\n"))))
1370 (defun elmo-imap4-delete-msgids (spec msgids)
1371 "If actual message-id is matched, then delete it."
1372 (let ((message-ids msgids)
1374 (num (length msgids)))
1377 (message "Deleting message...%d/%d" i num)
1378 (elmo-imap4-delete-msg-by-id spec (car message-ids))
1379 (setq message-ids (cdr message-ids)))
1380 (elmo-imap4-send-command-wait (elmo-imap4-get-session spec) "expunge")))
1382 (defun elmo-imap4-delete-msg-by-id (spec msgid)
1383 (let ((session (elmo-imap4-get-session spec)))
1384 (elmo-imap4-session-select-mailbox session
1385 (elmo-imap4-spec-mailbox spec))
1386 (elmo-imap4-delete-msgs-no-expunge
1388 (elmo-imap4-response-value
1389 (elmo-imap4-send-command-wait session
1391 (if elmo-imap4-use-uid
1392 "uid search header message-id "
1393 "search header message-id ")
1394 (elmo-imap4-field-body msgid)))
1397 (defun elmo-imap4-append-msg-by-id (spec msgid)
1398 (let ((session (elmo-imap4-get-session spec))
1400 (elmo-imap4-session-select-mailbox session
1401 (elmo-imap4-spec-mailbox spec))
1402 (setq send-buf (elmo-imap4-setup-send-buffer-from-file
1403 (elmo-cache-get-path msgid)))
1405 (elmo-imap4-send-command-wait
1409 (elmo-imap4-mailbox (elmo-imap4-spec-mailbox spec))
1411 (elmo-imap4-buffer-literal send-buf)))
1412 (kill-buffer send-buf)))
1415 (defun elmo-imap4-append-msg (spec string &optional msg no-see)
1416 (let ((session (elmo-imap4-get-session spec))
1418 (elmo-imap4-session-select-mailbox session
1419 (elmo-imap4-spec-mailbox spec))
1420 (setq send-buf (elmo-imap4-setup-send-buffer string))
1422 (elmo-imap4-send-command-wait
1426 (elmo-imap4-mailbox (elmo-imap4-spec-mailbox spec))
1427 (if no-see " " " (\\Seen) ")
1428 (elmo-imap4-buffer-literal send-buf)))
1429 (kill-buffer send-buf)))
1432 (defun elmo-imap4-copy-msgs (dst-spec
1433 msgs src-spec &optional expunge-it same-number)
1434 "Equivalence of hostname, username is assumed."
1435 (let ((session (elmo-imap4-get-session src-spec)))
1436 (elmo-imap4-session-select-mailbox session
1437 (elmo-imap4-spec-mailbox src-spec))
1439 (elmo-imap4-send-command-wait session
1442 (if elmo-imap4-use-uid
1447 (elmo-imap4-spec-mailbox dst-spec))))
1448 (setq msgs (cdr msgs)))
1450 (elmo-imap4-send-command-wait session "expunge"))
1453 (defun elmo-imap4-server-diff-async-callback-1 (status data)
1454 (funcall elmo-imap4-server-diff-async-callback
1455 (cons (elmo-imap4-response-value status 'unseen)
1456 (elmo-imap4-response-value status 'messages))
1459 (defun elmo-imap4-server-diff-async (spec)
1460 (let ((session (elmo-imap4-get-session spec)))
1462 ;; (elmo-imap4-commit spec)
1463 (with-current-buffer (elmo-network-session-buffer session)
1464 (setq elmo-imap4-status-callback
1465 'elmo-imap4-server-diff-async-callback-1)
1466 (setq elmo-imap4-status-callback-data
1467 elmo-imap4-server-diff-async-callback-data))
1468 (elmo-imap4-send-command session
1472 (elmo-imap4-spec-mailbox spec))
1473 " (unseen messages)"))))
1475 (defun elmo-imap4-server-diff (spec)
1477 (let ((session (elmo-imap4-get-session spec))
1480 ;;; (elmo-imap4-commit spec)
1481 (with-current-buffer (elmo-network-session-buffer session)
1482 (setq elmo-imap4-status-callback nil)
1483 (setq elmo-imap4-status-callback-data nil))
1485 (elmo-imap4-send-command-wait session
1489 (elmo-imap4-spec-mailbox spec))
1490 " (unseen messages)")))
1491 (setq response (elmo-imap4-response-value response 'status))
1492 (cons (elmo-imap4-response-value response 'unseen)
1493 (elmo-imap4-response-value response 'messages))))
1495 (defun elmo-imap4-use-cache-p (spec number)
1496 elmo-imap4-use-cache)
1498 (defun elmo-imap4-local-file-p (spec number)
1501 (defun elmo-imap4-port-label (spec)
1503 (if (elmo-imap4-spec-stream-type spec)
1504 (concat "!" (symbol-name
1505 (elmo-network-stream-type-symbol
1506 (elmo-imap4-spec-stream-type spec)))))))
1509 (defsubst elmo-imap4-portinfo (spec)
1510 (list (elmo-imap4-spec-hostname spec) (elmo-imap4-spec-port spec)))
1512 (defun elmo-imap4-plugged-p (spec)
1513 (apply 'elmo-plugged-p
1514 (append (elmo-imap4-portinfo spec)
1515 (list nil (quote (elmo-imap4-port-label spec))))))
1517 (defun elmo-imap4-set-plugged (spec plugged add)
1518 (apply 'elmo-set-plugged plugged
1519 (append (elmo-imap4-portinfo spec)
1520 (list nil nil (quote (elmo-imap4-port-label spec)) add))))
1522 (defalias 'elmo-imap4-sync-number-alist 'elmo-generic-sync-number-alist)
1526 (defvar elmo-imap4-server-eol "\r\n"
1527 "The EOL string sent from the server.")
1529 (defvar elmo-imap4-client-eol "\r\n"
1530 "The EOL string we send to the server.")
1532 (defun elmo-imap4-find-next-line ()
1533 "Return point at end of current line, taking into account literals.
1534 Return nil if no complete line has arrived."
1535 (when (re-search-forward (concat elmo-imap4-server-eol "\\|{\\([0-9]+\\)}"
1536 elmo-imap4-server-eol)
1538 (if (match-string 1)
1539 (if (< (point-max) (+ (point) (string-to-number (match-string 1))))
1541 (goto-char (+ (point) (string-to-number (match-string 1))))
1542 (elmo-imap4-find-next-line))
1545 (defun elmo-imap4-sentinel (process string)
1546 (delete-process process))
1548 (defun elmo-imap4-arrival-filter (proc string)
1549 "IMAP process filter."
1550 (with-current-buffer (process-buffer proc)
1551 (elmo-imap4-debug "-> %s" string)
1552 (goto-char (point-max))
1555 (goto-char (point-min))
1556 (while (setq end (elmo-imap4-find-next-line))
1558 (narrow-to-region (point-min) end)
1559 (delete-backward-char (length elmo-imap4-server-eol))
1560 (goto-char (point-min))
1562 (cond ((eq elmo-imap4-status 'initial)
1563 (setq elmo-imap4-current-response
1565 (list 'greeting (elmo-imap4-parse-greeting)))))
1566 ((or (eq elmo-imap4-status 'auth)
1567 (eq elmo-imap4-status 'nonauth)
1568 (eq elmo-imap4-status 'selected)
1569 (eq elmo-imap4-status 'examine))
1570 (setq elmo-imap4-current-response
1572 (elmo-imap4-parse-response)
1573 elmo-imap4-current-response)))
1575 (message "Unknown state %s in arrival filter"
1576 elmo-imap4-status))))
1577 (delete-region (point-min) (point-max)))))))
1581 (defsubst elmo-imap4-forward ()
1582 (or (eobp) (forward-char 1)))
1584 (defsubst elmo-imap4-parse-number ()
1585 (when (looking-at "[0-9]+")
1587 (string-to-number (match-string 0))
1588 (goto-char (match-end 0)))))
1590 (defsubst elmo-imap4-parse-literal ()
1591 (when (looking-at "{\\([0-9]+\\)}\r\n")
1592 (let ((pos (match-end 0))
1593 (len (string-to-number (match-string 1))))
1594 (if (< (point-max) (+ pos len))
1596 (goto-char (+ pos len))
1597 (buffer-substring pos (+ pos len))))))
1598 ;;; (list ' pos (+ pos len))))))
1600 (defsubst elmo-imap4-parse-string ()
1601 (cond ((eq (char-after (point)) ?\")
1603 (let ((p (point)) (name ""))
1604 (skip-chars-forward "^\"\\\\")
1605 (setq name (buffer-substring p (point)))
1606 (while (eq (char-after (point)) ?\\)
1607 (setq p (1+ (point)))
1609 (skip-chars-forward "^\"\\\\")
1610 (setq name (concat name (buffer-substring p (point)))))
1613 ((eq (char-after (point)) ?{)
1614 (elmo-imap4-parse-literal))))
1616 (defsubst elmo-imap4-parse-nil ()
1617 (if (looking-at "NIL")
1618 (goto-char (match-end 0))))
1620 (defsubst elmo-imap4-parse-nstring ()
1621 (or (elmo-imap4-parse-string)
1622 (and (elmo-imap4-parse-nil)
1625 (defsubst elmo-imap4-parse-astring ()
1626 (or (elmo-imap4-parse-string)
1627 (buffer-substring (point)
1628 (if (re-search-forward "[(){ \r\n%*\"\\]" nil t)
1629 (goto-char (1- (match-end 0)))
1633 (defsubst elmo-imap4-parse-address ()
1635 (when (eq (char-after (point)) ?\()
1636 (elmo-imap4-forward)
1637 (setq address (vector (prog1 (elmo-imap4-parse-nstring)
1638 (elmo-imap4-forward))
1639 (prog1 (elmo-imap4-parse-nstring)
1640 (elmo-imap4-forward))
1641 (prog1 (elmo-imap4-parse-nstring)
1642 (elmo-imap4-forward))
1643 (elmo-imap4-parse-nstring)))
1644 (when (eq (char-after (point)) ?\))
1645 (elmo-imap4-forward)
1648 (defsubst elmo-imap4-parse-address-list ()
1649 (if (eq (char-after (point)) ?\()
1650 (let (address addresses)
1651 (elmo-imap4-forward)
1652 (while (and (not (eq (char-after (point)) ?\)))
1653 ;; next line for MS Exchange bug
1654 (progn (and (eq (char-after (point)) ? ) (elmo-imap4-forward)) t)
1655 (setq address (elmo-imap4-parse-address)))
1656 (setq addresses (cons address addresses)))
1657 (when (eq (char-after (point)) ?\))
1658 (elmo-imap4-forward)
1659 (nreverse addresses)))
1660 (assert (elmo-imap4-parse-nil))))
1662 (defsubst elmo-imap4-parse-mailbox ()
1663 (let ((mailbox (elmo-imap4-parse-astring)))
1664 (if (string-equal "INBOX" (upcase mailbox))
1668 (defun elmo-imap4-parse-greeting ()
1669 "Parse a IMAP greeting."
1670 (cond ((looking-at "\\* OK ")
1671 (setq elmo-imap4-status 'nonauth))
1672 ((looking-at "\\* PREAUTH ")
1673 (setq elmo-imap4-status 'auth))
1674 ((looking-at "\\* BYE ")
1675 (setq elmo-imap4-status 'closed))))
1677 (defun elmo-imap4-parse-response ()
1678 "Parse a IMAP command response."
1680 (case (setq token (elmo-read (current-buffer)))
1682 (skip-chars-forward " ")
1683 (list 'continue-req (buffer-substring (point) (point-max)))))
1684 (* (case (prog1 (setq token (elmo-read (current-buffer)))
1685 (elmo-imap4-forward))
1686 (OK (elmo-imap4-parse-resp-text-code))
1687 (NO (elmo-imap4-parse-resp-text-code))
1688 (BAD (elmo-imap4-parse-resp-text-code))
1689 (BYE (elmo-imap4-parse-bye))
1691 (elmo-imap4-parse-flag-list)))
1692 (LIST (list 'list (elmo-imap4-parse-data-list)))
1693 (LSUB (list 'lsub (elmo-imap4-parse-data-list)))
1696 (elmo-read (concat "("
1697 (buffer-substring (point) (point-max))
1699 (STATUS (elmo-imap4-parse-status))
1701 (NAMESPACE (elmo-imap4-parse-namespace))
1702 (CAPABILITY (list 'capability
1704 (concat "(" (downcase (buffer-substring
1705 (point) (point-max)))
1707 (ACL (elmo-imap4-parse-acl))
1708 (t (case (prog1 (elmo-read (current-buffer))
1709 (elmo-imap4-forward))
1710 (EXISTS (list 'exists token))
1711 (RECENT (list 'recent token))
1712 (EXPUNGE (list 'expunge token))
1713 (FETCH (elmo-imap4-parse-fetch token))
1714 (t (list 'garbage (buffer-string)))))))
1715 (t (if (not (string-match elmo-imap4-seq-prefix (symbol-name token)))
1716 (list 'garbage (buffer-string))
1717 (case (prog1 (elmo-read (current-buffer))
1718 (elmo-imap4-forward))
1720 (setq elmo-imap4-parsing nil)
1721 (setq token (symbol-name token))
1722 (elmo-unintern token)
1723 (elmo-imap4-debug "*%s* OK arrived" token)
1724 (setq elmo-imap4-reached-tag token)
1725 (list 'ok (elmo-imap4-parse-resp-text-code))))
1727 (setq elmo-imap4-parsing nil)
1728 (setq token (symbol-name token))
1729 (elmo-unintern token)
1730 (elmo-imap4-debug "*%s* NO arrived" token)
1731 (setq elmo-imap4-reached-tag token)
1733 (when (eq (char-after (point)) ?\[)
1734 (setq code (buffer-substring (point)
1735 (search-forward "]")))
1736 (elmo-imap4-forward))
1737 (setq text (buffer-substring (point) (point-max)))
1738 (list 'no (list code text)))))
1740 (setq elmo-imap4-parsing nil)
1741 (elmo-imap4-debug "*%s* BAD arrived" token)
1742 (setq token (symbol-name token))
1743 (elmo-unintern token)
1744 (setq elmo-imap4-reached-tag token)
1746 (when (eq (char-after (point)) ?\[)
1747 (setq code (buffer-substring (point)
1748 (search-forward "]")))
1749 (elmo-imap4-forward))
1750 (setq text (buffer-substring (point) (point-max)))
1751 (list 'bad (list code text)))))
1752 (t (list 'garbage (buffer-string)))))))))
1754 (defun elmo-imap4-parse-bye ()
1756 (when (eq (char-after (point)) ?\[)
1757 (setq code (buffer-substring (point)
1758 (search-forward "]")))
1759 (elmo-imap4-forward))
1760 (setq text (buffer-substring (point) (point-max)))
1761 (list 'bye (list code text))))
1763 (defun elmo-imap4-parse-text ()
1764 (goto-char (point-min))
1765 (when (search-forward "[" nil t)
1766 (search-forward "]")
1767 (elmo-imap4-forward))
1768 (list 'text (buffer-substring (point) (point-max))))
1770 (defun elmo-imap4-parse-resp-text-code ()
1771 (when (eq (char-after (point)) ?\[)
1772 (elmo-imap4-forward)
1773 (cond ((search-forward "PERMANENTFLAGS " nil t)
1774 (list 'permanentflags (elmo-imap4-parse-flag-list)))
1775 ((search-forward "UIDNEXT " nil t)
1776 (list 'uidnext (elmo-read (current-buffer))))
1777 ((search-forward "UNSEEN " nil t)
1778 (list 'unseen (elmo-read (current-buffer))))
1779 ((looking-at "UIDVALIDITY \\([0-9]+\\)")
1780 (list 'uidvalidity (match-string 1)))
1781 ((search-forward "READ-ONLY" nil t)
1782 (list 'read-only t))
1783 ((search-forward "READ-WRITE" nil t)
1784 (list 'read-write t))
1785 ((search-forward "NEWNAME " nil t)
1786 (let (oldname newname)
1787 (setq oldname (elmo-imap4-parse-string))
1788 (elmo-imap4-forward)
1789 (setq newname (elmo-imap4-parse-string))
1790 (list 'newname newname oldname)))
1791 ((search-forward "TRYCREATE" nil t)
1792 (list 'trycreate t))
1793 ((looking-at "APPENDUID \\([0-9]+\\) \\([0-9]+\\)")
1795 (list (match-string 1)
1796 (string-to-number (match-string 2)))))
1797 ((looking-at "COPYUID \\([0-9]+\\) \\([0-9,:]+\\) \\([0-9,:]+\\)")
1798 (list 'copyuid (list (match-string 1)
1801 ((search-forward "ALERT] " nil t)
1802 (message "IMAP server information: %s"
1803 (buffer-substring (point) (point-max))))
1804 (t (list 'unknown)))))
1806 (defun elmo-imap4-parse-data-list ()
1807 (let (flags delimiter mailbox)
1808 (setq flags (elmo-imap4-parse-flag-list))
1809 (when (looking-at " NIL\\| \"\\\\?\\(.\\)\"")
1810 (setq delimiter (match-string 1))
1811 (goto-char (1+ (match-end 0)))
1812 (when (setq mailbox (elmo-imap4-parse-mailbox))
1813 (list mailbox flags delimiter)))))
1815 (defsubst elmo-imap4-parse-header-list ()
1816 (when (eq (char-after (point)) ?\()
1818 (while (not (eq (char-after (point)) ?\)))
1819 (elmo-imap4-forward)
1820 (push (elmo-imap4-parse-astring) strlist))
1821 (elmo-imap4-forward)
1822 (nreverse strlist))))
1824 (defsubst elmo-imap4-parse-fetch-body-section ()
1826 (buffer-substring (point)
1828 (progn (re-search-forward "[] ]" nil t)
1830 (if (eq (char-before) ? )
1832 (mapconcat 'identity
1833 (cons section (elmo-imap4-parse-header-list)) " ")
1834 (search-forward "]" nil t))
1837 (defun elmo-imap4-parse-fetch (response)
1838 (when (eq (char-after (point)) ?\()
1840 (while (not (eq (char-after (point)) ?\)))
1841 (elmo-imap4-forward)
1842 (let ((token (elmo-imap4-fetch-read (current-buffer))))
1843 (elmo-imap4-forward)
1845 (cond ((eq token 'UID)
1846 (list 'uid (condition-case nil
1847 (elmo-read (current-buffer))
1850 (list 'flags (elmo-imap4-parse-flag-list)))
1851 ((eq token 'ENVELOPE)
1852 (list 'envelope (elmo-imap4-parse-envelope)))
1853 ((eq token 'INTERNALDATE)
1854 (list 'internaldate (elmo-imap4-parse-string)))
1856 (list 'rfc822 (elmo-imap4-parse-nstring)))
1857 ((eq token (intern elmo-imap4-rfc822-header))
1858 (list 'rfc822header (elmo-imap4-parse-nstring)))
1859 ((eq token (intern elmo-imap4-rfc822-text))
1860 (list 'rfc822text (elmo-imap4-parse-nstring)))
1861 ((eq token (intern elmo-imap4-rfc822-size))
1862 (list 'rfc822size (elmo-read (current-buffer))))
1864 (if (eq (char-before) ?\[)
1867 (upcase (elmo-imap4-parse-fetch-body-section))
1869 (eq (char-after (point)) ?<)
1870 (buffer-substring (1+ (point))
1872 (search-forward ">" nil t)
1874 (progn (elmo-imap4-forward)
1875 (elmo-imap4-parse-nstring)))
1876 (list 'body (elmo-imap4-parse-body))))
1877 ((eq token 'BODYSTRUCTURE)
1878 (list 'bodystructure (elmo-imap4-parse-body)))))
1879 (setq list (cons element list))))
1880 (and elmo-imap4-fetch-callback
1881 (elmo-imap4-fetch-callback list elmo-imap4-fetch-callback-data))
1882 (list 'fetch list))))
1884 (defun elmo-imap4-parse-status ()
1885 (let ((mailbox (elmo-imap4-parse-mailbox))
1887 (when (and mailbox (search-forward "(" nil t))
1888 (while (not (eq (char-after (point)) ?\)))
1891 (let ((token (elmo-read (current-buffer))))
1892 (cond ((eq token 'MESSAGES)
1893 (list 'messages (elmo-read (current-buffer))))
1895 (list 'recent (elmo-read (current-buffer))))
1896 ((eq token 'UIDNEXT)
1897 (list 'uidnext (elmo-read (current-buffer))))
1898 ((eq token 'UIDVALIDITY)
1899 (and (looking-at " \\([0-9]+\\)")
1900 (prog1 (list 'uidvalidity (match-string 1))
1901 (goto-char (match-end 1)))))
1903 (list 'unseen (elmo-read (current-buffer))))
1906 "Unknown status data %s in mailbox %s ignored"
1909 (and elmo-imap4-status-callback
1910 (funcall elmo-imap4-status-callback
1912 elmo-imap4-status-callback-data))
1913 (list 'status status)))
1916 (defmacro elmo-imap4-value (value)
1917 (` (if (eq (, value) 'NIL) nil
1920 (defmacro elmo-imap4-nth (pos list)
1921 (` (let ((value (nth (, pos) (, list))))
1922 (elmo-imap4-value value))))
1924 (defun elmo-imap4-parse-namespace ()
1927 (copy-sequence elmo-imap4-extra-namespace-alist)
1928 (elmo-imap4-parse-namespace-subr
1929 (elmo-read (concat "(" (buffer-substring
1930 (point) (point-max))
1933 (defun elmo-imap4-parse-namespace-subr (ns)
1934 (let (prefix delim namespace-alist default-delim)
1935 ;; 0: personal, 1: other, 2: shared
1937 (setq namespace-alist
1938 (nconc namespace-alist
1942 (setq prefix (elmo-imap4-nth 0 namespace)
1943 delim (elmo-imap4-nth 1 namespace))
1944 (if (and prefix delim
1946 (concat (regexp-quote delim) "\\'")
1948 (setq prefix (substring prefix 0
1949 (match-beginning 0))))
1950 (if (eq (length prefix) 0)
1951 (progn (setq default-delim delim) nil)
1954 (if (string= (downcase prefix) "inbox")
1955 "[Ii][Nn][Bb][Oo][Xx]"
1956 (regexp-quote prefix))
1959 (elmo-imap4-nth i ns))))))
1961 (setq namespace-alist
1962 (nconc namespace-alist
1963 (list (cons "^.*$" default-delim)))))
1966 (defun elmo-imap4-parse-acl ()
1967 (let ((mailbox (elmo-imap4-parse-mailbox))
1968 identifier rights acl)
1969 (while (eq (char-after (point)) ?\ )
1970 (elmo-imap4-forward)
1971 (setq identifier (elmo-imap4-parse-astring))
1972 (elmo-imap4-forward)
1973 (setq rights (elmo-imap4-parse-astring))
1974 (setq acl (append acl (list (cons identifier rights)))))
1975 (list 'acl acl mailbox)))
1977 (defun elmo-imap4-parse-flag-list ()
1978 (let ((str (buffer-substring (+ (point) 1)
1979 (progn (search-forward ")" nil t)
1981 (unless (eq (length str) 0)
1982 (split-string str))))
1984 (defun elmo-imap4-parse-envelope ()
1985 (when (eq (char-after (point)) ?\()
1986 (elmo-imap4-forward)
1987 (vector (prog1 (elmo-imap4-parse-nstring);; date
1988 (elmo-imap4-forward))
1989 (prog1 (elmo-imap4-parse-nstring);; subject
1990 (elmo-imap4-forward))
1991 (prog1 (elmo-imap4-parse-address-list);; from
1992 (elmo-imap4-forward))
1993 (prog1 (elmo-imap4-parse-address-list);; sender
1994 (elmo-imap4-forward))
1995 (prog1 (elmo-imap4-parse-address-list);; reply-to
1996 (elmo-imap4-forward))
1997 (prog1 (elmo-imap4-parse-address-list);; to
1998 (elmo-imap4-forward))
1999 (prog1 (elmo-imap4-parse-address-list);; cc
2000 (elmo-imap4-forward))
2001 (prog1 (elmo-imap4-parse-address-list);; bcc
2002 (elmo-imap4-forward))
2003 (prog1 (elmo-imap4-parse-nstring);; in-reply-to
2004 (elmo-imap4-forward))
2005 (prog1 (elmo-imap4-parse-nstring);; message-id
2006 (elmo-imap4-forward)))))
2008 (defsubst elmo-imap4-parse-string-list ()
2009 (cond ((eq (char-after (point)) ?\();; body-fld-param
2011 (elmo-imap4-forward)
2012 (while (setq str (elmo-imap4-parse-string))
2014 (elmo-imap4-forward))
2015 (nreverse strlist)))
2016 ((elmo-imap4-parse-nil)
2019 (defun elmo-imap4-parse-body-extension ()
2020 (if (eq (char-after (point)) ?\()
2022 (elmo-imap4-forward)
2023 (push (elmo-imap4-parse-body-extension) b-e)
2024 (while (eq (char-after (point)) ?\ )
2025 (elmo-imap4-forward)
2026 (push (elmo-imap4-parse-body-extension) b-e))
2027 (assert (eq (char-after (point)) ?\)))
2028 (elmo-imap4-forward)
2030 (or (elmo-imap4-parse-number)
2031 (elmo-imap4-parse-nstring))))
2033 (defsubst elmo-imap4-parse-body-ext ()
2035 (when (eq (char-after (point)) ?\ );; body-fld-dsp
2036 (elmo-imap4-forward)
2038 (if (eq (char-after (point)) ?\()
2040 (elmo-imap4-forward)
2041 (push (elmo-imap4-parse-string) dsp)
2042 (elmo-imap4-forward)
2043 (push (elmo-imap4-parse-string-list) dsp)
2044 (elmo-imap4-forward))
2045 (assert (elmo-imap4-parse-nil)))
2046 (push (nreverse dsp) ext))
2047 (when (eq (char-after (point)) ?\ );; body-fld-lang
2048 (elmo-imap4-forward)
2049 (if (eq (char-after (point)) ?\()
2050 (push (elmo-imap4-parse-string-list) ext)
2051 (push (elmo-imap4-parse-nstring) ext))
2052 (while (eq (char-after (point)) ?\ );; body-extension
2053 (elmo-imap4-forward)
2054 (setq ext (append (elmo-imap4-parse-body-extension) ext)))))
2057 (defun elmo-imap4-parse-body ()
2059 (when (eq (char-after (point)) ?\()
2060 (elmo-imap4-forward)
2061 (if (eq (char-after (point)) ?\()
2063 (while (and (eq (char-after (point)) ?\()
2064 (setq subbody (elmo-imap4-parse-body)))
2065 (push subbody body))
2066 (elmo-imap4-forward)
2067 (push (elmo-imap4-parse-string) body);; media-subtype
2068 (when (eq (char-after (point)) ?\ );; body-ext-mpart:
2069 (elmo-imap4-forward)
2070 (if (eq (char-after (point)) ?\();; body-fld-param
2071 (push (elmo-imap4-parse-string-list) body)
2072 (push (and (elmo-imap4-parse-nil) nil) body))
2074 (append (elmo-imap4-parse-body-ext) body)));; body-ext-...
2075 (assert (eq (char-after (point)) ?\)))
2076 (elmo-imap4-forward)
2079 (push (elmo-imap4-parse-string) body);; media-type
2080 (elmo-imap4-forward)
2081 (push (elmo-imap4-parse-string) body);; media-subtype
2082 (elmo-imap4-forward)
2083 ;; next line for Sun SIMS bug
2084 (and (eq (char-after (point)) ? ) (elmo-imap4-forward))
2085 (if (eq (char-after (point)) ?\();; body-fld-param
2086 (push (elmo-imap4-parse-string-list) body)
2087 (push (and (elmo-imap4-parse-nil) nil) body))
2088 (elmo-imap4-forward)
2089 (push (elmo-imap4-parse-nstring) body);; body-fld-id
2090 (elmo-imap4-forward)
2091 (push (elmo-imap4-parse-nstring) body);; body-fld-desc
2092 (elmo-imap4-forward)
2093 (push (elmo-imap4-parse-string) body);; body-fld-enc
2094 (elmo-imap4-forward)
2095 (push (elmo-imap4-parse-number) body);; body-fld-octets
2097 ;; ok, we're done parsing the required parts, what comes now is one
2100 ;; envelope (then we're parsing body-type-msg)
2101 ;; body-fld-lines (then we're parsing body-type-text)
2102 ;; body-ext-1part (then we're parsing body-type-basic)
2104 ;; the problem is that the two first are in turn optionally followed
2105 ;; by the third. So we parse the first two here (if there are any)...
2107 (when (eq (char-after (point)) ?\ )
2108 (elmo-imap4-forward)
2110 (cond ((eq (char-after (point)) ?\();; body-type-msg:
2111 (push (elmo-imap4-parse-envelope) body);; envelope
2112 (elmo-imap4-forward)
2113 (push (elmo-imap4-parse-body) body);; body
2114 (elmo-imap4-forward)
2115 (push (elmo-imap4-parse-number) body));; body-fld-lines
2116 ((setq lines (elmo-imap4-parse-number));; body-type-text:
2117 (push lines body));; body-fld-lines
2119 (backward-char)))));; no match...
2121 ;; ...and then parse the third one here...
2123 (when (eq (char-after (point)) ?\ );; body-ext-1part:
2124 (elmo-imap4-forward)
2125 (push (elmo-imap4-parse-nstring) body);; body-fld-md5
2127 (append (elmo-imap4-parse-body-ext) body)));; body-ext-1part..
2129 (assert (eq (char-after (point)) ?\)))
2130 (elmo-imap4-forward)
2134 (product-provide (provide 'elmo-imap4) (require 'elmo-version))
2136 ;;; elmo-imap4.el ends here