1 ;;; elmo2.el -- ELMO main file (I don't remember why this is 2).
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.
40 (require 'elmo-localdir)
45 ; (require 'elmo-multi)
46 (require 'elmo-filter)
47 (require 'elmo-archive)
48 ;(require 'elmo-cache2)
51 (if (or (featurep 'dbm)
54 (featurep 'berkeley-db))
55 (require 'elmo-database))
57 (elmo-define-error 'elmo-error "Error" 'error)
58 (elmo-define-error 'elmo-open-error "Cannot open" 'elmo-error)
59 (elmo-define-error 'elmo-authenticate-error "Login failed" 'elmo-open-error)
60 (elmo-define-error 'elmo-imap4-bye-error "IMAP4 BYE response" 'elmo-open-error)
64 (if (featurep 'elmo-net)
65 (elmo-network-clear-session-cache))
66 (if (featurep 'elmo-nntp)
67 (elmo-nntp-flush-connection))
68 (if (get-buffer elmo-work-buf-name)
69 (kill-buffer elmo-work-buf-name))
72 (defun elmo-cleanup-variables ()
73 (setq elmo-folder-info-hashtb nil
74 elmo-nntp-groups-hashtb nil
75 elmo-nntp-list-folders-cache nil
78 ;; (cons of max . estimated message number) elmo-max-of-folder (folder)
79 (defun elmo-max-of-folder (folder)
80 (if (elmo-folder-plugged-p folder)
81 (elmo-call-func folder "max-of-folder")
82 (elmo-dop-max-of-folder folder)))
84 ;; list elmo-list-folder (folder)
85 (defun elmo-list-folder (folder)
86 (if (elmo-folder-plugged-p folder)
87 (elmo-call-func folder "list-folder")
88 (elmo-dop-list-folder folder)))
90 ;; list elmo-list-folders (folder)
91 (defun elmo-list-folders (folder &optional hierarchy)
92 (elmo-call-func folder "list-folders" hierarchy))
94 ;; bool elmo-folder-exists-p (folder)
95 (defun elmo-folder-exists-p (folder)
96 (if (elmo-folder-plugged-p folder)
97 (elmo-call-func folder "folder-exists-p")
98 (elmo-dop-folder-exists-p folder)))
100 ;; bool elmo-folder-creatable-p (folder)
101 (defun elmo-folder-creatable-p (folder)
102 (elmo-call-func folder "folder-creatable-p"))
104 ;; bool elmo-create-folder (folder)
106 (defun elmo-create-folder (folder)
107 (if (elmo-folder-plugged-p folder)
108 (elmo-call-func folder "create-folder")
109 (elmo-dop-create-folder folder)))
111 (defun elmo-delete-folder (folder)
112 (let ((type (elmo-folder-get-type folder)))
113 (if (or (not (memq type '(localdir localnews archive imap4 maildir)))
114 (if (elmo-folder-plugged-p folder)
115 (elmo-call-func folder "delete-folder")
116 (elmo-dop-delete-folder folder)))
117 ;; If folder doesn't support delete folder, delete msgdb path only.
118 (elmo-msgdb-delete-path folder))))
120 (defun elmo-rename-folder (old-folder new-folder)
121 (let ((old-type (elmo-folder-get-type old-folder))
122 (new-type (elmo-folder-get-type new-folder)))
123 (if (not (eq old-type new-type))
124 (error "not same folder type")
125 (unless (and (memq old-type '(localdir localnews archive imap4))
126 (elmo-folder-identical-system-p old-folder new-folder))
127 (error "rename folder not supported"))
128 (if (elmo-folder-plugged-p old-folder)
130 (if (or (file-exists-p (elmo-msgdb-expand-path new-folder))
131 (elmo-folder-exists-p new-folder))
132 (error "already exists folder: %s" new-folder)
134 (elmo-call-func old-folder "rename-folder"
135 (elmo-folder-get-spec new-folder))
136 (elmo-msgdb-rename-path old-folder new-folder))
137 (elmo-dop-rename-folder old-folder new-folder)))))
139 (defun elmo-read-msg-no-cache (folder msg outbuf)
140 "Read messsage specified by FOLDER and MSG(number) into OUTBUF
142 (elmo-call-func folder "read-msg" msg outbuf))
144 (defun elmo-force-cache-msg (folder number msgid &optional loc-alist)
145 "Force cache message."
146 (let* ((cache-file (elmo-cache-get-path msgid))
149 (setq dir (directory-file-name (file-name-directory cache-file)))
150 (if (not (file-exists-p dir))
151 (elmo-make-directory dir))
152 (if (elmo-local-file-p folder number)
153 (elmo-copy-file (elmo-get-msg-filename folder number loc-alist)
156 (elmo-call-func folder "read-msg" number (current-buffer))
157 (as-binary-output-file
158 (write-region (point-min) (point-max) cache-file nil 'no-msg)))))))
160 (defun elmo-prefetch-msg (folder msg outbuf msgdb)
161 "Read message into outbuf with cacheing."
163 (let* ((number-alist (elmo-msgdb-get-number-alist
164 (or msgdb (elmo-msgdb-load folder))))
165 (dir (elmo-msgdb-expand-path folder))
166 (message-id (cdr (assq msg number-alist)))
169 ret-val part-num real-fld-num)
171 (if (elmo-cache-exists-p message-id)
173 ;; cache doesn't exist.
174 (setq real-fld-num (elmo-get-real-folder-number
176 (setq type (elmo-folder-get-type (car real-fld-num)))
177 (cond ((eq type 'imap4)
178 (setq ret-val (elmo-imap4-prefetch-msg
179 (elmo-folder-get-spec (car real-fld-num))
182 ((elmo-folder-local-p (car real-fld-num)))
183 (t (setq ret-val (elmo-call-func (car real-fld-num)
185 (cdr real-fld-num) outbuf))))
187 (elmo-cache-save message-id
188 (elmo-string-partial-p ret-val)
192 (defun elmo-prefetch-msgs (folder msgs)
193 "prefetch messages for queueing."
194 (let* ((msgdb (elmo-msgdb-load folder))
195 (number-alist (elmo-msgdb-get-number-alist msgdb))
200 (setq msg (car msgs))
201 (setq msgid (cdr (assq msg number-alist)))
202 (message "%s:Prefetching... %d/%d message(s)"
204 (setq count (+ 1 count)) len)
205 (elmo-force-cache-msg folder msg msgid)
206 (setq msgs (cdr msgs)))))
208 ;; elmo-read-msg (folder msg outbuf msgdb)
210 (defun elmo-read-msg (folder msg outbuf msgdb &optional force-reload)
211 "Read message into outbuf."
212 (let ((inhibit-read-only t))
213 ;;Only use elmo-read-msg-with-cache, because if folder is network and
214 ;;elmo-use-cache-p is nil, cannot read important msg. (by muse)
215 ;;(if (not (elmo-use-cache-p folder msg))
216 ;; (elmo-read-msg-no-cache folder msg outbuf)
217 (elmo-read-msg-with-cache folder msg outbuf msgdb force-reload)))
219 (defun elmo-read-msg-with-cache (folder msg outbuf msgdb
220 &optional force-reload)
221 "Read message into outbuf with cacheing."
222 (let* ((number-alist (elmo-msgdb-get-number-alist
223 (or msgdb (elmo-msgdb-load folder))))
224 (dir (elmo-msgdb-expand-path folder))
225 (message-id (cdr (assq msg number-alist)))
226 (type (elmo-folder-number-get-type folder msg))
228 ret-val part-num real-fld-num)
230 (if (and (not force-reload)
231 (not (elmo-local-file-p folder msg)))
232 (setq ret-val (elmo-cache-read message-id folder msg)))
235 ;; cache doesn't exist.
236 (setq real-fld-num (elmo-get-real-folder-number
238 (if (setq ret-val (elmo-call-func (car real-fld-num)
240 (cdr real-fld-num) outbuf))
242 (not (elmo-local-file-p folder msg))
243 (elmo-use-cache-p folder msg))
244 (elmo-cache-save message-id
245 (elmo-string-partial-p ret-val)
249 (defun elmo-copy-msgs (src-folder msgs dst-folder &optional msgdb same-number)
250 (let* ((src-spec (elmo-folder-get-spec src-folder))
252 (elmo-msgdb-get-location msgdb)
253 (elmo-msgdb-location-load
254 (elmo-msgdb-expand-path nil src-spec)))))
255 (if (eq (car src-spec) 'archive)
256 (elmo-archive-copy-msgs-froms
257 (elmo-folder-get-spec dst-folder)
258 msgs src-spec loc-alist same-number)
259 (elmo-call-func dst-folder "copy-msgs"
260 msgs src-spec loc-alist same-number))))
262 (defun elmo-move-msgs (src-folder msgs dst-folder
263 &optional msgdb all done
269 (let* ((db (or msgdb (elmo-msgdb-load src-folder)))
270 (number-alist (elmo-msgdb-get-number-alist db))
271 (mark-alist (elmo-msgdb-get-mark-alist db))
274 (all-msg-num (or all len))
275 (done-msg-num (or done 0))
276 (progress-message (if no-delete
277 "Copying messages..."
278 "Moving messages..."))
279 (tmp-buf (get-buffer-create " *elmo-move-msg*"))
281 ret-val real-fld-num done-copy dir pair
282 mes-string message-id src-cache i unseen seen-list)
283 (setq i done-msg-num)
285 (when (and (not (eq dst-folder 'null))
286 (elmo-folder-direct-copy-p src-folder dst-folder))
287 (message (concat (if no-delete "Copying" "Moving")
288 " %d message(s)...") (length messages))
289 (unless (elmo-copy-msgs src-folder
294 (error "Copy message to %s failed" dst-folder))
297 (setq real-fld-num (elmo-get-real-folder-number src-folder
299 (setq message-id (cdr (setq pair (assq (car messages) number-alist))))
301 (if (and (not (eq dst-folder 'null))
302 (not (and unread-marks
305 (cadr (assq (car messages) mark-alist))
307 (setq seen-list (cons message-id seen-list)))
308 (unless (or (eq dst-folder 'null) done-copy)
309 (if (and (elmo-folder-plugged-p src-folder)
310 (elmo-folder-plugged-p dst-folder)
311 (elmo-folder-identical-system-p (car real-fld-num)
313 ;; online and identical system...so copy 'em!
315 (elmo-copy-msgs (car real-fld-num)
316 (list (cdr real-fld-num))
320 (error "Copy message to %s failed" dst-folder))
321 ;; use cache if exists.
322 ;; if there's other message with same message-id,
324 (elmo-read-msg src-folder (car messages)
326 (and (elmo-folder-plugged-p src-folder)
331 (cdr (memq pair number-alist)))
335 (unless (eq (buffer-size) 0)
336 (unless (elmo-append-msg dst-folder (buffer-string) message-id
337 (if same-number (car messages))
338 ;; null means all unread.
339 (or (null unread-marks)
341 (error "move: append message to %s failed" dst-folder)))))
342 ;; delete src cache if it is partial.
343 (elmo-cache-delete-partial message-id src-folder (car messages))
344 (setq ret-val (nconc ret-val (list (car messages))))
345 (when (> all-msg-num elmo-display-progress-threshold)
347 (elmo-display-progress
348 'elmo-move-msgs progress-message
349 (/ (* i 100) all-msg-num)))
350 (setq messages (cdr messages)))
352 (unless (eq dst-folder 'null)
353 (setq dir (elmo-msgdb-expand-path dst-folder))
354 (elmo-msgdb-seen-save dir
355 (append (elmo-msgdb-seen-load dir) seen-list)))
356 (kill-buffer tmp-buf)
357 (if (and (not no-delete) ret-val)
359 (if (not no-delete-info)
360 (message "Cleaning up src folder..."))
361 (if (and (elmo-delete-msgs src-folder ret-val db)
362 (elmo-msgdb-delete-msgs src-folder ret-val db t))
364 (message "move: delete messages from %s failed." src-folder)
368 (not no-delete-info))
369 (message "Cleaning up src folder...done.")
374 (message "Copying messages...done.")
377 (message "No message was moved.")
378 (message "Moving messages failed.")
382 ;; boolean elmo-delete-msgs (folder msgs)
383 (defun elmo-delete-msgs (folder msgs &optional msgdb)
384 ;; remove from real folder.
385 (if (elmo-folder-plugged-p folder)
386 (elmo-call-func folder "delete-msgs" msgs)
387 (elmo-dop-delete-msgs folder msgs msgdb)))
390 ;; Server side search.
392 (defun elmo-search (folder condition &optional from-msgs)
393 (let ((type (elmo-folder-get-type folder)))
394 (if (elmo-folder-plugged-p folder)
395 (elmo-call-func folder "search" condition from-msgs)
396 (elmo-cache-search-all folder condition from-msgs))))
398 (defun elmo-msgdb-create (folder numlist new-mark already-mark
399 seen-mark important-mark seen-list)
400 (if (elmo-folder-plugged-p folder)
401 (elmo-call-func folder "msgdb-create" numlist new-mark already-mark
402 seen-mark important-mark seen-list)
403 (elmo-dop-msgdb-create folder numlist new-mark already-mark
404 seen-mark important-mark seen-list)))
406 (defun elmo-make-folder-numbers-list (folder msgs)
407 (let ((msg-list msgs)
411 (when (> (car msg-list) 0)
412 (setq pair (elmo-get-real-folder-number folder (car msg-list)))
413 (if (setq fld-list (assoc (car pair) ret-val))
414 (setcdr fld-list (cons (cdr pair) (cdr fld-list)))
415 (setq ret-val (cons (cons (car pair) (list (cdr pair))) ret-val))))
416 (setq msg-list (cdr msg-list)))
419 (defun elmo-call-func-on-markable-msgs (folder func-name msgs msgdb)
421 (let ((folder-numbers (elmo-make-folder-numbers-list folder msgs))
423 (while folder-numbers
426 (elmo-folder-get-spec
427 (car (car folder-numbers)))))
429 (memq type '(maildir internal)))
430 (if (elmo-folder-plugged-p folder)
431 (elmo-call-func (car (car folder-numbers)) func-name
432 (cdr (car folder-numbers)))
433 (if elmo-enable-disconnected-operation
434 (elmo-dop-call-func-on-msgs
435 (car (car folder-numbers)) ; real folder
437 (cdr (car folder-numbers)) ; real number
439 (error "Unplugged"))))
440 (setq folder-numbers (cdr folder-numbers))))))
442 (defun elmo-unmark-important (folder msgs msgdb)
443 (elmo-call-func-on-markable-msgs folder "unmark-important" msgs msgdb))
445 (defun elmo-mark-as-important (folder msgs msgdb)
446 (elmo-call-func-on-markable-msgs folder "mark-as-important" msgs msgdb))
448 (defun elmo-mark-as-read (folder msgs msgdb)
449 (elmo-call-func-on-markable-msgs folder "mark-as-read" msgs msgdb))
451 (defun elmo-mark-as-unread (folder msgs msgdb)
452 (elmo-call-func-on-markable-msgs folder "mark-as-unread" msgs msgdb))
454 (defun elmo-msgdb-create-as-numlist (folder numlist new-mark already-mark
455 seen-mark important-mark seen-list)
456 (if (elmo-folder-plugged-p folder)
457 (elmo-call-func folder "msgdb-create-as-numlist" numlist
458 new-mark already-mark seen-mark important-mark seen-list)
459 (elmo-dop-msgdb-create-as-numlist
460 folder numlist new-mark already-mark
461 seen-mark important-mark seen-list)))
463 ;; msgdb elmo-msgdb-load (folder)
464 (defun elmo-msgdb-load (folder &optional spec)
465 (message "Loading msgdb for %s..." folder)
466 (let* ((path (elmo-msgdb-expand-path folder spec))
467 (overview (elmo-msgdb-overview-load path))
470 (elmo-msgdb-number-load path)
471 (elmo-msgdb-mark-load path)
472 (elmo-msgdb-location-load path)
473 (elmo-msgdb-make-overview-hashtb overview)
475 (message "Loading msgdb for %s...done." folder)
476 (elmo-folder-set-info-max-by-numdb folder (nth 1 ret-val))
479 ;; boolean elmo-msgdb-save (folder msgdb)
480 (defun elmo-msgdb-save (folder msgdb)
481 (message "Saving msgdb for %s..." folder)
483 (let ((path (elmo-msgdb-expand-path folder)))
484 (elmo-msgdb-overview-save path (car msgdb))
485 (elmo-msgdb-number-save path (cadr msgdb))
486 (elmo-msgdb-mark-save path (caddr msgdb))
487 (elmo-msgdb-location-save path (cadddr msgdb))
488 ;(elmo-sync-validity folder);; for validity check!!
490 (message "Saving msgdb for %s...done." folder)
491 (elmo-folder-set-info-max-by-numdb folder (cadr msgdb)))
493 (defun elmo-msgdb-add-msgs-to-seen-list-subr (msgs msgdb seen-marks seen-list)
495 (let* ((seen-mark-list (string-to-char-list seen-marks))
496 (number-alist (elmo-msgdb-get-number-alist msgdb))
497 (mark-alist (elmo-msgdb-get-mark-alist msgdb))
500 (if (setq ent (assq (car msgs) mark-alist))
501 (if (memq (string-to-char (cadr ent)) seen-mark-list)
503 (cons (cdr (assq (car msgs) number-alist)) seen-list)))
504 ;; no mark ... seen...
506 (cons (cdr (assq (car msgs) number-alist)) seen-list)))
507 (setq msgs (cdr msgs)))
510 (defun elmo-msgdb-add-msgs-to-seen-list (folder msgs msgdb seen-marks)
512 (unless (eq folder 'null) ;; black hole
513 (let* ((dir (elmo-msgdb-expand-path folder))
514 (seen-list (elmo-msgdb-seen-load dir)))
516 (elmo-msgdb-add-msgs-to-seen-list-subr
517 msgs msgdb seen-marks seen-list))
518 (elmo-msgdb-seen-save dir seen-list))))
520 ;; msgdb elmo-append-msg (folder string)
521 (defun elmo-append-msg (folder string &optional message-id msg no-see)
522 (let ((type (elmo-folder-get-type folder))
524 (cond ((eq type 'imap4)
525 (if (elmo-folder-plugged-p folder)
526 (elmo-call-func folder "append-msg" string msg no-see)
527 (elmo-dop-append-msg folder string message-id)))
530 (elmo-cache-append-msg
531 (elmo-folder-get-spec folder)
532 string message-id msg no-see)
533 (error "elmo-cache-append-msg require message-id")))
535 (elmo-call-func folder "append-msg" string msg no-see)))))
537 (defun elmo-check-validity (folder)
538 (elmo-call-func folder "check-validity"
540 elmo-msgdb-validity-filename
541 (elmo-msgdb-expand-path folder))))
543 (defun elmo-pack-number (folder msgdb arg)
544 (let ((type (elmo-folder-get-type folder)))
545 (if (memq type '(localdir localnews))
546 (elmo-call-func folder "pack-number" msgdb arg)
547 (error "pack-number not supported"))))
549 (defun elmo-sync-validity (folder)
550 (elmo-call-func folder "sync-validity"
552 elmo-msgdb-validity-filename
553 (elmo-msgdb-expand-path folder))))
555 (defun elmo-use-cache-p (folder number)
556 (elmo-call-func folder "use-cache-p" number)
559 (defun elmo-local-file-p (folder number)
560 (elmo-call-func folder "local-file-p" number))
562 (defun elmo-folder-portinfo (folder)
564 (elmo-call-func folder "portinfo")
567 (defun elmo-folder-plugged-p (folder)
569 (or (elmo-folder-local-p folder)
570 (elmo-call-func folder "plugged-p"))))
572 (defun elmo-folder-set-plugged (folder plugged &optional add)
573 (if (elmo-folder-local-p folder)
575 (elmo-call-func folder "set-plugged" plugged add)))
577 (defun elmo-generic-sync-number-alist (spec number-alist)
578 "Just return number-alist."
581 (defun elmo-generic-list-folder-unread (spec mark-alist unread-marks)
585 (function (lambda (x)
586 (if (member (cadr (assq (car x) mark-alist)) unread-marks)
590 (defun elmo-generic-list-folder-important (spec overview)
593 (defun elmo-update-number (folder msgdb)
594 (when (elmo-folder-plugged-p folder)
595 (message "Synchronize number...")
596 (let* ((numlist (elmo-msgdb-get-number-alist msgdb))
597 (len (length numlist))
599 (if (eq (length (setq
601 (elmo-call-func folder "sync-number-alist" numlist)))
604 (elmo-msgdb-set-number-alist msgdb new-numlist)
605 (message "Synchronize number...done.")
608 (defun elmo-get-msg-filename (folder number &optional loc-alist)
609 "Available if elmo-local-file-p is t."
610 (elmo-call-func folder "get-msg-filename" number loc-alist))
612 (defun elmo-strict-folder-diff (fld &optional number-alist)
614 (let* ((dir (elmo-msgdb-expand-path fld))
615 (nalist (or number-alist
616 (elmo-msgdb-number-load dir)))
617 (in-db (sort (mapcar 'car nalist) '<))
618 (in-folder (elmo-list-folder fld))
619 append-list delete-list diff)
620 (cons (if (equal in-folder in-db)
622 (setq diff (elmo-list-diff
626 (setq append-list (car diff))
627 (setq delete-list (cadr diff))
631 (- 0 (length delete-list))
633 (length in-folder))))
635 (defun elmo-list-folder-unread (folder mark-alist unread-marks)
636 (elmo-call-func folder "list-folder-unread" mark-alist unread-marks))
638 (defun elmo-list-folder-important (folder overview)
640 ;; server side importants...(append only.)
641 (if (elmo-folder-plugged-p folder)
642 (setq importants (elmo-call-func folder "list-folder-important"
644 (or elmo-msgdb-global-mark-alist
645 (setq elmo-msgdb-global-mark-alist
646 (elmo-object-load (expand-file-name
647 elmo-msgdb-global-mark-filename
651 (if (assoc (elmo-msgdb-overview-entity-get-id (car overview))
652 elmo-msgdb-global-mark-alist)
653 (setq importants (cons
654 (elmo-msgdb-overview-entity-get-number
657 (setq overview (cdr overview)))
660 (defun elmo-generic-commit (folder)
663 (defun elmo-commit (folder)
664 (elmo-call-func folder "commit"))
666 (defun elmo-clear-killed (folder)
667 (elmo-msgdb-killed-list-save (elmo-msgdb-expand-path folder) nil))
669 (defvar elmo-folder-diff-async-callback nil)
670 (defvar elmo-folder-diff-async-callback-data nil)
672 (defun elmo-folder-diff-async (folder)
673 "Get diff of FOLDER asynchronously.
674 `elmo-folder-diff-async-callback' is called with arguments of
675 FOLDER and DIFF (cons cell of UNSEEN and MESSAGES).
676 Currently works on IMAP4 folder only."
677 (if (eq (elmo-folder-get-type folder) 'imap4)
678 ;; Only works on imap4 with server diff.
680 (setq elmo-imap4-server-diff-async-callback
681 elmo-folder-diff-async-callback)
682 (setq elmo-imap4-server-diff-async-callback-data
683 elmo-folder-diff-async-callback-data)
684 (elmo-imap4-server-diff-async (elmo-folder-get-spec folder)))
685 (and elmo-folder-diff-async-callback
686 (funcall elmo-folder-diff-async-callback
688 (elmo-folder-diff folder)))))
690 ;; returns cons cell of (unsync . number-of-messages-in-folder)
691 (defun elmo-folder-diff (fld &optional number-alist)
693 (let ((type (elmo-folder-get-type fld)))
694 (cond ((eq type 'multi)
695 (elmo-multi-folder-diff fld))
696 ((and (eq type 'filter)
697 (or (elmo-multi-p fld)
699 (vectorp (nth 1 (elmo-folder-get-spec fld)))))
700 ;; not partial...unsync number is unknown.
702 (cdr (elmo-folder-diff
703 (nth 2 (elmo-folder-get-spec fld)))))))
704 ((and (eq type 'imap4)
705 elmo-use-server-diff)
706 (elmo-call-func fld "server-diff")) ;; imap4 server side diff.
708 (let ((cached-in-db-max (elmo-folder-get-info-max fld))
709 (in-folder (elmo-max-of-folder fld))
714 (not cached-in-db-max))
715 (let* ((dir (elmo-msgdb-expand-path fld))
716 (nalist (or number-alist
717 (elmo-msgdb-number-load dir))))
719 (setq in-db (sort (mapcar 'car nalist) '<))
720 (setq in-db-max (or (nth (max 0 (1- (length in-db))) in-db)
722 (if (not number-alist)
723 ;; Number-alist is not used.
724 (elmo-folder-set-info-hashtb fld in-db-max
727 ;; (and in-db (length in-db))
730 ;; info-cache exists.
731 (setq in-db-max cached-in-db-max))
732 (setq unsync (if (and in-db
734 (- (car in-folder) in-db-max)
738 (if (null (car in-folder))
740 (setq nomif (cdr in-folder))
741 (if (and unsync nomif (> unsync nomif))
743 (cons (or unsync 0) (or nomif 0)))))))
745 (defsubst elmo-folder-get-info (folder &optional hashtb)
746 (elmo-get-hash-val folder
747 (or hashtb elmo-folder-info-hashtb)))
749 (defun elmo-folder-set-info-hashtb (folder max numbers &optional new unread)
750 (let ((info (elmo-folder-get-info folder)))
752 (or new (setq new (nth 0 info)))
753 (or unread (setq unread (nth 1 info)))
754 (or numbers (setq numbers (nth 2 info)))
755 (or max (setq max (nth 3 info))))
756 (elmo-set-hash-val folder
757 (list new unread numbers max)
758 elmo-folder-info-hashtb)))
760 (defun elmo-multi-get-number-alist-list (number-alist)
761 (let ((alist (sort number-alist (function (lambda (x y) (< (car x)
764 one-alist ret-val num)
766 (setq cur-number (+ cur-number 1))
770 (/ (- (setq num (car (car alist)))
771 (* elmo-multi-divide-number cur-number))
772 elmo-multi-divide-number)))
773 (setq one-alist (nconc
777 (% num (* elmo-multi-divide-number cur-number))
778 (cdr (car alist))))))
779 (setq alist (cdr alist)))
780 (setq ret-val (nconc ret-val (list one-alist))))
783 (defun elmo-multi-folder-diff (fld)
784 (let ((flds (cdr (elmo-folder-get-spec fld)))
786 (elmo-multi-get-number-alist-list
787 (elmo-msgdb-number-load (elmo-msgdb-expand-path fld))))
789 diffs (unsync 0) (nomif 0))
791 (setq diffs (nconc diffs (list (elmo-folder-diff (car flds)
795 (setq count (+ 1 count))
796 (setq flds (cdr flds)))
798 (and (car (car diffs))
799 (setq unsync (+ unsync (car (car diffs)))))
800 (setq nomif (+ nomif (cdr (car diffs))))
801 (setq diffs (cdr diffs)))
802 (elmo-folder-set-info-hashtb fld nil nomif)
803 (cons unsync nomif)))
805 (defun elmo-folder-set-info-max-by-numdb (folder msgdb-number)
806 (let ((num-db (sort (mapcar 'car msgdb-number) '<)))
807 (elmo-folder-set-info-hashtb
809 (or (nth (max 0 (1- (length num-db))) num-db) 0)
810 nil ;;(length num-db)
813 (defun elmo-folder-get-info-max (folder)
814 "Get folder info from cache."
815 (nth 3 (elmo-folder-get-info folder)))
817 (defun elmo-folder-get-info-length (folder)
818 (nth 2 (elmo-folder-get-info folder)))
820 (defun elmo-folder-get-info-unread (folder)
821 (nth 1 (elmo-folder-get-info folder)))
823 (defun elmo-folder-info-make-hashtb (info-alist hashtb)
824 (let* ((hashtb (or hashtb
825 (elmo-make-hash (length info-alist)))))
828 (let ((info (cadr x)))
829 (and (intern-soft (car x) hashtb)
830 (elmo-set-hash-val (car x)
831 (list (nth 2 info) ;; new
832 (nth 3 info) ;; unread
833 (nth 1 info) ;; length
837 (setq elmo-folder-info-hashtb hashtb)))
839 (defun elmo-crosspost-message-set (message-id folders &optional type)
840 (if (assoc message-id elmo-crosspost-message-alist)
841 (setcdr (assoc message-id elmo-crosspost-message-alist)
843 (setq elmo-crosspost-message-alist
844 (nconc elmo-crosspost-message-alist
845 (list (list message-id folders type))))))
847 (defun elmo-crosspost-message-delete (message-id folders)
848 (let* ((id-fld (assoc message-id elmo-crosspost-message-alist))
849 (folder-list (nth 1 id-fld)))
851 (if (setq folder-list (elmo-list-delete folders folder-list))
852 (setcar (cdr id-fld) folder-list)
853 (setq elmo-crosspost-message-alist
854 (delete id-fld elmo-crosspost-message-alist))))))
857 (defun elmo-get-msgs-with-mark (mark-alist mark)
860 (if (string= (cadr (car mark-alist)) mark)
861 (cons (car (car mark-alist)) ret-val))
862 (setq mark-alist (cdr mark-alist)))
865 (defun elmo-buffer-cache-message (fld msg &optional msgdb force-reload)
866 (let* ((msg-id (cdr (assq msg (elmo-msgdb-get-number-alist msgdb))))
867 (hit (elmo-buffer-cache-hit (list fld msg msg-id)))
870 (elmo-buffer-cache-sort
871 (elmo-buffer-cache-entry-make (list fld msg msg-id) hit))
872 (setq hit (elmo-buffer-cache-add (list fld msg msg-id)))
874 (if (or force-reload read)
878 (elmo-read-msg fld msg
882 (elmo-buffer-cache-delete)
883 (error "read message %s/%s is quitted" fld msg))
885 (elmo-buffer-cache-delete)
886 (signal (car err) (cdr err))
887 nil))) ;; will not be used
888 hit)) ;; retrun value
890 (defun elmo-read-msg-with-buffer-cache (fld msg outbuf msgdb &optional force-reload)
891 (if elmo-use-buffer-cache
893 (when (setq hit (elmo-buffer-cache-message
894 (elmo-string fld) msg
899 (setq start (point-min) end (point-max)))
900 (insert-buffer-substring hit start end)))
901 (elmo-read-msg fld msg outbuf msgdb force-reload)))
903 (defun elmo-folder-pipe-p (folder)
904 (let ((type (elmo-folder-get-type folder)))
907 (let ((flds (cdr (elmo-folder-get-spec folder))))
910 (if (elmo-folder-pipe-p (car flds))
917 (nth 2 (elmo-folder-get-spec folder))))
922 (defun elmo-multi-p (folder)
923 (let ((type (elmo-folder-get-type folder)))
929 (elmo-pipe-spec-dst (elmo-folder-get-spec folder))))
932 (nth 2 (elmo-folder-get-spec folder))))
937 (defun elmo-get-real-folder-number (folder number)
938 (let ((type (elmo-folder-get-type folder)))
941 (elmo-multi-get-real-folder-number folder number))
943 (elmo-get-real-folder-number
944 (elmo-pipe-spec-dst (elmo-folder-get-spec folder) )
947 (elmo-get-real-folder-number
948 (nth 2 (elmo-folder-get-spec folder)) number))
953 (defun elmo-folder-get-primitive-spec-list (folder &optional spec-list)
954 (let ((type (elmo-folder-get-type folder))
957 ((or (eq type 'multi)
959 (let ((flds (cdr (elmo-folder-get-spec folder)))
962 (setq spec (elmo-folder-get-primitive-spec-list (car flds)))
963 (if (not (memq (car spec) specs))
964 (setq specs (append specs spec)))
965 (setq flds (cdr flds)))))
968 (elmo-folder-get-primitive-spec-list
969 (nth 2 (elmo-folder-get-spec folder)))))
971 (setq specs (list (elmo-folder-get-spec folder)))
975 (defun elmo-folder-get-primitive-folder-list (folder)
976 (let* ((type (elmo-folder-get-type folder)))
978 ((or (eq type 'multi)
980 (let ((flds (cdr (elmo-folder-get-spec folder)))
983 (setq ret-val (append ret-val
984 (elmo-folder-get-primitive-folder-list
986 (setq flds (cdr flds)))
989 (elmo-folder-get-primitive-folder-list
990 (nth 2 (elmo-folder-get-spec folder))))
995 (defun elmo-folder-contains-multi (folder)
996 (let ((cur-spec (elmo-folder-get-spec folder)))
1000 ((eq (car cur-spec) 'filter)
1001 (setq cur-spec (elmo-folder-get-spec (nth 2 cur-spec))))
1002 ((eq (car cur-spec) 'pipe)
1003 (setq cur-spec (elmo-folder-get-spec (elmo-pipe-spec-src cur-spec))))
1004 ((eq (car cur-spec) 'multi)
1006 (t (setq cur-spec nil)))))
1009 (defun elmo-folder-contains-type (folder type)
1010 (let ((spec (elmo-folder-get-spec folder)))
1012 ((eq (car spec) 'filter)
1013 (elmo-folder-contains-type (nth 2 spec) type))
1014 ((eq (car spec) 'pipe)
1015 (elmo-folder-contains-type (elmo-pipe-spec-dst spec) type))
1016 ((eq (car spec) 'multi)
1017 (let ((folders (cdr spec)))
1020 (if (elmo-folder-contains-type (car folders) type)
1022 (setq folders (cdr folders))))))
1023 ((eq (car spec) type)
1027 (defun elmo-folder-number-get-spec (folder number)
1028 (let ((type (elmo-folder-get-type folder)))
1031 (elmo-multi-folder-number-get-spec folder number))
1033 (elmo-folder-number-get-spec
1034 (elmo-pipe-spec-dst (elmo-folder-get-spec folder)) number))
1036 (elmo-folder-number-get-spec
1037 (nth 2 (elmo-folder-get-spec folder)) number))
1039 (elmo-folder-get-spec folder)
1042 (defun elmo-folder-number-get-type (folder number)
1043 (car (elmo-folder-number-get-spec folder number)))
1045 (defun elmo-multi-folder-number-get-spec (folder number)
1046 (let* ((spec (elmo-folder-get-spec folder))
1048 (fld (nth (- (/ number elmo-multi-divide-number) 1) flds)))
1049 (elmo-folder-number-get-spec fld number)))
1052 (autoload 'elmo-imap4-get-connection "elmo-imap4")
1053 (autoload 'elmo-nntp-make-groups-hashtb "elmo-nntp")
1054 (autoload 'elmo-nntp-post "elmo-nntp")
1055 (autoload 'elmo-localdir-max-of-folder "elmo-localdir")
1056 (autoload 'elmo-localdir-msgdb-create-overview-entity-from-file "elmo-localdir")
1057 (autoload 'elmo-multi-folder-diff "elmo-multi")
1058 (autoload 'elmo-archive-copy-msgs-froms "elmo-archive")
1060 ;;; elmo2.el ends here