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>
54 ;; silence byte compiler.
62 (defun-maybe starttls-negotiate (a))
63 (defun-maybe elmo-generic-list-folder-unread (spec number-alist mark-alist unread-marks))
64 (defun-maybe elmo-generic-folder-diff (spec folder number-list))
65 (defsubst-maybe utf7-decode-string (string &optional imap) string))
67 (defvar elmo-imap4-use-lock t
68 "USE IMAP4 with locking process.")
70 ;;; internal variables
72 (defvar elmo-imap4-seq-prefix "elmo-imap4")
73 (defvar elmo-imap4-seqno 0)
74 (defvar elmo-imap4-use-uid t
75 "Use UID as message number.")
77 (defvar elmo-imap4-current-response nil)
78 (defvar elmo-imap4-status nil)
79 (defvar elmo-imap4-reached-tag "elmo-imap40")
81 ;;; buffer local variables
83 (defvar elmo-imap4-extra-namespace-alist
84 '(("^{.*/nntp}.*$" . ".")) ; Default is for UW's remote nntp mailbox...
85 "Extra namespace alist. A list of cons cell like: (REGEXP . DELIMITER).")
86 (defvar elmo-imap4-default-hierarchy-delimiter "/")
88 (defvar elmo-imap4-server-capability nil)
89 (defvar elmo-imap4-server-namespace nil)
91 (defvar elmo-imap4-parsing nil) ; indicates parsing.
93 (defvar elmo-imap4-fetch-callback nil)
94 (defvar elmo-imap4-fetch-callback-data nil)
95 (defvar elmo-imap4-status-callback nil)
96 (defvar elmo-imap4-status-callback-data nil)
98 (defvar elmo-imap4-server-diff-async-callback nil)
99 (defvar elmo-imap4-server-diff-async-callback-data nil)
101 ;;; progress...(no use?)
102 (defvar elmo-imap4-count-progress nil)
103 (defvar elmo-imap4-count-progress-message nil)
104 (defvar elmo-imap4-progress-count nil)
106 ;;; XXX Temporal implementation
107 (defvar elmo-imap4-current-msgdb nil)
109 (defvar elmo-imap4-local-variables
111 elmo-imap4-current-response
114 elmo-imap4-reached-tag
115 elmo-imap4-count-progress
116 elmo-imap4-count-progress-message
117 elmo-imap4-progress-count
118 elmo-imap4-fetch-callback
119 elmo-imap4-fetch-callback-data
120 elmo-imap4-status-callback
121 elmo-imap4-status-callback-data
122 elmo-imap4-current-msgdb))
126 (defconst elmo-imap4-quoted-specials-list '(?\\ ?\"))
128 (defconst elmo-imap4-non-atom-char-regex
130 (concat "[^" "]!#$&'+,./0-9:;<=>?@A-Z[^_`a-z|}~-" "]")))
132 (defconst elmo-imap4-non-text-char-regex
135 "]\x01-\x09\x0b\x0c\x0e-\x1f\x7f !\"#$%&'()*+,./0-9:;<=>?@A-Z[\\^_`a-z{|}~-"
138 (defconst elmo-imap4-literal-threshold 1024
139 "Limitation of characters that can be used in a quoted string.")
142 (defvar elmo-imap4-debug nil
143 "Non-nil forces IMAP4 folder as debug mode.
144 Debug information is inserted in the buffer \"*IMAP4 DEBUG*\"")
146 (defvar elmo-imap4-debug-inhibit-logging nil)
151 (luna-define-class elmo-imap4-session (elmo-network-session)
152 (capability current-mailbox read-only))
153 (luna-define-internal-accessors 'elmo-imap4-session))
157 (defsubst elmo-imap4-spec-mailbox (spec)
160 (defsubst elmo-imap4-spec-username (spec)
163 (defsubst elmo-imap4-spec-auth (spec)
166 (defsubst elmo-imap4-spec-hostname (spec)
169 (defsubst elmo-imap4-spec-port (spec)
172 (defsubst elmo-imap4-spec-stream-type (spec)
178 (defsubst elmo-imap4-debug (message &rest args)
180 (with-current-buffer (get-buffer-create "*IMAP4 DEBUG*")
181 (goto-char (point-max))
182 (if elmo-imap4-debug-inhibit-logging
183 (insert "NO LOGGING\n")
184 (insert (apply 'format message args) "\n")))))
188 (defmacro elmo-imap4-response-continue-req-p (response)
189 "Returns non-nil if RESPONSE is '+' response."
190 (` (assq 'continue-req (, response))))
192 (defmacro elmo-imap4-response-ok-p (response)
193 "Returns non-nil if RESPONSE is an 'OK' response."
194 (` (assq 'ok (, response))))
196 (defmacro elmo-imap4-response-bye-p (response)
197 "Returns non-nil if RESPONSE is an 'BYE' response."
198 (` (assq 'bye (, response))))
200 (defmacro elmo-imap4-response-value (response symbol)
201 "Get value of the SYMBOL from RESPONSE."
202 (` (nth 1 (assq (, symbol) (, response)))))
204 (defsubst elmo-imap4-response-value-all (response symbol)
205 "Get all value of the SYMBOL from RESPONSE."
208 (if (eq (car (car response)) symbol)
209 (setq matched (nconc matched (nth 1 (car response)))))
210 (setq response (cdr response)))
213 (defmacro elmo-imap4-response-error-text (response)
214 "Returns text of NO, BAD, BYE response."
215 (` (nth 1 (or (elmo-imap4-response-value (, response) 'no)
216 (elmo-imap4-response-value (, response) 'bad)
217 (elmo-imap4-response-value (, response) 'bye)))))
219 (defmacro elmo-imap4-response-bodydetail-text (response)
220 "Returns text of BODY[section]<partial>."
221 (` (nth 3 (assq 'bodydetail (, response)))))
223 ;;; Session commands.
225 ; (defun elmo-imap4-send-command-wait (session command)
226 ; "Send COMMAND to the SESSION and wait for response.
227 ; Returns RESPONSE (parsed lisp object) of IMAP session."
228 ; (elmo-imap4-read-response session
229 ; (elmo-imap4-send-command
233 (defun elmo-imap4-send-command-wait (session command)
234 "Send COMMAND to the SESSION.
235 Returns RESPONSE (parsed lisp object) of IMAP session.
236 If response is not `OK', causes error with IMAP response text."
237 (elmo-imap4-accept-ok session
238 (elmo-imap4-send-command
242 (defun elmo-imap4-send-command (session command)
243 "Send COMMAND to the SESSION.
244 Returns a TAG string which is assigned to the COMAND."
245 (let* ((command-args (if (listp command)
248 (process (elmo-network-session-process-internal session))
249 cmdstr tag token kind)
250 (with-current-buffer (process-buffer process)
251 (setq tag (concat elmo-imap4-seq-prefix
253 (setq elmo-imap4-seqno (+ 1 elmo-imap4-seqno)))))
254 (setq cmdstr (concat tag " "))
255 ;; (erase-buffer) No need.
256 (goto-char (point-min))
257 (if (elmo-imap4-response-bye-p elmo-imap4-current-response)
258 (signal 'elmo-imap4-bye-error
259 (list (elmo-imap4-response-error-text
260 elmo-imap4-current-response))))
261 (setq elmo-imap4-current-response nil)
262 (if elmo-imap4-parsing
263 (error "IMAP process is running. Please wait (or plug again.)"))
264 (setq elmo-imap4-parsing t)
265 (elmo-imap4-debug "<-(%s)- %s" tag command)
266 (while (setq token (car command-args))
267 (cond ((stringp token) ; formatted
268 (setq cmdstr (concat cmdstr token)))
269 ((listp token) ; unformatted
270 (setq kind (car token))
271 (cond ((eq kind 'atom)
272 (setq cmdstr (concat cmdstr (nth 1 token))))
276 (elmo-imap4-format-quoted (nth 1 token)))))
278 (setq cmdstr (concat cmdstr
279 (format "{%d}" (nth 2 token))))
280 (process-send-string process cmdstr)
281 (process-send-string process "\r\n")
283 (elmo-imap4-accept-continue-req session)
284 (cond ((stringp (nth 1 token))
285 (setq cmdstr (nth 1 token)))
286 ((bufferp (nth 1 token))
287 (with-current-buffer (nth 1 token)
291 (+ (point-min) (nth 2 token)))))
293 (error "Wrong argument for literal"))))
295 (error "Unknown token kind %s" kind))))
297 (error "Invalid argument")))
298 (setq command-args (cdr command-args)))
300 (process-send-string process cmdstr))
301 (process-send-string process "\r\n")
304 (defun elmo-imap4-send-string (session string)
305 "Send STRING to the SESSION."
306 (with-current-buffer (process-buffer
307 (elmo-network-session-process-internal session))
308 (setq elmo-imap4-current-response nil)
309 (goto-char (point-min))
310 (elmo-imap4-debug "<-- %s" string)
311 (process-send-string (elmo-network-session-process-internal session)
313 (process-send-string (elmo-network-session-process-internal session)
316 (defun elmo-imap4-read-response (session tag)
317 "Read parsed response from SESSION.
318 TAG is the tag of the command"
319 (with-current-buffer (process-buffer
320 (elmo-network-session-process-internal session))
321 (while (not (or (string= tag elmo-imap4-reached-tag)
322 (elmo-imap4-response-bye-p elmo-imap4-current-response)))
323 (when (memq (process-status
324 (elmo-network-session-process-internal session))
326 (accept-process-output (elmo-network-session-process-internal session)
328 (elmo-imap4-debug "=>%s" (prin1-to-string elmo-imap4-current-response))
329 (setq elmo-imap4-parsing nil)
330 elmo-imap4-current-response))
332 (defsubst elmo-imap4-read-untagged (process)
333 (with-current-buffer (process-buffer process)
334 (while (not elmo-imap4-current-response)
335 (accept-process-output process 1))
336 (elmo-imap4-debug "=>%s" (prin1-to-string elmo-imap4-current-response))
337 elmo-imap4-current-response))
339 (defun elmo-imap4-read-continue-req (session)
340 "Returns a text following to continue-req in SESSION.
341 If response is not `+' response, returns nil."
342 (elmo-imap4-response-value
343 (elmo-imap4-read-untagged
344 (elmo-network-session-process-internal session))
347 (defun elmo-imap4-accept-continue-req (session)
348 "Returns non-nil if `+' (continue-req) response is arrived in SESSION.
349 If response is not `+' response, cause an error."
352 (elmo-imap4-read-untagged
353 (elmo-network-session-process-internal session)))
354 (or (elmo-imap4-response-continue-req-p response)
355 (error "IMAP error: %s"
356 (or (elmo-imap4-response-error-text response)
357 "No continut-req from server.")))))
359 (defun elmo-imap4-read-ok (session tag)
360 "Returns non-nil if `OK' response of the command with TAG is arrived
361 in SESSION. If response is not `OK' response, returns nil."
362 (elmo-imap4-response-ok-p
363 (elmo-imap4-read-response session tag)))
365 (defun elmo-imap4-accept-ok (session tag)
366 "Accept only `OK' response from SESSION.
367 If response is not `OK' response, causes error with IMAP response text."
368 (let ((response (elmo-imap4-read-response session tag)))
369 (if (elmo-imap4-response-ok-p response)
371 (if (elmo-imap4-response-bye-p response)
372 (signal 'elmo-imap4-bye-error
373 (list (elmo-imap4-response-error-text response)))
374 (error "IMAP error: %s"
375 (or (elmo-imap4-response-error-text response)
376 "No `OK' response from server."))))))
379 (defun elmo-imap4-session-check (session)
380 (elmo-imap4-send-command-wait session "check"))
382 (defun elmo-imap4-atom-p (string)
383 "Return t if STRING is an atom defined in rfc2060."
384 (if (string= string "")
387 (not (string-match elmo-imap4-non-atom-char-regex string)))))
389 (defun elmo-imap4-quotable-p (string)
390 "Return t if STRING can be formatted as a quoted defined in rfc2060."
392 (not (string-match elmo-imap4-non-text-char-regex string))))
394 (defun elmo-imap4-nil (string)
395 "Return a list represents the special atom \"NIL\" defined in rfc2060, \
397 Otherwise return nil."
401 (defun elmo-imap4-atom (string)
402 "Return a list represents STRING as an atom defined in rfc2060.
403 Return nil if STRING is not an atom. See `elmo-imap4-atom-p'."
404 (if (elmo-imap4-atom-p string)
405 (list 'atom string)))
407 (defun elmo-imap4-quoted (string)
408 "Return a list represents STRING as a quoted defined in rfc2060.
409 Return nil if STRING can not be formatted as a quoted. See `elmo-imap4-quotable-p'."
410 (if (elmo-imap4-quotable-p string)
411 (list 'quoted string)))
413 (defun elmo-imap4-literal-1 (string-or-buffer length)
414 "Internal function for `elmo-imap4-literal' and `elmo-imap4-buffer-literal'.
415 Return a list represents STRING-OR-BUFFER as a literal defined in rfc2060.
416 STRING-OR-BUFFER must be an encoded string or a single-byte string or a single-byte buffer.
417 LENGTH must be the number of octets for STRING-OR-BUFFER."
418 (list 'literal string-or-buffer length))
420 (defun elmo-imap4-literal (string)
421 "Return a list represents STRING as a literal defined in rfc2060.
422 STRING must be an encoded or a single-byte string."
423 (elmo-imap4-literal-1 string (length string)))
425 (defun elmo-imap4-buffer-literal (buffer)
426 "Return a list represents BUFFER as a literal defined in rfc2060.
427 BUFFER must be a single-byte buffer."
428 (elmo-imap4-literal-1 buffer (with-current-buffer buffer
431 (defun elmo-imap4-string-1 (string length)
432 "Internal function for `elmo-imap4-string' and `elmo-imap4-buffer-string'.
433 Return a list represents STRING as a string defined in rfc2060.
434 STRING must be an encoded or a single-byte string.
435 LENGTH must be the number of octets for STRING."
436 (or (elmo-imap4-quoted string)
437 (elmo-imap4-literal-1 string length)))
439 (defun elmo-imap4-string (string)
440 "Return a list represents STRING as a string defined in rfc2060.
441 STRING must be an encoded or a single-byte string."
442 (let ((length (length string)))
443 (if (< elmo-imap4-literal-threshold length)
444 (elmo-imap4-literal-1 string length)
445 (elmo-imap4-string-1 string length))))
447 (defun elmo-imap4-buffer-string (buffer)
448 "Return a list represents BUFFER as a string defined in rfc2060.
449 BUFFER must be a single-byte buffer."
450 (let ((length (with-current-buffer buffer
452 (if (< elmo-imap4-literal-threshold length)
453 (elmo-imap4-literal-1 buffer length)
454 (elmo-imap4-string-1 (with-current-buffer buffer
458 (defun elmo-imap4-astring-1 (string length)
459 "Internal function for `elmo-imap4-astring' and `elmo-imap4-buffer-astring'.
460 Return a list represents STRING as an astring defined in rfc2060.
461 STRING must be an encoded or a single-byte string.
462 LENGTH must be the number of octets for STRING."
463 (or (elmo-imap4-atom string)
464 (elmo-imap4-string-1 string length)))
466 (defun elmo-imap4-astring (string)
467 "Return a list represents STRING as an astring defined in rfc2060.
468 STRING must be an encoded or a single-byte string."
469 (let ((length (length string)))
470 (if (< elmo-imap4-literal-threshold length)
471 (elmo-imap4-literal-1 string length)
472 (elmo-imap4-astring-1 string length))))
474 (defun elmo-imap4-buffer-astring (buffer)
475 "Return a list represents BUFFER as an astring defined in rfc2060.
476 BUFFER must be a single-byte buffer."
477 (let ((length (with-current-buffer buffer
479 (if (< elmo-imap4-literal-threshold length)
480 (elmo-imap4-literal-1 buffer length)
481 (elmo-imap4-astring-1 (with-current-buffer buffer
485 (defun elmo-imap4-nstring (string)
486 "Return a list represents STRING as a nstring defined in rfc2060.
487 STRING must be an encoded or a single-byte string."
488 (or (elmo-imap4-nil string)
489 (elmo-imap4-string string)))
491 (defun elmo-imap4-buffer-nstring (buffer)
492 "Return a list represents BUFFER as a nstring defined in rfc2060.
493 BUFFER must be a single-byte buffer."
494 (or (elmo-imap4-nil buffer)
495 (elmo-imap4-buffer-string buffer)))
497 (defalias 'elmo-imap4-mailbox 'elmo-imap4-astring)
498 (defalias 'elmo-imap4-field-body 'elmo-imap4-astring)
499 (defalias 'elmo-imap4-userid 'elmo-imap4-astring)
500 (defalias 'elmo-imap4-password 'elmo-imap4-astring)
502 (defun elmo-imap4-format-quoted (string)
503 "Return STRING in a form of the quoted-string defined in rfc2060."
505 (std11-wrap-as-quoted-pairs string elmo-imap4-quoted-specials-list)
508 (defsubst elmo-imap4-response-get-selectable-mailbox-list (response)
512 (if (and (eq 'list (car entry))
513 (not (member "\\NoSelect" (nth 1 (nth 1 entry)))))
514 (car (nth 1 entry))))
518 (defun elmo-imap4-list-folders (spec &optional hierarchy)
519 (let* ((root (elmo-imap4-spec-mailbox spec))
520 (session (elmo-imap4-get-session spec))
523 (elmo-string-matched-assoc
525 (with-current-buffer (elmo-network-session-buffer session)
526 elmo-imap4-server-namespace)))
527 elmo-imap4-default-hierarchy-delimiter))
528 result append-serv type)
531 (not (string= root ""))
532 (not (string-match (concat "\\(.*\\)"
536 (setq root (concat root delim)))
537 (setq result (elmo-imap4-response-get-selectable-mailbox-list
538 (elmo-imap4-send-command-wait
540 (list "list " (elmo-imap4-mailbox root) " *"))))
541 (unless (string= (elmo-imap4-spec-username spec)
542 elmo-default-imap4-user)
543 (setq append-serv (concat ":" (elmo-imap4-spec-username spec))))
544 (unless (eq (elmo-imap4-spec-auth spec)
545 elmo-default-imap4-authenticate-type)
547 (concat append-serv "/" (symbol-name (elmo-imap4-spec-auth spec)))))
548 (unless (string= (elmo-imap4-spec-hostname spec)
549 elmo-default-imap4-server)
550 (setq append-serv (concat append-serv "@" (elmo-imap4-spec-hostname
552 (unless (eq (elmo-imap4-spec-port spec)
553 elmo-default-imap4-port)
554 (setq append-serv (concat append-serv ":"
556 (elmo-imap4-spec-port spec)))))
557 (setq type (elmo-imap4-spec-stream-type spec))
558 (unless (eq (elmo-network-stream-type-symbol type)
559 elmo-default-imap4-stream-type)
561 (setq append-serv (concat append-serv
562 (elmo-network-stream-type-spec-string
565 (let (folder folders ret)
566 (while (setq folders (car result))
569 (concat "^\\(" root "[^" delim "]" "+\\)" delim)
571 (setq folder (match-string 1 folders)))
574 (append ret (list (list
575 (concat "%" (elmo-imap4-decode-folder-string folder)
577 (eval append-serv)))))))
580 (mapcar '(lambda (fld)
583 (concat "^" (regexp-quote folder))
587 (setq ret (append ret (list
588 (concat "%" (elmo-imap4-decode-folder-string folders)
590 (eval append-serv))))))
591 (setq result (cdr result))))
593 (mapcar (lambda (fld)
594 (concat "%" (elmo-imap4-decode-folder-string fld)
596 (eval append-serv))))
599 (defun elmo-imap4-folder-exists-p (spec)
600 (let ((session (elmo-imap4-get-session spec)))
602 (elmo-imap4-session-current-mailbox-internal session)
603 (elmo-imap4-spec-mailbox spec))
605 (elmo-imap4-session-select-mailbox
607 (elmo-imap4-spec-mailbox spec)
610 (defun elmo-imap4-folder-creatable-p (spec)
613 (defun elmo-imap4-create-folder-maybe (spec dummy)
614 (unless (elmo-imap4-folder-exists-p spec)
615 (elmo-imap4-create-folder spec)))
617 (defun elmo-imap4-create-folder (spec)
618 (elmo-imap4-send-command-wait
619 (elmo-imap4-get-session spec)
620 (list "create " (elmo-imap4-mailbox
621 (elmo-imap4-spec-mailbox spec)))))
623 (defun elmo-imap4-delete-folder (spec)
624 (let ((session (elmo-imap4-get-session spec))
626 (when (elmo-imap4-spec-mailbox spec)
627 (when (setq msgs (elmo-imap4-list-folder spec))
628 (elmo-imap4-delete-msgs spec msgs))
629 ;; (elmo-imap4-send-command-wait session "close")
630 (elmo-imap4-send-command-wait
633 (elmo-imap4-mailbox (elmo-imap4-spec-mailbox spec)))))))
635 (defun elmo-imap4-rename-folder (old-spec new-spec)
636 ;;;(elmo-imap4-send-command-wait session "close")
637 (elmo-imap4-send-command-wait
638 (elmo-imap4-get-session old-spec)
641 (elmo-imap4-spec-mailbox old-spec))
644 (elmo-imap4-spec-mailbox new-spec)))))
646 (defun elmo-imap4-max-of-folder (spec)
647 (let ((session (elmo-imap4-get-session spec))
648 (killed (and elmo-use-killed-list
649 (elmo-msgdb-killed-list-load
650 (elmo-msgdb-expand-path spec))))
652 (with-current-buffer (elmo-network-session-buffer session)
653 (setq elmo-imap4-status-callback nil)
654 (setq elmo-imap4-status-callback-data nil))
655 (setq status (elmo-imap4-response-value
656 (elmo-imap4-send-command-wait
660 (elmo-imap4-spec-mailbox spec))
661 " (uidnext messages)"))
664 (- (elmo-imap4-response-value status 'uidnext) 1)
667 (elmo-imap4-response-value status 'messages)
668 (elmo-msgdb-killed-list-length killed))
669 (elmo-imap4-response-value status 'messages)))))
671 (defun elmo-imap4-folder-diff (spec folder &optional number-list)
672 (if elmo-use-server-diff
673 (elmo-imap4-server-diff spec)
674 (elmo-generic-folder-diff spec folder number-list)))
676 (defun elmo-imap4-get-session (spec &optional if-exists)
677 (elmo-network-get-session
680 (elmo-imap4-spec-hostname spec)
681 (elmo-imap4-spec-port spec)
682 (elmo-imap4-spec-username spec)
683 (elmo-imap4-spec-auth spec)
684 (elmo-imap4-spec-stream-type spec)
687 (defun elmo-imap4-commit (spec)
688 (if (elmo-imap4-plugged-p spec)
689 (let ((session (elmo-imap4-get-session spec 'if-exists)))
692 (elmo-imap4-session-current-mailbox-internal session)
693 (elmo-imap4-spec-mailbox spec))
694 (if elmo-imap4-use-select-to-update-status
695 (elmo-imap4-session-select-mailbox
697 (elmo-imap4-spec-mailbox spec)
699 (elmo-imap4-session-check session)))))))
701 (defun elmo-imap4-session-select-mailbox (session mailbox
702 &optional force no-error)
703 "Select MAILBOX in SESSION.
704 If optional argument FORCE is non-nil, select mailbox even if current mailbox
706 If second optional argument NO-ERROR is non-nil, don't cause an error when
707 selecting folder was failed.
708 Returns response value if selecting folder succeed. "
711 (elmo-imap4-session-current-mailbox-internal session)
713 (let (response result)
716 (elmo-imap4-read-response
718 (elmo-imap4-send-command
722 (elmo-imap4-mailbox mailbox)))))
723 (if (setq result (elmo-imap4-response-ok-p response))
725 (elmo-imap4-session-set-current-mailbox-internal session mailbox)
726 (elmo-imap4-session-set-read-only-internal
728 (nth 1 (assq 'read-only (assq 'ok response)))))
729 (elmo-imap4-session-set-current-mailbox-internal session nil)
732 (elmo-imap4-response-error-text response)
733 (format "Select %s failed" mailbox))))))
734 (and result response))))
736 (defun elmo-imap4-check-validity (spec validity-file)
738 ;;;(elmo-imap4-send-command-wait
739 ;;;(elmo-imap4-get-session spec)
741 ;;; (elmo-imap4-mailbox
742 ;;; (elmo-imap4-spec-mailbox spec))
743 ;;; " (uidvalidity)")))
746 (defun elmo-imap4-sync-validity (spec validity-file)
750 (defun elmo-imap4-list (spec flag)
751 (let ((session (elmo-imap4-get-session spec)))
752 (elmo-imap4-session-select-mailbox session
753 (elmo-imap4-spec-mailbox spec))
754 (elmo-imap4-response-value
755 (elmo-imap4-send-command-wait
757 (format (if elmo-imap4-use-uid "uid search %s"
761 (defun elmo-imap4-list-folder (spec)
762 (let ((killed (and elmo-use-killed-list
763 (elmo-msgdb-killed-list-load
764 (elmo-msgdb-expand-path spec))))
766 (setq numbers (elmo-imap4-list spec "all"))
767 (elmo-living-messages numbers killed)))
769 (defun elmo-imap4-list-folder-unread (spec number-alist mark-alist
771 (if (and (elmo-imap4-plugged-p spec)
772 (elmo-imap4-use-flag-p spec))
773 (elmo-imap4-list spec "unseen")
774 (elmo-generic-list-folder-unread spec number-alist mark-alist
777 (defun elmo-imap4-list-folder-important (spec number-alist)
778 (if (and (elmo-imap4-plugged-p spec)
779 (elmo-imap4-use-flag-p spec))
780 (elmo-imap4-list spec "flagged")))
782 (defmacro elmo-imap4-detect-search-charset (string)
785 (detect-mime-charset-region (point-min) (point-max)))))
787 (defun elmo-imap4-search-internal-primitive (spec session filter from-msgs)
788 (let ((search-key (elmo-filter-key filter))
789 (imap-search-keys '("bcc" "body" "cc" "from" "subject" "to"))
792 ((string= "last" search-key)
793 (let ((numbers (or from-msgs (elmo-imap4-list-folder spec))))
794 (nthcdr (max (- (length numbers)
795 (string-to-int (elmo-filter-value filter)))
798 ((string= "first" search-key)
799 (let* ((numbers (or from-msgs (elmo-imap4-list-folder spec)))
800 (rest (nthcdr (string-to-int (elmo-filter-value filter) )
802 (mapcar '(lambda (x) (delete x numbers)) rest)
804 ((or (string= "since" search-key)
805 (string= "before" search-key))
806 (setq search-key (concat "sent" search-key))
807 (elmo-imap4-response-value
808 (elmo-imap4-send-command-wait session
810 (if elmo-imap4-use-uid
811 "uid search %s%s%s %s"
815 (if elmo-imap4-use-uid "uid ")
818 (elmo-imap4-make-number-set-list
822 (if (eq (elmo-filter-type filter)
826 (elmo-date-get-description
827 (elmo-date-get-datevec
828 (elmo-filter-value filter)))))
832 (if (eq (length (elmo-filter-value filter)) 0)
833 (setq charset 'us-ascii)
834 (elmo-imap4-detect-search-charset
835 (elmo-filter-value filter))))
836 (elmo-imap4-response-value
837 (elmo-imap4-send-command-wait session
839 (if elmo-imap4-use-uid "uid ")
843 (symbol-name charset))
847 (if elmo-imap4-use-uid "uid ")
850 (elmo-imap4-make-number-set-list
854 (if (eq (elmo-filter-type filter)
859 (elmo-filter-key filter)
863 (elmo-filter-key filter))
865 (encode-mime-charset-string
866 (elmo-filter-value filter) charset))))
869 (defun elmo-imap4-search-internal (spec session condition from-msgs)
873 (setq result (elmo-imap4-search-internal-primitive
874 spec session condition from-msgs)))
875 ((eq (car condition) 'and)
876 (setq result (elmo-imap4-search-internal spec session (nth 1 condition)
878 result (elmo-list-filter result
879 (elmo-imap4-search-internal
880 spec session (nth 2 condition)
882 ((eq (car condition) 'or)
883 (setq result (elmo-imap4-search-internal
884 spec session (nth 1 condition) from-msgs)
885 result (elmo-uniq-list
887 (elmo-imap4-search-internal
888 spec session (nth 2 condition) from-msgs)))
889 result (sort result '<))))))
892 (defun elmo-imap4-search (spec condition &optional from-msgs)
894 (let ((session (elmo-imap4-get-session spec)))
895 (elmo-imap4-session-select-mailbox
897 (elmo-imap4-spec-mailbox spec))
898 (elmo-imap4-search-internal spec session condition from-msgs))))
900 (defun elmo-imap4-use-flag-p (spec)
901 (not (string-match elmo-imap4-disuse-server-flag-mailbox-regexp
902 (elmo-imap4-spec-mailbox spec))))
906 ;; Emacs can parse dot symbol.
907 (defvar elmo-imap4-rfc822-size "RFC822\.SIZE")
908 (defvar elmo-imap4-rfc822-text "RFC822\.TEXT")
909 (defvar elmo-imap4-rfc822-header "RFC822\.HEADER")
910 (defvar elmo-imap4-rfc822-size "RFC822\.SIZE")
911 (defvar elmo-imap4-header-fields "HEADER\.FIELDS")
912 (defmacro elmo-imap4-replace-dot-symbols ()) ;; noop
913 (defalias 'elmo-imap4-fetch-read 'read)
917 ;; Cannot parse dot symbol.
918 (defvar elmo-imap4-rfc822-size "RFC822_SIZE")
919 (defvar elmo-imap4-header-fields "HEADER_FIELDS")
920 (defvar elmo-imap4-rfc822-size "RFC822_SIZE")
921 (defvar elmo-imap4-rfc822-text "RFC822_TEXT")
922 (defvar elmo-imap4-rfc822-header "RFC822_HEADER")
923 (defvar elmo-imap4-header-fields "HEADER_FIELDS")
924 (defun elmo-imap4-fetch-read (buffer)
925 (with-current-buffer buffer
928 (when (re-search-forward "[[ ]" nil t)
929 (goto-char (match-beginning 0))
930 (setq token (buffer-substring beg (point)))
931 (cond ((string= token "RFC822.SIZE")
932 (intern elmo-imap4-rfc822-size))
933 ((string= token "RFC822.HEADER")
934 (intern elmo-imap4-rfc822-header))
935 ((string= token "RFC822.TEXT")
936 (intern elmo-imap4-rfc822-text))
937 ((string= token "HEADER\.FIELDS")
938 (intern elmo-imap4-header-fields))
940 (elmo-read (current-buffer))))))))))
942 (defun elmo-imap4-make-number-set-list (msg-list &optional chop-length)
943 "Make RFC2060's message set specifier from MSG-LIST.
944 Returns a list of (NUMBER . SET-STRING).
945 SET-STRING is the message set specifier described in RFC2060.
946 NUMBER is contained message number in SET-STRING.
947 Every SET-STRING does not contain number of messages longer than CHOP-LENGTH.
948 If CHOP-LENGTH is not specified, message set is not chopped."
949 (let (count cont-list set-list)
950 (setq msg-list (sort (copy-sequence msg-list) '<))
955 (setq chop-length (length msg-list)))
956 (while (and (not (null msg-list))
957 (< count chop-length))
959 (elmo-number-set-append
960 cont-list (car msg-list)))
962 (setq msg-list (cdr msg-list)))
970 (format "%s:%s" (car x) (cdr x)))
976 (nreverse set-list)))
980 ;; read-mark -> "\\Seen"
981 ;; important -> "\\Flagged"
983 ;; (delete -> \\Deleted)
984 (defun elmo-imap4-mark-set-on-msgs (spec msgs mark &optional unmark no-expunge)
985 "SET flag of MSGS as MARK.
986 If optional argument UNMARK is non-nil, unmark."
987 (let ((session (elmo-imap4-get-session spec))
989 (elmo-imap4-session-select-mailbox session
990 (elmo-imap4-spec-mailbox spec))
991 (setq set-list (elmo-imap4-make-number-set-list msgs))
993 (with-current-buffer (elmo-network-session-buffer session)
994 (setq elmo-imap4-fetch-callback nil)
995 (setq elmo-imap4-fetch-callback-data nil))
996 (elmo-imap4-send-command-wait
999 (if elmo-imap4-use-uid
1000 "uid store %s %sflags.silent (%s)"
1001 "store %s %sflags.silent (%s)")
1002 (cdr (car set-list))
1006 (elmo-imap4-send-command-wait session "expunge")))
1009 (defun elmo-imap4-mark-as-important (spec msgs)
1010 (and (elmo-imap4-use-flag-p spec)
1011 (elmo-imap4-mark-set-on-msgs spec msgs "\\Flagged" nil 'no-expunge)))
1013 (defun elmo-imap4-mark-as-read (spec msgs)
1014 (and (elmo-imap4-use-flag-p spec)
1015 (elmo-imap4-mark-set-on-msgs spec msgs "\\Seen" nil 'no-expunge)))
1017 (defun elmo-imap4-unmark-important (spec msgs)
1018 (and (elmo-imap4-use-flag-p spec)
1019 (elmo-imap4-mark-set-on-msgs spec msgs "\\Flagged" 'unmark
1022 (defun elmo-imap4-mark-as-unread (spec msgs)
1023 (and (elmo-imap4-use-flag-p spec)
1024 (elmo-imap4-mark-set-on-msgs spec msgs "\\Seen" 'unmark 'no-expunge)))
1026 (defun elmo-imap4-delete-msgs (spec msgs)
1027 (elmo-imap4-mark-set-on-msgs spec msgs "\\Deleted"))
1029 (defun elmo-imap4-delete-msgs-no-expunge (spec msgs)
1030 (elmo-imap4-mark-set-on-msgs spec msgs "\\Deleted" nil 'no-expunge))
1032 (defun elmo-imap4-msgdb-create-as-numlist (spec numlist new-mark already-mark
1033 seen-mark important-mark
1035 "Create msgdb for SPEC for NUMLIST."
1036 (elmo-imap4-msgdb-create spec numlist new-mark already-mark
1037 seen-mark important-mark seen-list t))
1039 ;; Current buffer is process buffer.
1040 (defun elmo-imap4-fetch-callback (element app-data)
1041 (funcall elmo-imap4-fetch-callback
1043 (insert (or (elmo-imap4-response-bodydetail-text element)
1046 (goto-char (point-min))
1047 (while (search-forward "\r\n" nil t)
1048 (replace-match "\n"))
1049 (elmo-msgdb-create-overview-from-buffer
1050 (elmo-imap4-response-value element 'uid)
1051 (elmo-imap4-response-value element 'rfc822size)))
1052 (elmo-imap4-response-value element 'flags)
1057 ;; 0: new-mark 1: already-mark 2: seen-mark 3: important-mark
1058 ;; 4: seen-list 5: as-number
1059 (defun elmo-imap4-fetch-callback-1 (entity flags app-data)
1060 "A msgdb entity callback function."
1061 (let ((seen (member (car entity) (nth 4 app-data)))
1063 (if (member "\\Flagged" flags)
1064 (elmo-msgdb-global-mark-set (car entity) (nth 3 app-data)))
1065 (setq mark (or (elmo-msgdb-global-mark-get (car entity))
1066 (if (elmo-cache-exists-p (car entity)) ;; XXX
1067 (if (or (member "\\Seen" flags) seen)
1070 (if (or (member "\\Seen" flags) seen)
1071 (if elmo-imap4-use-cache
1073 (nth 0 app-data)))))
1074 (setq elmo-imap4-current-msgdb
1076 elmo-imap4-current-msgdb
1078 (list (cons (elmo-msgdb-overview-entity-get-number entity)
1082 (list (elmo-msgdb-overview-entity-get-number entity)
1085 (defun elmo-imap4-msgdb-create (spec numlist &rest args)
1086 "Create msgdb for SPEC."
1088 (let ((session (elmo-imap4-get-session spec))
1091 '("Subject" "From" "To" "Cc" "Date"
1092 "Message-Id" "References" "In-Reply-To")
1093 elmo-msgdb-extra-fields))
1095 (length (length numlist))
1097 (setq rfc2060 (memq 'imap4rev1
1098 (elmo-imap4-session-capability-internal
1100 (message "Getting overview...")
1101 (elmo-imap4-session-select-mailbox session
1102 (elmo-imap4-spec-mailbox spec))
1103 (setq set-list (elmo-imap4-make-number-set-list
1105 elmo-imap4-overview-fetch-chop-length))
1107 (with-current-buffer (elmo-network-session-buffer session)
1108 (setq elmo-imap4-current-msgdb nil
1109 elmo-imap4-fetch-callback 'elmo-imap4-fetch-callback-1
1110 elmo-imap4-fetch-callback-data args)
1112 (elmo-imap4-send-command-wait
1114 ;; get overview entity from IMAP4
1115 (format "%sfetch %s (%s rfc822.size flags)"
1116 (if elmo-imap4-use-uid "uid " "")
1117 (cdr (car set-list))
1119 (format "body.peek[header.fields %s]" headers)
1120 (format "%s" headers))))
1121 (when (> length elmo-display-progress-threshold)
1122 (setq total (+ total (car (car set-list))))
1123 (elmo-display-progress
1124 'elmo-imap4-msgdb-create "Getting overview..."
1125 (/ (* total 100) length)))
1126 (setq set-list (cdr set-list)))
1127 (message "Getting overview...done")
1128 elmo-imap4-current-msgdb))))
1130 (defun elmo-imap4-parse-capability (string)
1131 (if (string-match "^\\*\\(.*\\)$" string)
1133 (concat "(" (downcase (elmo-match-string 1 string)) ")"))))
1135 (defun elmo-imap4-login (session)
1136 (let ((elmo-imap4-debug-inhibit-logging t))
1140 (elmo-imap4-send-command
1143 (elmo-imap4-userid (elmo-network-session-user-internal session))
1145 (elmo-imap4-password
1146 (elmo-get-passwd (elmo-network-session-password-key session))))))
1147 (signal 'elmo-authenticate-error '(login)))))
1150 (defconst sasl-imap4-login-steps
1151 '(sasl-imap4-login-response))
1153 (defun sasl-imap4-login-response (client step)
1155 (sasl-client-name client)
1157 (sasl-read-passphrase
1158 (format "LOGIN passphrase for %s: " (sasl-client-name client)))))
1160 (put 'sasl-imap4-login 'sasl-mechanism
1161 (sasl-make-mechanism "IMAP4-LOGIN" sasl-imap4-login-steps))
1163 (provide 'sasl-imap4-login)
1166 elmo-network-initialize-session-buffer :after ((session
1167 elmo-imap4-session) buffer)
1168 (with-current-buffer buffer
1169 (mapcar 'make-variable-buffer-local elmo-imap4-local-variables)
1170 (setq elmo-imap4-seqno 0)
1171 (setq elmo-imap4-status 'initial)))
1173 (luna-define-method elmo-network-initialize-session ((session
1174 elmo-imap4-session))
1175 (let ((process (elmo-network-session-process-internal session)))
1176 (with-current-buffer (process-buffer process)
1177 ;; Skip garbage output from process before greeting.
1178 (while (and (memq (process-status process) '(open run))
1179 (goto-char (point-max))
1181 (not (elmo-imap4-parse-greeting)))
1182 (accept-process-output process 1))
1183 (set-process-filter process 'elmo-imap4-arrival-filter)
1184 (set-process-sentinel process 'elmo-imap4-sentinel)
1185 ;;; (while (and (memq (process-status process) '(open run))
1186 ;;; (eq elmo-imap4-status 'initial))
1187 ;;; (message "Waiting for server response...")
1188 ;;; (accept-process-output process 1))
1190 (unless (memq elmo-imap4-status '(nonauth auth))
1191 (signal 'elmo-open-error
1192 (list 'elmo-network-initialize-session)))
1193 (elmo-imap4-session-set-capability-internal
1195 (elmo-imap4-response-value
1196 (elmo-imap4-send-command-wait session "capability")
1198 (when (eq (elmo-network-stream-type-symbol
1199 (elmo-network-session-stream-type-internal session))
1202 (elmo-imap4-session-capability-internal session))
1203 (signal 'elmo-open-error
1204 '(elmo-imap4-starttls-error)))
1205 (elmo-imap4-send-command-wait session "starttls")
1206 (starttls-negotiate process)))))
1208 (luna-define-method elmo-network-authenticate-session ((session
1209 elmo-imap4-session))
1210 (with-current-buffer (process-buffer
1211 (elmo-network-session-process-internal session))
1212 (let* ((auth (elmo-network-session-auth-internal session))
1213 (auth (mapcar '(lambda (a)
1217 (if (listp auth) auth (list auth)))))
1218 (unless (or (eq elmo-imap4-status 'auth)
1220 (let* ((elmo-imap4-debug-inhibit-logging t)
1221 (sasl-mechanism-alist
1223 sasl-mechanism-alist
1224 (list '("IMAP4-LOGIN" sasl-imap4-login))))
1228 (mapcar '(lambda (cap)
1229 (if (string-match "^auth=\\(.*\\)$"
1231 (match-string 1 (upcase (symbol-name cap)))))
1232 (elmo-imap4-session-capability-internal session)))
1233 (list "IMAP4-LOGIN")))
1236 (sasl-find-mechanism sasl-mechanisms)
1237 (sasl-find-mechanism
1239 (mapcar '(lambda (cap) (upcase (symbol-name cap)))
1243 client name step response tag
1244 sasl-read-passphrase)
1246 (if (or elmo-imap4-force-login
1249 "There's no %s capability in server. continue?"
1250 (elmo-list-to-string
1251 (elmo-network-session-auth-internal session)))))
1252 (setq mechanism (sasl-find-mechanism
1254 (signal 'elmo-authenticate-error '(elmo-imap4-auth-no-mechanisms))))
1258 (elmo-network-session-user-internal session)
1260 (elmo-network-session-host-internal session)))
1261 ;;; (if elmo-imap4-auth-user-realm
1262 ;;; (sasl-client-set-property client 'realm elmo-imap4-auth-user-realm))
1263 (setq name (sasl-mechanism-name mechanism)
1264 step (sasl-next-step client nil))
1265 (elmo-network-session-set-auth-internal session
1266 (intern (downcase name)))
1267 (setq sasl-read-passphrase
1271 (elmo-network-session-password-key session)))))
1272 (if (string= name "IMAP4-LOGIN")
1274 (elmo-imap4-send-command
1276 (concat "LOGIN " (sasl-step-data step))))
1278 (elmo-imap4-send-command
1280 (concat "AUTHENTICATE " name
1281 (and (sasl-step-data step)
1284 (elmo-base64-encode-string
1285 (sasl-step-data step)
1286 'no-lin-break)))))))
1289 (setq response (elmo-imap4-read-untagged
1290 (elmo-network-session-process-internal session)))
1292 (null (elmo-imap4-response-continue-req-p response))
1293 (elmo-imap4-response-ok-p response)
1294 (or (sasl-next-step client step)
1296 (signal 'elmo-authenticate-error
1298 (concat "elmo-imap4-auth-"
1299 (downcase name))))))
1302 (elmo-base64-decode-string
1303 (elmo-imap4-response-value response 'continue-req)))
1304 (setq step (sasl-next-step client step))
1306 (elmo-imap4-send-string
1308 (if (sasl-step-data step)
1309 (elmo-base64-encode-string (sasl-step-data step)
1313 (luna-define-method elmo-network-setup-session ((session
1314 elmo-imap4-session))
1315 (with-current-buffer (elmo-network-session-buffer session)
1316 (when (memq 'namespace (elmo-imap4-session-capability-internal session))
1317 (setq elmo-imap4-server-namespace
1318 (elmo-imap4-response-value
1319 (elmo-imap4-send-command-wait session "namespace")
1322 (defun elmo-imap4-setup-send-buffer (string)
1323 (let ((tmp-buf (get-buffer-create " *elmo-imap4-setup-send-buffer*")))
1326 (set-buffer tmp-buf)
1328 (elmo-set-buffer-multibyte nil)
1330 (goto-char (point-min))
1331 (if (eq (re-search-forward "^$" nil t)
1334 (goto-char (point-min))
1335 (while (search-forward "\n" nil t)
1336 (replace-match "\r\n"))))
1339 (defun elmo-imap4-read-part (folder msg part)
1340 (let* ((spec (elmo-folder-get-spec folder))
1341 (session (elmo-imap4-get-session spec)))
1342 (elmo-imap4-session-select-mailbox session
1343 (elmo-imap4-spec-mailbox spec))
1344 (with-current-buffer (elmo-network-session-buffer session)
1345 (setq elmo-imap4-fetch-callback nil)
1346 (setq elmo-imap4-fetch-callback-data nil))
1348 (elmo-imap4-response-bodydetail-text
1349 (elmo-imap4-response-value-all
1350 (elmo-imap4-send-command-wait session
1352 (if elmo-imap4-use-uid
1353 "uid fetch %s body.peek[%s]"
1354 "fetch %s body.peek[%s]")
1358 (defun elmo-imap4-prefetch-msg (spec msg outbuf)
1359 (elmo-imap4-read-msg spec msg outbuf 'unseen))
1361 (defun elmo-imap4-read-msg (spec msg outbuf
1362 &optional leave-seen-flag-untouched)
1363 (let ((session (elmo-imap4-get-session spec))
1365 (elmo-imap4-session-select-mailbox session
1366 (elmo-imap4-spec-mailbox spec))
1367 (with-current-buffer (elmo-network-session-buffer session)
1368 (setq elmo-imap4-fetch-callback nil)
1369 (setq elmo-imap4-fetch-callback-data nil))
1371 (elmo-imap4-send-command-wait session
1373 (if elmo-imap4-use-uid
1374 "uid fetch %s rfc822%s"
1375 "fetch %s rfc822%s")
1377 (if leave-seen-flag-untouched
1379 (and (setq response (elmo-imap4-response-value
1380 (elmo-imap4-response-value-all
1383 (with-current-buffer outbuf
1386 (elmo-delete-cr-get-content-type)))))
1388 (defun elmo-imap4-setup-send-buffer-from-file (file)
1389 (let ((tmp-buf (get-buffer-create
1390 " *elmo-imap4-setup-send-buffer-from-file*")))
1393 (set-buffer tmp-buf)
1395 (as-binary-input-file
1396 (insert-file-contents file))
1397 (goto-char (point-min))
1398 (if (eq (re-search-forward "^$" nil t)
1401 (goto-char (point-min))
1402 (while (search-forward "\n" nil t)
1403 (replace-match "\r\n"))))
1406 (defun elmo-imap4-delete-msgids (spec msgids)
1407 "If actual message-id is matched, then delete it."
1408 (let ((message-ids msgids)
1410 (num (length msgids)))
1413 (message "Deleting message...%d/%d" i num)
1414 (elmo-imap4-delete-msg-by-id spec (car message-ids))
1415 (setq message-ids (cdr message-ids)))
1416 (elmo-imap4-send-command-wait (elmo-imap4-get-session spec) "expunge")))
1418 (defun elmo-imap4-delete-msg-by-id (spec msgid)
1419 (let ((session (elmo-imap4-get-session spec)))
1420 (elmo-imap4-session-select-mailbox session
1421 (elmo-imap4-spec-mailbox spec))
1422 (elmo-imap4-delete-msgs-no-expunge
1424 (elmo-imap4-response-value
1425 (elmo-imap4-send-command-wait session
1427 (if elmo-imap4-use-uid
1428 "uid search header message-id "
1429 "search header message-id ")
1430 (elmo-imap4-field-body msgid)))
1433 (defun elmo-imap4-append-msg-by-id (spec msgid)
1434 (let ((session (elmo-imap4-get-session spec))
1436 (elmo-imap4-session-select-mailbox session
1437 (elmo-imap4-spec-mailbox spec))
1438 (setq send-buf (elmo-imap4-setup-send-buffer-from-file
1439 (elmo-cache-get-path msgid)))
1441 (elmo-imap4-send-command-wait
1445 (elmo-imap4-mailbox (elmo-imap4-spec-mailbox spec))
1447 (elmo-imap4-buffer-literal send-buf)))
1448 (kill-buffer send-buf)))
1451 (defun elmo-imap4-append-msg (spec string &optional msg no-see)
1452 (let ((session (elmo-imap4-get-session spec))
1454 (elmo-imap4-session-select-mailbox session
1455 (elmo-imap4-spec-mailbox spec))
1456 (setq send-buf (elmo-imap4-setup-send-buffer string))
1458 (elmo-imap4-send-command-wait
1462 (elmo-imap4-mailbox (elmo-imap4-spec-mailbox spec))
1463 (if no-see " " " (\\Seen) ")
1464 (elmo-imap4-buffer-literal send-buf)))
1465 (kill-buffer send-buf)))
1468 (defun elmo-imap4-copy-msgs (dst-spec
1469 msgs src-spec &optional expunge-it same-number)
1470 "Equivalence of hostname, username is assumed."
1471 (let ((session (elmo-imap4-get-session src-spec)))
1472 (elmo-imap4-session-select-mailbox session
1473 (elmo-imap4-spec-mailbox src-spec))
1475 (elmo-imap4-send-command-wait session
1478 (if elmo-imap4-use-uid
1483 (elmo-imap4-spec-mailbox dst-spec))))
1484 (setq msgs (cdr msgs)))
1486 (elmo-imap4-send-command-wait session "expunge"))
1489 (defun elmo-imap4-server-diff-async-callback-1 (status data)
1490 (funcall elmo-imap4-server-diff-async-callback
1491 (cons (elmo-imap4-response-value status 'unseen)
1492 (elmo-imap4-response-value status 'messages))
1495 (defun elmo-imap4-server-diff-async (spec)
1496 (let ((session (elmo-imap4-get-session spec)))
1498 ;; (elmo-imap4-commit spec)
1499 (with-current-buffer (elmo-network-session-buffer session)
1500 (setq elmo-imap4-status-callback
1501 'elmo-imap4-server-diff-async-callback-1)
1502 (setq elmo-imap4-status-callback-data
1503 elmo-imap4-server-diff-async-callback-data))
1504 (elmo-imap4-send-command session
1508 (elmo-imap4-spec-mailbox spec))
1509 " (unseen messages)"))))
1511 (defun elmo-imap4-server-diff (spec)
1513 (let ((session (elmo-imap4-get-session spec))
1516 ;;; (elmo-imap4-commit spec)
1517 (with-current-buffer (elmo-network-session-buffer session)
1518 (setq elmo-imap4-status-callback nil)
1519 (setq elmo-imap4-status-callback-data nil))
1521 (elmo-imap4-send-command-wait session
1525 (elmo-imap4-spec-mailbox spec))
1526 " (unseen messages)")))
1527 (setq response (elmo-imap4-response-value response 'status))
1528 (cons (elmo-imap4-response-value response 'unseen)
1529 (elmo-imap4-response-value response 'messages))))
1531 (defun elmo-imap4-use-cache-p (spec number)
1532 elmo-imap4-use-cache)
1534 (defun elmo-imap4-local-file-p (spec number)
1537 (defun elmo-imap4-port-label (spec)
1539 (if (elmo-imap4-spec-stream-type spec)
1540 (concat "!" (symbol-name
1541 (elmo-network-stream-type-symbol
1542 (elmo-imap4-spec-stream-type spec)))))))
1545 (defsubst elmo-imap4-portinfo (spec)
1546 (list (elmo-imap4-spec-hostname spec) (elmo-imap4-spec-port spec)))
1548 (defun elmo-imap4-plugged-p (spec)
1549 (apply 'elmo-plugged-p
1550 (append (elmo-imap4-portinfo spec)
1551 (list nil (quote (elmo-imap4-port-label spec))))))
1553 (defun elmo-imap4-set-plugged (spec plugged add)
1554 (apply 'elmo-set-plugged plugged
1555 (append (elmo-imap4-portinfo spec)
1556 (list nil nil (quote (elmo-imap4-port-label spec)) add))))
1558 (defalias 'elmo-imap4-sync-number-alist 'elmo-generic-sync-number-alist)
1562 (defvar elmo-imap4-server-eol "\r\n"
1563 "The EOL string sent from the server.")
1565 (defvar elmo-imap4-client-eol "\r\n"
1566 "The EOL string we send to the server.")
1568 (defun elmo-imap4-find-next-line ()
1569 "Return point at end of current line, taking into account literals.
1570 Return nil if no complete line has arrived."
1571 (when (re-search-forward (concat elmo-imap4-server-eol "\\|{\\([0-9]+\\)}"
1572 elmo-imap4-server-eol)
1574 (if (match-string 1)
1575 (if (< (point-max) (+ (point) (string-to-number (match-string 1))))
1577 (goto-char (+ (point) (string-to-number (match-string 1))))
1578 (elmo-imap4-find-next-line))
1581 (defun elmo-imap4-sentinel (process string)
1582 (delete-process process))
1584 (defun elmo-imap4-arrival-filter (proc string)
1585 "IMAP process filter."
1586 (with-current-buffer (process-buffer proc)
1587 (elmo-imap4-debug "-> %s" string)
1588 (goto-char (point-max))
1591 (goto-char (point-min))
1592 (while (setq end (elmo-imap4-find-next-line))
1594 (narrow-to-region (point-min) end)
1595 (delete-backward-char (length elmo-imap4-server-eol))
1596 (goto-char (point-min))
1598 (cond ((eq elmo-imap4-status 'initial)
1599 (setq elmo-imap4-current-response
1601 (list 'greeting (elmo-imap4-parse-greeting)))))
1602 ((or (eq elmo-imap4-status 'auth)
1603 (eq elmo-imap4-status 'nonauth)
1604 (eq elmo-imap4-status 'selected)
1605 (eq elmo-imap4-status 'examine))
1606 (setq elmo-imap4-current-response
1608 (elmo-imap4-parse-response)
1609 elmo-imap4-current-response)))
1611 (message "Unknown state %s in arrival filter"
1612 elmo-imap4-status))))
1613 (delete-region (point-min) (point-max)))))))
1617 (defsubst elmo-imap4-forward ()
1618 (or (eobp) (forward-char 1)))
1620 (defsubst elmo-imap4-parse-number ()
1621 (when (looking-at "[0-9]+")
1623 (string-to-number (match-string 0))
1624 (goto-char (match-end 0)))))
1626 (defsubst elmo-imap4-parse-literal ()
1627 (when (looking-at "{\\([0-9]+\\)}\r\n")
1628 (let ((pos (match-end 0))
1629 (len (string-to-number (match-string 1))))
1630 (if (< (point-max) (+ pos len))
1632 (goto-char (+ pos len))
1633 (buffer-substring pos (+ pos len))))))
1634 ;;; (list ' pos (+ pos len))))))
1636 (defsubst elmo-imap4-parse-string ()
1637 (cond ((eq (char-after (point)) ?\")
1639 (let ((p (point)) (name ""))
1640 (skip-chars-forward "^\"\\\\")
1641 (setq name (buffer-substring p (point)))
1642 (while (eq (char-after (point)) ?\\)
1643 (setq p (1+ (point)))
1645 (skip-chars-forward "^\"\\\\")
1646 (setq name (concat name (buffer-substring p (point)))))
1649 ((eq (char-after (point)) ?{)
1650 (elmo-imap4-parse-literal))))
1652 (defsubst elmo-imap4-parse-nil ()
1653 (if (looking-at "NIL")
1654 (goto-char (match-end 0))))
1656 (defsubst elmo-imap4-parse-nstring ()
1657 (or (elmo-imap4-parse-string)
1658 (and (elmo-imap4-parse-nil)
1661 (defsubst elmo-imap4-parse-astring ()
1662 (or (elmo-imap4-parse-string)
1663 (buffer-substring (point)
1664 (if (re-search-forward "[(){ \r\n%*\"\\]" nil t)
1665 (goto-char (1- (match-end 0)))
1669 (defsubst elmo-imap4-parse-address ()
1671 (when (eq (char-after (point)) ?\()
1672 (elmo-imap4-forward)
1673 (setq address (vector (prog1 (elmo-imap4-parse-nstring)
1674 (elmo-imap4-forward))
1675 (prog1 (elmo-imap4-parse-nstring)
1676 (elmo-imap4-forward))
1677 (prog1 (elmo-imap4-parse-nstring)
1678 (elmo-imap4-forward))
1679 (elmo-imap4-parse-nstring)))
1680 (when (eq (char-after (point)) ?\))
1681 (elmo-imap4-forward)
1684 (defsubst elmo-imap4-parse-address-list ()
1685 (if (eq (char-after (point)) ?\()
1686 (let (address addresses)
1687 (elmo-imap4-forward)
1688 (while (and (not (eq (char-after (point)) ?\)))
1689 ;; next line for MS Exchange bug
1690 (progn (and (eq (char-after (point)) ? ) (elmo-imap4-forward)) t)
1691 (setq address (elmo-imap4-parse-address)))
1692 (setq addresses (cons address addresses)))
1693 (when (eq (char-after (point)) ?\))
1694 (elmo-imap4-forward)
1695 (nreverse addresses)))
1696 (assert (elmo-imap4-parse-nil))))
1698 (defsubst elmo-imap4-parse-mailbox ()
1699 (let ((mailbox (elmo-imap4-parse-astring)))
1700 (if (string-equal "INBOX" (upcase mailbox))
1704 (defun elmo-imap4-parse-greeting ()
1705 "Parse a IMAP greeting."
1706 (cond ((looking-at "\\* OK ")
1707 (setq elmo-imap4-status 'nonauth))
1708 ((looking-at "\\* PREAUTH ")
1709 (setq elmo-imap4-status 'auth))
1710 ((looking-at "\\* BYE ")
1711 (setq elmo-imap4-status 'closed))))
1713 (defun elmo-imap4-parse-response ()
1714 "Parse a IMAP command response."
1716 (case (setq token (elmo-read (current-buffer)))
1718 (skip-chars-forward " ")
1719 (list 'continue-req (buffer-substring (point) (point-max)))))
1720 (* (case (prog1 (setq token (elmo-read (current-buffer)))
1721 (elmo-imap4-forward))
1722 (OK (elmo-imap4-parse-resp-text-code))
1723 (NO (elmo-imap4-parse-resp-text-code))
1724 (BAD (elmo-imap4-parse-resp-text-code))
1725 (BYE (elmo-imap4-parse-bye))
1727 (elmo-imap4-parse-flag-list)))
1728 (LIST (list 'list (elmo-imap4-parse-data-list)))
1729 (LSUB (list 'lsub (elmo-imap4-parse-data-list)))
1732 (elmo-read (concat "("
1733 (buffer-substring (point) (point-max))
1735 (STATUS (elmo-imap4-parse-status))
1737 (NAMESPACE (elmo-imap4-parse-namespace))
1738 (CAPABILITY (list 'capability
1740 (concat "(" (downcase (buffer-substring
1741 (point) (point-max)))
1743 (ACL (elmo-imap4-parse-acl))
1744 (t (case (prog1 (elmo-read (current-buffer))
1745 (elmo-imap4-forward))
1746 (EXISTS (list 'exists token))
1747 (RECENT (list 'recent token))
1748 (EXPUNGE (list 'expunge token))
1749 (FETCH (elmo-imap4-parse-fetch token))
1750 (t (list 'garbage (buffer-string)))))))
1751 (t (if (not (string-match elmo-imap4-seq-prefix (symbol-name token)))
1752 (list 'garbage (buffer-string))
1753 (case (prog1 (elmo-read (current-buffer))
1754 (elmo-imap4-forward))
1756 (setq elmo-imap4-parsing nil)
1757 (setq token (symbol-name token))
1758 (elmo-unintern token)
1759 (elmo-imap4-debug "*%s* OK arrived" token)
1760 (setq elmo-imap4-reached-tag token)
1761 (list 'ok (elmo-imap4-parse-resp-text-code))))
1763 (setq elmo-imap4-parsing nil)
1764 (setq token (symbol-name token))
1765 (elmo-unintern token)
1766 (elmo-imap4-debug "*%s* NO arrived" token)
1767 (setq elmo-imap4-reached-tag token)
1769 (when (eq (char-after (point)) ?\[)
1770 (setq code (buffer-substring (point)
1771 (search-forward "]")))
1772 (elmo-imap4-forward))
1773 (setq text (buffer-substring (point) (point-max)))
1774 (list 'no (list code text)))))
1776 (setq elmo-imap4-parsing nil)
1777 (elmo-imap4-debug "*%s* BAD arrived" token)
1778 (setq token (symbol-name token))
1779 (elmo-unintern token)
1780 (setq elmo-imap4-reached-tag token)
1782 (when (eq (char-after (point)) ?\[)
1783 (setq code (buffer-substring (point)
1784 (search-forward "]")))
1785 (elmo-imap4-forward))
1786 (setq text (buffer-substring (point) (point-max)))
1787 (list 'bad (list code text)))))
1788 (t (list 'garbage (buffer-string)))))))))
1790 (defun elmo-imap4-parse-bye ()
1792 (when (eq (char-after (point)) ?\[)
1793 (setq code (buffer-substring (point)
1794 (search-forward "]")))
1795 (elmo-imap4-forward))
1796 (setq text (buffer-substring (point) (point-max)))
1797 (list 'bye (list code text))))
1799 (defun elmo-imap4-parse-text ()
1800 (goto-char (point-min))
1801 (when (search-forward "[" nil t)
1802 (search-forward "]")
1803 (elmo-imap4-forward))
1804 (list 'text (buffer-substring (point) (point-max))))
1806 (defun elmo-imap4-parse-resp-text-code ()
1807 (when (eq (char-after (point)) ?\[)
1808 (elmo-imap4-forward)
1809 (cond ((search-forward "PERMANENTFLAGS " nil t)
1810 (list 'permanentflags (elmo-imap4-parse-flag-list)))
1811 ((search-forward "UIDNEXT " nil t)
1812 (list 'uidnext (elmo-read (current-buffer))))
1813 ((search-forward "UNSEEN " nil t)
1814 (list 'unseen (elmo-read (current-buffer))))
1815 ((looking-at "UIDVALIDITY \\([0-9]+\\)")
1816 (list 'uidvalidity (match-string 1)))
1817 ((search-forward "READ-ONLY" nil t)
1818 (list 'read-only t))
1819 ((search-forward "READ-WRITE" nil t)
1820 (list 'read-write t))
1821 ((search-forward "NEWNAME " nil t)
1822 (let (oldname newname)
1823 (setq oldname (elmo-imap4-parse-string))
1824 (elmo-imap4-forward)
1825 (setq newname (elmo-imap4-parse-string))
1826 (list 'newname newname oldname)))
1827 ((search-forward "TRYCREATE" nil t)
1828 (list 'trycreate t))
1829 ((looking-at "APPENDUID \\([0-9]+\\) \\([0-9]+\\)")
1831 (list (match-string 1)
1832 (string-to-number (match-string 2)))))
1833 ((looking-at "COPYUID \\([0-9]+\\) \\([0-9,:]+\\) \\([0-9,:]+\\)")
1834 (list 'copyuid (list (match-string 1)
1837 ((search-forward "ALERT] " nil t)
1838 (message "IMAP server information: %s"
1839 (buffer-substring (point) (point-max))))
1840 (t (list 'unknown)))))
1842 (defun elmo-imap4-parse-data-list ()
1843 (let (flags delimiter mailbox)
1844 (setq flags (elmo-imap4-parse-flag-list))
1845 (when (looking-at " NIL\\| \"\\\\?\\(.\\)\"")
1846 (setq delimiter (match-string 1))
1847 (goto-char (1+ (match-end 0)))
1848 (when (setq mailbox (elmo-imap4-parse-mailbox))
1849 (list mailbox flags delimiter)))))
1851 (defsubst elmo-imap4-parse-header-list ()
1852 (when (eq (char-after (point)) ?\()
1854 (while (not (eq (char-after (point)) ?\)))
1855 (elmo-imap4-forward)
1856 (push (elmo-imap4-parse-astring) strlist))
1857 (elmo-imap4-forward)
1858 (nreverse strlist))))
1860 (defsubst elmo-imap4-parse-fetch-body-section ()
1862 (buffer-substring (point)
1864 (progn (re-search-forward "[] ]" nil t)
1866 (if (eq (char-before) ? )
1868 (mapconcat 'identity
1869 (cons section (elmo-imap4-parse-header-list)) " ")
1870 (search-forward "]" nil t))
1873 (defun elmo-imap4-parse-fetch (response)
1874 (when (eq (char-after (point)) ?\()
1876 (while (not (eq (char-after (point)) ?\)))
1877 (elmo-imap4-forward)
1878 (let ((token (elmo-imap4-fetch-read (current-buffer))))
1879 (elmo-imap4-forward)
1881 (cond ((eq token 'UID)
1882 (list 'uid (condition-case nil
1883 (elmo-read (current-buffer))
1886 (list 'flags (elmo-imap4-parse-flag-list)))
1887 ((eq token 'ENVELOPE)
1888 (list 'envelope (elmo-imap4-parse-envelope)))
1889 ((eq token 'INTERNALDATE)
1890 (list 'internaldate (elmo-imap4-parse-string)))
1892 (list 'rfc822 (elmo-imap4-parse-nstring)))
1893 ((eq token (intern elmo-imap4-rfc822-header))
1894 (list 'rfc822header (elmo-imap4-parse-nstring)))
1895 ((eq token (intern elmo-imap4-rfc822-text))
1896 (list 'rfc822text (elmo-imap4-parse-nstring)))
1897 ((eq token (intern elmo-imap4-rfc822-size))
1898 (list 'rfc822size (elmo-read (current-buffer))))
1900 (if (eq (char-before) ?\[)
1903 (upcase (elmo-imap4-parse-fetch-body-section))
1905 (eq (char-after (point)) ?<)
1906 (buffer-substring (1+ (point))
1908 (search-forward ">" nil t)
1910 (progn (elmo-imap4-forward)
1911 (elmo-imap4-parse-nstring)))
1912 (list 'body (elmo-imap4-parse-body))))
1913 ((eq token 'BODYSTRUCTURE)
1914 (list 'bodystructure (elmo-imap4-parse-body)))))
1915 (setq list (cons element list))))
1916 (and elmo-imap4-fetch-callback
1917 (elmo-imap4-fetch-callback list elmo-imap4-fetch-callback-data))
1918 (list 'fetch list))))
1920 (defun elmo-imap4-parse-status ()
1921 (let ((mailbox (elmo-imap4-parse-mailbox))
1923 (when (and mailbox (search-forward "(" nil t))
1924 (while (not (eq (char-after (point)) ?\)))
1927 (let ((token (elmo-read (current-buffer))))
1928 (cond ((eq token 'MESSAGES)
1929 (list 'messages (elmo-read (current-buffer))))
1931 (list 'recent (elmo-read (current-buffer))))
1932 ((eq token 'UIDNEXT)
1933 (list 'uidnext (elmo-read (current-buffer))))
1934 ((eq token 'UIDVALIDITY)
1935 (and (looking-at " \\([0-9]+\\)")
1936 (prog1 (list 'uidvalidity (match-string 1))
1937 (goto-char (match-end 1)))))
1939 (list 'unseen (elmo-read (current-buffer))))
1942 "Unknown status data %s in mailbox %s ignored"
1945 (and elmo-imap4-status-callback
1946 (funcall elmo-imap4-status-callback
1948 elmo-imap4-status-callback-data))
1949 (list 'status status)))
1952 (defmacro elmo-imap4-value (value)
1953 (` (if (eq (, value) 'NIL) nil
1956 (defmacro elmo-imap4-nth (pos list)
1957 (` (let ((value (nth (, pos) (, list))))
1958 (elmo-imap4-value value))))
1960 (defun elmo-imap4-parse-namespace ()
1963 (copy-sequence elmo-imap4-extra-namespace-alist)
1964 (elmo-imap4-parse-namespace-subr
1965 (elmo-read (concat "(" (buffer-substring
1966 (point) (point-max))
1969 (defun elmo-imap4-parse-namespace-subr (ns)
1970 (let (prefix delim namespace-alist default-delim)
1971 ;; 0: personal, 1: other, 2: shared
1973 (setq namespace-alist
1974 (nconc namespace-alist
1978 (setq prefix (elmo-imap4-nth 0 namespace)
1979 delim (elmo-imap4-nth 1 namespace))
1980 (if (and prefix delim
1982 (concat (regexp-quote delim) "\\'")
1984 (setq prefix (substring prefix 0
1985 (match-beginning 0))))
1986 (if (eq (length prefix) 0)
1987 (progn (setq default-delim delim) nil)
1990 (if (string= (downcase prefix) "inbox")
1991 "[Ii][Nn][Bb][Oo][Xx]"
1992 (regexp-quote prefix))
1995 (elmo-imap4-nth i ns))))))
1997 (setq namespace-alist
1998 (nconc namespace-alist
1999 (list (cons "^.*$" default-delim)))))
2002 (defun elmo-imap4-parse-acl ()
2003 (let ((mailbox (elmo-imap4-parse-mailbox))
2004 identifier rights acl)
2005 (while (eq (char-after (point)) ?\ )
2006 (elmo-imap4-forward)
2007 (setq identifier (elmo-imap4-parse-astring))
2008 (elmo-imap4-forward)
2009 (setq rights (elmo-imap4-parse-astring))
2010 (setq acl (append acl (list (cons identifier rights)))))
2011 (list 'acl acl mailbox)))
2013 (defun elmo-imap4-parse-flag-list ()
2014 (let ((str (buffer-substring (+ (point) 1)
2015 (progn (search-forward ")" nil t)
2017 (unless (eq (length str) 0)
2018 (split-string str))))
2020 (defun elmo-imap4-parse-envelope ()
2021 (when (eq (char-after (point)) ?\()
2022 (elmo-imap4-forward)
2023 (vector (prog1 (elmo-imap4-parse-nstring);; date
2024 (elmo-imap4-forward))
2025 (prog1 (elmo-imap4-parse-nstring);; subject
2026 (elmo-imap4-forward))
2027 (prog1 (elmo-imap4-parse-address-list);; from
2028 (elmo-imap4-forward))
2029 (prog1 (elmo-imap4-parse-address-list);; sender
2030 (elmo-imap4-forward))
2031 (prog1 (elmo-imap4-parse-address-list);; reply-to
2032 (elmo-imap4-forward))
2033 (prog1 (elmo-imap4-parse-address-list);; to
2034 (elmo-imap4-forward))
2035 (prog1 (elmo-imap4-parse-address-list);; cc
2036 (elmo-imap4-forward))
2037 (prog1 (elmo-imap4-parse-address-list);; bcc
2038 (elmo-imap4-forward))
2039 (prog1 (elmo-imap4-parse-nstring);; in-reply-to
2040 (elmo-imap4-forward))
2041 (prog1 (elmo-imap4-parse-nstring);; message-id
2042 (elmo-imap4-forward)))))
2044 (defsubst elmo-imap4-parse-string-list ()
2045 (cond ((eq (char-after (point)) ?\();; body-fld-param
2047 (elmo-imap4-forward)
2048 (while (setq str (elmo-imap4-parse-string))
2050 (elmo-imap4-forward))
2051 (nreverse strlist)))
2052 ((elmo-imap4-parse-nil)
2055 (defun elmo-imap4-parse-body-extension ()
2056 (if (eq (char-after (point)) ?\()
2058 (elmo-imap4-forward)
2059 (push (elmo-imap4-parse-body-extension) b-e)
2060 (while (eq (char-after (point)) ?\ )
2061 (elmo-imap4-forward)
2062 (push (elmo-imap4-parse-body-extension) b-e))
2063 (assert (eq (char-after (point)) ?\)))
2064 (elmo-imap4-forward)
2066 (or (elmo-imap4-parse-number)
2067 (elmo-imap4-parse-nstring))))
2069 (defsubst elmo-imap4-parse-body-ext ()
2071 (when (eq (char-after (point)) ?\ );; body-fld-dsp
2072 (elmo-imap4-forward)
2074 (if (eq (char-after (point)) ?\()
2076 (elmo-imap4-forward)
2077 (push (elmo-imap4-parse-string) dsp)
2078 (elmo-imap4-forward)
2079 (push (elmo-imap4-parse-string-list) dsp)
2080 (elmo-imap4-forward))
2081 (assert (elmo-imap4-parse-nil)))
2082 (push (nreverse dsp) ext))
2083 (when (eq (char-after (point)) ?\ );; body-fld-lang
2084 (elmo-imap4-forward)
2085 (if (eq (char-after (point)) ?\()
2086 (push (elmo-imap4-parse-string-list) ext)
2087 (push (elmo-imap4-parse-nstring) ext))
2088 (while (eq (char-after (point)) ?\ );; body-extension
2089 (elmo-imap4-forward)
2090 (setq ext (append (elmo-imap4-parse-body-extension) ext)))))
2093 (defun elmo-imap4-parse-body ()
2095 (when (eq (char-after (point)) ?\()
2096 (elmo-imap4-forward)
2097 (if (eq (char-after (point)) ?\()
2099 (while (and (eq (char-after (point)) ?\()
2100 (setq subbody (elmo-imap4-parse-body)))
2101 (push subbody body))
2102 (elmo-imap4-forward)
2103 (push (elmo-imap4-parse-string) body);; media-subtype
2104 (when (eq (char-after (point)) ?\ );; body-ext-mpart:
2105 (elmo-imap4-forward)
2106 (if (eq (char-after (point)) ?\();; body-fld-param
2107 (push (elmo-imap4-parse-string-list) body)
2108 (push (and (elmo-imap4-parse-nil) nil) body))
2110 (append (elmo-imap4-parse-body-ext) body)));; body-ext-...
2111 (assert (eq (char-after (point)) ?\)))
2112 (elmo-imap4-forward)
2115 (push (elmo-imap4-parse-string) body);; media-type
2116 (elmo-imap4-forward)
2117 (push (elmo-imap4-parse-string) body);; media-subtype
2118 (elmo-imap4-forward)
2119 ;; next line for Sun SIMS bug
2120 (and (eq (char-after (point)) ? ) (elmo-imap4-forward))
2121 (if (eq (char-after (point)) ?\();; body-fld-param
2122 (push (elmo-imap4-parse-string-list) body)
2123 (push (and (elmo-imap4-parse-nil) nil) body))
2124 (elmo-imap4-forward)
2125 (push (elmo-imap4-parse-nstring) body);; body-fld-id
2126 (elmo-imap4-forward)
2127 (push (elmo-imap4-parse-nstring) body);; body-fld-desc
2128 (elmo-imap4-forward)
2129 (push (elmo-imap4-parse-string) body);; body-fld-enc
2130 (elmo-imap4-forward)
2131 (push (elmo-imap4-parse-number) body);; body-fld-octets
2133 ;; ok, we're done parsing the required parts, what comes now is one
2136 ;; envelope (then we're parsing body-type-msg)
2137 ;; body-fld-lines (then we're parsing body-type-text)
2138 ;; body-ext-1part (then we're parsing body-type-basic)
2140 ;; the problem is that the two first are in turn optionally followed
2141 ;; by the third. So we parse the first two here (if there are any)...
2143 (when (eq (char-after (point)) ?\ )
2144 (elmo-imap4-forward)
2146 (cond ((eq (char-after (point)) ?\();; body-type-msg:
2147 (push (elmo-imap4-parse-envelope) body);; envelope
2148 (elmo-imap4-forward)
2149 (push (elmo-imap4-parse-body) body);; body
2150 (elmo-imap4-forward)
2151 (push (elmo-imap4-parse-number) body));; body-fld-lines
2152 ((setq lines (elmo-imap4-parse-number));; body-type-text:
2153 (push lines body));; body-fld-lines
2155 (backward-char)))));; no match...
2157 ;; ...and then parse the third one here...
2159 (when (eq (char-after (point)) ?\ );; body-ext-1part:
2160 (elmo-imap4-forward)
2161 (push (elmo-imap4-parse-nstring) body);; body-fld-md5
2163 (append (elmo-imap4-parse-body-ext) body)));; body-ext-1part..
2165 (assert (eq (char-after (point)) ?\)))
2166 (elmo-imap4-forward)
2170 (product-provide (provide 'elmo-imap4) (require 'elmo-version))
2172 ;;; elmo-imap4.el ends here