1 ;;; elmo-imap4.el -- IMAP4 Interface for ELMO.
3 ;; Copyright 1998,1999,2000 Yuuichi Teranishi <teranisi@gohome.org>
5 ;; Author: Yuuichi Teranishi <teranisi@gohome.org>
6 ;; Keywords: mail, net news
8 ;; This file is part of ELMO (Elisp Library for Message Orchestration).
10 ;; This program is free software; you can redistribute it and/or modify
11 ;; it under the terms of the GNU General Public License as published by
12 ;; the Free Software Foundation; either version 2, or (at your option)
15 ;; This program is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING. If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
41 ;; silence byte compiler.
49 (defun-maybe sasl-cram-md5 (username passphrase challenge))
50 (defun-maybe sasl-digest-md5-digest-response
51 (digest-challenge username passwd serv-type host &optional realm))
52 (defun-maybe starttls-negotiate (a))
53 (defun-maybe elmo-generic-list-folder-unread (spec mark-alist unread-marks))
54 (defsubst-maybe utf7-decode-string (string &optional imap) string))
56 (defvar elmo-imap4-use-lock t
57 "USE IMAP4 with locking process.")
61 (defvar elmo-imap4-seq-prefix "elmo-imap4")
62 (defvar elmo-imap4-seqno 0)
63 (defvar elmo-imap4-connection-cache nil
64 "Cache of imap connection.")
65 (defvar elmo-imap4-use-uid t
66 "Use UID as message number.")
68 ;; buffer local variable
69 (defvar elmo-imap4-read-point 0)
71 (defvar elmo-imap4-extra-namespace-alist
72 '(("^{.*/nntp}.*$" . ".")) ; Default is for UW's remote nntp mailbox...
73 "Extra namespace alist. A list of cons cell like: (REGEXP . DELIMITER) ")
75 ;; buffer local variable
76 (defvar elmo-imap4-server-capability nil)
77 (defvar elmo-imap4-server-namespace nil)
79 (defvar elmo-imap4-lock nil)
82 (defvar elmo-imap4-debug nil
83 "Non-nil forces IMAP4 folder as debug mode.
84 Debug information is inserted in the buffer \"*IMAP4 DEBUG*\"")
86 (defsubst elmo-imap4-debug (message &rest args)
88 (with-current-buffer (get-buffer-create "*IMAP4 DEBUG*")
89 (goto-char (point-max))
90 (insert (apply 'format message args) "\n"))))
92 (defun elmo-imap4-flush-connection ()
94 (let ((cache elmo-imap4-connection-cache)
97 (setq buffer (car (cdr (car cache))))
98 (if buffer (kill-buffer buffer))
99 (setq process (car (cdr (cdr (car cache)))))
100 (if process (delete-process process))
101 (setq cache (cdr cache)))
102 (setq elmo-imap4-connection-cache nil)))
104 (defsubst elmo-imap4-get-process (spec)
105 (elmo-imap4-connection-get-process (elmo-imap4-get-connection spec)))
107 (defun elmo-imap4-process-folder-list (string)
109 (let ((case-fold-search t)
111 (elmo-set-buffer-multibyte nil)
113 (goto-char (point-min))
114 ;; XXX This doesn't consider literal name response.
115 (while (re-search-forward
116 "\\* LIST (\\([^)]*\\)) \"[^\"]*\" \\([^\n]*\\)$" nil t)
117 (unless (string-match "noselect"
118 (elmo-match-buffer 1))
119 (setq val (elmo-match-buffer 2))
120 (if (string-match "^\"\\(.*\\)\"$" val)
121 (setq val (match-string 1 val)))
127 (defun elmo-imap4-list-folders (spec &optional hierarchy)
129 (let* ((root (elmo-imap4-spec-folder spec))
130 (process (elmo-imap4-get-process spec))
133 (elmo-string-matched-assoc root
136 (process-buffer process))
137 elmo-imap4-server-namespace)))
139 response result append-serv ssl)
142 (not (string= root ""))
143 (not (string-match (concat "\\(.*\\)"
147 (setq root (concat root delim)))
148 (elmo-imap4-send-command (process-buffer process)
150 (format "list \"%s\" *" root))
151 (setq response (elmo-imap4-read-response (process-buffer process)
153 (setq result (elmo-imap4-process-folder-list response))
154 (unless (string= (elmo-imap4-spec-username spec)
155 elmo-default-imap4-user)
156 (setq append-serv (concat ":" (elmo-imap4-spec-username spec))))
157 (unless (string= (elmo-imap4-spec-hostname spec)
158 elmo-default-imap4-server)
159 (setq append-serv (concat append-serv "@" (elmo-imap4-spec-hostname
161 (unless (eq (elmo-imap4-spec-port spec)
162 elmo-default-imap4-port)
163 (setq append-serv (concat append-serv ":"
165 (elmo-imap4-spec-port spec)))))
166 (unless (eq (setq ssl (elmo-imap4-spec-ssl spec))
167 elmo-default-imap4-ssl)
169 (setq append-serv (concat append-serv "!")))
170 (if (eq ssl 'starttls)
171 (setq append-serv (concat append-serv "!"))))
172 (mapcar '(lambda (fld)
173 (concat "%" (elmo-imap4-decode-folder-string fld)
175 (eval append-serv))))
178 (defun elmo-imap4-folder-exists-p (spec)
179 (let ((process (elmo-imap4-get-process spec)))
180 (elmo-imap4-send-command (process-buffer process)
182 (format "status \"%s\" (messages)"
183 (elmo-imap4-spec-folder spec)))
184 (elmo-imap4-read-response (process-buffer process) process)))
186 (defun elmo-imap4-folder-creatable-p (spec)
189 (defun elmo-imap4-create-folder-maybe (spec dummy)
190 "Create folder if necessary."
191 (if (not (elmo-imap4-folder-exists-p spec))
192 (elmo-imap4-create-folder spec)))
194 (defun elmo-imap4-create-folder (spec)
195 (let ((process (elmo-imap4-get-process spec))
196 (folder (elmo-imap4-spec-folder spec)))
198 ;; For UW imapd 4.6, this workaround is needed to create #mh mailbox.
199 ; (if (string-match "^\\(#mh/\\).*[^/]$" folder)
200 ; (setq folder (concat folder "/"))) ;; make directory
201 (elmo-imap4-send-command (process-buffer process)
203 (format "create %s" folder))
204 (if (null (elmo-imap4-read-response (process-buffer process)
206 (error "Create folder %s failed" folder)
209 (defun elmo-imap4-delete-folder (spec)
210 (let ((process (elmo-imap4-get-process spec))
212 (when (elmo-imap4-spec-folder spec)
213 (when (setq msgs (elmo-imap4-list-folder spec))
214 (elmo-imap4-delete-msgs spec msgs))
215 (elmo-imap4-send-command (process-buffer process) process "close")
216 (elmo-imap4-read-response (process-buffer process) process)
217 (elmo-imap4-send-command (process-buffer process)
220 (elmo-imap4-spec-folder spec)))
221 (if (null (elmo-imap4-read-response (process-buffer process)
223 (error "Delete folder %s failed" (elmo-imap4-spec-folder spec))
226 (defun elmo-imap4-rename-folder (old-spec new-spec)
227 (let ((process (elmo-imap4-get-process old-spec)))
228 (when (elmo-imap4-spec-folder old-spec)
229 (elmo-imap4-send-command (process-buffer process) process "close")
230 (elmo-imap4-read-response (process-buffer process) process)
231 (elmo-imap4-send-command (process-buffer process)
233 (format "rename %s %s"
234 (elmo-imap4-spec-folder old-spec)
235 (elmo-imap4-spec-folder new-spec)))
236 (if (null (elmo-imap4-read-response (process-buffer process) process))
237 (error "Rename folder from %s to %s failed"
238 (elmo-imap4-spec-folder old-spec)
239 (elmo-imap4-spec-folder new-spec))
242 (defun elmo-imap4-max-of-folder (spec)
244 (let* ((process (elmo-imap4-get-process spec))
246 (elmo-imap4-send-command (process-buffer process)
248 (format "status \"%s\" (uidnext messages)"
249 (elmo-imap4-spec-folder spec)))
250 (setq response (elmo-imap4-read-response (process-buffer process)
252 (when (and response (string-match
253 "\\* STATUS [^(]* \\(([^)]*)\\)" response))
254 (setq response (read (downcase (elmo-match-string 1 response))))
255 (cons (- (cadr (memq 'uidnext response)) 1)
256 (cadr (memq 'messages response)))))))
258 (defun elmo-imap4-get-connection (spec)
259 (let* ((user (elmo-imap4-spec-username spec))
260 (server (elmo-imap4-spec-hostname spec))
261 (port (elmo-imap4-spec-port spec))
262 (auth (elmo-imap4-spec-auth spec))
263 (ssl (elmo-imap4-spec-ssl spec))
264 (user-at-host (format "%s@%s" user server))
265 ret-val result buffer process proc-stat
266 user-at-host-on-port)
267 (if (not (elmo-plugged-p server port))
269 (setq user-at-host-on-port
270 (concat user-at-host ":" (int-to-string port)
271 (if (eq ssl 'starttls) "!!" (if ssl "!"))))
272 (setq ret-val (assoc user-at-host-on-port
273 elmo-imap4-connection-cache))
275 (or (eq (setq proc-stat
276 (process-status (cadr (cdr ret-val))))
278 (eq proc-stat 'exit)))
279 ;; connection is closed...
281 (kill-buffer (car (cdr ret-val)))
282 (setq elmo-imap4-connection-cache
283 (delete ret-val elmo-imap4-connection-cache))
287 (setq ret-val (cdr ret-val)) ;; connection cache exists.
290 (elmo-imap4-open-connection server user auth port
291 (elmo-get-passwd user-at-host)
294 (error "Connection failed"))
295 (elmo-imap4-debug "Connected to %s" user-at-host-on-port)
296 (setq buffer (car result))
297 (setq process (cdr result))
298 (when (and process (null buffer))
299 (elmo-remove-passwd user-at-host)
300 (delete-process process)
301 (error "Login failed"))
302 (setq elmo-imap4-connection-cache
303 (append elmo-imap4-connection-cache
305 (cons user-at-host-on-port
306 (setq ret-val (list buffer process
311 (defun elmo-imap4-process-filter (process output)
313 (with-current-buffer (process-buffer process)
314 (goto-char (point-max))
318 (if (looking-at (concat
320 elmo-imap4-seq-prefix
321 (int-to-string elmo-imap4-seqno)
322 "\\|^\\* OK\\|^\\* BYE\\'\\|^\\+\\)[^\n]*\n\\'"))
324 (setq elmo-imap4-lock nil) ; unlock process buffer.
325 (elmo-imap4-debug "unlock(%d) %s" elmo-imap4-seqno output))
326 (elmo-imap4-debug "continue(%d) %s" elmo-imap4-seqno output))
327 (goto-char (point-max)))))
329 (defun elmo-imap4-read-response (buffer process &optional not-command)
332 (let ((case-fold-search nil)
333 (response-string nil)
334 (response-continue t)
337 (while response-continue
338 (goto-char elmo-imap4-read-point)
339 (while (not (search-forward "\r\n" nil t))
340 (accept-process-output process)
341 (goto-char elmo-imap4-read-point))
343 (setq match-end (point))
344 (setq response-string
345 (buffer-substring elmo-imap4-read-point (- match-end 2)))
346 (goto-char elmo-imap4-read-point)
347 (if (looking-at (format "%s[0-9]+ OK.*$\\|\\+.*$"
348 elmo-imap4-seq-prefix))
349 (progn (setq response-continue nil)
350 (setq elmo-imap4-read-point match-end)
353 (concat return-value "\n" response-string)
355 (if (looking-at (format "\\(. BYE.*\\|%s[0-9]+ \\(NO\\|BAD\\).*\\)$"
356 elmo-imap4-seq-prefix))
357 (progn (setq response-continue nil)
358 (setq elmo-imap4-read-point match-end)
359 (elmo-imap4-debug "error response: %s" response-string)
360 (setq return-value nil))
361 (setq elmo-imap4-read-point match-end)
363 (setq response-continue nil))
366 (concat return-value "\n" response-string)
368 (setq elmo-imap4-read-point match-end)))
371 (defun elmo-imap4-read-contents (buffer process)
375 (let ((case-fold-search nil)
376 (response-string nil)
378 (goto-char elmo-imap4-read-point)
379 (while (not (re-search-forward
380 (format "%s[0-9]+ \\(NO\\|BAD\\|OK\\).*$"
381 elmo-imap4-seq-prefix)
383 (accept-process-output process)
384 (goto-char elmo-imap4-read-point))
386 (setq match-end (point))
387 (setq response-string (buffer-substring
388 elmo-imap4-read-point match-end))
389 (if (eq (length response-string) 0)
393 (defun elmo-imap4-read-bytes (buffer process bytes)
396 (let ((case-fold-search nil)
399 (setq start elmo-imap4-read-point);; starting point
400 (while (< (point-max) (+ start bytes))
401 (accept-process-output process))
402 (setq return-value (buffer-substring
403 start (+ start bytes)))
404 (setq return-value (elmo-delete-cr return-value))
405 (setq elmo-imap4-read-point bytes)
408 (defun elmo-imap4-read-body (buffer process bytes outbuf)
409 (let (start gc-message ret-val)
410 (with-current-buffer buffer
411 (setq start elmo-imap4-read-point)
412 (while (< (point-max) (+ start bytes))
413 (accept-process-output process))
414 (with-current-buffer outbuf
416 (insert-buffer-substring buffer start (+ start bytes))
417 (setq ret-val (elmo-delete-cr-get-content-type)))
418 (setq elmo-imap4-read-point (+ start bytes))
421 (defun elmo-imap4-noop (connection)
422 (let ((buffer (car connection))
423 (process (cadr connection)))
425 (elmo-imap4-send-command buffer
427 (elmo-imap4-read-response buffer process))))
429 (defun elmo-imap4-commit (spec)
431 (let ((connection (elmo-imap4-get-connection spec))
432 response ret-val beg end)
433 (and (not (null (elmo-imap4-spec-folder spec)))
434 (if (not (string= (elmo-imap4-connection-get-cwf connection)
435 (elmo-imap4-spec-folder spec)))
436 (if (null (setq response
437 (elmo-imap4-select-folder
438 (elmo-imap4-spec-folder spec)
440 (error "Select folder failed"))
441 (if elmo-imap4-use-select-to-update-status
442 (elmo-imap4-select-folder
443 (elmo-imap4-spec-folder spec)
445 (elmo-imap4-check connection)))))))
447 (defun elmo-imap4-check (connection)
448 (let ((process (elmo-imap4-connection-get-process connection)))
450 (elmo-imap4-send-command (process-buffer process)
452 (elmo-imap4-read-response (process-buffer process) process))))
454 (defun elmo-imap4-select-folder (folder connection)
455 (let ((process (elmo-imap4-connection-get-process connection))
460 (elmo-imap4-send-command (process-buffer process)
461 process (format "select \"%s\""
463 (setq response (elmo-imap4-read-response
464 (process-buffer process) process)))
467 (setcar (cddr connection) nil)
468 (error "Select folder failed"))
469 (setcar (cddr connection) folder))))
472 (defun elmo-imap4-check-validity (spec validity-file)
473 "get uidvalidity value from server and compare it with validity-file."
474 (let* ((process (elmo-imap4-get-process spec))
477 (elmo-imap4-send-command (process-buffer process)
479 (format "status \"%s\" (uidvalidity)"
480 (elmo-imap4-spec-folder spec)))
481 (setq response (elmo-imap4-read-response
482 (process-buffer process) process))
483 (if (string-match "UIDVALIDITY \\([0-9]+\\)" response)
484 (string= (elmo-get-file-string validity-file)
485 (elmo-match-string 1 response))
488 (defun elmo-imap4-sync-validity (spec validity-file)
489 "get uidvalidity value from server and save it to validity-file."
490 (let* ((process (elmo-imap4-get-process spec))
493 (elmo-imap4-send-command (process-buffer process)
495 (format "status \"%s\" (uidvalidity)"
496 (elmo-imap4-spec-folder spec)))
497 (setq response (elmo-imap4-read-response
498 (process-buffer process) process))
499 (if (string-match "UIDVALIDITY \\([0-9]+\\)" response)
502 (elmo-match-string 1 response)
507 (defsubst elmo-imap4-list (spec str)
509 (let* ((connection (elmo-imap4-get-connection spec))
510 (process (elmo-imap4-connection-get-process connection))
511 response ret-val beg end)
512 (and (elmo-imap4-spec-folder spec)
513 (if (not (string= (elmo-imap4-connection-get-cwf connection)
514 (elmo-imap4-spec-folder spec)))
515 (if (null (setq response
516 (elmo-imap4-select-folder
517 (elmo-imap4-spec-folder spec)
519 (error "Select folder failed"))
520 ;; for status update.
521 (if elmo-imap4-use-select-to-update-status
522 (elmo-imap4-select-folder (elmo-imap4-spec-folder spec)
524 (unless (elmo-imap4-check connection)
525 ;; Check failed...not selected??
526 (elmo-imap4-select-folder (elmo-imap4-spec-folder spec)
528 (elmo-imap4-send-command (process-buffer process)
530 (format (if elmo-imap4-use-uid
533 (setq response (elmo-imap4-read-response (process-buffer process)
535 (if (and response (string-match "\\* SEARCH" response))
537 (setq response (substring response (match-end 0)))
538 (if (string-match "\n" response)
540 (setq end (match-end 0))
541 (setq ret-val (read (concat "(" (substring
544 (error "SEARCH failed"))))
547 (defun elmo-imap4-list-folder (spec)
548 (elmo-imap4-list spec "all"))
550 (defun elmo-imap4-list-folder-unread (spec mark-alist unread-marks)
551 (if (elmo-imap4-use-flag-p spec)
552 (elmo-imap4-list spec "unseen")
553 (elmo-generic-list-folder-unread spec mark-alist unread-marks)))
555 (defun elmo-imap4-list-folder-important (spec overview)
556 (and (elmo-imap4-use-flag-p spec)
557 (elmo-imap4-list spec "flagged")))
559 (defun elmo-imap4-search-internal (process buffer filter)
560 (let ((search-key (elmo-filter-key filter))
563 ((or (string= "since" search-key)
564 (string= "before" search-key))
565 (setq search-key (concat "sent" search-key))
566 (elmo-imap4-send-command buffer process
568 (if elmo-imap4-use-uid
572 (elmo-date-get-description
573 (elmo-date-get-datevec
574 (elmo-filter-value filter))))))
576 (setq word (encode-mime-charset-string (elmo-filter-value filter)
577 elmo-search-mime-charset))
578 (elmo-imap4-send-command buffer process
580 (if elmo-imap4-use-uid
581 "uid search CHARSET %s%s %s {%d}"
582 " search CHARSET %s%s %s {%d}")
583 (symbol-name elmo-search-mime-charset)
584 (if (eq (elmo-filter-type filter) 'unmatch)
586 (elmo-filter-key filter)
588 (if (null (elmo-imap4-read-response buffer process t))
589 (error "Searching failed because of server capability??"))
590 (elmo-imap4-send-string buffer process word)))
591 (if (null (setq response (elmo-imap4-read-response buffer process)))
592 (error "Search failed for %s" (elmo-filter-key filter)))
593 (if (string-match "^\\* SEARCH\\([^\n]*\\)$" response)
594 (read (concat "(" (elmo-match-string 1 response) ")"))
595 (error "SEARCH failed"))))
597 (defun elmo-imap4-search (spec condition &optional from-msgs)
599 (let* ((connection (elmo-imap4-get-connection spec))
600 (process (elmo-imap4-connection-get-process connection))
601 response ret-val len word)
602 (if (and (elmo-imap4-spec-folder spec)
603 (not (string= (elmo-imap4-connection-get-cwf connection)
604 (elmo-imap4-spec-folder spec)))
605 (null (elmo-imap4-select-folder
606 (elmo-imap4-spec-folder spec) connection)))
607 (error "Select folder failed"))
609 (setq response (elmo-imap4-search-internal process
610 (process-buffer process)
612 (setq ret-val (nconc ret-val response))
613 (setq condition (cdr condition)))
617 (elmo-uniq-list (sort ret-val '<)))
618 (elmo-uniq-list (sort ret-val '<))))))
620 (defsubst elmo-imap4-value (value)
621 (if (eq value 'NIL) nil
624 (defmacro elmo-imap4-nth (pos list)
625 (` (let ((value (nth (, pos) (, list))))
630 (defun elmo-imap4-use-flag-p (spec)
631 (not (string-match elmo-imap4-disuse-server-flag-mailbox-regexp
632 (elmo-imap4-spec-folder spec))))
634 (defsubst elmo-imap4-make-address (name mbox host)
636 (concat name " <" mbox "@" host ">"))
638 (concat mbox "@" host))))
642 ;; Emacs can parse dot symbol.
643 (defvar elmo-imap4-rfc822-size "RFC822\.SIZE")
644 (defvar elmo-imap4-header-fields "HEADER\.FIELDS")
645 (defmacro elmo-imap4-replace-dot-symbols ()) ;; noop
648 ;; Cannot parse dot symbol, replace it.
649 (defvar elmo-imap4-rfc822-size "RFC822_SIZE")
650 (defvar elmo-imap4-header-fields "HEADER_FIELDS")
651 (defmacro elmo-imap4-replace-dot-symbols ()
652 (goto-char (point-min))
653 (while (re-search-forward "RFC822\\.SIZE" nil t)
654 (replace-match elmo-imap4-rfc822-size))
655 (goto-char (point-min))
656 (while (re-search-forward "HEADER\\.FIELDS" nil t)
657 (replace-match elmo-imap4-header-fields))
658 (goto-char (point-min)))))
660 (defsubst elmo-imap4-make-attributes-object (string)
663 (elmo-set-buffer-multibyte nil)
665 (goto-char (point-min))
666 (let ((case-fold-search t))
667 (goto-char (point-min))
668 (while (re-search-forward "{\\([0-9]+\\)}\r\n" nil t)
670 (goto-char (+ (point)
671 (string-to-int (elmo-match-buffer 1))))
672 (setq str (save-match-data
673 (elmo-replace-in-string
674 (buffer-substring (match-end 0) (point))
676 (delete-region (match-beginning 0) (point))
677 (insert (prin1-to-string str))))
678 (goto-char (point-min))
679 (elmo-imap4-replace-dot-symbols)
680 (read (current-buffer))))))
683 (defun elmo-imap4-parse-overview-string (string)
685 (error "Getting overview failed"))
687 (let (ret-val beg attr number)
688 (elmo-set-buffer-multibyte nil)
690 (goto-char (point-min))
692 (if (re-search-forward "^\* \\([0-9]+\\) FETCH"
696 (unless elmo-imap4-use-uid
697 (setq number (string-to-int (elmo-match-buffer 1))))
698 (while (re-search-forward
699 "^\* \\([0-9]+\\) FETCH"
701 (setq attr (elmo-imap4-make-attributes-object
702 (buffer-substring beg (match-beginning 0))))
704 (unless elmo-imap4-use-uid
705 (setq attr(nconc (list 'UID number) attr))
706 (setq number (string-to-int (elmo-match-buffer 1))))
707 (setq ret-val (cons attr ret-val)))
708 ;; process last one...
709 (setq attr (elmo-imap4-make-attributes-object
710 (buffer-substring beg (point-max))))
711 (unless elmo-imap4-use-uid
712 (setq attr(nconc (list 'UID number) attr)))
713 (setq ret-val (cons attr ret-val))))
714 (nreverse ret-val))))
716 (defun elmo-imap4-create-msgdb-from-overview-string (str
724 (let ((case-fold-search t)
725 (size-sym (intern elmo-imap4-rfc822-size))
726 overview attr-list attr pair section
727 number important message-id from-list from-string
729 number-alist mark-alist
730 reference subject date-string size flags gmark seen
731 index extras extra-fields sym value)
732 (setq attr-list (elmo-imap4-parse-overview-string str))
734 (setq attr (car attr-list))
735 ;; Remove section data. (origin octed is not considered.(OK?))
736 (setq section (cadr (memq 'BODY attr)))
737 (if (vectorp section)
740 (setq number (cadr (memq 'UID attr)))
741 (when (or (null numlist)
742 (memq number numlist))
744 (setq sym (car attr))
745 (setq value (cadr attr))
746 (setq attr (cdr (cdr attr)))
755 (setq extra-fields (elmo-collect-field-from-string value t)))
757 ;; According to rfc2060,
758 ;; 0 date, 1 subject, 2 from, 3 sender,
759 ;; 4 reply-to, 5 to, 6 cc, 7 bcc, 8 in-reply-to, 9 message-id.
760 (setq date-string (elmo-imap4-nth 0 value))
761 (setq subject (elmo-mime-string (or (elmo-imap4-nth 1 value)
763 (setq from-list (car (elmo-imap4-nth 2 value)))
764 (setq from-string (or
765 (and (or (elmo-imap4-nth 0 from-list)
766 (elmo-imap4-nth 2 from-list)
767 (elmo-imap4-nth 3 from-list))
770 (elmo-imap4-make-address
771 (elmo-imap4-nth 0 from-list)
772 (elmo-imap4-nth 2 from-list)
773 (elmo-imap4-nth 3 from-list))
776 (setq to-string (mapconcat
778 (elmo-imap4-make-address
779 (elmo-imap4-nth 0 to)
780 (elmo-imap4-nth 2 to)
781 (elmo-imap4-nth 3 to)))
782 (elmo-imap4-nth 5 value) ","))
783 (setq cc-string (mapconcat
785 (elmo-imap4-make-address
786 (elmo-imap4-nth 0 cc)
787 (elmo-imap4-nth 2 cc)
788 (elmo-imap4-nth 3 cc)))
789 (elmo-imap4-nth 6 value) ","))
790 (setq reference (elmo-msgdb-get-last-message-id
791 (elmo-imap4-nth 8 value)))
792 (setq message-id (elmo-imap4-nth 9 value)))))
793 (when (setq pair (assoc "references" extra-fields))
794 (setq extra-fields (delq pair extra-fields)))
796 (setq reference (elmo-msgdb-get-last-message-id (cdr pair))))
798 (elmo-msgdb-append-element
803 (elmo-mime-string from-string)
804 (elmo-mime-string subject)
810 (if (memq 'Flagged flags)
811 (elmo-msgdb-global-mark-set message-id important-mark))
813 (elmo-msgdb-number-add number-alist number message-id))
814 (setq seen (member message-id seen-list))
815 (if (setq gmark (or (elmo-msgdb-global-mark-get message-id)
816 (if (elmo-cache-exists-p message-id) ;; XXX
817 (if (or (memq 'Seen flags) seen)
820 (if (or (memq 'Seen flags) seen)
821 (if elmo-imap4-use-cache
824 (setq mark-alist (elmo-msgdb-mark-append
827 ;; managing mark with message-id is evil.
829 (setq attr-list (cdr attr-list)))
830 (list overview number-alist mark-alist)))
832 (defun elmo-imap4-add-to-cont-list (cont-list msg)
833 (let ((elist cont-list)
836 (while (and elist (not found))
837 (setq entity (car elist))
840 (eq (+ 1 (cdr entity)) msg))
843 ((and (integerp entity)
844 (eq (+ 1 entity) msg))
845 (setcar elist (cons entity msg))
847 ((or (and (integerp entity) (eq entity msg))
849 (<= (car entity) msg)
850 (<= msg (cdr entity)))) ; included
851 (setq found t))); noop
852 (setq elist (cdr elist)))
854 (setq ret-val (append cont-list (list msg))))
857 (defun elmo-imap4-make-number-set-list (msg-list &optional chop-length)
858 "Make RFC2060's message set specifier from MSG-LIST.
859 Returns a list of (NUMBER . SET-STRING).
860 SET-STRING is the message set specifier described in RFC2060.
861 NUMBER is contained message number in SET-STRING.
862 Every SET-STRING does not contain number of messages longer than CHOP-LENGTH.
863 If CHOP-LENGTH is not specified, message set is not chopped."
864 (let (count cont-list set-list)
865 (setq msg-list (sort msg-list '<))
870 (setq chop-length (length msg-list)))
871 (while (and (not (null msg-list))
872 (< count chop-length))
874 (elmo-imap4-add-to-cont-list
875 cont-list (car msg-list)))
877 (setq msg-list (cdr msg-list)))
885 (format "%s:%s" (car x) (cdr x)))
891 (nreverse set-list)))
895 ;; read-mark -> "\\Seen"
896 ;; important -> "\\Flagged"
898 ;; (delete -> \\Deleted)
899 (defun elmo-imap4-mark-set-on-msgs (spec msgs mark &optional unmark no-expunge)
900 "SET flag of MSGS as MARK.
901 If optional argument UNMARK is non-nil, unmark."
903 (let* ((connection (elmo-imap4-get-connection spec))
904 (process (elmo-imap4-connection-get-process connection))
905 (msg-list (copy-sequence msgs))
907 (if (and (elmo-imap4-spec-folder spec)
908 (not (string= (elmo-imap4-connection-get-cwf connection)
909 (elmo-imap4-spec-folder spec)))
910 (null (elmo-imap4-select-folder
911 (elmo-imap4-spec-folder spec) connection)))
912 (error "Select folder failed"))
913 (setq set-list (elmo-imap4-make-number-set-list msg-list))
915 (elmo-imap4-send-command (process-buffer process)
918 (if elmo-imap4-use-uid
919 "uid store %s %sflags.silent (%s)"
920 "store %s %sflags.silent (%s)")
924 (unless (elmo-imap4-read-response (process-buffer process) process)
925 (error "Store %s flag failed" mark))
927 (elmo-imap4-send-command
928 (process-buffer process) process "expunge")
929 (unless (elmo-imap4-read-response (process-buffer process) process)
930 (error "Expunge failed"))))
933 (defun elmo-imap4-mark-as-important (spec msgs)
934 (and (elmo-imap4-use-flag-p spec)
935 (elmo-imap4-mark-set-on-msgs spec msgs "\\Flagged" nil 'no-expunge)))
937 (defun elmo-imap4-mark-as-read (spec msgs)
938 (and (elmo-imap4-use-flag-p spec)
939 (elmo-imap4-mark-set-on-msgs spec msgs "\\Seen" nil 'no-expunge)))
941 (defun elmo-imap4-unmark-important (spec msgs)
942 (and (elmo-imap4-use-flag-p spec)
943 (elmo-imap4-mark-set-on-msgs spec msgs "\\Flagged" 'unmark
946 (defun elmo-imap4-mark-as-unread (spec msgs)
947 (and (elmo-imap4-use-flag-p spec)
948 (elmo-imap4-mark-set-on-msgs spec msgs "\\Seen" 'unmark 'no-expunge)))
950 (defun elmo-imap4-delete-msgs (spec msgs)
951 (elmo-imap4-mark-set-on-msgs spec msgs "\\Deleted"))
953 (defun elmo-imap4-delete-msgs-no-expunge (spec msgs)
954 (elmo-imap4-mark-set-on-msgs spec msgs "\\Deleted" nil 'no-expunge))
956 (defun elmo-imap4-msgdb-create-as-numlist (spec numlist new-mark already-mark
957 seen-mark important-mark
959 "Create msgdb for SPEC for NUMLIST."
960 (elmo-imap4-msgdb-create spec numlist new-mark already-mark
961 seen-mark important-mark seen-list t))
963 (defun elmo-imap4-msgdb-create (spec numlist new-mark already-mark seen-mark
964 important-mark seen-list &optional as-num)
965 "Create msgdb for SPEC."
968 (let* ((connection (elmo-imap4-get-connection spec))
969 (process (elmo-imap4-connection-get-process connection))
970 (filter (and as-num numlist))
972 (extra-fields (if elmo-msgdb-extra-fields
973 (concat " " (mapconcat
975 elmo-msgdb-extra-fields " "))
977 rfc2060 count ret-val set-list ov-str length)
978 (setq rfc2060 (with-current-buffer (process-buffer process)
979 (if (memq 'imap4rev1 elmo-imap4-server-capability)
981 (if (memq 'imap4 elmo-imap4-server-capability)
983 (error "No IMAP4 capability!!")))))
985 (setq length (length numlist))
986 (setq set-list (elmo-imap4-make-number-set-list
988 elmo-imap4-overview-fetch-chop-length))
989 (message "Getting overview...")
990 (if (and (elmo-imap4-spec-folder spec)
991 (not (string= (elmo-imap4-connection-get-cwf connection)
992 (elmo-imap4-spec-folder spec)))
993 (null (elmo-imap4-select-folder
994 (elmo-imap4-spec-folder spec) connection)))
995 (error "Select imap folder %s failed"
996 (elmo-imap4-spec-folder spec)))
998 (elmo-imap4-send-command
999 (process-buffer process)
1001 ;; get overview entity from IMAP4
1005 (if elmo-imap4-use-uid "uid " "")
1006 "fetch %s (envelope body.peek[header.fields (references"
1008 ")] rfc822.size flags)")
1010 (if elmo-imap4-use-uid "uid " "")
1011 "fetch %s (envelope rfc822.size flags)"))
1012 (cdr (car set-list))))
1013 ;; process string while waiting for response
1014 (with-current-buffer (process-buffer process)
1019 (elmo-imap4-create-msgdb-from-overview-string
1021 (elmo-imap4-spec-folder spec)
1022 new-mark already-mark seen-mark important-mark
1023 seen-list filter)))))
1024 (setq count (+ count (car (car set-list))))
1025 (setq ov-str (elmo-imap4-read-contents (process-buffer process)
1027 (elmo-display-progress
1028 'elmo-imap4-msgdb-create "Getting overview..."
1029 (/ (* count 100) length))
1030 (setq set-list (cdr set-list)))
1031 ;; process last one.
1032 (with-current-buffer (process-buffer process)
1037 (elmo-imap4-create-msgdb-from-overview-string
1039 (elmo-imap4-spec-folder spec)
1040 new-mark already-mark seen-mark important-mark
1041 seen-list filter)))))
1042 (message "Getting overview...done.")
1045 (defun elmo-imap4-parse-response (string)
1046 (if (string-match "^\\*\\(.*\\)$" string)
1047 (read (concat "(" (elmo-match-string 1 string) ")"))))
1049 (defun elmo-imap4-parse-capability (string)
1050 (if (string-match "^\\*\\(.*\\)$" string)
1051 (read (concat "(" (downcase (elmo-match-string 1 string)) ")"))))
1053 (defun elmo-imap4-parse-namespace (obj)
1054 (let ((ns (cdr obj))
1057 cur namespace-alist)
1058 ;; 0: personal, 1: other, 2: shared
1060 (setq cur (elmo-imap4-nth i ns))
1063 (setq prefix (elmo-imap4-nth 0 (car cur)))
1064 (setq delim (elmo-imap4-nth 1 (car cur)))
1065 (if (and prefix delim
1066 (string-match (concat "\\(.*\\)"
1067 (regexp-quote delim)
1070 (setq prefix (substring prefix (match-beginning 1)(match-end 1))))
1071 (setq namespace-alist (nconc namespace-alist
1073 (concat "^" (regexp-quote prefix)
1076 (setq cur (cdr cur))))
1078 elmo-imap4-extra-namespace-alist
1079 (sort namespace-alist
1082 (length (car y))))))))
1084 (defun elmo-imap4-open-connection (imap4-server user auth port passphrase ssl)
1085 "Open Imap connection and returns
1086 the list of (process session-buffer current-working-folder).
1087 Return nil if connection failed."
1090 process-buffer ret-val response capability)
1093 (setq process-buffer
1094 (get-buffer-create (format " *IMAP session to %s:%d" host port)))
1096 (set-buffer process-buffer)
1097 (elmo-set-buffer-multibyte nil)
1098 (make-variable-buffer-local 'elmo-imap4-server-capability)
1099 (make-variable-buffer-local 'elmo-imap4-lock)
1102 (elmo-open-network-stream "IMAP" process-buffer host port ssl))
1103 (and (null process) (throw 'done nil))
1104 (set-process-filter process 'elmo-imap4-process-filter)
1105 ;; flush connections when exiting...
1107 (set-buffer process-buffer)
1108 (make-local-variable 'elmo-imap4-read-point)
1109 (setq elmo-imap4-read-point (point-min))
1110 (if (null (setq response
1111 (elmo-imap4-read-response process-buffer process t)))
1113 (when (string-match "^\\* PREAUTH" response)
1114 (setq ret-val (cons process-buffer process))
1116 (elmo-imap4-send-command process-buffer process "capability")
1117 (setq elmo-imap4-server-capability
1118 (elmo-imap4-parse-capability
1119 (elmo-imap4-read-response process-buffer process)))
1120 (setq capability elmo-imap4-server-capability)
1121 (if (eq ssl 'starttls)
1122 (if (and (memq 'starttls capability)
1124 (elmo-imap4-send-command process-buffer process "starttls")
1126 (elmo-imap4-read-response process-buffer process)))
1129 (concat "^\\(" elmo-imap4-seq-prefix
1130 (int-to-string elmo-imap4-seqno)
1133 (starttls-negotiate process)
1134 (error "STARTTLS aborted")))
1135 (if (or (and (string= "auth" auth)
1136 (not (memq 'auth=login capability)))
1137 (and (string= "cram-md5" auth)
1138 (not (memq 'auth=cram-md5 capability)))
1139 (and (string= "digest-md5" auth)
1140 (not (memq 'auth=digest-md5 capability))))
1141 (if (or elmo-imap4-force-login
1144 "There's no %s capability in server. continue?" auth)))
1146 (error "Login aborted")))
1148 ((string= "auth" auth)
1149 (elmo-imap4-send-command
1150 process-buffer process "authenticate login" 'no-lock)
1152 (when (null (elmo-imap4-read-response process-buffer process t))
1153 (setq ret-val (cons nil process))
1155 (elmo-imap4-send-string
1156 process-buffer process (elmo-base64-encode-string user))
1157 (when (null (elmo-imap4-read-response process-buffer process t))
1158 (setq ret-val (cons nil process))
1160 (elmo-imap4-send-string
1161 process-buffer process (elmo-base64-encode-string passphrase))
1162 (when (null (elmo-imap4-read-response process-buffer process))
1163 (setq ret-val (cons nil process))
1165 (setq ret-val (cons process-buffer process)))
1166 ((string= "cram-md5" auth)
1167 (elmo-imap4-send-command
1168 process-buffer process "authenticate cram-md5" 'no-lock)
1169 (when (null (setq response
1170 (elmo-imap4-read-response
1171 process-buffer process t)))
1172 (setq ret-val (cons nil process))
1174 (setq response (cadr (split-string response " ")))
1175 (elmo-imap4-send-string
1176 process-buffer process
1177 (elmo-base64-encode-string
1178 (sasl-cram-md5 user passphrase
1179 (elmo-base64-decode-string response))))
1180 (when (null (elmo-imap4-read-response process-buffer process))
1181 (setq ret-val (cons nil process))
1183 (setq ret-val (cons process-buffer process)))
1184 ((string= "digest-md5" auth)
1185 (elmo-imap4-send-command
1186 process-buffer process "authenticate digest-md5" 'no-lock)
1187 (when (null (setq response
1188 (elmo-imap4-read-response
1189 process-buffer process t)))
1190 (setq ret-val (cons nil process))
1192 (setq response (cadr (split-string response " ")))
1193 (elmo-imap4-send-string
1194 process-buffer process
1195 (elmo-base64-encode-string
1196 (sasl-digest-md5-digest-response
1197 (elmo-base64-decode-string response)
1198 user passphrase "imap" host)
1200 (when (null (elmo-imap4-read-response
1201 process-buffer process t))
1202 (setq ret-val (cons nil process))
1204 (elmo-imap4-send-string process-buffer process "")
1205 (when (null (elmo-imap4-read-response process-buffer process))
1206 (setq ret-val (cons nil process))
1208 (setq ret-val (cons process-buffer process)))
1209 (t ;; not auth... try login
1210 (elmo-imap4-send-command
1211 process-buffer process
1212 (format "login %s \"%s\"" user
1213 (elmo-replace-in-string passphrase
1215 nil 'no-log) ;; No LOGGING.
1216 (if (null (elmo-imap4-read-response process-buffer process))
1217 (setq ret-val (cons nil process))
1218 (setq ret-val (cons process-buffer process)))))
1219 ;; get namespace of server if possible.
1220 (when (memq 'namespace elmo-imap4-server-capability)
1221 (elmo-imap4-send-command process-buffer process "namespace")
1222 (setq elmo-imap4-server-namespace
1223 (elmo-imap4-parse-namespace
1224 (elmo-imap4-parse-response
1225 (elmo-imap4-read-response process-buffer process))))))))
1228 (defun elmo-imap4-get-seqno ()
1229 (setq elmo-imap4-seqno (+ 1 elmo-imap4-seqno)))
1231 (defun elmo-imap4-setup-send-buffer (string)
1232 (let ((tmp-buf (get-buffer-create " *elmo-imap4-setup-send-buffer*")))
1235 (set-buffer tmp-buf)
1237 (elmo-set-buffer-multibyte nil)
1239 (goto-char (point-min))
1240 (if (eq (re-search-forward "^$" nil t)
1243 (goto-char (point-min))
1244 (while (search-forward "\n" nil t)
1245 (replace-match "\r\n"))))
1248 (defun elmo-imap4-send-command (buffer process command &optional no-lock
1250 "Send COMMAND string to server with sequence number."
1253 (when (and elmo-imap4-use-lock
1255 (elmo-imap4-debug "send: (%d) is still locking." elmo-imap4-seqno)
1256 (error "IMAP4 process is locked; Please try later (or plug again)"))
1258 (goto-char (point-min))
1259 (setq elmo-imap4-read-point (point))
1263 (elmo-imap4-debug "lock(%d): (No-logging command)." (+ elmo-imap4-seqno 1))
1264 (elmo-imap4-debug "lock(%d): %s" (+ elmo-imap4-seqno 1) command))
1265 (setq elmo-imap4-lock t))
1266 (process-send-string process (concat (format "%s%d "
1267 elmo-imap4-seq-prefix
1268 (elmo-imap4-get-seqno))
1270 (process-send-string process "\r\n")))
1272 (defun elmo-imap4-send-string (buffer process string)
1273 "Send STRING to server."
1277 (goto-char (point-min))
1278 (setq elmo-imap4-read-point (point))
1279 (process-send-string process string)
1280 (process-send-string process "\r\n")))
1282 (defun elmo-imap4-read-part (folder msg part)
1284 (let* ((spec (elmo-folder-get-spec folder))
1285 (connection (elmo-imap4-get-connection spec))
1286 (process (elmo-imap4-connection-get-process connection))
1287 response ret-val bytes)
1288 (when (elmo-imap4-spec-folder spec)
1289 (when (not (string= (elmo-imap4-connection-get-cwf connection)
1290 (elmo-imap4-spec-folder spec)))
1291 (if (null (setq response
1292 (elmo-imap4-select-folder
1293 (elmo-imap4-spec-folder spec) connection)))
1294 (error "Select folder failed")))
1295 (elmo-imap4-send-command (process-buffer process)
1298 (if elmo-imap4-use-uid
1299 "uid fetch %s body.peek[%s]"
1300 "fetch %s body.peek[%s]")
1302 (if (null (setq response (elmo-imap4-read-response
1303 (process-buffer process)
1305 (error "Fetch failed"))
1307 (while (string-match "^\\* OK" response)
1308 (if (null (setq response (elmo-imap4-read-response
1309 (process-buffer process)
1311 (error "Fetch failed"))))
1313 (if (string-match ".*{\\([0-9]+\\)}" response)
1316 (elmo-match-string 1 response)))
1317 (error "Fetch failed")))
1318 (if (null (setq response (elmo-imap4-read-bytes
1319 (process-buffer process) process bytes)))
1320 (error "Fetch message failed"))
1321 (setq ret-val response)
1322 (elmo-imap4-read-response (process-buffer process)
1323 process)) ;; ignore remaining..
1326 (defun elmo-imap4-prefetch-msg (spec msg outbuf)
1327 (elmo-imap4-read-msg spec msg outbuf 'unseen))
1329 (defun elmo-imap4-read-msg (spec msg outbuf
1330 &optional leave-seen-flag-untouched)
1332 (let* ((connection (elmo-imap4-get-connection spec))
1333 (process (elmo-imap4-connection-get-process connection))
1334 response ret-val bytes)
1336 (when (elmo-imap4-spec-folder spec)
1337 (when (not (string= (elmo-imap4-connection-get-cwf connection)
1338 (elmo-imap4-spec-folder spec)))
1339 (if (null (setq response
1340 (elmo-imap4-select-folder
1341 (elmo-imap4-spec-folder spec)
1343 (error "Select folder failed")))
1344 (elmo-imap4-send-command (process-buffer process)
1347 (if elmo-imap4-use-uid
1348 "uid fetch %s body%s[]"
1349 "fetch %s body%s[]")
1351 (if leave-seen-flag-untouched
1353 (if (null (setq response (elmo-imap4-read-response
1354 (process-buffer process)
1356 (error "Fetch failed"))
1358 (while (string-match "^\\* OK" response)
1359 (if (null (setq response (elmo-imap4-read-response
1360 (process-buffer process)
1362 (error "Fetch failed"))))
1364 (if (string-match ".*{\\([0-9]+\\)}" response)
1367 (elmo-match-string 1 response)))
1368 (error "Fetch failed")))
1369 (setq ret-val (elmo-imap4-read-body
1370 (process-buffer process)
1371 process bytes outbuf))
1372 (elmo-imap4-read-response (process-buffer process)
1373 process)) ;; ignore remaining..
1377 (defun elmo-imap4-setup-send-buffer-from-file (file)
1378 (let ((tmp-buf (get-buffer-create
1379 " *elmo-imap4-setup-send-buffer-from-file*")))
1382 (set-buffer tmp-buf)
1384 (as-binary-input-file
1385 (insert-file-contents file))
1386 (goto-char (point-min))
1387 (if (eq (re-search-forward "^$" nil t)
1390 (goto-char (point-min))
1391 (while (search-forward "\n" nil t)
1392 (replace-match "\r\n"))))
1395 (defun elmo-imap4-delete-msgids (spec msgids)
1396 "If actual message-id is matched, then delete it."
1397 (let ((message-ids msgids)
1399 (num (length msgids)))
1402 (message "Deleting message...%d/%d" i num)
1403 (elmo-imap4-delete-msg-by-id spec (car message-ids))
1404 (setq message-ids (cdr message-ids)))
1405 (let* ((connection (elmo-imap4-get-connection spec))
1406 (process (elmo-imap4-connection-get-process connection)))
1407 (elmo-imap4-send-command (process-buffer process)
1409 (if (null (elmo-imap4-read-response (process-buffer process)
1411 (error "Expunge failed")))))
1413 (defun elmo-imap4-delete-msg-by-id (spec msgid)
1415 (let* ((connection (elmo-imap4-get-connection spec))
1416 (process (elmo-imap4-connection-get-process connection))
1417 ;;(size (length string))
1419 (if (and (elmo-imap4-spec-folder spec)
1420 (not (string= (elmo-imap4-connection-get-cwf connection)
1421 (elmo-imap4-spec-folder spec)))
1422 (null (elmo-imap4-select-folder
1423 (elmo-imap4-spec-folder spec)
1425 (error "Select folder failed"))
1427 (elmo-imap4-send-command (process-buffer process)
1430 (if elmo-imap4-use-uid
1431 "uid search header message-id \"%s\""
1432 "search header message-id \"%s\"")
1434 (setq response (elmo-imap4-read-response
1435 (process-buffer process) process))
1437 (string-match "^\\* SEARCH\\([^\n]*\\)$" response))
1438 (setq msgs (read (concat "(" (elmo-match-string 1 response) ")")))
1439 (error "SEARCH failed"))
1440 (elmo-imap4-delete-msgs-no-expunge spec msgs)))))
1442 (defun elmo-imap4-append-msg-by-id (spec msgid)
1444 (let* ((connection (elmo-imap4-get-connection spec))
1445 (process (elmo-imap4-connection-get-process connection))
1447 (if (and (elmo-imap4-spec-folder spec)
1448 (not (string= (elmo-imap4-connection-get-cwf connection)
1449 (elmo-imap4-spec-folder spec)))
1450 (null (elmo-imap4-select-folder
1451 (elmo-imap4-spec-folder spec) connection)))
1452 (error "Select folder failed"))
1454 (setq send-buf (elmo-imap4-setup-send-buffer-from-file
1455 (elmo-cache-get-path msgid)))
1456 (set-buffer send-buf)
1457 (elmo-imap4-send-command (process-buffer process)
1459 (format "append %s (\\Seen) {%d}"
1460 (elmo-imap4-spec-folder spec)
1462 (process-send-string process (buffer-string))
1463 (process-send-string process "\r\n") ; finished appending.
1465 (kill-buffer send-buf)
1466 (if (null (elmo-imap4-read-response (process-buffer process)
1468 (error "Append failed")))
1471 (defun elmo-imap4-append-msg (spec string &optional msg no-see)
1473 (let* ((connection (elmo-imap4-get-connection spec))
1474 (process (elmo-imap4-connection-get-process connection))
1476 (if (and (elmo-imap4-spec-folder spec)
1477 (not (string= (elmo-imap4-connection-get-cwf connection)
1478 (elmo-imap4-spec-folder spec)))
1479 (null (elmo-imap4-select-folder (elmo-imap4-spec-folder spec)
1481 (error "Select folder failed"))
1483 (setq send-buf (elmo-imap4-setup-send-buffer string))
1484 (set-buffer send-buf)
1485 (elmo-imap4-send-command (process-buffer process)
1487 (format "append %s %s{%d}"
1488 (elmo-imap4-spec-folder spec)
1489 (if no-see "" "(\\Seen) ")
1491 (if (null (elmo-imap4-read-response (process-buffer process)
1493 (error "Cannot append messages to this folder"))
1494 (process-send-string process (buffer-string))
1495 (process-send-string process "\r\n") ; finished appending.
1497 (kill-buffer send-buf)
1499 (if (null (elmo-imap4-read-response (process-buffer process)
1501 (error "Append failed")))
1504 (defun elmo-imap4-copy-msgs (dst-spec msgs src-spec &optional expunge-it same-number)
1505 "Equivalence of hostname, username is assumed."
1507 (let* ((src-folder (elmo-imap4-spec-folder src-spec))
1508 (dst-folder (elmo-imap4-spec-folder dst-spec))
1509 (connection (elmo-imap4-get-connection src-spec))
1510 (process (elmo-imap4-connection-get-process connection))
1513 (not (string= (elmo-imap4-connection-get-cwf connection)
1515 (null (elmo-imap4-select-folder
1516 src-folder connection)))
1517 (error "Select folder failed"))
1519 (elmo-imap4-send-command (process-buffer process)
1522 (if elmo-imap4-use-uid
1525 (car mlist) dst-folder))
1526 (if (null (elmo-imap4-read-response (process-buffer process)
1528 (error "Copy failed")
1529 (setq mlist (cdr mlist))))
1531 (elmo-imap4-send-command (process-buffer process)
1533 (if (null (elmo-imap4-read-response (process-buffer process)
1535 (error "Expunge failed")))
1538 (defun elmo-imap4-server-diff (spec)
1541 (let* ((connection (elmo-imap4-get-connection spec))
1542 (process (elmo-imap4-connection-get-process connection))
1544 ;; commit when same folder.
1545 (if (string= (elmo-imap4-connection-get-cwf connection)
1546 (elmo-imap4-spec-folder spec))
1547 (elmo-imap4-commit spec))
1548 (elmo-imap4-send-command (process-buffer process)
1551 "status \"%s\" (unseen messages)"
1552 (elmo-imap4-spec-folder spec)))
1553 (setq response (elmo-imap4-read-response
1554 (process-buffer process) process))
1555 (when (string-match "\\* STATUS [^(]* \\(([^)]*)\\)" response)
1556 (setq response (read (downcase (elmo-match-string 1 response))))
1557 (cons (cadr (memq 'unseen response))
1558 (cadr (memq 'messages response)))))))
1560 (defun elmo-imap4-use-cache-p (spec number)
1561 elmo-imap4-use-cache)
1563 (defun elmo-imap4-local-file-p (spec number)
1566 (defun elmo-imap4-port-label (spec)
1568 (if (nth 6 spec) "!ssl" "")))
1570 (defsubst elmo-imap4-portinfo (spec)
1571 (list (elmo-imap4-spec-hostname spec) (elmo-imap4-spec-port spec)))
1573 (defun elmo-imap4-plugged-p (spec)
1574 (apply 'elmo-plugged-p
1575 (append (elmo-imap4-portinfo spec)
1576 (list nil (quote (elmo-imap4-port-label spec))))))
1578 (defun elmo-imap4-set-plugged (spec plugged add)
1579 (apply 'elmo-set-plugged plugged
1580 (append (elmo-imap4-portinfo spec)
1581 (list nil nil (quote (elmo-imap4-port-label spec)) add))))
1583 (defalias 'elmo-imap4-sync-number-alist 'elmo-generic-sync-number-alist)
1585 (provide 'elmo-imap4)
1587 ;;; elmo-imap4.el ends here