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>
50 (eval-when-compile (require 'cl))
52 (defvar elmo-imap4-use-lock t
53 "USE IMAP4 with locking process.")
55 ;;; internal variables
57 (defvar elmo-imap4-seq-prefix "elmo-imap4")
58 (defvar elmo-imap4-seqno 0)
59 (defvar elmo-imap4-use-uid t
60 "Use UID as message number.")
62 (defvar elmo-imap4-current-response nil)
63 (defvar elmo-imap4-status nil)
64 (defvar elmo-imap4-reached-tag "elmo-imap40")
66 ;;; buffer local variables
68 (defvar elmo-imap4-extra-namespace-alist
69 '(("^{.*/nntp}.*$" . ".")) ; Default is for UW's remote nntp mailbox...
70 "Extra namespace alist. A list of cons cell like: (REGEXP . DELIMITER).")
71 (defvar elmo-imap4-default-hierarchy-delimiter "/")
73 (defvar elmo-imap4-server-capability nil)
74 (defvar elmo-imap4-server-namespace nil)
76 (defvar elmo-imap4-parsing nil) ; indicates parsing.
78 (defvar elmo-imap4-fetch-callback nil)
79 (defvar elmo-imap4-fetch-callback-data nil)
80 (defvar elmo-imap4-status-callback nil)
81 (defvar elmo-imap4-status-callback-data nil)
83 (defvar elmo-imap4-server-diff-async-callback nil)
84 (defvar elmo-imap4-server-diff-async-callback-data nil)
86 ;;; progress...(no use?)
87 (defvar elmo-imap4-count-progress nil)
88 (defvar elmo-imap4-count-progress-message nil)
89 (defvar elmo-imap4-progress-count nil)
91 ;;; XXX Temporal implementation
92 (defvar elmo-imap4-current-msgdb nil)
94 (defvar elmo-imap4-local-variables
96 elmo-imap4-current-response
99 elmo-imap4-reached-tag
100 elmo-imap4-count-progress
101 elmo-imap4-count-progress-message
102 elmo-imap4-progress-count
103 elmo-imap4-fetch-callback
104 elmo-imap4-fetch-callback-data
105 elmo-imap4-status-callback
106 elmo-imap4-status-callback-data
107 elmo-imap4-current-msgdb))
111 (defconst elmo-imap4-quoted-specials-list '(?\\ ?\"))
113 (defconst elmo-imap4-non-atom-char-regex
115 (concat "[^" "]!#$&'+,./0-9:;<=>?@A-Z[^_`a-z|}~-" "]")))
117 (defconst elmo-imap4-non-text-char-regex
120 "]\x01-\x09\x0b\x0c\x0e-\x1f\x7f !\"#$%&'()*+,./0-9:;<=>?@A-Z[\\^_`a-z{|}~-"
123 (defconst elmo-imap4-literal-threshold 1024
124 "Limitation of characters that can be used in a quoted string.")
127 (defvar elmo-imap4-debug nil
128 "Non-nil forces IMAP4 folder as debug mode.
129 Debug information is inserted in the buffer \"*IMAP4 DEBUG*\"")
131 (defvar elmo-imap4-debug-inhibit-logging nil)
136 (luna-define-class elmo-imap4-session (elmo-network-session)
137 (capability current-mailbox read-only))
138 (luna-define-internal-accessors 'elmo-imap4-session))
142 (defsubst elmo-imap4-spec-mailbox (spec)
145 (defsubst elmo-imap4-spec-username (spec)
148 (defsubst elmo-imap4-spec-auth (spec)
151 (defsubst elmo-imap4-spec-hostname (spec)
154 (defsubst elmo-imap4-spec-port (spec)
157 (defsubst elmo-imap4-spec-stream-type (spec)
163 (defsubst elmo-imap4-debug (message &rest args)
165 (with-current-buffer (get-buffer-create "*IMAP4 DEBUG*")
166 (goto-char (point-max))
167 (if elmo-imap4-debug-inhibit-logging
168 (insert "NO LOGGING\n")
169 (insert (apply 'format message args) "\n")))))
173 (defmacro elmo-imap4-response-continue-req-p (response)
174 "Returns non-nil if RESPONSE is '+' response."
175 (` (assq 'continue-req (, response))))
177 (defmacro elmo-imap4-response-ok-p (response)
178 "Returns non-nil if RESPONSE is an 'OK' response."
179 (` (assq 'ok (, response))))
181 (defmacro elmo-imap4-response-bye-p (response)
182 "Returns non-nil if RESPONSE is an 'BYE' response."
183 (` (assq 'bye (, response))))
185 (defmacro elmo-imap4-response-value (response symbol)
186 "Get value of the SYMBOL from RESPONSE."
187 (` (nth 1 (assq (, symbol) (, response)))))
189 (defsubst elmo-imap4-response-value-all (response symbol)
190 "Get all value of the SYMBOL from RESPONSE."
193 (if (eq (car (car response)) symbol)
194 (setq matched (nconc matched (nth 1 (car response)))))
195 (setq response (cdr response)))
198 (defmacro elmo-imap4-response-error-text (response)
199 "Returns text of NO, BAD, BYE response."
200 (` (nth 1 (or (elmo-imap4-response-value (, response) 'no)
201 (elmo-imap4-response-value (, response) 'bad)
202 (elmo-imap4-response-value (, response) 'bye)))))
204 (defmacro elmo-imap4-response-bodydetail-text (response)
205 "Returns text of BODY[section]<partial>."
206 (` (nth 3 (assq 'bodydetail (, response)))))
208 ;;; Session commands.
210 ; (defun elmo-imap4-send-command-wait (session command)
211 ; "Send COMMAND to the SESSION and wait for response.
212 ; Returns RESPONSE (parsed lisp object) of IMAP session."
213 ; (elmo-imap4-read-response session
214 ; (elmo-imap4-send-command
218 (defun elmo-imap4-send-command-wait (session command)
219 "Send COMMAND to the SESSION.
220 Returns RESPONSE (parsed lisp object) of IMAP session.
221 If response is not `OK', causes error with IMAP response text."
222 (elmo-imap4-accept-ok session
223 (elmo-imap4-send-command
227 (defun elmo-imap4-send-command (session command)
228 "Send COMMAND to the SESSION.
229 Returns a TAG string which is assigned to the COMAND."
230 (let* ((command-args (if (listp command)
233 (process (elmo-network-session-process-internal session))
234 cmdstr tag token kind)
235 (with-current-buffer (process-buffer process)
236 (setq tag (concat elmo-imap4-seq-prefix
238 (setq elmo-imap4-seqno (+ 1 elmo-imap4-seqno)))))
239 (setq cmdstr (concat tag " "))
240 ;; (erase-buffer) No need.
241 (goto-char (point-min))
242 (if (elmo-imap4-response-bye-p elmo-imap4-current-response)
243 (signal 'elmo-imap4-bye-error
244 (list (elmo-imap4-response-error-text
245 elmo-imap4-current-response))))
246 (setq elmo-imap4-current-response nil)
247 (if elmo-imap4-parsing
248 (error "IMAP process is running. Please wait (or plug again.)"))
249 (setq elmo-imap4-parsing t)
250 (elmo-imap4-debug "<-(%s)- %s" tag command)
251 (while (setq token (car command-args))
252 (cond ((stringp token) ; formatted
253 (setq cmdstr (concat cmdstr token)))
254 ((listp token) ; unformatted
255 (setq kind (car token))
256 (cond ((eq kind 'atom)
257 (setq cmdstr (concat cmdstr (nth 1 token))))
261 (elmo-imap4-format-quoted (nth 1 token)))))
263 (setq cmdstr (concat cmdstr
264 (format "{%d}" (nth 2 token))))
265 (process-send-string process cmdstr)
266 (process-send-string process "\r\n")
268 (elmo-imap4-accept-continue-req session)
269 (cond ((stringp (nth 1 token))
270 (setq cmdstr (nth 1 token)))
271 ((bufferp (nth 1 token))
272 (with-current-buffer (nth 1 token)
276 (+ (point-min) (nth 2 token)))))
278 (error "Wrong argument for literal"))))
280 (error "Unknown token kind %s" kind))))
282 (error "Invalid argument")))
283 (setq command-args (cdr command-args)))
285 (process-send-string process cmdstr))
286 (process-send-string process "\r\n")
289 (defun elmo-imap4-send-string (session string)
290 "Send STRING to the SESSION."
291 (with-current-buffer (process-buffer
292 (elmo-network-session-process-internal session))
293 (setq elmo-imap4-current-response nil)
294 (goto-char (point-min))
295 (elmo-imap4-debug "<-- %s" string)
296 (process-send-string (elmo-network-session-process-internal session)
298 (process-send-string (elmo-network-session-process-internal session)
301 (defun elmo-imap4-read-response (session tag)
302 "Read parsed response from SESSION.
303 TAG is the tag of the command"
304 (with-current-buffer (process-buffer
305 (elmo-network-session-process-internal session))
306 (while (not (or (string= tag elmo-imap4-reached-tag)
307 (elmo-imap4-response-bye-p elmo-imap4-current-response)))
308 (when (memq (process-status
309 (elmo-network-session-process-internal session))
311 (accept-process-output (elmo-network-session-process-internal session)
313 (elmo-imap4-debug "=>%s" (prin1-to-string elmo-imap4-current-response))
314 (setq elmo-imap4-parsing nil)
315 elmo-imap4-current-response))
317 (defsubst elmo-imap4-read-untagged (process)
318 (with-current-buffer (process-buffer process)
319 (while (not elmo-imap4-current-response)
320 (accept-process-output process 1))
321 (elmo-imap4-debug "=>%s" (prin1-to-string elmo-imap4-current-response))
322 elmo-imap4-current-response))
324 (defun elmo-imap4-read-continue-req (session)
325 "Returns a text following to continue-req in SESSION.
326 If response is not `+' response, returns nil."
327 (elmo-imap4-response-value
328 (elmo-imap4-read-untagged
329 (elmo-network-session-process-internal session))
332 (defun elmo-imap4-accept-continue-req (session)
333 "Returns non-nil if `+' (continue-req) response is arrived in SESSION.
334 If response is not `+' response, cause an error."
337 (elmo-imap4-read-untagged
338 (elmo-network-session-process-internal session)))
339 (or (elmo-imap4-response-continue-req-p response)
340 (error "IMAP error: %s"
341 (or (elmo-imap4-response-error-text response)
342 "No continut-req from server.")))))
344 (defun elmo-imap4-read-ok (session tag)
345 "Returns non-nil if `OK' response of the command with TAG is arrived
346 in SESSION. If response is not `OK' response, returns nil."
347 (elmo-imap4-response-ok-p
348 (elmo-imap4-read-response session tag)))
350 (defun elmo-imap4-accept-ok (session tag)
351 "Accept only `OK' response from SESSION.
352 If response is not `OK' response, causes error with IMAP response text."
353 (let ((response (elmo-imap4-read-response session tag)))
354 (if (elmo-imap4-response-ok-p response)
356 (if (elmo-imap4-response-bye-p response)
357 (signal 'elmo-imap4-bye-error
358 (list (elmo-imap4-response-error-text response)))
359 (error "IMAP error: %s"
360 (or (elmo-imap4-response-error-text response)
361 "No `OK' response from server."))))))
364 (defun elmo-imap4-session-check (session)
365 (with-current-buffer (elmo-network-session-buffer session)
366 (setq elmo-imap4-fetch-callback nil)
367 (setq elmo-imap4-fetch-callback-data nil))
368 (elmo-imap4-send-command-wait session "check"))
370 (defun elmo-imap4-atom-p (string)
371 "Return t if STRING is an atom defined in rfc2060."
372 (if (string= string "")
375 (not (string-match elmo-imap4-non-atom-char-regex string)))))
377 (defun elmo-imap4-quotable-p (string)
378 "Return t if STRING can be formatted as a quoted defined in rfc2060."
380 (not (string-match elmo-imap4-non-text-char-regex string))))
382 (defun elmo-imap4-nil (string)
383 "Return a list represents the special atom \"NIL\" defined in rfc2060, \
385 Otherwise return nil."
389 (defun elmo-imap4-atom (string)
390 "Return a list represents STRING as an atom defined in rfc2060.
391 Return nil if STRING is not an atom. See `elmo-imap4-atom-p'."
392 (if (elmo-imap4-atom-p string)
393 (list 'atom string)))
395 (defun elmo-imap4-quoted (string)
396 "Return a list represents STRING as a quoted defined in rfc2060.
397 Return nil if STRING can not be formatted as a quoted. See `elmo-imap4-quotable-p'."
398 (if (elmo-imap4-quotable-p string)
399 (list 'quoted string)))
401 (defun elmo-imap4-literal-1 (string-or-buffer length)
402 "Internal function for `elmo-imap4-literal' and `elmo-imap4-buffer-literal'.
403 Return a list represents STRING-OR-BUFFER as a literal defined in rfc2060.
404 STRING-OR-BUFFER must be an encoded string or a single-byte string or a single-byte buffer.
405 LENGTH must be the number of octets for STRING-OR-BUFFER."
406 (list 'literal string-or-buffer length))
408 (defun elmo-imap4-literal (string)
409 "Return a list represents STRING as a literal defined in rfc2060.
410 STRING must be an encoded or a single-byte string."
411 (elmo-imap4-literal-1 string (length string)))
413 (defun elmo-imap4-buffer-literal (buffer)
414 "Return a list represents BUFFER as a literal defined in rfc2060.
415 BUFFER must be a single-byte buffer."
416 (elmo-imap4-literal-1 buffer (with-current-buffer buffer
419 (defun elmo-imap4-string-1 (string length)
420 "Internal function for `elmo-imap4-string' and `elmo-imap4-buffer-string'.
421 Return a list represents STRING as a string defined in rfc2060.
422 STRING must be an encoded or a single-byte string.
423 LENGTH must be the number of octets for STRING."
424 (or (elmo-imap4-quoted string)
425 (elmo-imap4-literal-1 string length)))
427 (defun elmo-imap4-string (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 (let ((length (length string)))
431 (if (< elmo-imap4-literal-threshold length)
432 (elmo-imap4-literal-1 string length)
433 (elmo-imap4-string-1 string length))))
435 (defun elmo-imap4-buffer-string (buffer)
436 "Return a list represents BUFFER as a string defined in rfc2060.
437 BUFFER must be a single-byte buffer."
438 (let ((length (with-current-buffer buffer
440 (if (< elmo-imap4-literal-threshold length)
441 (elmo-imap4-literal-1 buffer length)
442 (elmo-imap4-string-1 (with-current-buffer buffer
446 (defun elmo-imap4-astring-1 (string length)
447 "Internal function for `elmo-imap4-astring' and `elmo-imap4-buffer-astring'.
448 Return a list represents STRING as an astring defined in rfc2060.
449 STRING must be an encoded or a single-byte string.
450 LENGTH must be the number of octets for STRING."
451 (or (elmo-imap4-atom string)
452 (elmo-imap4-string-1 string length)))
454 (defun elmo-imap4-astring (string)
455 "Return a list represents STRING as an astring defined in rfc2060.
456 STRING must be an encoded or a single-byte string."
457 (let ((length (length string)))
458 (if (< elmo-imap4-literal-threshold length)
459 (elmo-imap4-literal-1 string length)
460 (elmo-imap4-astring-1 string length))))
462 (defun elmo-imap4-buffer-astring (buffer)
463 "Return a list represents BUFFER as an astring defined in rfc2060.
464 BUFFER must be a single-byte buffer."
465 (let ((length (with-current-buffer buffer
467 (if (< elmo-imap4-literal-threshold length)
468 (elmo-imap4-literal-1 buffer length)
469 (elmo-imap4-astring-1 (with-current-buffer buffer
473 (defun elmo-imap4-nstring (string)
474 "Return a list represents STRING as a nstring defined in rfc2060.
475 STRING must be an encoded or a single-byte string."
476 (or (elmo-imap4-nil string)
477 (elmo-imap4-string string)))
479 (defun elmo-imap4-buffer-nstring (buffer)
480 "Return a list represents BUFFER as a nstring defined in rfc2060.
481 BUFFER must be a single-byte buffer."
482 (or (elmo-imap4-nil buffer)
483 (elmo-imap4-buffer-string buffer)))
485 (defalias 'elmo-imap4-mailbox 'elmo-imap4-astring)
486 (defalias 'elmo-imap4-field-body 'elmo-imap4-astring)
487 (defalias 'elmo-imap4-userid 'elmo-imap4-astring)
488 (defalias 'elmo-imap4-password 'elmo-imap4-astring)
490 (defun elmo-imap4-format-quoted (string)
491 "Return STRING in a form of the quoted-string defined in rfc2060."
493 (std11-wrap-as-quoted-pairs string elmo-imap4-quoted-specials-list)
496 (defsubst elmo-imap4-response-get-selectable-mailbox-list (response)
500 (if (and (eq 'list (car entry))
501 (not (member "\\NoSelect" (nth 1 (nth 1 entry)))))
502 (car (nth 1 entry))))
506 (defun elmo-imap4-list-folders (spec &optional hierarchy)
507 (let* ((root (elmo-imap4-spec-mailbox spec))
508 (session (elmo-imap4-get-session spec))
511 (elmo-string-matched-assoc
513 (with-current-buffer (elmo-network-session-buffer session)
514 elmo-imap4-server-namespace)))
515 elmo-imap4-default-hierarchy-delimiter))
516 result append-serv type)
519 (not (string= root ""))
520 (not (string-match (concat "\\(.*\\)"
524 (setq root (concat root delim)))
525 (setq result (elmo-imap4-response-get-selectable-mailbox-list
526 (elmo-imap4-send-command-wait
528 (list "list " (elmo-imap4-mailbox root) " *"))))
529 (unless (string= (elmo-imap4-spec-username spec)
530 elmo-default-imap4-user)
531 (setq append-serv (concat ":" (elmo-imap4-spec-username spec))))
532 (unless (eq (elmo-imap4-spec-auth spec)
533 elmo-default-imap4-authenticate-type)
535 (concat append-serv "/" (symbol-name (elmo-imap4-spec-auth spec)))))
536 (unless (string= (elmo-imap4-spec-hostname spec)
537 elmo-default-imap4-server)
538 (setq append-serv (concat append-serv "@" (elmo-imap4-spec-hostname
540 (unless (eq (elmo-imap4-spec-port spec)
541 elmo-default-imap4-port)
542 (setq append-serv (concat append-serv ":"
544 (elmo-imap4-spec-port spec)))))
545 (setq type (elmo-imap4-spec-stream-type spec))
546 (unless (eq (elmo-network-stream-type-symbol type)
547 elmo-default-imap4-stream-type)
549 (setq append-serv (concat append-serv
550 (elmo-network-stream-type-spec-string
553 (let (folder folders ret)
554 (while (setq folders (car result))
557 (concat "^\\(" root "[^" delim "]" "+\\)" delim)
559 (setq folder (match-string 1 folders)))
562 (append ret (list (list
563 (concat "%" (elmo-imap4-decode-folder-string folder)
565 (eval append-serv)))))))
568 (mapcar '(lambda (fld)
571 (concat "^" (regexp-quote folder))
575 (setq ret (append ret (list
576 (concat "%" (elmo-imap4-decode-folder-string folders)
578 (eval append-serv))))))
579 (setq result (cdr result))))
581 (mapcar (lambda (fld)
582 (concat "%" (elmo-imap4-decode-folder-string fld)
584 (eval append-serv))))
587 (defun elmo-imap4-folder-exists-p (spec)
588 (let ((session (elmo-imap4-get-session spec)))
590 (elmo-imap4-session-current-mailbox-internal session)
591 (elmo-imap4-spec-mailbox spec))
593 (elmo-imap4-session-select-mailbox
595 (elmo-imap4-spec-mailbox spec)
598 (defun elmo-imap4-folder-creatable-p (spec)
601 (defun elmo-imap4-create-folder-maybe (spec dummy)
602 (unless (elmo-imap4-folder-exists-p spec)
603 (elmo-imap4-create-folder spec)))
605 (defun elmo-imap4-create-folder (spec)
606 (elmo-imap4-send-command-wait
607 (elmo-imap4-get-session spec)
608 (list "create " (elmo-imap4-mailbox
609 (elmo-imap4-spec-mailbox spec)))))
611 (defun elmo-imap4-delete-folder (spec)
612 (let ((session (elmo-imap4-get-session spec))
614 (when (elmo-imap4-spec-mailbox spec)
615 (when (setq msgs (elmo-imap4-list-folder spec))
616 (elmo-imap4-delete-msgs spec msgs))
617 (elmo-imap4-send-command-wait session "close")
618 (elmo-imap4-send-command-wait
621 (elmo-imap4-mailbox (elmo-imap4-spec-mailbox spec)))))))
623 (defun elmo-imap4-rename-folder (old-spec new-spec)
624 (let ((session (elmo-imap4-get-session old-spec)))
625 (elmo-imap4-session-select-mailbox session
626 (elmo-imap4-spec-mailbox old-spec))
627 (elmo-imap4-send-command-wait session "close")
628 (elmo-imap4-send-command-wait
632 (elmo-imap4-spec-mailbox old-spec))
635 (elmo-imap4-spec-mailbox new-spec))))))
637 (defun elmo-imap4-max-of-folder (spec)
638 (let ((session (elmo-imap4-get-session spec))
639 (killed (and elmo-use-killed-list
640 (elmo-msgdb-killed-list-load
641 (elmo-msgdb-expand-path spec))))
643 (with-current-buffer (elmo-network-session-buffer session)
644 (setq elmo-imap4-status-callback nil)
645 (setq elmo-imap4-status-callback-data nil))
646 (setq status (elmo-imap4-response-value
647 (elmo-imap4-send-command-wait
651 (elmo-imap4-spec-mailbox spec))
652 " (uidnext messages)"))
655 (- (elmo-imap4-response-value status 'uidnext) 1)
658 (elmo-imap4-response-value status 'messages)
659 (elmo-msgdb-killed-list-length killed))
660 (elmo-imap4-response-value status 'messages)))))
662 (defun elmo-imap4-folder-diff (spec folder &optional number-list)
663 (if elmo-use-server-diff
664 (elmo-imap4-server-diff spec)
665 (elmo-generic-folder-diff spec folder number-list)))
667 (defun elmo-imap4-get-session (spec &optional if-exists)
668 (elmo-network-get-session
671 (elmo-imap4-spec-hostname spec)
672 (elmo-imap4-spec-port spec)
673 (elmo-imap4-spec-username spec)
674 (elmo-imap4-spec-auth spec)
675 (elmo-imap4-spec-stream-type spec)
678 (defun elmo-imap4-commit (spec)
679 (if (elmo-imap4-plugged-p spec)
680 (let ((session (elmo-imap4-get-session spec 'if-exists)))
683 (elmo-imap4-session-current-mailbox-internal session)
684 (elmo-imap4-spec-mailbox spec))
685 (if elmo-imap4-use-select-to-update-status
686 (elmo-imap4-session-select-mailbox
688 (elmo-imap4-spec-mailbox spec)
690 (elmo-imap4-session-check session)))))))
692 (defun elmo-imap4-session-select-mailbox (session mailbox
693 &optional force no-error)
694 "Select MAILBOX in SESSION.
695 If optional argument FORCE is non-nil, select mailbox even if current mailbox
697 If second optional argument NO-ERROR is non-nil, don't cause an error when
698 selecting folder was failed.
699 Returns response value if selecting folder succeed. "
702 (elmo-imap4-session-current-mailbox-internal session)
704 (let (response result)
707 (elmo-imap4-read-response
709 (elmo-imap4-send-command
713 (elmo-imap4-mailbox mailbox)))))
714 (if (setq result (elmo-imap4-response-ok-p response))
716 (elmo-imap4-session-set-current-mailbox-internal session mailbox)
717 (elmo-imap4-session-set-read-only-internal
719 (nth 1 (assq 'read-only (assq 'ok response)))))
720 (elmo-imap4-session-set-current-mailbox-internal session nil)
723 (elmo-imap4-response-error-text response)
724 (format "Select %s failed" mailbox))))))
725 (and result response))))
727 (defun elmo-imap4-check-validity (spec validity-file)
729 ;;;(elmo-imap4-send-command-wait
730 ;;;(elmo-imap4-get-session spec)
732 ;;; (elmo-imap4-mailbox
733 ;;; (elmo-imap4-spec-mailbox spec))
734 ;;; " (uidvalidity)")))
737 (defun elmo-imap4-sync-validity (spec validity-file)
741 (defun elmo-imap4-list (spec flag)
742 (let ((session (elmo-imap4-get-session spec)))
743 (elmo-imap4-session-select-mailbox session
744 (elmo-imap4-spec-mailbox spec))
745 (elmo-imap4-response-value
746 (elmo-imap4-send-command-wait
748 (format (if elmo-imap4-use-uid "uid search %s"
752 (defun elmo-imap4-list-folder (spec)
753 (let ((killed (and elmo-use-killed-list
754 (elmo-msgdb-killed-list-load
755 (elmo-msgdb-expand-path spec))))
757 (setq numbers (elmo-imap4-list spec "all"))
758 (elmo-living-messages numbers killed)))
760 (defun elmo-imap4-list-folder-unread (spec number-alist mark-alist
762 (if (and (elmo-imap4-plugged-p spec)
763 (elmo-imap4-use-flag-p spec))
764 (elmo-imap4-list spec "unseen")
765 (elmo-generic-list-folder-unread spec number-alist mark-alist
768 (defun elmo-imap4-list-folder-important (spec number-alist)
769 (if (and (elmo-imap4-plugged-p spec)
770 (elmo-imap4-use-flag-p spec))
771 (elmo-imap4-list spec "flagged")))
773 (defmacro elmo-imap4-detect-search-charset (string)
776 (detect-mime-charset-region (point-min) (point-max)))))
778 (defun elmo-imap4-search-internal-primitive (spec session filter from-msgs)
779 (let ((search-key (elmo-filter-key filter))
780 (imap-search-keys '("bcc" "body" "cc" "from" "subject" "to"))
783 ((string= "last" search-key)
784 (let ((numbers (or from-msgs (elmo-imap4-list-folder spec))))
785 (nthcdr (max (- (length numbers)
786 (string-to-int (elmo-filter-value filter)))
789 ((string= "first" search-key)
790 (let* ((numbers (or from-msgs (elmo-imap4-list-folder spec)))
791 (rest (nthcdr (string-to-int (elmo-filter-value filter) )
793 (mapcar '(lambda (x) (delete x numbers)) rest)
795 ((or (string= "since" search-key)
796 (string= "before" search-key))
797 (setq search-key (concat "sent" search-key))
798 (elmo-imap4-response-value
799 (elmo-imap4-send-command-wait session
801 (if elmo-imap4-use-uid
802 "uid search %s%s%s %s"
806 (if elmo-imap4-use-uid "uid ")
809 (elmo-imap4-make-number-set-list
813 (if (eq (elmo-filter-type filter)
817 (elmo-date-get-description
818 (elmo-date-get-datevec
819 (elmo-filter-value filter)))))
823 (if (eq (length (elmo-filter-value filter)) 0)
824 (setq charset 'us-ascii)
825 (elmo-imap4-detect-search-charset
826 (elmo-filter-value filter))))
827 (elmo-imap4-response-value
828 (elmo-imap4-send-command-wait session
830 (if elmo-imap4-use-uid "uid ")
834 (symbol-name charset))
838 (if elmo-imap4-use-uid "uid ")
841 (elmo-imap4-make-number-set-list
845 (if (eq (elmo-filter-type filter)
850 (elmo-filter-key filter)
854 (elmo-filter-key filter))
856 (encode-mime-charset-string
857 (elmo-filter-value filter) charset))))
860 (defun elmo-imap4-search-internal (spec session condition from-msgs)
864 (setq result (elmo-imap4-search-internal-primitive
865 spec session condition from-msgs)))
866 ((eq (car condition) 'and)
867 (setq result (elmo-imap4-search-internal spec session (nth 1 condition)
869 result (elmo-list-filter result
870 (elmo-imap4-search-internal
871 spec session (nth 2 condition)
873 ((eq (car condition) 'or)
874 (setq result (elmo-imap4-search-internal
875 spec session (nth 1 condition) from-msgs)
876 result (elmo-uniq-list
878 (elmo-imap4-search-internal
879 spec session (nth 2 condition) from-msgs)))
880 result (sort result '<))))))
883 (defun elmo-imap4-search (spec condition &optional from-msgs)
885 (let ((session (elmo-imap4-get-session spec)))
886 (elmo-imap4-session-select-mailbox
888 (elmo-imap4-spec-mailbox spec))
889 (elmo-imap4-search-internal spec session condition from-msgs))))
891 (defun elmo-imap4-use-flag-p (spec)
892 (not (string-match elmo-imap4-disuse-server-flag-mailbox-regexp
893 (elmo-imap4-spec-mailbox spec))))
897 ;; Emacs can parse dot symbol.
898 (defvar elmo-imap4-rfc822-size "RFC822\.SIZE")
899 (defvar elmo-imap4-rfc822-text "RFC822\.TEXT")
900 (defvar elmo-imap4-rfc822-header "RFC822\.HEADER")
901 (defvar elmo-imap4-rfc822-size "RFC822\.SIZE")
902 (defvar elmo-imap4-header-fields "HEADER\.FIELDS")
903 (defmacro elmo-imap4-replace-dot-symbols ()) ;; noop
904 (defalias 'elmo-imap4-fetch-read 'read)
908 ;; Cannot parse dot symbol.
909 (defvar elmo-imap4-rfc822-size "RFC822_SIZE")
910 (defvar elmo-imap4-header-fields "HEADER_FIELDS")
911 (defvar elmo-imap4-rfc822-size "RFC822_SIZE")
912 (defvar elmo-imap4-rfc822-text "RFC822_TEXT")
913 (defvar elmo-imap4-rfc822-header "RFC822_HEADER")
914 (defvar elmo-imap4-header-fields "HEADER_FIELDS")
915 (defun elmo-imap4-fetch-read (buffer)
916 (with-current-buffer buffer
919 (when (re-search-forward "[[ ]" nil t)
920 (goto-char (match-beginning 0))
921 (setq token (buffer-substring beg (point)))
922 (cond ((string= token "RFC822.SIZE")
923 (intern elmo-imap4-rfc822-size))
924 ((string= token "RFC822.HEADER")
925 (intern elmo-imap4-rfc822-header))
926 ((string= token "RFC822.TEXT")
927 (intern elmo-imap4-rfc822-text))
928 ((string= token "HEADER\.FIELDS")
929 (intern elmo-imap4-header-fields))
931 (elmo-read (current-buffer))))))))))
933 (defun elmo-imap4-make-number-set-list (msg-list &optional chop-length)
934 "Make RFC2060's message set specifier from MSG-LIST.
935 Returns a list of (NUMBER . SET-STRING).
936 SET-STRING is the message set specifier described in RFC2060.
937 NUMBER is contained message number in SET-STRING.
938 Every SET-STRING does not contain number of messages longer than CHOP-LENGTH.
939 If CHOP-LENGTH is not specified, message set is not chopped."
940 (let (count cont-list set-list)
941 (setq msg-list (sort (copy-sequence msg-list) '<))
946 (setq chop-length (length msg-list)))
947 (while (and (not (null msg-list))
948 (< count chop-length))
950 (elmo-number-set-append
951 cont-list (car msg-list)))
953 (setq msg-list (cdr msg-list)))
961 (format "%s:%s" (car x) (cdr x)))
967 (nreverse set-list)))
971 ;; read-mark -> "\\Seen"
972 ;; important -> "\\Flagged"
974 ;; (delete -> \\Deleted)
975 (defun elmo-imap4-mark-set-on-msgs (spec msgs mark &optional unmark no-expunge)
976 "SET flag of MSGS as MARK.
977 If optional argument UNMARK is non-nil, unmark."
978 (let ((session (elmo-imap4-get-session spec))
980 (elmo-imap4-session-select-mailbox session
981 (elmo-imap4-spec-mailbox spec))
982 (setq set-list (elmo-imap4-make-number-set-list msgs))
984 (with-current-buffer (elmo-network-session-buffer session)
985 (setq elmo-imap4-fetch-callback nil)
986 (setq elmo-imap4-fetch-callback-data nil))
987 (elmo-imap4-send-command-wait
990 (if elmo-imap4-use-uid
991 "uid store %s %sflags.silent (%s)"
992 "store %s %sflags.silent (%s)")
997 (elmo-imap4-send-command-wait session "expunge")))
1000 (defun elmo-imap4-mark-as-important (spec msgs)
1001 (and (elmo-imap4-use-flag-p spec)
1002 (elmo-imap4-mark-set-on-msgs spec msgs "\\Flagged" nil 'no-expunge)))
1004 (defun elmo-imap4-mark-as-read (spec msgs)
1005 (and (elmo-imap4-use-flag-p spec)
1006 (elmo-imap4-mark-set-on-msgs spec msgs "\\Seen" nil 'no-expunge)))
1008 (defun elmo-imap4-unmark-important (spec msgs)
1009 (and (elmo-imap4-use-flag-p spec)
1010 (elmo-imap4-mark-set-on-msgs spec msgs "\\Flagged" 'unmark
1013 (defun elmo-imap4-mark-as-unread (spec msgs)
1014 (and (elmo-imap4-use-flag-p spec)
1015 (elmo-imap4-mark-set-on-msgs spec msgs "\\Seen" 'unmark 'no-expunge)))
1017 (defun elmo-imap4-delete-msgs (spec msgs)
1018 (elmo-imap4-mark-set-on-msgs spec msgs "\\Deleted"))
1020 (defun elmo-imap4-delete-msgs-no-expunge (spec msgs)
1021 (elmo-imap4-mark-set-on-msgs spec msgs "\\Deleted" nil 'no-expunge))
1023 (defun elmo-imap4-msgdb-create-as-numlist (spec numlist new-mark already-mark
1024 seen-mark important-mark
1026 "Create msgdb for SPEC for NUMLIST."
1027 (elmo-imap4-msgdb-create spec numlist new-mark already-mark
1028 seen-mark important-mark seen-list t))
1030 ;; Current buffer is process buffer.
1031 (defun elmo-imap4-fetch-callback (element app-data)
1032 (funcall elmo-imap4-fetch-callback
1034 (insert (or (elmo-imap4-response-bodydetail-text element)
1037 (goto-char (point-min))
1038 (while (search-forward "\r\n" nil t)
1039 (replace-match "\n"))
1040 (elmo-msgdb-create-overview-from-buffer
1041 (elmo-imap4-response-value element 'uid)
1042 (elmo-imap4-response-value element 'rfc822size)))
1043 (elmo-imap4-response-value element 'flags)
1049 ;; 0: new-mark 1: already-mark 2: seen-mark 3: important-mark
1051 ;; and result of use-flag-p.
1052 (defun elmo-imap4-fetch-callback-1 (entity flags app-data)
1053 "A msgdb entity callback function."
1054 (let* ((use-flag (cdr app-data))
1055 (app-data (car app-data))
1056 (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
1064 (member "\\Seen" flags)))
1069 (member "\\Seen" flags)))
1070 (if elmo-imap4-use-cache
1072 (nth 0 app-data)))))
1073 (setq elmo-imap4-current-msgdb
1075 elmo-imap4-current-msgdb
1077 (list (cons (elmo-msgdb-overview-entity-get-number entity)
1081 (list (elmo-msgdb-overview-entity-get-number entity)
1084 (defun elmo-imap4-msgdb-create (spec numlist &rest args)
1085 "Create msgdb for SPEC."
1087 (let ((session (elmo-imap4-get-session spec))
1090 '("Subject" "From" "To" "Cc" "Date"
1091 "Message-Id" "References" "In-Reply-To")
1092 elmo-msgdb-extra-fields))
1094 (length (length numlist))
1096 (setq rfc2060 (memq 'imap4rev1
1097 (elmo-imap4-session-capability-internal
1099 (message "Getting overview...")
1100 (elmo-imap4-session-select-mailbox session
1101 (elmo-imap4-spec-mailbox spec))
1102 (setq set-list (elmo-imap4-make-number-set-list
1104 elmo-imap4-overview-fetch-chop-length))
1106 (with-current-buffer (elmo-network-session-buffer session)
1107 (setq elmo-imap4-current-msgdb nil
1108 elmo-imap4-fetch-callback 'elmo-imap4-fetch-callback-1
1109 elmo-imap4-fetch-callback-data (cons args
1110 (elmo-imap4-use-flag-p
1113 (elmo-imap4-send-command-wait
1115 ;; get overview entity from IMAP4
1116 (format "%sfetch %s (%s rfc822.size flags)"
1117 (if elmo-imap4-use-uid "uid " "")
1118 (cdr (car set-list))
1120 (format "body.peek[header.fields %s]" headers)
1121 (format "%s" headers))))
1122 (when (> length elmo-display-progress-threshold)
1123 (setq total (+ total (car (car set-list))))
1124 (elmo-display-progress
1125 'elmo-imap4-msgdb-create "Getting overview..."
1126 (/ (* total 100) length)))
1127 (setq set-list (cdr set-list)))
1128 (message "Getting overview...done")
1129 elmo-imap4-current-msgdb))))
1131 (defun elmo-imap4-parse-capability (string)
1132 (if (string-match "^\\*\\(.*\\)$" string)
1134 (concat "(" (downcase (elmo-match-string 1 string)) ")"))))
1136 (defun elmo-imap4-clear-login (session)
1137 (let ((elmo-imap4-debug-inhibit-logging t))
1141 (elmo-imap4-send-command
1144 (elmo-imap4-userid (elmo-network-session-user-internal session))
1146 (elmo-imap4-password
1147 (elmo-get-passwd (elmo-network-session-password-key session))))))
1148 (signal 'elmo-authenticate-error '(elmo-imap4-clear-login)))))
1150 (defun elmo-imap4-auth-login (session)
1151 (let ((tag (elmo-imap4-send-command session "authenticate login"))
1152 (elmo-imap4-debug-inhibit-logging t))
1153 (or (elmo-imap4-read-continue-req session)
1154 (signal 'elmo-authenticate-error '(elmo-imap4-auth-login)))
1155 (elmo-imap4-send-string session
1156 (elmo-base64-encode-string
1157 (elmo-network-session-user-internal session)))
1158 (or (elmo-imap4-read-continue-req session)
1159 (signal 'elmo-authenticate-error '(elmo-imap4-auth-login)))
1160 (elmo-imap4-send-string session
1161 (elmo-base64-encode-string
1163 (elmo-network-session-password-key session))))
1164 (or (elmo-imap4-read-ok session tag)
1165 (signal 'elmo-authenticate-error '(elmo-imap4-auth-login)))
1166 (setq elmo-imap4-status 'auth)))
1169 elmo-network-initialize-session-buffer :after ((session
1170 elmo-imap4-session) buffer)
1171 (with-current-buffer buffer
1172 (mapcar 'make-variable-buffer-local elmo-imap4-local-variables)
1173 (setq elmo-imap4-seqno 0)
1174 (setq elmo-imap4-status 'initial)))
1176 (luna-define-method elmo-network-initialize-session ((session
1177 elmo-imap4-session))
1178 (let ((process (elmo-network-session-process-internal session)))
1179 (with-current-buffer (process-buffer process)
1180 ;; Skip garbage output from process before greeting.
1181 (while (and (memq (process-status process) '(open run))
1182 (goto-char (point-max))
1184 (not (elmo-imap4-parse-greeting)))
1185 (accept-process-output process 1))
1186 (set-process-filter process 'elmo-imap4-arrival-filter)
1187 (set-process-sentinel process 'elmo-imap4-sentinel)
1188 ;;; (while (and (memq (process-status process) '(open run))
1189 ;;; (eq elmo-imap4-status 'initial))
1190 ;;; (message "Waiting for server response...")
1191 ;;; (accept-process-output process 1))
1193 (unless (memq elmo-imap4-status '(nonauth auth))
1194 (signal 'elmo-open-error
1195 (list 'elmo-network-initialize-session)))
1196 (elmo-imap4-session-set-capability-internal
1198 (elmo-imap4-response-value
1199 (elmo-imap4-send-command-wait session "capability")
1201 (when (eq (elmo-network-stream-type-symbol
1202 (elmo-network-session-stream-type-internal session))
1205 (elmo-imap4-session-capability-internal session))
1206 (signal 'elmo-open-error
1207 '(elmo-imap4-starttls-error)))
1208 (elmo-imap4-send-command-wait session "starttls")
1209 (starttls-negotiate process)))))
1211 (luna-define-method elmo-network-authenticate-session ((session
1212 elmo-imap4-session))
1213 (with-current-buffer (process-buffer
1214 (elmo-network-session-process-internal session))
1215 (let* ((auth (elmo-network-session-auth-internal session))
1216 (auth (if (listp auth) auth (list auth))))
1217 (unless (or (eq elmo-imap4-status 'auth)
1220 ((eq 'clear (car auth))
1221 (elmo-imap4-clear-login session))
1222 ((eq 'login (car auth))
1223 (elmo-imap4-auth-login session))
1225 (let* ((elmo-imap4-debug-inhibit-logging t)
1230 (if (string-match "^auth=\\(.*\\)$"
1232 (match-string 1 (upcase (symbol-name cap)))))
1233 (elmo-imap4-session-capability-internal session))))
1235 (sasl-find-mechanism
1237 (mapcar '(lambda (cap) (upcase (symbol-name cap)))
1241 client name step response tag
1242 sasl-read-passphrase)
1244 (if (or elmo-imap4-force-login
1247 "There's no %s capability in server. continue?"
1248 (elmo-list-to-string
1249 (elmo-network-session-auth-internal session)))))
1250 (setq mechanism (sasl-find-mechanism
1252 (signal 'elmo-authenticate-error
1253 '(elmo-imap4-auth-no-mechanisms))))
1257 (elmo-network-session-user-internal session)
1259 (elmo-network-session-host-internal session)))
1260 ;;; (if elmo-imap4-auth-user-realm
1261 ;;; (sasl-client-set-property client 'realm elmo-imap4-auth-user-realm))
1262 (setq name (sasl-mechanism-name mechanism)
1263 step (sasl-next-step client nil))
1264 (elmo-network-session-set-auth-internal
1266 (intern (downcase name)))
1267 (setq sasl-read-passphrase
1271 (elmo-network-session-password-key session)))))
1273 (elmo-imap4-send-command
1275 (concat "AUTHENTICATE " name
1276 (and (sasl-step-data step)
1279 (elmo-base64-encode-string
1280 (sasl-step-data step)
1281 'no-lin-break)))))) ;)
1285 (elmo-imap4-read-untagged
1286 (elmo-network-session-process-internal session)))
1287 (if (elmo-imap4-response-continue-req-p response)
1288 (unless (sasl-next-step client step)
1289 ;; response is '+' but there's no next step.
1290 (signal 'elmo-authenticate-error
1292 (concat "elmo-imap4-auth-"
1293 (downcase name))))))
1295 (if (elmo-imap4-response-ok-p response)
1296 (throw 'done nil) ; finished.
1297 ;; response is NO or BAD.
1298 (signal 'elmo-authenticate-error
1300 (concat "elmo-imap4-auth-"
1301 (downcase name)))))))
1304 (elmo-base64-decode-string
1305 (elmo-imap4-response-value response 'continue-req)))
1306 (setq step (sasl-next-step client step))
1308 (elmo-imap4-send-string
1310 (if (sasl-step-data step)
1311 (elmo-base64-encode-string (sasl-step-data step)
1315 (luna-define-method elmo-network-setup-session ((session
1316 elmo-imap4-session))
1317 (with-current-buffer (elmo-network-session-buffer session)
1318 (when (memq 'namespace (elmo-imap4-session-capability-internal session))
1319 (setq elmo-imap4-server-namespace
1320 (elmo-imap4-response-value
1321 (elmo-imap4-send-command-wait session "namespace")
1324 (defun elmo-imap4-setup-send-buffer (string)
1325 (let ((tmp-buf (get-buffer-create " *elmo-imap4-setup-send-buffer*")))
1328 (set-buffer tmp-buf)
1330 (elmo-set-buffer-multibyte nil)
1332 (goto-char (point-min))
1333 (if (eq (re-search-forward "^$" nil t)
1336 (goto-char (point-min))
1337 (while (search-forward "\n" nil t)
1338 (replace-match "\r\n"))))
1341 (defun elmo-imap4-read-part (folder msg part)
1342 (let* ((spec (elmo-folder-get-spec folder))
1343 (session (elmo-imap4-get-session spec)))
1344 (elmo-imap4-session-select-mailbox session
1345 (elmo-imap4-spec-mailbox spec))
1346 (with-current-buffer (elmo-network-session-buffer session)
1347 (setq elmo-imap4-fetch-callback nil)
1348 (setq elmo-imap4-fetch-callback-data nil))
1350 (elmo-imap4-response-bodydetail-text
1351 (elmo-imap4-response-value-all
1352 (elmo-imap4-send-command-wait session
1354 (if elmo-imap4-use-uid
1355 "uid fetch %s body.peek[%s]"
1356 "fetch %s body.peek[%s]")
1360 (defun elmo-imap4-prefetch-msg (spec msg outbuf)
1361 (elmo-imap4-read-msg spec msg outbuf nil 'unseen))
1363 (defun elmo-imap4-read-msg (spec msg outbuf
1364 &optional msgdb leave-seen-flag-untouched)
1365 (let ((session (elmo-imap4-get-session spec))
1367 (elmo-imap4-session-select-mailbox session
1368 (elmo-imap4-spec-mailbox spec))
1369 (with-current-buffer (elmo-network-session-buffer session)
1370 (setq elmo-imap4-fetch-callback nil)
1371 (setq elmo-imap4-fetch-callback-data nil))
1373 (elmo-imap4-send-command-wait session
1375 (if elmo-imap4-use-uid
1376 "uid fetch %s body%s[]"
1377 "fetch %s body%s[]")
1379 (if leave-seen-flag-untouched
1381 (and (setq response (elmo-imap4-response-bodydetail-text
1382 (elmo-imap4-response-value-all
1384 (with-current-buffer outbuf
1387 (elmo-delete-cr-get-content-type)))))
1389 (defun elmo-imap4-setup-send-buffer-from-file (file)
1390 (let ((tmp-buf (get-buffer-create
1391 " *elmo-imap4-setup-send-buffer-from-file*")))
1394 (set-buffer tmp-buf)
1396 (as-binary-input-file
1397 (insert-file-contents file))
1398 (goto-char (point-min))
1399 (if (eq (re-search-forward "^$" nil t)
1402 (goto-char (point-min))
1403 (while (search-forward "\n" nil t)
1404 (replace-match "\r\n"))))
1407 (defun elmo-imap4-delete-msgids (spec msgids)
1408 "If actual message-id is matched, then delete it."
1409 (let ((message-ids msgids)
1411 (num (length msgids)))
1414 (message "Deleting message...%d/%d" i num)
1415 (elmo-imap4-delete-msg-by-id spec (car message-ids))
1416 (setq message-ids (cdr message-ids)))
1417 (elmo-imap4-send-command-wait (elmo-imap4-get-session spec) "expunge")))
1419 (defun elmo-imap4-delete-msg-by-id (spec msgid)
1420 (let ((session (elmo-imap4-get-session spec)))
1421 (elmo-imap4-session-select-mailbox session
1422 (elmo-imap4-spec-mailbox spec))
1423 (elmo-imap4-delete-msgs-no-expunge
1425 (elmo-imap4-response-value
1426 (elmo-imap4-send-command-wait session
1428 (if elmo-imap4-use-uid
1429 "uid search header message-id "
1430 "search header message-id ")
1431 (elmo-imap4-field-body msgid)))
1434 (defun elmo-imap4-append-msg-by-id (spec msgid)
1435 (let ((session (elmo-imap4-get-session spec))
1437 (elmo-imap4-session-select-mailbox session
1438 (elmo-imap4-spec-mailbox spec))
1439 (setq send-buf (elmo-imap4-setup-send-buffer-from-file
1440 (elmo-cache-get-path msgid)))
1442 (elmo-imap4-send-command-wait
1446 (elmo-imap4-mailbox (elmo-imap4-spec-mailbox spec))
1448 (elmo-imap4-buffer-literal send-buf)))
1449 (kill-buffer send-buf)))
1452 (defun elmo-imap4-append-msg (spec string &optional msg no-see)
1453 (let ((session (elmo-imap4-get-session spec))
1455 (elmo-imap4-session-select-mailbox session
1456 (elmo-imap4-spec-mailbox spec))
1457 (setq send-buf (elmo-imap4-setup-send-buffer string))
1459 (elmo-imap4-send-command-wait
1463 (elmo-imap4-mailbox (elmo-imap4-spec-mailbox spec))
1464 (if no-see " " " (\\Seen) ")
1465 (elmo-imap4-buffer-literal send-buf)))
1466 (kill-buffer send-buf)))
1469 (defun elmo-imap4-copy-msgs (dst-spec
1470 msgs src-spec &optional expunge-it same-number)
1471 "Equivalence of hostname, username is assumed."
1472 (let ((session (elmo-imap4-get-session src-spec)))
1473 (elmo-imap4-session-select-mailbox session
1474 (elmo-imap4-spec-mailbox src-spec))
1476 (elmo-imap4-send-command-wait session
1479 (if elmo-imap4-use-uid
1484 (elmo-imap4-spec-mailbox dst-spec))))
1485 (setq msgs (cdr msgs)))
1487 (elmo-imap4-send-command-wait session "expunge"))
1490 (defun elmo-imap4-server-diff-async-callback-1 (status data)
1491 (funcall elmo-imap4-server-diff-async-callback
1492 (cons (elmo-imap4-response-value status 'unseen)
1493 (elmo-imap4-response-value status 'messages))
1496 (defun elmo-imap4-server-diff-async (spec)
1497 (let ((session (elmo-imap4-get-session spec)))
1499 ;; (elmo-imap4-commit spec)
1500 (with-current-buffer (elmo-network-session-buffer session)
1501 (setq elmo-imap4-status-callback
1502 'elmo-imap4-server-diff-async-callback-1)
1503 (setq elmo-imap4-status-callback-data
1504 elmo-imap4-server-diff-async-callback-data))
1505 (elmo-imap4-send-command session
1509 (elmo-imap4-spec-mailbox spec))
1510 " (unseen messages)"))))
1512 (defun elmo-imap4-server-diff (spec)
1514 (let ((session (elmo-imap4-get-session spec))
1517 ;;; (elmo-imap4-commit spec)
1518 (with-current-buffer (elmo-network-session-buffer session)
1519 (setq elmo-imap4-status-callback nil)
1520 (setq elmo-imap4-status-callback-data nil))
1522 (elmo-imap4-send-command-wait session
1526 (elmo-imap4-spec-mailbox spec))
1527 " (unseen messages)")))
1528 (setq response (elmo-imap4-response-value response 'status))
1529 (cons (elmo-imap4-response-value response 'unseen)
1530 (elmo-imap4-response-value response 'messages))))
1532 (defun elmo-imap4-use-cache-p (spec number)
1533 elmo-imap4-use-cache)
1535 (defun elmo-imap4-local-file-p (spec number)
1538 (defun elmo-imap4-port-label (spec)
1540 (if (elmo-imap4-spec-stream-type spec)
1541 (concat "!" (symbol-name
1542 (elmo-network-stream-type-symbol
1543 (elmo-imap4-spec-stream-type spec)))))))
1546 (defsubst elmo-imap4-portinfo (spec)
1547 (list (elmo-imap4-spec-hostname spec) (elmo-imap4-spec-port spec)))
1549 (defun elmo-imap4-plugged-p (spec)
1550 (apply 'elmo-plugged-p
1551 (append (elmo-imap4-portinfo spec)
1552 (list nil (quote (elmo-imap4-port-label spec))))))
1554 (defun elmo-imap4-set-plugged (spec plugged add)
1555 (apply 'elmo-set-plugged plugged
1556 (append (elmo-imap4-portinfo spec)
1557 (list nil nil (quote (elmo-imap4-port-label spec)) add))))
1559 (defalias 'elmo-imap4-sync-number-alist 'elmo-generic-sync-number-alist)
1563 (defvar elmo-imap4-server-eol "\r\n"
1564 "The EOL string sent from the server.")
1566 (defvar elmo-imap4-client-eol "\r\n"
1567 "The EOL string we send to the server.")
1569 (defun elmo-imap4-find-next-line ()
1570 "Return point at end of current line, taking into account literals.
1571 Return nil if no complete line has arrived."
1572 (when (re-search-forward (concat elmo-imap4-server-eol "\\|{\\([0-9]+\\)}"
1573 elmo-imap4-server-eol)
1575 (if (match-string 1)
1576 (if (< (point-max) (+ (point) (string-to-number (match-string 1))))
1578 (goto-char (+ (point) (string-to-number (match-string 1))))
1579 (elmo-imap4-find-next-line))
1582 (defun elmo-imap4-sentinel (process string)
1583 (delete-process process))
1585 (defun elmo-imap4-arrival-filter (proc string)
1586 "IMAP process filter."
1587 (when (buffer-live-p (process-buffer proc))
1588 (with-current-buffer (process-buffer proc)
1589 (elmo-imap4-debug "-> %s" string)
1590 (goto-char (point-max))
1593 (goto-char (point-min))
1594 (while (setq end (elmo-imap4-find-next-line))
1596 (narrow-to-region (point-min) end)
1597 (delete-backward-char (length elmo-imap4-server-eol))
1598 (goto-char (point-min))
1600 (cond ((eq elmo-imap4-status 'initial)
1601 (setq elmo-imap4-current-response
1603 (list 'greeting (elmo-imap4-parse-greeting)))))
1604 ((or (eq elmo-imap4-status 'auth)
1605 (eq elmo-imap4-status 'nonauth)
1606 (eq elmo-imap4-status 'selected)
1607 (eq elmo-imap4-status 'examine))
1608 (setq elmo-imap4-current-response
1610 (elmo-imap4-parse-response)
1611 elmo-imap4-current-response)))
1613 (message "Unknown state %s in arrival filter"
1614 elmo-imap4-status))))
1615 (delete-region (point-min) (point-max))))))))
1619 (defsubst elmo-imap4-forward ()
1620 (or (eobp) (forward-char 1)))
1622 (defsubst elmo-imap4-parse-number ()
1623 (when (looking-at "[0-9]+")
1625 (string-to-number (match-string 0))
1626 (goto-char (match-end 0)))))
1628 (defsubst elmo-imap4-parse-literal ()
1629 (when (looking-at "{\\([0-9]+\\)}\r\n")
1630 (let ((pos (match-end 0))
1631 (len (string-to-number (match-string 1))))
1632 (if (< (point-max) (+ pos len))
1634 (goto-char (+ pos len))
1635 (buffer-substring pos (+ pos len))))))
1636 ;;; (list ' pos (+ pos len))))))
1638 (defsubst elmo-imap4-parse-string ()
1639 (cond ((eq (char-after (point)) ?\")
1641 (let ((p (point)) (name ""))
1642 (skip-chars-forward "^\"\\\\")
1643 (setq name (buffer-substring p (point)))
1644 (while (eq (char-after (point)) ?\\)
1645 (setq p (1+ (point)))
1647 (skip-chars-forward "^\"\\\\")
1648 (setq name (concat name (buffer-substring p (point)))))
1651 ((eq (char-after (point)) ?{)
1652 (elmo-imap4-parse-literal))))
1654 (defsubst elmo-imap4-parse-nil ()
1655 (if (looking-at "NIL")
1656 (goto-char (match-end 0))))
1658 (defsubst elmo-imap4-parse-nstring ()
1659 (or (elmo-imap4-parse-string)
1660 (and (elmo-imap4-parse-nil)
1663 (defsubst elmo-imap4-parse-astring ()
1664 (or (elmo-imap4-parse-string)
1665 (buffer-substring (point)
1666 (if (re-search-forward "[(){ \r\n%*\"\\]" nil t)
1667 (goto-char (1- (match-end 0)))
1671 (defsubst elmo-imap4-parse-address ()
1673 (when (eq (char-after (point)) ?\()
1674 (elmo-imap4-forward)
1675 (setq address (vector (prog1 (elmo-imap4-parse-nstring)
1676 (elmo-imap4-forward))
1677 (prog1 (elmo-imap4-parse-nstring)
1678 (elmo-imap4-forward))
1679 (prog1 (elmo-imap4-parse-nstring)
1680 (elmo-imap4-forward))
1681 (elmo-imap4-parse-nstring)))
1682 (when (eq (char-after (point)) ?\))
1683 (elmo-imap4-forward)
1686 (defsubst elmo-imap4-parse-address-list ()
1687 (if (eq (char-after (point)) ?\()
1688 (let (address addresses)
1689 (elmo-imap4-forward)
1690 (while (and (not (eq (char-after (point)) ?\)))
1691 ;; next line for MS Exchange bug
1692 (progn (and (eq (char-after (point)) ? ) (elmo-imap4-forward)) t)
1693 (setq address (elmo-imap4-parse-address)))
1694 (setq addresses (cons address addresses)))
1695 (when (eq (char-after (point)) ?\))
1696 (elmo-imap4-forward)
1697 (nreverse addresses)))
1698 (assert (elmo-imap4-parse-nil))))
1700 (defsubst elmo-imap4-parse-mailbox ()
1701 (let ((mailbox (elmo-imap4-parse-astring)))
1702 (if (string-equal "INBOX" (upcase mailbox))
1706 (defun elmo-imap4-parse-greeting ()
1707 "Parse a IMAP greeting."
1708 (cond ((looking-at "\\* OK ")
1709 (setq elmo-imap4-status 'nonauth))
1710 ((looking-at "\\* PREAUTH ")
1711 (setq elmo-imap4-status 'auth))
1712 ((looking-at "\\* BYE ")
1713 (setq elmo-imap4-status 'closed))))
1715 (defun elmo-imap4-parse-response ()
1716 "Parse a IMAP command response."
1718 (case (setq token (elmo-read (current-buffer)))
1720 (skip-chars-forward " ")
1721 (list 'continue-req (buffer-substring (point) (point-max)))))
1722 (* (case (prog1 (setq token (elmo-read (current-buffer)))
1723 (elmo-imap4-forward))
1724 (OK (elmo-imap4-parse-resp-text-code))
1725 (NO (elmo-imap4-parse-resp-text-code))
1726 (BAD (elmo-imap4-parse-resp-text-code))
1727 (BYE (elmo-imap4-parse-bye))
1729 (elmo-imap4-parse-flag-list)))
1730 (LIST (list 'list (elmo-imap4-parse-data-list)))
1731 (LSUB (list 'lsub (elmo-imap4-parse-data-list)))
1734 (elmo-read (concat "("
1735 (buffer-substring (point) (point-max))
1737 (STATUS (elmo-imap4-parse-status))
1739 (NAMESPACE (elmo-imap4-parse-namespace))
1740 (CAPABILITY (list 'capability
1742 (concat "(" (downcase (buffer-substring
1743 (point) (point-max)))
1745 (ACL (elmo-imap4-parse-acl))
1746 (t (case (prog1 (elmo-read (current-buffer))
1747 (elmo-imap4-forward))
1748 (EXISTS (list 'exists token))
1749 (RECENT (list 'recent token))
1750 (EXPUNGE (list 'expunge token))
1751 (FETCH (elmo-imap4-parse-fetch token))
1752 (t (list 'garbage (buffer-string)))))))
1753 (t (if (not (string-match elmo-imap4-seq-prefix (symbol-name token)))
1754 (list 'garbage (buffer-string))
1755 (case (prog1 (elmo-read (current-buffer))
1756 (elmo-imap4-forward))
1758 (setq elmo-imap4-parsing nil)
1759 (setq token (symbol-name token))
1760 (elmo-unintern token)
1761 (elmo-imap4-debug "*%s* OK arrived" token)
1762 (setq elmo-imap4-reached-tag token)
1763 (list 'ok (elmo-imap4-parse-resp-text-code))))
1765 (setq elmo-imap4-parsing nil)
1766 (setq token (symbol-name token))
1767 (elmo-unintern token)
1768 (elmo-imap4-debug "*%s* NO arrived" token)
1769 (setq elmo-imap4-reached-tag token)
1771 (when (eq (char-after (point)) ?\[)
1772 (setq code (buffer-substring (point)
1773 (search-forward "]")))
1774 (elmo-imap4-forward))
1775 (setq text (buffer-substring (point) (point-max)))
1776 (list 'no (list code text)))))
1778 (setq elmo-imap4-parsing nil)
1779 (elmo-imap4-debug "*%s* BAD arrived" token)
1780 (setq token (symbol-name token))
1781 (elmo-unintern token)
1782 (setq elmo-imap4-reached-tag token)
1784 (when (eq (char-after (point)) ?\[)
1785 (setq code (buffer-substring (point)
1786 (search-forward "]")))
1787 (elmo-imap4-forward))
1788 (setq text (buffer-substring (point) (point-max)))
1789 (list 'bad (list code text)))))
1790 (t (list 'garbage (buffer-string)))))))))
1792 (defun elmo-imap4-parse-bye ()
1794 (when (eq (char-after (point)) ?\[)
1795 (setq code (buffer-substring (point)
1796 (search-forward "]")))
1797 (elmo-imap4-forward))
1798 (setq text (buffer-substring (point) (point-max)))
1799 (list 'bye (list code text))))
1801 (defun elmo-imap4-parse-text ()
1802 (goto-char (point-min))
1803 (when (search-forward "[" nil t)
1804 (search-forward "]")
1805 (elmo-imap4-forward))
1806 (list 'text (buffer-substring (point) (point-max))))
1808 (defun elmo-imap4-parse-resp-text-code ()
1809 (when (eq (char-after (point)) ?\[)
1810 (elmo-imap4-forward)
1811 (cond ((search-forward "PERMANENTFLAGS " nil t)
1812 (list 'permanentflags (elmo-imap4-parse-flag-list)))
1813 ((search-forward "UIDNEXT " nil t)
1814 (list 'uidnext (elmo-read (current-buffer))))
1815 ((search-forward "UNSEEN " nil t)
1816 (list 'unseen (elmo-read (current-buffer))))
1817 ((looking-at "UIDVALIDITY \\([0-9]+\\)")
1818 (list 'uidvalidity (match-string 1)))
1819 ((search-forward "READ-ONLY" nil t)
1820 (list 'read-only t))
1821 ((search-forward "READ-WRITE" nil t)
1822 (list 'read-write t))
1823 ((search-forward "NEWNAME " nil t)
1824 (let (oldname newname)
1825 (setq oldname (elmo-imap4-parse-string))
1826 (elmo-imap4-forward)
1827 (setq newname (elmo-imap4-parse-string))
1828 (list 'newname newname oldname)))
1829 ((search-forward "TRYCREATE" nil t)
1830 (list 'trycreate t))
1831 ((looking-at "APPENDUID \\([0-9]+\\) \\([0-9]+\\)")
1833 (list (match-string 1)
1834 (string-to-number (match-string 2)))))
1835 ((looking-at "COPYUID \\([0-9]+\\) \\([0-9,:]+\\) \\([0-9,:]+\\)")
1836 (list 'copyuid (list (match-string 1)
1839 ((search-forward "ALERT] " nil t)
1840 (message "IMAP server information: %s"
1841 (buffer-substring (point) (point-max))))
1842 (t (list 'unknown)))))
1844 (defun elmo-imap4-parse-data-list ()
1845 (let (flags delimiter mailbox)
1846 (setq flags (elmo-imap4-parse-flag-list))
1847 (when (looking-at " NIL\\| \"\\\\?\\(.\\)\"")
1848 (setq delimiter (match-string 1))
1849 (goto-char (1+ (match-end 0)))
1850 (when (setq mailbox (elmo-imap4-parse-mailbox))
1851 (list mailbox flags delimiter)))))
1853 (defsubst elmo-imap4-parse-header-list ()
1854 (when (eq (char-after (point)) ?\()
1856 (while (not (eq (char-after (point)) ?\)))
1857 (elmo-imap4-forward)
1858 (push (elmo-imap4-parse-astring) strlist))
1859 (elmo-imap4-forward)
1860 (nreverse strlist))))
1862 (defsubst elmo-imap4-parse-fetch-body-section ()
1864 (buffer-substring (point)
1866 (progn (re-search-forward "[] ]" nil t)
1868 (if (eq (char-before) ? )
1870 (mapconcat 'identity
1871 (cons section (elmo-imap4-parse-header-list)) " ")
1872 (search-forward "]" nil t))
1875 (defun elmo-imap4-parse-fetch (response)
1876 (when (eq (char-after (point)) ?\()
1878 (while (not (eq (char-after (point)) ?\)))
1879 (elmo-imap4-forward)
1880 (let ((token (elmo-imap4-fetch-read (current-buffer))))
1881 (elmo-imap4-forward)
1883 (cond ((eq token 'UID)
1884 (list 'uid (condition-case nil
1885 (elmo-read (current-buffer))
1888 (list 'flags (elmo-imap4-parse-flag-list)))
1889 ((eq token 'ENVELOPE)
1890 (list 'envelope (elmo-imap4-parse-envelope)))
1891 ((eq token 'INTERNALDATE)
1892 (list 'internaldate (elmo-imap4-parse-string)))
1894 (list 'rfc822 (elmo-imap4-parse-nstring)))
1895 ((eq token (intern elmo-imap4-rfc822-header))
1896 (list 'rfc822header (elmo-imap4-parse-nstring)))
1897 ((eq token (intern elmo-imap4-rfc822-text))
1898 (list 'rfc822text (elmo-imap4-parse-nstring)))
1899 ((eq token (intern elmo-imap4-rfc822-size))
1900 (list 'rfc822size (elmo-read (current-buffer))))
1902 (if (eq (char-before) ?\[)
1905 (upcase (elmo-imap4-parse-fetch-body-section))
1907 (eq (char-after (point)) ?<)
1908 (buffer-substring (1+ (point))
1910 (search-forward ">" nil t)
1912 (progn (elmo-imap4-forward)
1913 (elmo-imap4-parse-nstring)))
1914 (list 'body (elmo-imap4-parse-body))))
1915 ((eq token 'BODYSTRUCTURE)
1916 (list 'bodystructure (elmo-imap4-parse-body)))))
1917 (setq list (cons element list))))
1918 (and elmo-imap4-fetch-callback
1919 (elmo-imap4-fetch-callback list elmo-imap4-fetch-callback-data))
1920 (list 'fetch list))))
1922 (defun elmo-imap4-parse-status ()
1923 (let ((mailbox (elmo-imap4-parse-mailbox))
1925 (when (and mailbox (search-forward "(" nil t))
1926 (while (not (eq (char-after (point)) ?\)))
1929 (let ((token (elmo-read (current-buffer))))
1930 (cond ((eq token 'MESSAGES)
1931 (list 'messages (elmo-read (current-buffer))))
1933 (list 'recent (elmo-read (current-buffer))))
1934 ((eq token 'UIDNEXT)
1935 (list 'uidnext (elmo-read (current-buffer))))
1936 ((eq token 'UIDVALIDITY)
1937 (and (looking-at " \\([0-9]+\\)")
1938 (prog1 (list 'uidvalidity (match-string 1))
1939 (goto-char (match-end 1)))))
1941 (list 'unseen (elmo-read (current-buffer))))
1944 "Unknown status data %s in mailbox %s ignored"
1947 (and elmo-imap4-status-callback
1948 (funcall elmo-imap4-status-callback
1950 elmo-imap4-status-callback-data))
1951 (list 'status status)))
1954 (defmacro elmo-imap4-value (value)
1955 (` (if (eq (, value) 'NIL) nil
1958 (defmacro elmo-imap4-nth (pos list)
1959 (` (let ((value (nth (, pos) (, list))))
1960 (elmo-imap4-value value))))
1962 (defun elmo-imap4-parse-namespace ()
1965 (copy-sequence elmo-imap4-extra-namespace-alist)
1966 (elmo-imap4-parse-namespace-subr
1967 (elmo-read (concat "(" (buffer-substring
1968 (point) (point-max))
1971 (defun elmo-imap4-parse-namespace-subr (ns)
1972 (let (prefix delim namespace-alist default-delim)
1973 ;; 0: personal, 1: other, 2: shared
1975 (setq namespace-alist
1976 (nconc namespace-alist
1980 (setq prefix (elmo-imap4-nth 0 namespace)
1981 delim (elmo-imap4-nth 1 namespace))
1982 (if (and prefix delim
1984 (concat (regexp-quote delim) "\\'")
1986 (setq prefix (substring prefix 0
1987 (match-beginning 0))))
1988 (if (eq (length prefix) 0)
1989 (progn (setq default-delim delim) nil)
1992 (if (string= (downcase prefix) "inbox")
1993 "[Ii][Nn][Bb][Oo][Xx]"
1994 (regexp-quote prefix))
1997 (elmo-imap4-nth i ns))))))
1999 (setq namespace-alist
2000 (nconc namespace-alist
2001 (list (cons "^.*$" default-delim)))))
2004 (defun elmo-imap4-parse-acl ()
2005 (let ((mailbox (elmo-imap4-parse-mailbox))
2006 identifier rights acl)
2007 (while (eq (char-after (point)) ?\ )
2008 (elmo-imap4-forward)
2009 (setq identifier (elmo-imap4-parse-astring))
2010 (elmo-imap4-forward)
2011 (setq rights (elmo-imap4-parse-astring))
2012 (setq acl (append acl (list (cons identifier rights)))))
2013 (list 'acl acl mailbox)))
2015 (defun elmo-imap4-parse-flag-list ()
2016 (let ((str (buffer-substring (+ (point) 1)
2017 (progn (search-forward ")" nil t)
2019 (unless (eq (length str) 0)
2020 (split-string str))))
2022 (defun elmo-imap4-parse-envelope ()
2023 (when (eq (char-after (point)) ?\()
2024 (elmo-imap4-forward)
2025 (vector (prog1 (elmo-imap4-parse-nstring);; date
2026 (elmo-imap4-forward))
2027 (prog1 (elmo-imap4-parse-nstring);; subject
2028 (elmo-imap4-forward))
2029 (prog1 (elmo-imap4-parse-address-list);; from
2030 (elmo-imap4-forward))
2031 (prog1 (elmo-imap4-parse-address-list);; sender
2032 (elmo-imap4-forward))
2033 (prog1 (elmo-imap4-parse-address-list);; reply-to
2034 (elmo-imap4-forward))
2035 (prog1 (elmo-imap4-parse-address-list);; to
2036 (elmo-imap4-forward))
2037 (prog1 (elmo-imap4-parse-address-list);; cc
2038 (elmo-imap4-forward))
2039 (prog1 (elmo-imap4-parse-address-list);; bcc
2040 (elmo-imap4-forward))
2041 (prog1 (elmo-imap4-parse-nstring);; in-reply-to
2042 (elmo-imap4-forward))
2043 (prog1 (elmo-imap4-parse-nstring);; message-id
2044 (elmo-imap4-forward)))))
2046 (defsubst elmo-imap4-parse-string-list ()
2047 (cond ((eq (char-after (point)) ?\();; body-fld-param
2049 (elmo-imap4-forward)
2050 (while (setq str (elmo-imap4-parse-string))
2052 (elmo-imap4-forward))
2053 (nreverse strlist)))
2054 ((elmo-imap4-parse-nil)
2057 (defun elmo-imap4-parse-body-extension ()
2058 (if (eq (char-after (point)) ?\()
2060 (elmo-imap4-forward)
2061 (push (elmo-imap4-parse-body-extension) b-e)
2062 (while (eq (char-after (point)) ?\ )
2063 (elmo-imap4-forward)
2064 (push (elmo-imap4-parse-body-extension) b-e))
2065 (assert (eq (char-after (point)) ?\)))
2066 (elmo-imap4-forward)
2068 (or (elmo-imap4-parse-number)
2069 (elmo-imap4-parse-nstring))))
2071 (defsubst elmo-imap4-parse-body-ext ()
2073 (when (eq (char-after (point)) ?\ );; body-fld-dsp
2074 (elmo-imap4-forward)
2076 (if (eq (char-after (point)) ?\()
2078 (elmo-imap4-forward)
2079 (push (elmo-imap4-parse-string) dsp)
2080 (elmo-imap4-forward)
2081 (push (elmo-imap4-parse-string-list) dsp)
2082 (elmo-imap4-forward))
2083 (assert (elmo-imap4-parse-nil)))
2084 (push (nreverse dsp) ext))
2085 (when (eq (char-after (point)) ?\ );; body-fld-lang
2086 (elmo-imap4-forward)
2087 (if (eq (char-after (point)) ?\()
2088 (push (elmo-imap4-parse-string-list) ext)
2089 (push (elmo-imap4-parse-nstring) ext))
2090 (while (eq (char-after (point)) ?\ );; body-extension
2091 (elmo-imap4-forward)
2092 (setq ext (append (elmo-imap4-parse-body-extension) ext)))))
2095 (defun elmo-imap4-parse-body ()
2097 (when (eq (char-after (point)) ?\()
2098 (elmo-imap4-forward)
2099 (if (eq (char-after (point)) ?\()
2101 (while (and (eq (char-after (point)) ?\()
2102 (setq subbody (elmo-imap4-parse-body)))
2103 (push subbody body))
2104 (elmo-imap4-forward)
2105 (push (elmo-imap4-parse-string) body);; media-subtype
2106 (when (eq (char-after (point)) ?\ );; body-ext-mpart:
2107 (elmo-imap4-forward)
2108 (if (eq (char-after (point)) ?\();; body-fld-param
2109 (push (elmo-imap4-parse-string-list) body)
2110 (push (and (elmo-imap4-parse-nil) nil) body))
2112 (append (elmo-imap4-parse-body-ext) body)));; body-ext-...
2113 (assert (eq (char-after (point)) ?\)))
2114 (elmo-imap4-forward)
2117 (push (elmo-imap4-parse-string) body);; media-type
2118 (elmo-imap4-forward)
2119 (push (elmo-imap4-parse-string) body);; media-subtype
2120 (elmo-imap4-forward)
2121 ;; next line for Sun SIMS bug
2122 (and (eq (char-after (point)) ? ) (elmo-imap4-forward))
2123 (if (eq (char-after (point)) ?\();; body-fld-param
2124 (push (elmo-imap4-parse-string-list) body)
2125 (push (and (elmo-imap4-parse-nil) nil) body))
2126 (elmo-imap4-forward)
2127 (push (elmo-imap4-parse-nstring) body);; body-fld-id
2128 (elmo-imap4-forward)
2129 (push (elmo-imap4-parse-nstring) body);; body-fld-desc
2130 (elmo-imap4-forward)
2131 (push (elmo-imap4-parse-string) body);; body-fld-enc
2132 (elmo-imap4-forward)
2133 (push (elmo-imap4-parse-number) body);; body-fld-octets
2135 ;; ok, we're done parsing the required parts, what comes now is one
2138 ;; envelope (then we're parsing body-type-msg)
2139 ;; body-fld-lines (then we're parsing body-type-text)
2140 ;; body-ext-1part (then we're parsing body-type-basic)
2142 ;; the problem is that the two first are in turn optionally followed
2143 ;; by the third. So we parse the first two here (if there are any)...
2145 (when (eq (char-after (point)) ?\ )
2146 (elmo-imap4-forward)
2148 (cond ((eq (char-after (point)) ?\();; body-type-msg:
2149 (push (elmo-imap4-parse-envelope) body);; envelope
2150 (elmo-imap4-forward)
2151 (push (elmo-imap4-parse-body) body);; body
2152 (elmo-imap4-forward)
2153 (push (elmo-imap4-parse-number) body));; body-fld-lines
2154 ((setq lines (elmo-imap4-parse-number));; body-type-text:
2155 (push lines body));; body-fld-lines
2157 (backward-char)))));; no match...
2159 ;; ...and then parse the third one here...
2161 (when (eq (char-after (point)) ?\ );; body-ext-1part:
2162 (elmo-imap4-forward)
2163 (push (elmo-imap4-parse-nstring) body);; body-fld-md5
2165 (append (elmo-imap4-parse-body-ext) body)));; body-ext-1part..
2167 (assert (eq (char-after (point)) ?\)))
2168 (elmo-imap4-forward)
2172 (product-provide (provide 'elmo-imap4) (require 'elmo-version))
2174 ;;; elmo-imap4.el ends here