1 ;;; elmo-multi.el -- Multiple Folder Interface for ELMO.
3 ;; Copyright (C) 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.
35 (defvar elmo-multi-divide-number 100000
36 "*Multi divider number.")
40 (luna-define-class elmo-multi-folder (elmo-folder)
41 (children divide-number))
42 (luna-define-internal-accessors 'elmo-multi-folder))
44 (luna-define-method elmo-folder-initialize ((folder
47 (elmo-multi-folder-set-children-internal
49 (mapcar 'elmo-make-folder (split-string name ",")))
50 (elmo-multi-folder-set-divide-number-internal
52 elmo-multi-divide-number)
55 (luna-define-method elmo-folder-open-internal ((folder elmo-multi-folder))
56 (dolist (fld (elmo-multi-folder-children-internal folder))
57 (elmo-folder-open-internal fld)))
59 (luna-define-method elmo-folder-check ((folder elmo-multi-folder))
60 (dolist (fld (elmo-multi-folder-children-internal folder))
61 (elmo-folder-check fld)))
63 (luna-define-method elmo-folder-close-internal ((folder elmo-multi-folder))
64 (dolist (fld (elmo-multi-folder-children-internal folder))
65 (elmo-folder-close-internal fld)))
67 (luna-define-method elmo-folder-expand-msgdb-path ((folder
69 (expand-file-name (elmo-replace-string-as-filename
70 (elmo-folder-name-internal folder))
71 (expand-file-name "multi"
74 (luna-define-method elmo-folder-get-primitive-list ((folder elmo-multi-folder))
77 'elmo-folder-get-primitive-list
78 (elmo-multi-folder-children-internal folder))))
80 (luna-define-method elmo-folder-contains-type ((folder elmo-multi-folder) type)
81 (let ((children (elmo-multi-folder-children-internal folder))
84 (when (elmo-folder-contains-type (car children) type)
87 (setq children (cdr children)))
90 (luna-define-method elmo-message-use-cache-p ((folder elmo-multi-folder)
92 (elmo-message-use-cache-p
93 (nth (- (/ number (elmo-multi-folder-divide-number-internal folder)) 1)
94 (elmo-multi-folder-children-internal folder))
95 (% number (elmo-multi-folder-divide-number-internal folder))))
97 (luna-define-method elmo-message-folder ((folder elmo-multi-folder)
99 (nth (- (/ number (elmo-multi-folder-divide-number-internal folder)) 1)
100 (elmo-multi-folder-children-internal folder)))
102 (defun elmo-multi-msgdb (msgdb base)
103 (list (mapcar (function
105 (elmo-msgdb-overview-entity-set-number
108 (elmo-msgdb-overview-entity-get-number x)))))
118 (cdr x)))) (nth 2 msgdb))))
120 (defun elmo-multi-split-numbers (folder numlist &optional as-is)
121 (let ((numbers (sort numlist '<))
122 (divider (elmo-multi-folder-divide-number-internal folder))
124 one-list numbers-list)
126 (setq cur-number (+ cur-number 1))
131 (* divider cur-number))
133 (setq one-list (nconc
139 (* divider cur-number))))))
140 (setq numbers (cdr numbers)))
141 (setq numbers-list (nconc numbers-list (list one-list))))
144 (luna-define-method elmo-folder-msgdb-create ((folder elmo-multi-folder)
145 numbers new-mark already-mark
146 seen-mark important-mark
148 (let* ((folders (elmo-multi-folder-children-internal folder))
149 overview number-alist mark-alist entity
154 (setq numbers-list (elmo-multi-split-numbers folder numbers))
156 (while (< cur-number (length folders))
157 (if (nth cur-number numbers-list)
162 (elmo-folder-msgdb-create (nth cur-number folders)
163 (nth cur-number numbers-list)
164 new-mark already-mark
165 seen-mark important-mark
167 (* (elmo-multi-folder-divide-number-internal folder)
169 (setq cur-number (1+ cur-number)))
170 (elmo-msgdb-sort-by-date msgdb)))
172 (luna-define-method elmo-folder-process-crosspost ((folder elmo-multi-folder)
175 (let ((number-alists (elmo-multi-split-number-alist
177 (elmo-msgdb-get-number-alist
178 (elmo-folder-msgdb folder))))
180 (dolist (child (elmo-multi-folder-children-internal folder))
181 (elmo-folder-process-crosspost child (car number-alists))
182 (setq cur-number (+ 1 cur-number)
183 number-alists (cdr number-alists)))))
185 (defsubst elmo-multi-folder-append-msgdb (folder append-msgdb)
187 (let* ((number-alist (elmo-msgdb-get-number-alist append-msgdb))
188 (all-alist (copy-sequence (append
189 (elmo-msgdb-get-number-alist
190 (elmo-folder-msgdb folder))
193 overview to-be-deleted
196 (setq all-alist (delq (car cur) all-alist))
197 ;; same message id exists.
198 (if (setq same (rassoc (cdr (car cur)) all-alist))
199 (unless (= (/ (car (car cur))
200 (elmo-multi-folder-divide-number-internal folder))
202 (elmo-multi-folder-divide-number-internal folder)))
203 ;; base is also same...delete it!
205 (append to-be-deleted (list (car (car cur)))))))
206 (setq cur (cdr cur)))
207 (cond ((eq (elmo-folder-process-duplicates-internal folder)
210 (elmo-msgdb-append-to-killed-list folder to-be-deleted)
211 (setq overview (elmo-delete-if
213 (memq (elmo-msgdb-overview-entity-get-number
216 (elmo-msgdb-get-overview append-msgdb)))
217 ;; Should be mark as read.
218 (elmo-folder-mark-as-read folder to-be-deleted)
219 (elmo-msgdb-set-overview append-msgdb overview))
220 ((eq (elmo-folder-process-duplicates-internal folder)
222 ;; Mark as read duplicates.
223 (elmo-folder-mark-as-read folder to-be-deleted))
226 (setq to-be-deleted nil)))
227 (elmo-folder-set-msgdb-internal folder
229 (elmo-folder-msgdb folder)
231 (length to-be-deleted))
234 (luna-define-method elmo-folder-append-msgdb ((folder elmo-multi-folder)
236 (elmo-multi-folder-append-msgdb folder append-msgdb))
238 (defmacro elmo-multi-real-folder-number (folder number)
239 "Returns a cons cell of real FOLDER and NUMBER."
242 (elmo-multi-folder-divide-number-internal (, folder)))
243 1) (elmo-multi-folder-children-internal (, folder)))
244 (% (, number) (elmo-multi-folder-divide-number-internal
247 (defsubst elmo-multi-find-fetch-strategy (folder entity ignore-cache)
249 (let ((pair (elmo-multi-real-folder-number
251 (elmo-msgdb-overview-entity-get-number entity)))
252 (new-entity (elmo-msgdb-copy-overview-entity entity)))
254 (elmo-msgdb-overview-entity-set-number new-entity (cdr pair)))
255 (elmo-find-fetch-strategy (car pair) new-entity ignore-cache))
256 (elmo-make-fetch-strategy 'entire)))
258 (luna-define-method elmo-find-fetch-strategy
259 ((folder elmo-multi-folder)
260 entity &optional ignore-cache)
261 (elmo-multi-find-fetch-strategy folder entity ignore-cache))
263 (luna-define-method elmo-message-fetch ((folder elmo-multi-folder)
265 &optional section outbuf unseen)
266 (let ((pair (elmo-multi-real-folder-number folder number)))
267 (elmo-message-fetch (car pair) (cdr pair) strategy section outbuf unseen)))
269 (luna-define-method elmo-folder-delete-messages ((folder elmo-multi-folder)
271 (let ((flds (elmo-multi-folder-children-internal folder))
274 (setq one-list-list (elmo-multi-split-numbers folder numbers))
275 (while (< cur-number (length flds))
276 (elmo-folder-delete-messages (nth cur-number flds)
277 (nth cur-number one-list-list))
278 (setq cur-number (+ 1 cur-number)))
281 (luna-define-method elmo-folder-diff ((folder elmo-multi-folder)
283 (elmo-multi-folder-diff folder numbers))
285 (defun elmo-multi-folder-diff (folder numbers)
286 (let ((flds (elmo-multi-folder-children-internal folder))
287 (numbers (mapcar 'car
288 (elmo-msgdb-number-load
289 (elmo-folder-msgdb-path folder))))
290 (killed (elmo-msgdb-killed-list-load (elmo-folder-msgdb-path folder)))
296 ;; If first time, dummy numbers is used as current number list.
299 (divider (elmo-multi-folder-divide-number-internal folder)))
300 (dolist (folder flds)
303 (cons (* i divider) numbers)))))
305 (elmo-multi-split-numbers folder
308 (elmo-number-set-to-number-list killed)
311 (setq diffs (nconc diffs (list (elmo-folder-diff
314 (setq count (+ 1 count))
315 (setq num-list (cdr num-list))
316 (setq flds (cdr flds)))
318 (and (car (car diffs))
319 (setq unsync (+ unsync (car (car diffs)))))
320 (setq messages (+ messages (cdr (car diffs))))
321 (setq diffs (cdr diffs)))
322 (elmo-folder-set-info-hashtb folder nil messages)
323 (cons unsync messages)))
325 (defun elmo-multi-split-number-alist (folder number-alist)
326 (let ((alist (sort (copy-sequence number-alist)
327 (lambda (pair1 pair2)
328 (< (car pair1)(car pair2)))))
332 (setq cur-number (+ cur-number 1))
336 (/ (- (setq num (car (car alist)))
337 (* elmo-multi-divide-number cur-number))
338 (elmo-multi-folder-divide-number-internal folder))))
339 (setq one-alist (nconc
343 (% num (* (elmo-multi-folder-divide-number-internal
345 (cdr (car alist))))))
346 (setq alist (cdr alist)))
347 (setq split (nconc split (list one-alist))))
350 (defun elmo-multi-split-mark-alist (folder mark-alist)
352 (alist (sort (copy-sequence mark-alist)
353 (lambda (pair1 pair2)
354 (< (car pair1)(car pair2)))))
357 (setq cur-number (+ cur-number 1))
361 (/ (- (car (car alist))
362 (* (elmo-multi-folder-divide-number-internal
364 (elmo-multi-folder-divide-number-internal folder))))
365 (setq one-alist (nconc
368 (list (% (car (car alist))
369 (* (elmo-multi-folder-divide-number-internal
371 (cadr (car alist))))))
372 (setq alist (cdr alist)))
373 (setq result (nconc result (list one-alist))))
376 (luna-define-method elmo-folder-list-unreads-internal
377 ((folder elmo-multi-folder) unread-marks &optional mark-alist)
378 (elmo-multi-folder-list-unreads-internal folder unread-marks))
380 (defun elmo-multi-folder-list-unreads-internal (folder unread-marks)
381 (let ((folders (elmo-multi-folder-children-internal folder))
382 (mark-alists (elmo-multi-split-mark-alist
384 (elmo-msgdb-get-mark-alist
385 (elmo-folder-msgdb folder))))
390 (setq cur-number (+ cur-number 1))
391 (unless (listp (setq unreads
392 (elmo-folder-list-unreads-internal
393 (car folders) unread-marks (car mark-alists))))
394 (setq unreads (delq nil
397 (if (member (cadr x) unread-marks)
399 (car mark-alists)))))
406 (elmo-multi-folder-divide-number-internal
409 (setq mark-alists (cdr mark-alists)
410 folders (cdr folders)))
413 (luna-define-method elmo-folder-list-importants-internal
414 ((folder elmo-multi-folder) important-mark)
415 (let ((folders (elmo-multi-folder-children-internal folder))
416 (mark-alists (elmo-multi-split-mark-alist
418 (elmo-msgdb-get-mark-alist
419 (elmo-folder-msgdb folder))))
424 (setq cur-number (+ cur-number 1))
425 (unless (listp (setq importants
426 (elmo-folder-list-importants-internal
427 (car folders) important-mark)))
428 (setq importants (delq nil
431 (if (string= (cadr x) important-mark)
433 (car mark-alists)))))
435 (nconc all-importants
440 (elmo-multi-folder-divide-number-internal
443 (setq mark-alists (cdr mark-alists)
444 folders (cdr folders)))
447 (luna-define-method elmo-folder-list-messages-internal
448 ((folder elmo-multi-folder) &optional nohide)
449 (let* ((flds (elmo-multi-folder-children-internal folder))
453 (setq cur-number (+ cur-number 1))
454 (setq list (elmo-folder-list-messages-internal (car flds)))
463 (* (elmo-multi-folder-divide-number-internal
464 folder) cur-number) x)))
470 (eq cur-number (/ num
471 (elmo-multi-folder-divide-number-internal
475 (elmo-msgdb-get-number-alist
476 (elmo-folder-msgdb folder)))))))
477 (setq flds (cdr flds)))
480 (luna-define-method elmo-folder-exists-p ((folder elmo-multi-folder))
481 (let ((flds (elmo-multi-folder-children-internal folder)))
484 (unless (elmo-folder-exists-p (car flds))
486 (setq flds (cdr flds)))
489 (luna-define-method elmo-folder-creatable-p ((folder elmo-multi-folder))
490 (let ((flds (elmo-multi-folder-children-internal folder)))
493 (when (and (elmo-folder-creatable-p (car flds))
494 (not (elmo-folder-exists-p (car flds))))
495 ;; If folder already exists, don't to `creatable'.
496 ;; Because this function is called, when folder doesn't exists.
497 (throw 'creatable t))
498 (setq flds (cdr flds)))
501 (luna-define-method elmo-folder-create ((folder elmo-multi-folder))
502 (let ((flds (elmo-multi-folder-children-internal folder)))
505 (unless (or (elmo-folder-exists-p (car flds))
506 (elmo-folder-create (car flds)))
508 (setq flds (cdr flds)))
511 (luna-define-method elmo-folder-search ((folder elmo-multi-folder)
512 condition &optional numlist)
513 (let* ((flds (elmo-multi-folder-children-internal folder))
515 numlist-list cur-numlist ; for filtered search.
519 (elmo-multi-split-numbers folder numlist t)))
521 (setq cur-number (+ cur-number 1))
523 (setq cur-numlist (car numlist-list))
524 (if (null cur-numlist)
525 ;; t means filter all.
526 (setq cur-numlist t)))
527 (setq ret-val (append
535 (* (elmo-multi-folder-divide-number-internal
536 folder) cur-number) x)))
538 (car flds) condition)))))
540 (setq numlist-list (cdr numlist-list)))
541 (setq flds (cdr flds)))
544 (luna-define-method elmo-message-use-cache-p ((folder elmo-multi-folder)
546 (let ((pair (elmo-multi-real-folder-number folder number)))
547 (elmo-message-use-cache-p (car pair) (cdr pair))))
549 (luna-define-method elmo-message-file-p ((folder elmo-multi-folder) number)
550 (let ((pair (elmo-multi-real-folder-number folder number)))
551 (elmo-message-file-p (car pair) (cdr pair))))
553 (luna-define-method elmo-message-file-name ((folder elmo-multi-folder) number)
554 (let ((pair (elmo-multi-real-folder-number folder number)))
555 (elmo-message-file-name (car pair) (cdr pair))))
557 (luna-define-method elmo-folder-plugged-p ((folder elmo-multi-folder))
558 (let ((flds (elmo-multi-folder-children-internal folder)))
561 (unless (elmo-folder-plugged-p (car flds))
562 (throw 'plugged nil))
563 (setq flds (cdr flds)))
566 (luna-define-method elmo-folder-set-plugged ((folder elmo-multi-folder)
568 (let ((flds (elmo-multi-folder-children-internal folder)))
570 (elmo-folder-set-plugged fld plugged add))))
572 (defun elmo-multi-folder-numbers-list-assoc (folder folder-numbers)
574 (while folder-numbers
575 (when (string= (elmo-folder-name-internal (car (car folder-numbers)))
576 (elmo-folder-name-internal folder))
577 (setq ent (car folder-numbers)
579 (setq folder-numbers (cdr folder-numbers)))
582 (defun elmo-multi-make-folder-numbers-list (folder msgs)
583 (let ((msg-list msgs)
587 (when (and (numberp (car msg-list))
588 (> (car msg-list) 0))
589 (setq pair (elmo-multi-real-folder-number folder (car msg-list)))
590 (if (setq fld-list (elmo-multi-folder-numbers-list-assoc
593 (setcdr fld-list (cons (cdr pair) (cdr fld-list)))
594 (setq ret-val (cons (cons (car pair) (list (cdr pair))) ret-val))))
595 (setq msg-list (cdr msg-list)))
598 (luna-define-method elmo-folder-mark-as-important ((folder elmo-multi-folder)
600 (dolist (folder-numbers (elmo-multi-make-folder-numbers-list folder numbers))
601 (elmo-folder-mark-as-important (car folder-numbers)
602 (cdr folder-numbers)))
605 (luna-define-method elmo-folder-unmark-important ((folder elmo-multi-folder)
607 (dolist (folder-numbers (elmo-multi-make-folder-numbers-list folder numbers))
608 (elmo-folder-unmark-important (car folder-numbers)
609 (cdr folder-numbers)))
612 (luna-define-method elmo-folder-mark-as-read ((folder elmo-multi-folder)
614 (dolist (folder-numbers (elmo-multi-make-folder-numbers-list folder numbers))
615 (elmo-folder-mark-as-read (car folder-numbers)
616 (cdr folder-numbers)))
619 (luna-define-method elmo-folder-unmark-read ((folder elmo-multi-folder)
621 (dolist (folder-numbers (elmo-multi-make-folder-numbers-list folder numbers))
622 (elmo-folder-unmark-read (car folder-numbers)
623 (cdr folder-numbers)))
627 (product-provide (provide 'elmo-multi) (require 'elmo-version))
629 ;;; elmo-multi.el ends here