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 sasl-cram-md5 (username passphrase challenge))
63 ; (defun-maybe sasl-digest-md5-digest-response
64 ; (digest-challenge username passwd serv-type host &optional realm))
65 (defun-maybe starttls-negotiate (a))
66 (defun-maybe elmo-generic-list-folder-unread (spec number-alist mark-alist unread-marks))
67 (defun-maybe elmo-generic-folder-diff (spec folder number-list))
68 (defsubst-maybe utf7-decode-string (string &optional imap) string))
70 (defvar elmo-imap4-use-lock t
71 "USE IMAP4 with locking process.")
73 ;;; internal variables
75 (defvar elmo-imap4-seq-prefix "elmo-imap4")
76 (defvar elmo-imap4-seqno 0)
77 (defvar elmo-imap4-use-uid t
78 "Use UID as message number.")
80 (defvar elmo-imap4-current-response nil)
81 (defvar elmo-imap4-status nil)
82 (defvar elmo-imap4-reached-tag "elmo-imap40")
84 ;;; buffer local variables
86 (defvar elmo-imap4-extra-namespace-alist
87 '(("^{.*/nntp}.*$" . ".")) ; Default is for UW's remote nntp mailbox...
88 "Extra namespace alist. A list of cons cell like: (REGEXP . DELIMITER).")
89 (defvar elmo-imap4-default-hierarchy-delimiter "/")
91 (defvar elmo-imap4-server-capability nil)
92 (defvar elmo-imap4-server-namespace nil)
94 (defvar elmo-imap4-parsing nil) ; indicates parsing.
96 (defvar elmo-imap4-fetch-callback nil)
97 (defvar elmo-imap4-fetch-callback-data nil)
98 (defvar elmo-imap4-status-callback nil)
99 (defvar elmo-imap4-status-callback-data nil)
101 (defvar elmo-imap4-server-diff-async-callback nil)
102 (defvar elmo-imap4-server-diff-async-callback-data nil)
104 ;;; progress...(no use?)
105 (defvar elmo-imap4-count-progress nil)
106 (defvar elmo-imap4-count-progress-message nil)
107 (defvar elmo-imap4-progress-count nil)
109 ;;; XXX Temporal implementation
110 (defvar elmo-imap4-current-msgdb nil)
112 (defvar elmo-imap4-local-variables
114 elmo-imap4-current-response
117 elmo-imap4-reached-tag
118 elmo-imap4-count-progress
119 elmo-imap4-count-progress-message
120 elmo-imap4-progress-count
121 elmo-imap4-fetch-callback
122 elmo-imap4-fetch-callback-data
123 elmo-imap4-status-callback
124 elmo-imap4-status-callback-data
125 elmo-imap4-current-msgdb))
127 (defvar elmo-imap4-authenticator-alist
128 '((login elmo-imap4-auth-login)
129 (cram-md5 elmo-imap4-auth-cram-md5)
130 (digest-md5 elmo-imap4-auth-digest-md5)
131 (plain elmo-imap4-login))
132 "Definition of authenticators.")
136 (defconst elmo-imap4-quoted-specials-list '(?\\ ?\"))
138 (defconst elmo-imap4-non-atom-char-regex
140 (concat "[^" "]!#$&'+,./0-9:;<=>?@A-Z[^_`a-z|}~-" "]")))
142 (defconst elmo-imap4-non-text-char-regex
145 "]\x01-\x09\x0b\x0c\x0e-\x1f\x7f !\"#$%&'()*+,./0-9:;<=>?@A-Z[\\^_`a-z{|}~-"
148 (defconst elmo-imap4-literal-threshold 1024
149 "Limitation of characters that can be used in a quoted string.")
152 (defvar elmo-imap4-debug nil
153 "Non-nil forces IMAP4 folder as debug mode.
154 Debug information is inserted in the buffer \"*IMAP4 DEBUG*\"")
156 (defvar elmo-imap4-debug-inhibit-logging nil)
161 (luna-define-class elmo-imap4-session (elmo-network-session)
162 (capability current-mailbox read-only))
163 (luna-define-internal-accessors 'elmo-imap4-session))
167 (defsubst elmo-imap4-spec-mailbox (spec)
170 (defsubst elmo-imap4-spec-username (spec)
173 (defsubst elmo-imap4-spec-auth (spec)
176 (defsubst elmo-imap4-spec-hostname (spec)
179 (defsubst elmo-imap4-spec-port (spec)
182 (defsubst elmo-imap4-spec-stream-type (spec)
188 (defsubst elmo-imap4-debug (message &rest args)
190 (with-current-buffer (get-buffer-create "*IMAP4 DEBUG*")
191 (goto-char (point-max))
192 (if elmo-imap4-debug-inhibit-logging
193 (insert "NO LOGGING\n")
194 (insert (apply 'format message args) "\n")))))
198 (defmacro elmo-imap4-response-continue-req-p (response)
199 "Returns non-nil if RESPONSE is '+' response."
200 (` (assq 'continue-req (, response))))
202 (defmacro elmo-imap4-response-ok-p (response)
203 "Returns non-nil if RESPONSE is an 'OK' response."
204 (` (assq 'ok (, response))))
206 (defmacro elmo-imap4-response-bye-p (response)
207 "Returns non-nil if RESPONSE is an 'BYE' response."
208 (` (assq 'bye (, response))))
210 (defmacro elmo-imap4-response-value (response symbol)
211 "Get value of the SYMBOL from RESPONSE."
212 (` (nth 1 (assq (, symbol) (, response)))))
214 (defsubst elmo-imap4-response-value-all (response symbol)
215 "Get all value of the SYMBOL from RESPONSE."
218 (if (eq (car (car response)) symbol)
219 (setq matched (nconc matched (nth 1 (car response)))))
220 (setq response (cdr response)))
223 (defmacro elmo-imap4-response-error-text (response)
224 "Returns text of NO, BAD, BYE response."
225 (` (nth 1 (or (elmo-imap4-response-value (, response) 'no)
226 (elmo-imap4-response-value (, response) 'bad)
227 (elmo-imap4-response-value (, response) 'bye)))))
229 (defmacro elmo-imap4-response-bodydetail-text (response)
230 "Returns text of BODY[section]<partial>."
231 (` (nth 3 (assq 'bodydetail (, response)))))
233 ;;; Session commands.
235 ; (defun elmo-imap4-send-command-wait (session command)
236 ; "Send COMMAND to the SESSION and wait for response.
237 ; Returns RESPONSE (parsed lisp object) of IMAP session."
238 ; (elmo-imap4-read-response session
239 ; (elmo-imap4-send-command
243 (defun elmo-imap4-send-command-wait (session command)
244 "Send COMMAND to the SESSION.
245 Returns RESPONSE (parsed lisp object) of IMAP session.
246 If response is not `OK', causes error with IMAP response text."
247 (elmo-imap4-accept-ok session
248 (elmo-imap4-send-command
252 (defun elmo-imap4-send-command (session command)
253 "Send COMMAND to the SESSION.
254 Returns a TAG string which is assigned to the COMAND."
255 (let* ((command-args (if (listp command)
258 (process (elmo-network-session-process-internal session))
259 cmdstr tag token kind)
260 (with-current-buffer (process-buffer process)
261 (setq tag (concat elmo-imap4-seq-prefix
263 (setq elmo-imap4-seqno (+ 1 elmo-imap4-seqno)))))
264 (setq cmdstr (concat tag " "))
265 ;; (erase-buffer) No need.
266 (goto-char (point-min))
267 (if (elmo-imap4-response-bye-p elmo-imap4-current-response)
268 (signal 'elmo-imap4-bye-error
269 (list (elmo-imap4-response-error-text
270 elmo-imap4-current-response))))
271 (setq elmo-imap4-current-response nil)
272 (if elmo-imap4-parsing
273 (error "IMAP process is running. Please wait (or plug again.)"))
274 (setq elmo-imap4-parsing t)
275 (elmo-imap4-debug "<-(%s)- %s" tag command)
276 (while (setq token (car command-args))
277 (cond ((stringp token) ; formatted
278 (setq cmdstr (concat cmdstr token)))
279 ((listp token) ; unformatted
280 (setq kind (car token))
281 (cond ((eq kind 'atom)
282 (setq cmdstr (concat cmdstr (nth 1 token))))
286 (elmo-imap4-format-quoted (nth 1 token)))))
288 (setq cmdstr (concat cmdstr
289 (format "{%d}" (nth 2 token))))
290 (process-send-string process cmdstr)
291 (process-send-string process "\r\n")
293 (elmo-imap4-accept-continue-req session)
294 (cond ((stringp (nth 1 token))
295 (setq cmdstr (nth 1 token)))
296 ((bufferp (nth 1 token))
297 (with-current-buffer (nth 1 token)
301 (+ (point-min) (nth 2 token)))))
303 (error "Wrong argument for literal"))))
305 (error "Unknown token kind %s" kind))))
307 (error "Invalid argument")))
308 (setq command-args (cdr command-args)))
310 (process-send-string process cmdstr))
311 (process-send-string process "\r\n")
314 (defun elmo-imap4-send-string (session string)
315 "Send STRING to the SESSION."
316 (with-current-buffer (process-buffer
317 (elmo-network-session-process-internal session))
318 (setq elmo-imap4-current-response nil)
319 (goto-char (point-min))
320 (elmo-imap4-debug "<-- %s" string)
321 (process-send-string (elmo-network-session-process-internal session)
323 (process-send-string (elmo-network-session-process-internal session)
326 (defun elmo-imap4-read-response (session tag)
327 "Read parsed response from SESSION.
328 TAG is the tag of the command"
329 (with-current-buffer (process-buffer
330 (elmo-network-session-process-internal session))
331 (while (not (or (string= tag elmo-imap4-reached-tag)
332 (elmo-imap4-response-bye-p elmo-imap4-current-response)))
333 (when (memq (process-status
334 (elmo-network-session-process-internal session))
336 (accept-process-output (elmo-network-session-process-internal session)
338 (elmo-imap4-debug "=>%s" (prin1-to-string elmo-imap4-current-response))
339 (setq elmo-imap4-parsing nil)
340 elmo-imap4-current-response))
342 (defsubst elmo-imap4-read-untagged (process)
343 (with-current-buffer (process-buffer process)
344 (while (not elmo-imap4-current-response)
345 (accept-process-output process 1))
346 (elmo-imap4-debug "=>%s" (prin1-to-string elmo-imap4-current-response))
347 elmo-imap4-current-response))
349 (defun elmo-imap4-read-continue-req (session)
350 "Returns a text following to continue-req in SESSION.
351 If response is not `+' response, returns nil."
352 (elmo-imap4-response-value
353 (elmo-imap4-read-untagged
354 (elmo-network-session-process-internal session))
357 (defun elmo-imap4-accept-continue-req (session)
358 "Returns non-nil if `+' (continue-req) response is arrived in SESSION.
359 If response is not `+' response, cause an error."
362 (elmo-imap4-read-untagged
363 (elmo-network-session-process-internal session)))
364 (or (elmo-imap4-response-continue-req-p response)
365 (error "IMAP error: %s"
366 (or (elmo-imap4-response-error-text response)
367 "No continut-req from server.")))))
369 (defun elmo-imap4-read-ok (session tag)
370 "Returns non-nil if `OK' response of the command with TAG is arrived
371 in SESSION. If response is not `OK' response, returns nil."
372 (elmo-imap4-response-ok-p
373 (elmo-imap4-read-response session tag)))
375 (defun elmo-imap4-accept-ok (session tag)
376 "Accept only `OK' response from SESSION.
377 If response is not `OK' response, causes error with IMAP response text."
378 (let ((response (elmo-imap4-read-response session tag)))
379 (if (elmo-imap4-response-ok-p response)
381 (if (elmo-imap4-response-bye-p response)
382 (signal 'elmo-imap4-bye-error
383 (list (elmo-imap4-response-error-text response)))
384 (error "IMAP error: %s"
385 (or (elmo-imap4-response-error-text response)
386 "No `OK' response from server."))))))
389 (defun elmo-imap4-session-check (session)
390 (elmo-imap4-send-command-wait session "check"))
392 (defun elmo-imap4-atom-p (string)
393 "Return t if STRING is an atom defined in rfc2060."
394 (if (string= string "")
397 (not (string-match elmo-imap4-non-atom-char-regex string)))))
399 (defun elmo-imap4-quotable-p (string)
400 "Return t if STRING can be formatted as a quoted defined in rfc2060."
402 (not (string-match elmo-imap4-non-text-char-regex string))))
404 (defun elmo-imap4-nil (string)
405 "Return a list represents the special atom \"NIL\" defined in rfc2060, \
407 Otherwise return nil."
411 (defun elmo-imap4-atom (string)
412 "Return a list represents STRING as an atom defined in rfc2060.
413 Return nil if STRING is not an atom. See `elmo-imap4-atom-p'."
414 (if (elmo-imap4-atom-p string)
415 (list 'atom string)))
417 (defun elmo-imap4-quoted (string)
418 "Return a list represents STRING as a quoted defined in rfc2060.
419 Return nil if STRING can not be formatted as a quoted. See `elmo-imap4-quotable-p'."
420 (if (elmo-imap4-quotable-p string)
421 (list 'quoted string)))
423 (defun elmo-imap4-literal-1 (string-or-buffer length)
424 "Internal function for `elmo-imap4-literal' and `elmo-imap4-buffer-literal'.
425 Return a list represents STRING-OR-BUFFER as a literal defined in rfc2060.
426 STRING-OR-BUFFER must be an encoded string or a single-byte string or a single-byte buffer.
427 LENGTH must be the number of octets for STRING-OR-BUFFER."
428 (list 'literal string-or-buffer length))
430 (defun elmo-imap4-literal (string)
431 "Return a list represents STRING as a literal defined in rfc2060.
432 STRING must be an encoded or a single-byte string."
433 (elmo-imap4-literal-1 string (length string)))
435 (defun elmo-imap4-buffer-literal (buffer)
436 "Return a list represents BUFFER as a literal defined in rfc2060.
437 BUFFER must be a single-byte buffer."
438 (elmo-imap4-literal-1 buffer (with-current-buffer buffer
441 (defun elmo-imap4-string-1 (string length)
442 "Internal function for `elmo-imap4-string' and `elmo-imap4-buffer-string'.
443 Return a list represents STRING as a string defined in rfc2060.
444 STRING must be an encoded or a single-byte string.
445 LENGTH must be the number of octets for STRING."
446 (or (elmo-imap4-quoted string)
447 (elmo-imap4-literal-1 string length)))
449 (defun elmo-imap4-string (string)
450 "Return a list represents STRING as a string defined in rfc2060.
451 STRING must be an encoded or a single-byte string."
452 (let ((length (length string)))
453 (if (< elmo-imap4-literal-threshold length)
454 (elmo-imap4-literal-1 string length)
455 (elmo-imap4-string-1 string length))))
457 (defun elmo-imap4-buffer-string (buffer)
458 "Return a list represents BUFFER as a string defined in rfc2060.
459 BUFFER must be a single-byte buffer."
460 (let ((length (with-current-buffer buffer
462 (if (< elmo-imap4-literal-threshold length)
463 (elmo-imap4-literal-1 buffer length)
464 (elmo-imap4-string-1 (with-current-buffer buffer
468 (defun elmo-imap4-astring-1 (string length)
469 "Internal function for `elmo-imap4-astring' and `elmo-imap4-buffer-astring'.
470 Return a list represents STRING as an astring defined in rfc2060.
471 STRING must be an encoded or a single-byte string.
472 LENGTH must be the number of octets for STRING."
473 (or (elmo-imap4-atom string)
474 (elmo-imap4-string-1 string length)))
476 (defun elmo-imap4-astring (string)
477 "Return a list represents STRING as an astring defined in rfc2060.
478 STRING must be an encoded or a single-byte string."
479 (let ((length (length string)))
480 (if (< elmo-imap4-literal-threshold length)
481 (elmo-imap4-literal-1 string length)
482 (elmo-imap4-astring-1 string length))))
484 (defun elmo-imap4-buffer-astring (buffer)
485 "Return a list represents BUFFER as an astring defined in rfc2060.
486 BUFFER must be a single-byte buffer."
487 (let ((length (with-current-buffer buffer
489 (if (< elmo-imap4-literal-threshold length)
490 (elmo-imap4-literal-1 buffer length)
491 (elmo-imap4-astring-1 (with-current-buffer buffer
495 (defun elmo-imap4-nstring (string)
496 "Return a list represents STRING as a nstring defined in rfc2060.
497 STRING must be an encoded or a single-byte string."
498 (or (elmo-imap4-nil string)
499 (elmo-imap4-string string)))
501 (defun elmo-imap4-buffer-nstring (buffer)
502 "Return a list represents BUFFER as a nstring defined in rfc2060.
503 BUFFER must be a single-byte buffer."
504 (or (elmo-imap4-nil buffer)
505 (elmo-imap4-buffer-string buffer)))
507 (defalias 'elmo-imap4-mailbox 'elmo-imap4-astring)
508 (defalias 'elmo-imap4-field-body 'elmo-imap4-astring)
509 (defalias 'elmo-imap4-userid 'elmo-imap4-astring)
510 (defalias 'elmo-imap4-password 'elmo-imap4-astring)
512 (defun elmo-imap4-format-quoted (string)
513 "Return STRING in a form of the quoted-string defined in rfc2060."
515 (std11-wrap-as-quoted-pairs string elmo-imap4-quoted-specials-list)
518 (defsubst elmo-imap4-response-get-selectable-mailbox-list (response)
522 (if (and (eq 'list (car entry))
523 (not (member "\\NoSelect" (nth 1 (nth 1 entry)))))
524 (car (nth 1 entry))))
528 (defun elmo-imap4-list-folders (spec &optional hierarchy)
529 (let* ((root (elmo-imap4-spec-mailbox spec))
530 (session (elmo-imap4-get-session spec))
533 (elmo-string-matched-assoc
535 (with-current-buffer (elmo-network-session-buffer session)
536 elmo-imap4-server-namespace)))
537 elmo-imap4-default-hierarchy-delimiter))
538 result append-serv type)
541 (not (string= root ""))
542 (not (string-match (concat "\\(.*\\)"
546 (setq root (concat root delim)))
547 (setq result (elmo-imap4-response-get-selectable-mailbox-list
548 (elmo-imap4-send-command-wait
550 (list "list " (elmo-imap4-mailbox root) " *"))))
551 (unless (string= (elmo-imap4-spec-username spec)
552 elmo-default-imap4-user)
553 (setq append-serv (concat ":" (elmo-imap4-spec-username spec))))
554 (unless (eq (elmo-imap4-spec-auth spec)
555 elmo-default-imap4-authenticate-type)
557 (concat append-serv "/" (symbol-name (elmo-imap4-spec-auth spec)))))
558 (unless (string= (elmo-imap4-spec-hostname spec)
559 elmo-default-imap4-server)
560 (setq append-serv (concat append-serv "@" (elmo-imap4-spec-hostname
562 (unless (eq (elmo-imap4-spec-port spec)
563 elmo-default-imap4-port)
564 (setq append-serv (concat append-serv ":"
566 (elmo-imap4-spec-port spec)))))
567 (setq type (elmo-imap4-spec-stream-type spec))
568 (unless (eq (elmo-network-stream-type-symbol type)
569 elmo-default-imap4-stream-type)
571 (setq append-serv (concat append-serv
572 (elmo-network-stream-type-spec-string
575 (let (folder folders ret)
576 (while (setq folders (car result))
579 (concat "^\\(" root "[^" delim "]" "+\\)" delim)
581 (setq folder (match-string 1 folders)))
584 (append ret (list (list
585 (concat "%" (elmo-imap4-decode-folder-string folder)
587 (eval append-serv)))))))
590 (mapcar '(lambda (fld)
593 (concat "^" (regexp-quote folder))
597 (setq ret (append ret (list
598 (concat "%" (elmo-imap4-decode-folder-string folders)
600 (eval append-serv))))))
601 (setq result (cdr result))))
603 (mapcar (lambda (fld)
604 (concat "%" (elmo-imap4-decode-folder-string fld)
606 (eval append-serv))))
609 (defun elmo-imap4-folder-exists-p (spec)
610 (let ((session (elmo-imap4-get-session spec)))
612 (elmo-imap4-session-current-mailbox-internal session)
613 (elmo-imap4-spec-mailbox spec))
615 (elmo-imap4-session-select-mailbox
617 (elmo-imap4-spec-mailbox spec)
620 (defun elmo-imap4-folder-creatable-p (spec)
623 (defun elmo-imap4-create-folder-maybe (spec dummy)
624 (unless (elmo-imap4-folder-exists-p spec)
625 (elmo-imap4-create-folder spec)))
627 (defun elmo-imap4-create-folder (spec)
628 (elmo-imap4-send-command-wait
629 (elmo-imap4-get-session spec)
630 (list "create " (elmo-imap4-mailbox
631 (elmo-imap4-spec-mailbox spec)))))
633 (defun elmo-imap4-delete-folder (spec)
634 (let ((session (elmo-imap4-get-session spec))
636 (when (elmo-imap4-spec-mailbox spec)
637 (when (setq msgs (elmo-imap4-list-folder spec))
638 (elmo-imap4-delete-msgs spec msgs))
639 ;; (elmo-imap4-send-command-wait session "close")
640 (elmo-imap4-send-command-wait
643 (elmo-imap4-mailbox (elmo-imap4-spec-mailbox spec)))))))
645 (defun elmo-imap4-rename-folder (old-spec new-spec)
646 ;;;(elmo-imap4-send-command-wait session "close")
647 (elmo-imap4-send-command-wait
648 (elmo-imap4-get-session old-spec)
651 (elmo-imap4-spec-mailbox old-spec))
654 (elmo-imap4-spec-mailbox new-spec)))))
656 (defun elmo-imap4-max-of-folder (spec)
657 (let ((session (elmo-imap4-get-session spec))
658 (killed (and elmo-use-killed-list
659 (elmo-msgdb-killed-list-load
660 (elmo-msgdb-expand-path spec))))
662 (with-current-buffer (elmo-network-session-buffer session)
663 (setq elmo-imap4-status-callback nil)
664 (setq elmo-imap4-status-callback-data nil))
665 (setq status (elmo-imap4-response-value
666 (elmo-imap4-send-command-wait
670 (elmo-imap4-spec-mailbox spec))
671 " (uidnext messages)"))
674 (- (elmo-imap4-response-value status 'uidnext) 1)
677 (elmo-imap4-response-value status 'messages)
678 (elmo-msgdb-killed-list-length killed))
679 (elmo-imap4-response-value status 'messages)))))
681 (defun elmo-imap4-folder-diff (spec folder &optional number-list)
682 (if elmo-use-server-diff
683 (elmo-imap4-server-diff spec)
684 (elmo-generic-folder-diff spec folder number-list)))
686 (defun elmo-imap4-get-session (spec &optional if-exists)
687 (elmo-network-get-session
690 (elmo-imap4-spec-hostname spec)
691 (elmo-imap4-spec-port spec)
692 (elmo-imap4-spec-username spec)
693 (elmo-imap4-spec-auth spec)
694 (elmo-imap4-spec-stream-type spec)
697 (defun elmo-imap4-commit (spec)
698 (if (elmo-imap4-plugged-p spec)
699 (let ((session (elmo-imap4-get-session spec 'if-exists)))
702 (elmo-imap4-session-current-mailbox-internal session)
703 (elmo-imap4-spec-mailbox spec))
704 (if elmo-imap4-use-select-to-update-status
705 (elmo-imap4-session-select-mailbox
707 (elmo-imap4-spec-mailbox spec)
709 (elmo-imap4-session-check session)))))))
711 (defun elmo-imap4-session-select-mailbox (session mailbox
712 &optional force no-error)
713 "Select MAILBOX in SESSION.
714 If optional argument FORCE is non-nil, select mailbox even if current mailbox
716 If second optional argument NO-ERROR is non-nil, don't cause an error when
717 selecting folder was failed.
718 Returns response value if selecting folder succeed. "
721 (elmo-imap4-session-current-mailbox-internal session)
723 (let (response result)
726 (elmo-imap4-read-response
728 (elmo-imap4-send-command
732 (elmo-imap4-mailbox mailbox)))))
733 (if (setq result (elmo-imap4-response-ok-p response))
735 (elmo-imap4-session-set-current-mailbox-internal session mailbox)
736 (elmo-imap4-session-set-read-only-internal
738 (nth 1 (assq 'read-only (assq 'ok response)))))
739 (elmo-imap4-session-set-current-mailbox-internal session nil)
742 (elmo-imap4-response-error-text response)
743 (format "Select %s failed" mailbox))))))
744 (and result response))))
746 (defun elmo-imap4-check-validity (spec validity-file)
748 ;;;(elmo-imap4-send-command-wait
749 ;;;(elmo-imap4-get-session spec)
751 ;;; (elmo-imap4-mailbox
752 ;;; (elmo-imap4-spec-mailbox spec))
753 ;;; " (uidvalidity)")))
756 (defun elmo-imap4-sync-validity (spec validity-file)
760 (defun elmo-imap4-list (spec flag)
761 (let ((session (elmo-imap4-get-session spec)))
762 (elmo-imap4-session-select-mailbox session
763 (elmo-imap4-spec-mailbox spec))
764 (elmo-imap4-response-value
765 (elmo-imap4-send-command-wait
767 (format (if elmo-imap4-use-uid "uid search %s"
771 (defun elmo-imap4-list-folder (spec)
772 (let ((killed (and elmo-use-killed-list
773 (elmo-msgdb-killed-list-load
774 (elmo-msgdb-expand-path spec))))
776 (setq numbers (elmo-imap4-list spec "all"))
777 (elmo-living-messages numbers killed)))
779 (defun elmo-imap4-list-folder-unread (spec number-alist mark-alist
781 (if (and (elmo-imap4-plugged-p spec)
782 (elmo-imap4-use-flag-p spec))
783 (elmo-imap4-list spec "unseen")
784 (elmo-generic-list-folder-unread spec number-alist mark-alist
787 (defun elmo-imap4-list-folder-important (spec number-alist)
788 (if (and (elmo-imap4-plugged-p spec)
789 (elmo-imap4-use-flag-p spec))
790 (elmo-imap4-list spec "flagged")))
792 (defmacro elmo-imap4-detect-search-charset (string)
795 (detect-mime-charset-region (point-min) (point-max)))))
797 (defun elmo-imap4-search-internal-primitive (spec session filter from-msgs)
798 (let ((search-key (elmo-filter-key filter))
799 (imap-search-keys '("bcc" "body" "cc" "from" "subject" "to"))
802 ((string= "last" search-key)
803 (let ((numbers (or from-msgs (elmo-imap4-list-folder spec))))
804 (nthcdr (max (- (length numbers)
805 (string-to-int (elmo-filter-value filter)))
808 ((string= "first" search-key)
809 (let* ((numbers (or from-msgs (elmo-imap4-list-folder spec)))
810 (rest (nthcdr (string-to-int (elmo-filter-value filter) )
812 (mapcar '(lambda (x) (delete x numbers)) rest)
814 ((or (string= "since" search-key)
815 (string= "before" search-key))
816 (setq search-key (concat "sent" search-key))
817 (elmo-imap4-response-value
818 (elmo-imap4-send-command-wait session
820 (if elmo-imap4-use-uid
821 "uid search %s%s%s %s"
825 (if elmo-imap4-use-uid "uid ")
828 (elmo-imap4-make-number-set-list
832 (if (eq (elmo-filter-type filter)
836 (elmo-date-get-description
837 (elmo-date-get-datevec
838 (elmo-filter-value filter)))))
842 (if (eq (length (elmo-filter-value filter)) 0)
843 (setq charset 'us-ascii)
844 (elmo-imap4-detect-search-charset
845 (elmo-filter-value filter))))
846 (elmo-imap4-response-value
847 (elmo-imap4-send-command-wait session
849 (if elmo-imap4-use-uid "uid ")
853 (symbol-name charset))
857 (if elmo-imap4-use-uid "uid ")
860 (elmo-imap4-make-number-set-list
864 (if (eq (elmo-filter-type filter)
869 (elmo-filter-key filter)
873 (elmo-filter-key filter))
875 (encode-mime-charset-string
876 (elmo-filter-value filter) charset))))
879 (defun elmo-imap4-search-internal (spec session condition from-msgs)
883 (setq result (elmo-imap4-search-internal-primitive
884 spec session condition from-msgs)))
885 ((eq (car condition) 'and)
886 (setq result (elmo-imap4-search-internal spec session (nth 1 condition)
888 result (elmo-list-filter result
889 (elmo-imap4-search-internal
890 spec session (nth 2 condition)
892 ((eq (car condition) 'or)
893 (setq result (elmo-imap4-search-internal
894 spec session (nth 1 condition) from-msgs)
895 result (elmo-uniq-list
897 (elmo-imap4-search-internal
898 spec session (nth 2 condition) from-msgs)))
899 result (sort result '<))))))
902 (defun elmo-imap4-search (spec condition &optional from-msgs)
904 (let ((session (elmo-imap4-get-session spec)))
905 (elmo-imap4-session-select-mailbox
907 (elmo-imap4-spec-mailbox spec))
908 (elmo-imap4-search-internal spec session condition from-msgs))))
910 (defun elmo-imap4-use-flag-p (spec)
911 (not (string-match elmo-imap4-disuse-server-flag-mailbox-regexp
912 (elmo-imap4-spec-mailbox spec))))
916 ;; Emacs can parse dot symbol.
917 (defvar elmo-imap4-rfc822-size "RFC822\.SIZE")
918 (defvar elmo-imap4-rfc822-text "RFC822\.TEXT")
919 (defvar elmo-imap4-rfc822-header "RFC822\.HEADER")
920 (defvar elmo-imap4-rfc822-size "RFC822\.SIZE")
921 (defvar elmo-imap4-header-fields "HEADER\.FIELDS")
922 (defmacro elmo-imap4-replace-dot-symbols ()) ;; noop
923 (defalias 'elmo-imap4-fetch-read 'read)
927 ;; Cannot parse dot symbol.
928 (defvar elmo-imap4-rfc822-size "RFC822_SIZE")
929 (defvar elmo-imap4-header-fields "HEADER_FIELDS")
930 (defvar elmo-imap4-rfc822-size "RFC822_SIZE")
931 (defvar elmo-imap4-rfc822-text "RFC822_TEXT")
932 (defvar elmo-imap4-rfc822-header "RFC822_HEADER")
933 (defvar elmo-imap4-header-fields "HEADER_FIELDS")
934 (defun elmo-imap4-fetch-read (buffer)
935 (with-current-buffer buffer
938 (when (re-search-forward "[[ ]" nil t)
939 (goto-char (match-beginning 0))
940 (setq token (buffer-substring beg (point)))
941 (cond ((string= token "RFC822.SIZE")
942 (intern elmo-imap4-rfc822-size))
943 ((string= token "RFC822.HEADER")
944 (intern elmo-imap4-rfc822-header))
945 ((string= token "RFC822.TEXT")
946 (intern elmo-imap4-rfc822-text))
947 ((string= token "HEADER\.FIELDS")
948 (intern elmo-imap4-header-fields))
950 (elmo-read (current-buffer))))))))))
952 (defun elmo-imap4-make-number-set-list (msg-list &optional chop-length)
953 "Make RFC2060's message set specifier from MSG-LIST.
954 Returns a list of (NUMBER . SET-STRING).
955 SET-STRING is the message set specifier described in RFC2060.
956 NUMBER is contained message number in SET-STRING.
957 Every SET-STRING does not contain number of messages longer than CHOP-LENGTH.
958 If CHOP-LENGTH is not specified, message set is not chopped."
959 (let (count cont-list set-list)
960 (setq msg-list (sort (copy-sequence msg-list) '<))
965 (setq chop-length (length msg-list)))
966 (while (and (not (null msg-list))
967 (< count chop-length))
969 (elmo-number-set-append
970 cont-list (car msg-list)))
972 (setq msg-list (cdr msg-list)))
980 (format "%s:%s" (car x) (cdr x)))
986 (nreverse set-list)))
990 ;; read-mark -> "\\Seen"
991 ;; important -> "\\Flagged"
993 ;; (delete -> \\Deleted)
994 (defun elmo-imap4-mark-set-on-msgs (spec msgs mark &optional unmark no-expunge)
995 "SET flag of MSGS as MARK.
996 If optional argument UNMARK is non-nil, unmark."
997 (let ((session (elmo-imap4-get-session spec))
999 (elmo-imap4-session-select-mailbox session
1000 (elmo-imap4-spec-mailbox spec))
1001 (setq set-list (elmo-imap4-make-number-set-list msgs))
1003 (with-current-buffer (elmo-network-session-buffer session)
1004 (setq elmo-imap4-fetch-callback nil)
1005 (setq elmo-imap4-fetch-callback-data nil))
1006 (elmo-imap4-send-command-wait
1009 (if elmo-imap4-use-uid
1010 "uid store %s %sflags.silent (%s)"
1011 "store %s %sflags.silent (%s)")
1012 (cdr (car set-list))
1016 (elmo-imap4-send-command-wait session "expunge")))
1019 (defun elmo-imap4-mark-as-important (spec msgs)
1020 (and (elmo-imap4-use-flag-p spec)
1021 (elmo-imap4-mark-set-on-msgs spec msgs "\\Flagged" nil 'no-expunge)))
1023 (defun elmo-imap4-mark-as-read (spec msgs)
1024 (and (elmo-imap4-use-flag-p spec)
1025 (elmo-imap4-mark-set-on-msgs spec msgs "\\Seen" nil 'no-expunge)))
1027 (defun elmo-imap4-unmark-important (spec msgs)
1028 (and (elmo-imap4-use-flag-p spec)
1029 (elmo-imap4-mark-set-on-msgs spec msgs "\\Flagged" 'unmark
1032 (defun elmo-imap4-mark-as-unread (spec msgs)
1033 (and (elmo-imap4-use-flag-p spec)
1034 (elmo-imap4-mark-set-on-msgs spec msgs "\\Seen" 'unmark 'no-expunge)))
1036 (defun elmo-imap4-delete-msgs (spec msgs)
1037 (elmo-imap4-mark-set-on-msgs spec msgs "\\Deleted"))
1039 (defun elmo-imap4-delete-msgs-no-expunge (spec msgs)
1040 (elmo-imap4-mark-set-on-msgs spec msgs "\\Deleted" nil 'no-expunge))
1042 (defun elmo-imap4-msgdb-create-as-numlist (spec numlist new-mark already-mark
1043 seen-mark important-mark
1045 "Create msgdb for SPEC for NUMLIST."
1046 (elmo-imap4-msgdb-create spec numlist new-mark already-mark
1047 seen-mark important-mark seen-list t))
1049 ;; Current buffer is process buffer.
1050 (defun elmo-imap4-fetch-callback (element app-data)
1051 (funcall elmo-imap4-fetch-callback
1053 (insert (or (elmo-imap4-response-bodydetail-text element)
1056 (goto-char (point-min))
1057 (while (search-forward "\r\n" nil t)
1058 (replace-match "\n"))
1059 (elmo-msgdb-create-overview-from-buffer
1060 (elmo-imap4-response-value element 'uid)
1061 (elmo-imap4-response-value element 'rfc822size)))
1062 (elmo-imap4-response-value element 'flags)
1067 ;; 0: new-mark 1: already-mark 2: seen-mark 3: important-mark
1068 ;; 4: seen-list 5: as-number
1069 (defun elmo-imap4-fetch-callback-1 (entity flags app-data)
1070 "A msgdb entity callback function."
1071 (let ((seen (member (car entity) (nth 4 app-data)))
1073 (if (member "\\Flagged" flags)
1074 (elmo-msgdb-global-mark-set (car entity) (nth 3 app-data)))
1075 (setq mark (or (elmo-msgdb-global-mark-get (car entity))
1076 (if (elmo-cache-exists-p (car entity)) ;; XXX
1077 (if (or (member "\\Seen" flags) seen)
1080 (if (or (member "\\Seen" flags) seen)
1081 (if elmo-imap4-use-cache
1083 (nth 0 app-data)))))
1084 (setq elmo-imap4-current-msgdb
1086 elmo-imap4-current-msgdb
1088 (list (cons (elmo-msgdb-overview-entity-get-number entity)
1092 (list (elmo-msgdb-overview-entity-get-number entity)
1095 (defun elmo-imap4-msgdb-create (spec numlist &rest args)
1096 "Create msgdb for SPEC."
1098 (let ((session (elmo-imap4-get-session spec))
1101 '("Subject" "From" "To" "Cc" "Date"
1102 "Message-Id" "References" "In-Reply-To")
1103 elmo-msgdb-extra-fields))
1105 (length (length numlist))
1107 (setq rfc2060 (memq 'imap4rev1
1108 (elmo-imap4-session-capability-internal
1110 (message "Getting overview...")
1111 (elmo-imap4-session-select-mailbox session
1112 (elmo-imap4-spec-mailbox spec))
1113 (setq set-list (elmo-imap4-make-number-set-list
1115 elmo-imap4-overview-fetch-chop-length))
1117 (with-current-buffer (elmo-network-session-buffer session)
1118 (setq elmo-imap4-current-msgdb nil
1119 elmo-imap4-fetch-callback 'elmo-imap4-fetch-callback-1
1120 elmo-imap4-fetch-callback-data args)
1122 (elmo-imap4-send-command-wait
1124 ;; get overview entity from IMAP4
1125 (format "%sfetch %s (%s rfc822.size flags)"
1126 (if elmo-imap4-use-uid "uid " "")
1127 (cdr (car set-list))
1129 (format "body.peek[header.fields %s]" headers)
1130 (format "%s" headers))))
1131 (when (> length elmo-display-progress-threshold)
1132 (setq total (+ total (car (car set-list))))
1133 (elmo-display-progress
1134 'elmo-imap4-msgdb-create "Getting overview..."
1135 (/ (* total 100) length)))
1136 (setq set-list (cdr set-list)))
1137 (message "Getting overview...done")
1138 elmo-imap4-current-msgdb))))
1140 (defun elmo-imap4-parse-capability (string)
1141 (if (string-match "^\\*\\(.*\\)$" string)
1143 (concat "(" (downcase (elmo-match-string 1 string)) ")"))))
1145 ;; Current buffer is process buffer.
1146 (defun elmo-imap4-auth-login (session)
1147 (let ((tag (elmo-imap4-send-command session "authenticate login"))
1148 (elmo-imap4-debug-inhibit-logging t))
1149 (or (elmo-imap4-read-continue-req session)
1150 (signal 'elmo-authenticate-error '(elmo-imap4-auth-login)))
1151 (elmo-imap4-send-string session
1152 (elmo-base64-encode-string
1153 (elmo-network-session-user-internal session)))
1154 (or (elmo-imap4-read-continue-req session)
1155 (signal 'elmo-authenticate-error '(elmo-imap4-auth-login)))
1156 (elmo-imap4-send-string session
1157 (elmo-base64-encode-string
1159 (elmo-network-session-password-key session))))
1160 (or (elmo-imap4-read-ok session tag)
1161 (signal 'elmo-authenticate-error '(elmo-imap4-auth-login)))
1162 (setq elmo-imap4-status 'auth)))
1164 (defun elmo-imap4-auth-cram-md5 (session)
1165 (let ((tag (elmo-imap4-send-command session "authenticate cram-md5"))
1166 (elmo-imap4-debug-inhibit-logging t)
1168 (or (setq response (elmo-imap4-read-continue-req session))
1169 (signal 'elmo-authenticate-error
1170 '(elmo-imap4-auth-cram-md5)))
1171 (elmo-imap4-send-string
1173 (elmo-base64-encode-string
1174 (sasl-cram-md5 (elmo-network-session-user-internal session)
1176 (elmo-network-session-password-key session))
1177 (elmo-base64-decode-string response))))
1178 (or (elmo-imap4-read-ok session tag)
1179 (signal 'elmo-authenticate-error '(elmo-imap4-auth-cram-md5)))))
1181 (defun elmo-imap4-auth-digest-md5 (session)
1182 (let ((tag (elmo-imap4-send-command session "authenticate digest-md5"))
1183 (elmo-imap4-debug-inhibit-logging t)
1185 (or (setq response (elmo-imap4-read-continue-req session))
1186 (signal 'elmo-authenticate-error '(elmo-imap4-auth-digest-md5)))
1187 (elmo-imap4-send-string
1189 (elmo-base64-encode-string
1190 (sasl-digest-md5-digest-response
1191 (elmo-base64-decode-string response)
1192 (elmo-network-session-user-internal session)
1193 (elmo-get-passwd (elmo-network-session-password-key session))
1195 (elmo-network-session-password-key session))
1197 (or (setq response (elmo-imap4-read-continue-req session))
1198 (signal 'elmo-authenticate-error '(elmo-imap4-auth-digest-md5)))
1199 (elmo-imap4-send-string session "")
1200 (or (elmo-imap4-read-ok session tag)
1201 (signal 'elmo-authenticate-error '(elmo-imap4-auth-digest-md5)))))
1203 (defun elmo-imap4-login (session)
1204 (let ((elmo-imap4-debug-inhibit-logging t))
1208 (elmo-imap4-send-command
1211 (elmo-imap4-userid (elmo-network-session-user-internal session))
1213 (elmo-imap4-password
1214 (elmo-get-passwd (elmo-network-session-password-key session))))))
1215 (signal 'elmo-authenticate-error '(login)))))
1218 (defconst sasl-imap4-login-steps
1219 '(sasl-imap4-login-response))
1221 (defun sasl-imap4-login-response (client step)
1223 (sasl-client-name client)
1225 (sasl-read-passphrase
1226 (format "LOGIN passphrase for %s: " (sasl-client-name client)))))
1228 (put 'sasl-imap4-login 'sasl-mechanism
1229 (sasl-make-mechanism "IMAP4-LOGIN" sasl-imap4-login-steps))
1231 (provide 'sasl-imap4-login)
1234 elmo-network-initialize-session-buffer :after ((session
1235 elmo-imap4-session) buffer)
1236 (with-current-buffer buffer
1237 (mapcar 'make-variable-buffer-local elmo-imap4-local-variables)
1238 (setq elmo-imap4-seqno 0)
1239 (setq elmo-imap4-status 'initial)))
1241 (luna-define-method elmo-network-initialize-session ((session
1242 elmo-imap4-session))
1243 (let ((process (elmo-network-session-process-internal session)))
1244 (with-current-buffer (process-buffer process)
1245 ;; Skip garbage output from process before greeting.
1246 (while (and (memq (process-status process) '(open run))
1247 (goto-char (point-max))
1249 (not (elmo-imap4-parse-greeting)))
1250 (accept-process-output process 1))
1251 (set-process-filter process 'elmo-imap4-arrival-filter)
1252 (set-process-sentinel process 'elmo-imap4-sentinel)
1253 ;;; (while (and (memq (process-status process) '(open run))
1254 ;;; (eq elmo-imap4-status 'initial))
1255 ;;; (message "Waiting for server response...")
1256 ;;; (accept-process-output process 1))
1258 (unless (memq elmo-imap4-status '(nonauth auth))
1259 (signal 'elmo-open-error
1260 (list 'elmo-network-initialize-session)))
1261 (elmo-imap4-session-set-capability-internal
1263 (elmo-imap4-response-value
1264 (elmo-imap4-send-command-wait session "capability")
1266 (when (eq (elmo-network-stream-type-symbol
1267 (elmo-network-session-stream-type-internal session))
1270 (elmo-imap4-session-capability-internal session))
1271 (signal 'elmo-open-error
1272 '(elmo-imap4-starttls-error)))
1273 (elmo-imap4-send-command-wait session "starttls")
1274 (starttls-negotiate process)))))
1276 (luna-define-method elmo-network-authenticate-session ((session
1277 elmo-imap4-session))
1278 (with-current-buffer (process-buffer
1279 (elmo-network-session-process-internal session))
1280 (let* ((auth (elmo-network-session-auth-internal session))
1281 (auth (mapcar '(lambda (a)
1285 (if (listp auth) auth (list auth)))))
1286 (unless (or (eq elmo-imap4-status 'auth)
1288 (let* ((elmo-imap4-debug-inhibit-logging t)
1289 (sasl-mechanism-alist
1291 sasl-mechanism-alist
1292 (list '("IMAP4-LOGIN" sasl-imap4-login))))
1296 (mapcar '(lambda (cap)
1297 (if (string-match "^auth=\\(.*\\)$"
1299 (match-string 1 (upcase (symbol-name cap)))))
1300 (elmo-imap4-session-capability-internal session)))
1301 (list "IMAP4-LOGIN")))
1304 (sasl-find-mechanism sasl-mechanisms)
1305 (sasl-find-mechanism
1307 (mapcar '(lambda (cap) (upcase (symbol-name cap)))
1311 client name step response tag
1312 sasl-read-passphrase)
1314 (if (or elmo-imap4-force-login
1317 "There's no %s capability in server. continue?"
1318 (elmo-list-to-string
1319 (elmo-network-session-auth-internal session)))))
1320 (setq mechanism (sasl-find-mechanism
1322 (signal 'elmo-authenticate-error '(elmo-imap4-auth-no-mechanisms))))
1326 (elmo-network-session-user-internal session)
1328 (elmo-network-session-host-internal session)))
1329 ;;; (if elmo-imap4-auth-user-realm
1330 ;;; (sasl-client-set-property client 'realm elmo-imap4-auth-user-realm))
1331 (setq name (sasl-mechanism-name mechanism)
1332 step (sasl-next-step client nil))
1333 (elmo-network-session-set-auth-internal session
1334 (intern (downcase name)))
1335 (setq sasl-read-passphrase
1339 (elmo-network-session-password-key session)))))
1340 (if (string= name "IMAP4-LOGIN")
1342 (elmo-imap4-send-command
1344 (concat "LOGIN " (sasl-step-data step))))
1346 (elmo-imap4-send-command
1348 (concat "AUTHENTICATE " name
1349 (and (sasl-step-data step)
1352 (elmo-base64-encode-string
1353 (sasl-step-data step)
1354 'no-lin-break)))))))
1357 (setq response (elmo-imap4-read-untagged
1358 (elmo-network-session-process-internal session)))
1360 (null (elmo-imap4-response-continue-req-p response))
1361 (elmo-imap4-response-ok-p response)
1362 (or (sasl-next-step client step)
1364 (signal 'elmo-authenticate-error
1366 (concat "elmo-imap4-auth-"
1367 (downcase name))))))
1370 (elmo-base64-decode-string
1371 (elmo-imap4-response-value response 'continue-req)))
1372 (setq step (sasl-next-step client step))
1374 (elmo-imap4-send-string
1376 (if (sasl-step-data step)
1377 (elmo-base64-encode-string (sasl-step-data step)
1381 (luna-define-method elmo-network-setup-session ((session
1382 elmo-imap4-session))
1383 (with-current-buffer (elmo-network-session-buffer session)
1384 (when (memq 'namespace (elmo-imap4-session-capability-internal session))
1385 (setq elmo-imap4-server-namespace
1386 (elmo-imap4-response-value
1387 (elmo-imap4-send-command-wait session "namespace")
1390 (defun elmo-imap4-setup-send-buffer (string)
1391 (let ((tmp-buf (get-buffer-create " *elmo-imap4-setup-send-buffer*")))
1394 (set-buffer tmp-buf)
1396 (elmo-set-buffer-multibyte nil)
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-read-part (folder msg part)
1408 (let* ((spec (elmo-folder-get-spec folder))
1409 (session (elmo-imap4-get-session spec)))
1410 (elmo-imap4-session-select-mailbox session
1411 (elmo-imap4-spec-mailbox spec))
1412 (with-current-buffer (elmo-network-session-buffer session)
1413 (setq elmo-imap4-fetch-callback nil)
1414 (setq elmo-imap4-fetch-callback-data nil))
1416 (elmo-imap4-response-bodydetail-text
1417 (elmo-imap4-response-value-all
1418 (elmo-imap4-send-command-wait session
1420 (if elmo-imap4-use-uid
1421 "uid fetch %s body.peek[%s]"
1422 "fetch %s body.peek[%s]")
1426 (defun elmo-imap4-prefetch-msg (spec msg outbuf)
1427 (elmo-imap4-read-msg spec msg outbuf 'unseen))
1429 (defun elmo-imap4-read-msg (spec msg outbuf
1430 &optional leave-seen-flag-untouched)
1431 (let ((session (elmo-imap4-get-session spec))
1433 (elmo-imap4-session-select-mailbox session
1434 (elmo-imap4-spec-mailbox spec))
1435 (with-current-buffer (elmo-network-session-buffer session)
1436 (setq elmo-imap4-fetch-callback nil)
1437 (setq elmo-imap4-fetch-callback-data nil))
1439 (elmo-imap4-send-command-wait session
1441 (if elmo-imap4-use-uid
1442 "uid fetch %s rfc822%s"
1443 "fetch %s rfc822%s")
1445 (if leave-seen-flag-untouched
1447 (and (setq response (elmo-imap4-response-value
1448 (elmo-imap4-response-value-all
1451 (with-current-buffer outbuf
1454 (elmo-delete-cr-get-content-type)))))
1456 (defun elmo-imap4-setup-send-buffer-from-file (file)
1457 (let ((tmp-buf (get-buffer-create
1458 " *elmo-imap4-setup-send-buffer-from-file*")))
1461 (set-buffer tmp-buf)
1463 (as-binary-input-file
1464 (insert-file-contents file))
1465 (goto-char (point-min))
1466 (if (eq (re-search-forward "^$" nil t)
1469 (goto-char (point-min))
1470 (while (search-forward "\n" nil t)
1471 (replace-match "\r\n"))))
1474 (defun elmo-imap4-delete-msgids (spec msgids)
1475 "If actual message-id is matched, then delete it."
1476 (let ((message-ids msgids)
1478 (num (length msgids)))
1481 (message "Deleting message...%d/%d" i num)
1482 (elmo-imap4-delete-msg-by-id spec (car message-ids))
1483 (setq message-ids (cdr message-ids)))
1484 (elmo-imap4-send-command-wait (elmo-imap4-get-session spec) "expunge")))
1486 (defun elmo-imap4-delete-msg-by-id (spec msgid)
1487 (let ((session (elmo-imap4-get-session spec)))
1488 (elmo-imap4-session-select-mailbox session
1489 (elmo-imap4-spec-mailbox spec))
1490 (elmo-imap4-delete-msgs-no-expunge
1492 (elmo-imap4-response-value
1493 (elmo-imap4-send-command-wait session
1495 (if elmo-imap4-use-uid
1496 "uid search header message-id "
1497 "search header message-id ")
1498 (elmo-imap4-field-body msgid)))
1501 (defun elmo-imap4-append-msg-by-id (spec msgid)
1502 (let ((session (elmo-imap4-get-session spec))
1504 (elmo-imap4-session-select-mailbox session
1505 (elmo-imap4-spec-mailbox spec))
1506 (setq send-buf (elmo-imap4-setup-send-buffer-from-file
1507 (elmo-cache-get-path msgid)))
1509 (elmo-imap4-send-command-wait
1513 (elmo-imap4-mailbox (elmo-imap4-spec-mailbox spec))
1515 (elmo-imap4-buffer-literal send-buf)))
1516 (kill-buffer send-buf)))
1519 (defun elmo-imap4-append-msg (spec string &optional msg no-see)
1520 (let ((session (elmo-imap4-get-session spec))
1522 (elmo-imap4-session-select-mailbox session
1523 (elmo-imap4-spec-mailbox spec))
1524 (setq send-buf (elmo-imap4-setup-send-buffer string))
1526 (elmo-imap4-send-command-wait
1530 (elmo-imap4-mailbox (elmo-imap4-spec-mailbox spec))
1531 (if no-see " " " (\\Seen) ")
1532 (elmo-imap4-buffer-literal send-buf)))
1533 (kill-buffer send-buf)))
1536 (defun elmo-imap4-copy-msgs (dst-spec
1537 msgs src-spec &optional expunge-it same-number)
1538 "Equivalence of hostname, username is assumed."
1539 (let ((session (elmo-imap4-get-session src-spec)))
1540 (elmo-imap4-session-select-mailbox session
1541 (elmo-imap4-spec-mailbox src-spec))
1543 (elmo-imap4-send-command-wait session
1546 (if elmo-imap4-use-uid
1551 (elmo-imap4-spec-mailbox dst-spec))))
1552 (setq msgs (cdr msgs)))
1554 (elmo-imap4-send-command-wait session "expunge"))
1557 (defun elmo-imap4-server-diff-async-callback-1 (status data)
1558 (funcall elmo-imap4-server-diff-async-callback
1559 (cons (elmo-imap4-response-value status 'unseen)
1560 (elmo-imap4-response-value status 'messages))
1563 (defun elmo-imap4-server-diff-async (spec)
1564 (let ((session (elmo-imap4-get-session spec)))
1566 ;; (elmo-imap4-commit spec)
1567 (with-current-buffer (elmo-network-session-buffer session)
1568 (setq elmo-imap4-status-callback
1569 'elmo-imap4-server-diff-async-callback-1)
1570 (setq elmo-imap4-status-callback-data
1571 elmo-imap4-server-diff-async-callback-data))
1572 (elmo-imap4-send-command session
1576 (elmo-imap4-spec-mailbox spec))
1577 " (unseen messages)"))))
1579 (defun elmo-imap4-server-diff (spec)
1581 (let ((session (elmo-imap4-get-session spec))
1584 ;;; (elmo-imap4-commit spec)
1585 (with-current-buffer (elmo-network-session-buffer session)
1586 (setq elmo-imap4-status-callback nil)
1587 (setq elmo-imap4-status-callback-data nil))
1589 (elmo-imap4-send-command-wait session
1593 (elmo-imap4-spec-mailbox spec))
1594 " (unseen messages)")))
1595 (setq response (elmo-imap4-response-value response 'status))
1596 (cons (elmo-imap4-response-value response 'unseen)
1597 (elmo-imap4-response-value response 'messages))))
1599 (defun elmo-imap4-use-cache-p (spec number)
1600 elmo-imap4-use-cache)
1602 (defun elmo-imap4-local-file-p (spec number)
1605 (defun elmo-imap4-port-label (spec)
1607 (if (elmo-imap4-spec-stream-type spec)
1608 (concat "!" (symbol-name
1609 (elmo-network-stream-type-symbol
1610 (elmo-imap4-spec-stream-type spec)))))))
1613 (defsubst elmo-imap4-portinfo (spec)
1614 (list (elmo-imap4-spec-hostname spec) (elmo-imap4-spec-port spec)))
1616 (defun elmo-imap4-plugged-p (spec)
1617 (apply 'elmo-plugged-p
1618 (append (elmo-imap4-portinfo spec)
1619 (list nil (quote (elmo-imap4-port-label spec))))))
1621 (defun elmo-imap4-set-plugged (spec plugged add)
1622 (apply 'elmo-set-plugged plugged
1623 (append (elmo-imap4-portinfo spec)
1624 (list nil nil (quote (elmo-imap4-port-label spec)) add))))
1626 (defalias 'elmo-imap4-sync-number-alist 'elmo-generic-sync-number-alist)
1630 (defvar elmo-imap4-server-eol "\r\n"
1631 "The EOL string sent from the server.")
1633 (defvar elmo-imap4-client-eol "\r\n"
1634 "The EOL string we send to the server.")
1636 (defun elmo-imap4-find-next-line ()
1637 "Return point at end of current line, taking into account literals.
1638 Return nil if no complete line has arrived."
1639 (when (re-search-forward (concat elmo-imap4-server-eol "\\|{\\([0-9]+\\)}"
1640 elmo-imap4-server-eol)
1642 (if (match-string 1)
1643 (if (< (point-max) (+ (point) (string-to-number (match-string 1))))
1645 (goto-char (+ (point) (string-to-number (match-string 1))))
1646 (elmo-imap4-find-next-line))
1649 (defun elmo-imap4-sentinel (process string)
1650 (delete-process process))
1652 (defun elmo-imap4-arrival-filter (proc string)
1653 "IMAP process filter."
1654 (with-current-buffer (process-buffer proc)
1655 (elmo-imap4-debug "-> %s" string)
1656 (goto-char (point-max))
1659 (goto-char (point-min))
1660 (while (setq end (elmo-imap4-find-next-line))
1662 (narrow-to-region (point-min) end)
1663 (delete-backward-char (length elmo-imap4-server-eol))
1664 (goto-char (point-min))
1666 (cond ((eq elmo-imap4-status 'initial)
1667 (setq elmo-imap4-current-response
1669 (list 'greeting (elmo-imap4-parse-greeting)))))
1670 ((or (eq elmo-imap4-status 'auth)
1671 (eq elmo-imap4-status 'nonauth)
1672 (eq elmo-imap4-status 'selected)
1673 (eq elmo-imap4-status 'examine))
1674 (setq elmo-imap4-current-response
1676 (elmo-imap4-parse-response)
1677 elmo-imap4-current-response)))
1679 (message "Unknown state %s in arrival filter"
1680 elmo-imap4-status))))
1681 (delete-region (point-min) (point-max)))))))
1685 (defsubst elmo-imap4-forward ()
1686 (or (eobp) (forward-char 1)))
1688 (defsubst elmo-imap4-parse-number ()
1689 (when (looking-at "[0-9]+")
1691 (string-to-number (match-string 0))
1692 (goto-char (match-end 0)))))
1694 (defsubst elmo-imap4-parse-literal ()
1695 (when (looking-at "{\\([0-9]+\\)}\r\n")
1696 (let ((pos (match-end 0))
1697 (len (string-to-number (match-string 1))))
1698 (if (< (point-max) (+ pos len))
1700 (goto-char (+ pos len))
1701 (buffer-substring pos (+ pos len))))))
1702 ;;; (list ' pos (+ pos len))))))
1704 (defsubst elmo-imap4-parse-string ()
1705 (cond ((eq (char-after (point)) ?\")
1707 (let ((p (point)) (name ""))
1708 (skip-chars-forward "^\"\\\\")
1709 (setq name (buffer-substring p (point)))
1710 (while (eq (char-after (point)) ?\\)
1711 (setq p (1+ (point)))
1713 (skip-chars-forward "^\"\\\\")
1714 (setq name (concat name (buffer-substring p (point)))))
1717 ((eq (char-after (point)) ?{)
1718 (elmo-imap4-parse-literal))))
1720 (defsubst elmo-imap4-parse-nil ()
1721 (if (looking-at "NIL")
1722 (goto-char (match-end 0))))
1724 (defsubst elmo-imap4-parse-nstring ()
1725 (or (elmo-imap4-parse-string)
1726 (and (elmo-imap4-parse-nil)
1729 (defsubst elmo-imap4-parse-astring ()
1730 (or (elmo-imap4-parse-string)
1731 (buffer-substring (point)
1732 (if (re-search-forward "[(){ \r\n%*\"\\]" nil t)
1733 (goto-char (1- (match-end 0)))
1737 (defsubst elmo-imap4-parse-address ()
1739 (when (eq (char-after (point)) ?\()
1740 (elmo-imap4-forward)
1741 (setq address (vector (prog1 (elmo-imap4-parse-nstring)
1742 (elmo-imap4-forward))
1743 (prog1 (elmo-imap4-parse-nstring)
1744 (elmo-imap4-forward))
1745 (prog1 (elmo-imap4-parse-nstring)
1746 (elmo-imap4-forward))
1747 (elmo-imap4-parse-nstring)))
1748 (when (eq (char-after (point)) ?\))
1749 (elmo-imap4-forward)
1752 (defsubst elmo-imap4-parse-address-list ()
1753 (if (eq (char-after (point)) ?\()
1754 (let (address addresses)
1755 (elmo-imap4-forward)
1756 (while (and (not (eq (char-after (point)) ?\)))
1757 ;; next line for MS Exchange bug
1758 (progn (and (eq (char-after (point)) ? ) (elmo-imap4-forward)) t)
1759 (setq address (elmo-imap4-parse-address)))
1760 (setq addresses (cons address addresses)))
1761 (when (eq (char-after (point)) ?\))
1762 (elmo-imap4-forward)
1763 (nreverse addresses)))
1764 (assert (elmo-imap4-parse-nil))))
1766 (defsubst elmo-imap4-parse-mailbox ()
1767 (let ((mailbox (elmo-imap4-parse-astring)))
1768 (if (string-equal "INBOX" (upcase mailbox))
1772 (defun elmo-imap4-parse-greeting ()
1773 "Parse a IMAP greeting."
1774 (cond ((looking-at "\\* OK ")
1775 (setq elmo-imap4-status 'nonauth))
1776 ((looking-at "\\* PREAUTH ")
1777 (setq elmo-imap4-status 'auth))
1778 ((looking-at "\\* BYE ")
1779 (setq elmo-imap4-status 'closed))))
1781 (defun elmo-imap4-parse-response ()
1782 "Parse a IMAP command response."
1784 (case (setq token (elmo-read (current-buffer)))
1786 (skip-chars-forward " ")
1787 (list 'continue-req (buffer-substring (point) (point-max)))))
1788 (* (case (prog1 (setq token (elmo-read (current-buffer)))
1789 (elmo-imap4-forward))
1790 (OK (elmo-imap4-parse-resp-text-code))
1791 (NO (elmo-imap4-parse-resp-text-code))
1792 (BAD (elmo-imap4-parse-resp-text-code))
1793 (BYE (elmo-imap4-parse-bye))
1795 (elmo-imap4-parse-flag-list)))
1796 (LIST (list 'list (elmo-imap4-parse-data-list)))
1797 (LSUB (list 'lsub (elmo-imap4-parse-data-list)))
1800 (elmo-read (concat "("
1801 (buffer-substring (point) (point-max))
1803 (STATUS (elmo-imap4-parse-status))
1805 (NAMESPACE (elmo-imap4-parse-namespace))
1806 (CAPABILITY (list 'capability
1808 (concat "(" (downcase (buffer-substring
1809 (point) (point-max)))
1811 (ACL (elmo-imap4-parse-acl))
1812 (t (case (prog1 (elmo-read (current-buffer))
1813 (elmo-imap4-forward))
1814 (EXISTS (list 'exists token))
1815 (RECENT (list 'recent token))
1816 (EXPUNGE (list 'expunge token))
1817 (FETCH (elmo-imap4-parse-fetch token))
1818 (t (list 'garbage (buffer-string)))))))
1819 (t (if (not (string-match elmo-imap4-seq-prefix (symbol-name token)))
1820 (list 'garbage (buffer-string))
1821 (case (prog1 (elmo-read (current-buffer))
1822 (elmo-imap4-forward))
1824 (setq elmo-imap4-parsing nil)
1825 (setq token (symbol-name token))
1826 (elmo-unintern token)
1827 (elmo-imap4-debug "*%s* OK arrived" token)
1828 (setq elmo-imap4-reached-tag token)
1829 (list 'ok (elmo-imap4-parse-resp-text-code))))
1831 (setq elmo-imap4-parsing nil)
1832 (setq token (symbol-name token))
1833 (elmo-unintern token)
1834 (elmo-imap4-debug "*%s* NO arrived" token)
1835 (setq elmo-imap4-reached-tag token)
1837 (when (eq (char-after (point)) ?\[)
1838 (setq code (buffer-substring (point)
1839 (search-forward "]")))
1840 (elmo-imap4-forward))
1841 (setq text (buffer-substring (point) (point-max)))
1842 (list 'no (list code text)))))
1844 (setq elmo-imap4-parsing nil)
1845 (elmo-imap4-debug "*%s* BAD arrived" token)
1846 (setq token (symbol-name token))
1847 (elmo-unintern token)
1848 (setq elmo-imap4-reached-tag token)
1850 (when (eq (char-after (point)) ?\[)
1851 (setq code (buffer-substring (point)
1852 (search-forward "]")))
1853 (elmo-imap4-forward))
1854 (setq text (buffer-substring (point) (point-max)))
1855 (list 'bad (list code text)))))
1856 (t (list 'garbage (buffer-string)))))))))
1858 (defun elmo-imap4-parse-bye ()
1860 (when (eq (char-after (point)) ?\[)
1861 (setq code (buffer-substring (point)
1862 (search-forward "]")))
1863 (elmo-imap4-forward))
1864 (setq text (buffer-substring (point) (point-max)))
1865 (list 'bye (list code text))))
1867 (defun elmo-imap4-parse-text ()
1868 (goto-char (point-min))
1869 (when (search-forward "[" nil t)
1870 (search-forward "]")
1871 (elmo-imap4-forward))
1872 (list 'text (buffer-substring (point) (point-max))))
1874 (defun elmo-imap4-parse-resp-text-code ()
1875 (when (eq (char-after (point)) ?\[)
1876 (elmo-imap4-forward)
1877 (cond ((search-forward "PERMANENTFLAGS " nil t)
1878 (list 'permanentflags (elmo-imap4-parse-flag-list)))
1879 ((search-forward "UIDNEXT " nil t)
1880 (list 'uidnext (elmo-read (current-buffer))))
1881 ((search-forward "UNSEEN " nil t)
1882 (list 'unseen (elmo-read (current-buffer))))
1883 ((looking-at "UIDVALIDITY \\([0-9]+\\)")
1884 (list 'uidvalidity (match-string 1)))
1885 ((search-forward "READ-ONLY" nil t)
1886 (list 'read-only t))
1887 ((search-forward "READ-WRITE" nil t)
1888 (list 'read-write t))
1889 ((search-forward "NEWNAME " nil t)
1890 (let (oldname newname)
1891 (setq oldname (elmo-imap4-parse-string))
1892 (elmo-imap4-forward)
1893 (setq newname (elmo-imap4-parse-string))
1894 (list 'newname newname oldname)))
1895 ((search-forward "TRYCREATE" nil t)
1896 (list 'trycreate t))
1897 ((looking-at "APPENDUID \\([0-9]+\\) \\([0-9]+\\)")
1899 (list (match-string 1)
1900 (string-to-number (match-string 2)))))
1901 ((looking-at "COPYUID \\([0-9]+\\) \\([0-9,:]+\\) \\([0-9,:]+\\)")
1902 (list 'copyuid (list (match-string 1)
1905 ((search-forward "ALERT] " nil t)
1906 (message "IMAP server information: %s"
1907 (buffer-substring (point) (point-max))))
1908 (t (list 'unknown)))))
1910 (defun elmo-imap4-parse-data-list ()
1911 (let (flags delimiter mailbox)
1912 (setq flags (elmo-imap4-parse-flag-list))
1913 (when (looking-at " NIL\\| \"\\\\?\\(.\\)\"")
1914 (setq delimiter (match-string 1))
1915 (goto-char (1+ (match-end 0)))
1916 (when (setq mailbox (elmo-imap4-parse-mailbox))
1917 (list mailbox flags delimiter)))))
1919 (defsubst elmo-imap4-parse-header-list ()
1920 (when (eq (char-after (point)) ?\()
1922 (while (not (eq (char-after (point)) ?\)))
1923 (elmo-imap4-forward)
1924 (push (elmo-imap4-parse-astring) strlist))
1925 (elmo-imap4-forward)
1926 (nreverse strlist))))
1928 (defsubst elmo-imap4-parse-fetch-body-section ()
1930 (buffer-substring (point)
1932 (progn (re-search-forward "[] ]" nil t)
1934 (if (eq (char-before) ? )
1936 (mapconcat 'identity
1937 (cons section (elmo-imap4-parse-header-list)) " ")
1938 (search-forward "]" nil t))
1941 (defun elmo-imap4-parse-fetch (response)
1942 (when (eq (char-after (point)) ?\()
1944 (while (not (eq (char-after (point)) ?\)))
1945 (elmo-imap4-forward)
1946 (let ((token (elmo-imap4-fetch-read (current-buffer))))
1947 (elmo-imap4-forward)
1949 (cond ((eq token 'UID)
1950 (list 'uid (condition-case nil
1951 (elmo-read (current-buffer))
1954 (list 'flags (elmo-imap4-parse-flag-list)))
1955 ((eq token 'ENVELOPE)
1956 (list 'envelope (elmo-imap4-parse-envelope)))
1957 ((eq token 'INTERNALDATE)
1958 (list 'internaldate (elmo-imap4-parse-string)))
1960 (list 'rfc822 (elmo-imap4-parse-nstring)))
1961 ((eq token (intern elmo-imap4-rfc822-header))
1962 (list 'rfc822header (elmo-imap4-parse-nstring)))
1963 ((eq token (intern elmo-imap4-rfc822-text))
1964 (list 'rfc822text (elmo-imap4-parse-nstring)))
1965 ((eq token (intern elmo-imap4-rfc822-size))
1966 (list 'rfc822size (elmo-read (current-buffer))))
1968 (if (eq (char-before) ?\[)
1971 (upcase (elmo-imap4-parse-fetch-body-section))
1973 (eq (char-after (point)) ?<)
1974 (buffer-substring (1+ (point))
1976 (search-forward ">" nil t)
1978 (progn (elmo-imap4-forward)
1979 (elmo-imap4-parse-nstring)))
1980 (list 'body (elmo-imap4-parse-body))))
1981 ((eq token 'BODYSTRUCTURE)
1982 (list 'bodystructure (elmo-imap4-parse-body)))))
1983 (setq list (cons element list))))
1984 (and elmo-imap4-fetch-callback
1985 (elmo-imap4-fetch-callback list elmo-imap4-fetch-callback-data))
1986 (list 'fetch list))))
1988 (defun elmo-imap4-parse-status ()
1989 (let ((mailbox (elmo-imap4-parse-mailbox))
1991 (when (and mailbox (search-forward "(" nil t))
1992 (while (not (eq (char-after (point)) ?\)))
1995 (let ((token (elmo-read (current-buffer))))
1996 (cond ((eq token 'MESSAGES)
1997 (list 'messages (elmo-read (current-buffer))))
1999 (list 'recent (elmo-read (current-buffer))))
2000 ((eq token 'UIDNEXT)
2001 (list 'uidnext (elmo-read (current-buffer))))
2002 ((eq token 'UIDVALIDITY)
2003 (and (looking-at " \\([0-9]+\\)")
2004 (prog1 (list 'uidvalidity (match-string 1))
2005 (goto-char (match-end 1)))))
2007 (list 'unseen (elmo-read (current-buffer))))
2010 "Unknown status data %s in mailbox %s ignored"
2013 (and elmo-imap4-status-callback
2014 (funcall elmo-imap4-status-callback
2016 elmo-imap4-status-callback-data))
2017 (list 'status status)))
2020 (defmacro elmo-imap4-value (value)
2021 (` (if (eq (, value) 'NIL) nil
2024 (defmacro elmo-imap4-nth (pos list)
2025 (` (let ((value (nth (, pos) (, list))))
2026 (elmo-imap4-value value))))
2028 (defun elmo-imap4-parse-namespace ()
2031 (copy-sequence elmo-imap4-extra-namespace-alist)
2032 (elmo-imap4-parse-namespace-subr
2033 (elmo-read (concat "(" (buffer-substring
2034 (point) (point-max))
2037 (defun elmo-imap4-parse-namespace-subr (ns)
2038 (let (prefix delim namespace-alist default-delim)
2039 ;; 0: personal, 1: other, 2: shared
2041 (setq namespace-alist
2042 (nconc namespace-alist
2046 (setq prefix (elmo-imap4-nth 0 namespace)
2047 delim (elmo-imap4-nth 1 namespace))
2048 (if (and prefix delim
2050 (concat (regexp-quote delim) "\\'")
2052 (setq prefix (substring prefix 0
2053 (match-beginning 0))))
2054 (if (eq (length prefix) 0)
2055 (progn (setq default-delim delim) nil)
2058 (if (string= (downcase prefix) "inbox")
2059 "[Ii][Nn][Bb][Oo][Xx]"
2060 (regexp-quote prefix))
2063 (elmo-imap4-nth i ns))))))
2065 (setq namespace-alist
2066 (nconc namespace-alist
2067 (list (cons "^.*$" default-delim)))))
2070 (defun elmo-imap4-parse-acl ()
2071 (let ((mailbox (elmo-imap4-parse-mailbox))
2072 identifier rights acl)
2073 (while (eq (char-after (point)) ?\ )
2074 (elmo-imap4-forward)
2075 (setq identifier (elmo-imap4-parse-astring))
2076 (elmo-imap4-forward)
2077 (setq rights (elmo-imap4-parse-astring))
2078 (setq acl (append acl (list (cons identifier rights)))))
2079 (list 'acl acl mailbox)))
2081 (defun elmo-imap4-parse-flag-list ()
2082 (let ((str (buffer-substring (+ (point) 1)
2083 (progn (search-forward ")" nil t)
2085 (unless (eq (length str) 0)
2086 (split-string str))))
2088 (defun elmo-imap4-parse-envelope ()
2089 (when (eq (char-after (point)) ?\()
2090 (elmo-imap4-forward)
2091 (vector (prog1 (elmo-imap4-parse-nstring);; date
2092 (elmo-imap4-forward))
2093 (prog1 (elmo-imap4-parse-nstring);; subject
2094 (elmo-imap4-forward))
2095 (prog1 (elmo-imap4-parse-address-list);; from
2096 (elmo-imap4-forward))
2097 (prog1 (elmo-imap4-parse-address-list);; sender
2098 (elmo-imap4-forward))
2099 (prog1 (elmo-imap4-parse-address-list);; reply-to
2100 (elmo-imap4-forward))
2101 (prog1 (elmo-imap4-parse-address-list);; to
2102 (elmo-imap4-forward))
2103 (prog1 (elmo-imap4-parse-address-list);; cc
2104 (elmo-imap4-forward))
2105 (prog1 (elmo-imap4-parse-address-list);; bcc
2106 (elmo-imap4-forward))
2107 (prog1 (elmo-imap4-parse-nstring);; in-reply-to
2108 (elmo-imap4-forward))
2109 (prog1 (elmo-imap4-parse-nstring);; message-id
2110 (elmo-imap4-forward)))))
2112 (defsubst elmo-imap4-parse-string-list ()
2113 (cond ((eq (char-after (point)) ?\();; body-fld-param
2115 (elmo-imap4-forward)
2116 (while (setq str (elmo-imap4-parse-string))
2118 (elmo-imap4-forward))
2119 (nreverse strlist)))
2120 ((elmo-imap4-parse-nil)
2123 (defun elmo-imap4-parse-body-extension ()
2124 (if (eq (char-after (point)) ?\()
2126 (elmo-imap4-forward)
2127 (push (elmo-imap4-parse-body-extension) b-e)
2128 (while (eq (char-after (point)) ?\ )
2129 (elmo-imap4-forward)
2130 (push (elmo-imap4-parse-body-extension) b-e))
2131 (assert (eq (char-after (point)) ?\)))
2132 (elmo-imap4-forward)
2134 (or (elmo-imap4-parse-number)
2135 (elmo-imap4-parse-nstring))))
2137 (defsubst elmo-imap4-parse-body-ext ()
2139 (when (eq (char-after (point)) ?\ );; body-fld-dsp
2140 (elmo-imap4-forward)
2142 (if (eq (char-after (point)) ?\()
2144 (elmo-imap4-forward)
2145 (push (elmo-imap4-parse-string) dsp)
2146 (elmo-imap4-forward)
2147 (push (elmo-imap4-parse-string-list) dsp)
2148 (elmo-imap4-forward))
2149 (assert (elmo-imap4-parse-nil)))
2150 (push (nreverse dsp) ext))
2151 (when (eq (char-after (point)) ?\ );; body-fld-lang
2152 (elmo-imap4-forward)
2153 (if (eq (char-after (point)) ?\()
2154 (push (elmo-imap4-parse-string-list) ext)
2155 (push (elmo-imap4-parse-nstring) ext))
2156 (while (eq (char-after (point)) ?\ );; body-extension
2157 (elmo-imap4-forward)
2158 (setq ext (append (elmo-imap4-parse-body-extension) ext)))))
2161 (defun elmo-imap4-parse-body ()
2163 (when (eq (char-after (point)) ?\()
2164 (elmo-imap4-forward)
2165 (if (eq (char-after (point)) ?\()
2167 (while (and (eq (char-after (point)) ?\()
2168 (setq subbody (elmo-imap4-parse-body)))
2169 (push subbody body))
2170 (elmo-imap4-forward)
2171 (push (elmo-imap4-parse-string) body);; media-subtype
2172 (when (eq (char-after (point)) ?\ );; body-ext-mpart:
2173 (elmo-imap4-forward)
2174 (if (eq (char-after (point)) ?\();; body-fld-param
2175 (push (elmo-imap4-parse-string-list) body)
2176 (push (and (elmo-imap4-parse-nil) nil) body))
2178 (append (elmo-imap4-parse-body-ext) body)));; body-ext-...
2179 (assert (eq (char-after (point)) ?\)))
2180 (elmo-imap4-forward)
2183 (push (elmo-imap4-parse-string) body);; media-type
2184 (elmo-imap4-forward)
2185 (push (elmo-imap4-parse-string) body);; media-subtype
2186 (elmo-imap4-forward)
2187 ;; next line for Sun SIMS bug
2188 (and (eq (char-after (point)) ? ) (elmo-imap4-forward))
2189 (if (eq (char-after (point)) ?\();; body-fld-param
2190 (push (elmo-imap4-parse-string-list) body)
2191 (push (and (elmo-imap4-parse-nil) nil) body))
2192 (elmo-imap4-forward)
2193 (push (elmo-imap4-parse-nstring) body);; body-fld-id
2194 (elmo-imap4-forward)
2195 (push (elmo-imap4-parse-nstring) body);; body-fld-desc
2196 (elmo-imap4-forward)
2197 (push (elmo-imap4-parse-string) body);; body-fld-enc
2198 (elmo-imap4-forward)
2199 (push (elmo-imap4-parse-number) body);; body-fld-octets
2201 ;; ok, we're done parsing the required parts, what comes now is one
2204 ;; envelope (then we're parsing body-type-msg)
2205 ;; body-fld-lines (then we're parsing body-type-text)
2206 ;; body-ext-1part (then we're parsing body-type-basic)
2208 ;; the problem is that the two first are in turn optionally followed
2209 ;; by the third. So we parse the first two here (if there are any)...
2211 (when (eq (char-after (point)) ?\ )
2212 (elmo-imap4-forward)
2214 (cond ((eq (char-after (point)) ?\();; body-type-msg:
2215 (push (elmo-imap4-parse-envelope) body);; envelope
2216 (elmo-imap4-forward)
2217 (push (elmo-imap4-parse-body) body);; body
2218 (elmo-imap4-forward)
2219 (push (elmo-imap4-parse-number) body));; body-fld-lines
2220 ((setq lines (elmo-imap4-parse-number));; body-type-text:
2221 (push lines body));; body-fld-lines
2223 (backward-char)))));; no match...
2225 ;; ...and then parse the third one here...
2227 (when (eq (char-after (point)) ?\ );; body-ext-1part:
2228 (elmo-imap4-forward)
2229 (push (elmo-imap4-parse-nstring) body);; body-fld-md5
2231 (append (elmo-imap4-parse-body-ext) body)));; body-ext-1part..
2233 (assert (eq (char-after (point)) ?\)))
2234 (elmo-imap4-forward)
2238 (product-provide (provide 'elmo-imap4) (require 'elmo-version))
2240 ;;; elmo-imap4.el ends here