delete->dispose (summary mark operation)
[elisp/wanderlust.git] / elmo / elmo-multi.el
1 ;;; elmo-multi.el --- Multiple Folder Interface for ELMO.
2
3 ;; Copyright (C) 1998,1999,2000 Yuuichi Teranishi <teranisi@gohome.org>
4
5 ;; Author: Yuuichi Teranishi <teranisi@gohome.org>
6 ;; Keywords: mail, net news
7
8 ;; This file is part of ELMO (Elisp Library for Message Orchestration).
9
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)
13 ;; any later version.
14 ;;
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.
19 ;;
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.
24 ;;
25
26 ;;; Commentary:
27 ;;
28
29 ;;; Code:
30 ;;
31
32 (require 'elmo)
33 (require 'luna)
34
35 (defvar elmo-multi-divide-number 100000
36   "*Multi divider number.")
37
38 ;;; ELMO Multi folder
39 (eval-and-compile
40   (luna-define-class elmo-multi-folder (elmo-folder)
41                      (children divide-number))
42   (luna-define-internal-accessors 'elmo-multi-folder))
43
44 (defmacro elmo-multi-real-folder-number (folder number)
45   "Returns a cons cell of real FOLDER and NUMBER."
46   (` (cons (nth (- 
47                  (/ (, number)
48                     (elmo-multi-folder-divide-number-internal (, folder)))
49                  1) (elmo-multi-folder-children-internal (, folder)))
50            (% (, number) (elmo-multi-folder-divide-number-internal
51                           (, folder))))))
52
53 (luna-define-method elmo-folder-initialize ((folder
54                                              elmo-multi-folder)
55                                             name)
56   (while (> (length (car (setq name (elmo-parse-token name ",")))) 0)
57     (elmo-multi-folder-set-children-internal
58      folder
59      (nconc (elmo-multi-folder-children-internal
60              folder)
61             (list (elmo-make-folder (car name)))))
62     (setq name (cdr name))
63     (when (and (> (length name) 0)
64                (eq (aref name 0) ?,))
65       (setq name (substring name 1))))
66   (elmo-multi-folder-set-divide-number-internal
67    folder
68    elmo-multi-divide-number)
69   folder)
70
71 (luna-define-method elmo-folder-open-internal ((folder elmo-multi-folder))
72   (dolist (fld (elmo-multi-folder-children-internal folder))
73     (elmo-folder-open-internal fld)))
74
75 (luna-define-method elmo-folder-check ((folder elmo-multi-folder))
76   (dolist (fld (elmo-multi-folder-children-internal folder))
77     (elmo-folder-check fld)))
78
79 (luna-define-method elmo-folder-close-internal ((folder elmo-multi-folder))
80   (dolist (fld (elmo-multi-folder-children-internal folder))
81     (elmo-folder-close-internal fld)))
82
83 (luna-define-method elmo-folder-close :after ((folder elmo-multi-folder))
84   (dolist (fld (elmo-multi-folder-children-internal folder))
85     (elmo-folder-set-msgdb-internal fld nil)))
86
87 (luna-define-method elmo-folder-synchronize ((folder elmo-multi-folder)
88                                              &optional ignore-msgdb
89                                              no-check)
90   (dolist (fld (elmo-multi-folder-children-internal folder))
91     (elmo-folder-synchronize fld ignore-msgdb no-check))
92   0)
93
94 (luna-define-method elmo-folder-expand-msgdb-path ((folder
95                                                     elmo-multi-folder))
96   (expand-file-name (elmo-replace-string-as-filename
97                      (elmo-folder-name-internal folder))
98                     (expand-file-name "multi"
99                                       elmo-msgdb-directory)))
100
101 (luna-define-method elmo-folder-newsgroups ((folder elmo-multi-folder))
102   (delq nil
103         (elmo-flatten
104          (mapcar
105           'elmo-folder-newsgroups
106           (elmo-flatten
107            (mapcar
108             'elmo-folder-get-primitive-list
109             (elmo-multi-folder-children-internal folder)))))))
110
111 (luna-define-method elmo-folder-get-primitive-list ((folder elmo-multi-folder))
112   (elmo-flatten
113    (mapcar
114     'elmo-folder-get-primitive-list
115     (elmo-multi-folder-children-internal folder))))
116
117 (luna-define-method elmo-folder-contains-type ((folder elmo-multi-folder) type)
118   (let ((children (elmo-multi-folder-children-internal folder))
119         match)
120     (while children
121       (when (elmo-folder-contains-type (car children) type)
122         (setq match t)
123         (setq children nil))
124       (setq children (cdr children)))
125     match))
126
127 (luna-define-method elmo-message-folder ((folder elmo-multi-folder)
128                                          number)
129   (nth (- (/ number (elmo-multi-folder-divide-number-internal folder)) 1)
130        (elmo-multi-folder-children-internal folder)))
131
132 (luna-define-method elmo-message-entity ((folder elmo-multi-folder) key)
133   (cond
134    ((numberp key)
135     (let* ((pair (elmo-multi-real-folder-number folder key))
136            (entity (elmo-message-entity (car pair) (cdr pair))))
137       (when entity
138         (elmo-message-entity-set-number (elmo-message-copy-entity entity)
139                                         key))))
140    ((stringp key)
141     (let ((children (elmo-multi-folder-children-internal folder))
142           (cur-number 0)
143           match)
144       (while children
145         (setq cur-number (+ cur-number 1))
146         (when (setq match (elmo-message-entity (car children) key))
147           (setq match (elmo-message-copy-entity match))
148           (elmo-message-entity-set-number
149            match
150            (+ (* (elmo-multi-folder-divide-number-internal folder)
151                  cur-number)
152               (elmo-message-entity-number match)))
153           (setq children nil))
154         (setq children (cdr children)))
155       match))))
156
157 (luna-define-method elmo-message-field ((folder elmo-multi-folder)
158                                         number field)
159   (let ((pair (elmo-multi-real-folder-number folder number)))
160     (elmo-message-field (car pair) (cdr pair) field)))
161
162 (luna-define-method elmo-message-mark ((folder elmo-multi-folder) number)
163   (let ((pair (elmo-multi-real-folder-number folder number)))
164     (elmo-message-mark (car pair) (cdr pair))))
165
166 (defun elmo-multi-split-numbers (folder numlist &optional as-is)
167   (let ((numbers (sort numlist '<))
168         (divider (elmo-multi-folder-divide-number-internal folder))
169         (cur-number 0)
170         one-list numbers-list)
171     (while numbers
172       (setq cur-number (+ cur-number 1))
173       (setq one-list nil)
174       (while (and numbers
175                   (eq 0
176                       (/ (- (car numbers)
177                             (* divider cur-number))
178                          divider)))
179         (setq one-list (nconc
180                         one-list
181                         (list
182                          (if as-is
183                              (car numbers)
184                            (% (car numbers)
185                               (* divider cur-number))))))
186         (setq numbers (cdr numbers)))
187       (setq numbers-list (nconc numbers-list (list one-list))))
188     numbers-list))
189
190 (luna-define-method elmo-folder-process-crosspost ((folder elmo-multi-folder))
191   (dolist (child (elmo-multi-folder-children-internal folder))
192     (elmo-folder-process-crosspost child)))
193
194 (defsubst elmo-multi-find-fetch-strategy (folder entity ignore-cache)
195   (if entity
196       (let ((pair (elmo-multi-real-folder-number
197                    folder
198                    (elmo-msgdb-overview-entity-get-number entity)))
199             (new-entity (elmo-msgdb-copy-overview-entity entity)))
200         (setq new-entity
201               (elmo-msgdb-overview-entity-set-number new-entity (cdr pair)))
202         (elmo-find-fetch-strategy (car pair) new-entity ignore-cache))
203     (elmo-make-fetch-strategy 'entire)))
204
205 (luna-define-method elmo-find-fetch-strategy
206   ((folder elmo-multi-folder)
207    entity &optional ignore-cache)
208   (elmo-multi-find-fetch-strategy folder entity ignore-cache))
209
210 (luna-define-method elmo-message-fetch ((folder elmo-multi-folder)
211                                         number strategy
212                                         &optional section outbuf unseen)
213   (let ((pair (elmo-multi-real-folder-number folder number)))
214     (elmo-message-fetch (car pair) (cdr pair) strategy section outbuf unseen)))
215
216 (luna-define-method elmo-folder-delete-messages ((folder elmo-multi-folder)
217                                                  numbers)
218   (let ((flds (elmo-multi-folder-children-internal folder))
219         one-list-list
220         (cur-number 0))
221     (setq one-list-list (elmo-multi-split-numbers folder numbers))
222     (while (< cur-number (length flds))
223       (elmo-folder-delete-messages (nth cur-number flds)
224                                    (nth cur-number one-list-list))
225       (setq cur-number (+ 1 cur-number)))
226     t))
227
228 (luna-define-method elmo-folder-detach-messages ((folder elmo-multi-folder)
229                                                  numbers)
230   (let ((flds (elmo-multi-folder-children-internal folder))
231         one-list-list
232         (cur-number 0))
233     (setq one-list-list (elmo-multi-split-numbers folder numbers))
234     (while (< cur-number (length flds))
235       (elmo-folder-detach-messages (nth cur-number flds)
236                                    (nth cur-number one-list-list))
237       (setq cur-number (+ 1 cur-number)))
238     t))
239
240 (luna-define-method elmo-folder-diff ((folder elmo-multi-folder)
241                                       &optional numbers)
242   (elmo-multi-folder-diff folder numbers))
243
244 (defun elmo-multi-folder-diff (folder numbers)
245   (let ((flds (elmo-multi-folder-children-internal folder))
246         (num-list (and numbers (elmo-multi-split-numbers folder numbers)))
247         (unsync 0)
248         (messages 0)
249         diffs)
250     (while flds
251       (setq diffs (nconc diffs (list (elmo-folder-diff (car flds)
252                                                        (car num-list)))))
253       (setq flds (cdr flds)))
254     (while diffs
255       (and (car (car diffs))
256            (setq unsync (+ unsync (car (car diffs)))))
257       (setq messages  (+ messages (cdr (car diffs))))
258       (setq diffs (cdr diffs)))
259     (elmo-folder-set-info-hashtb folder nil messages)
260     (cons unsync messages)))
261
262 (luna-define-method elmo-folder-list-unreads ((folder elmo-multi-folder))
263   (let ((cur-number 0)
264         unreads)
265     (dolist (child (elmo-multi-folder-children-internal folder))
266       (setq cur-number (+ cur-number 1))
267       (setq unreads
268             (nconc
269              unreads
270              (mapcar (lambda (x)
271                        (+ x (* cur-number
272                                (elmo-multi-folder-divide-number-internal
273                                 folder))))
274                      (elmo-folder-list-unreads child)))))
275     unreads))
276
277 (luna-define-method elmo-folder-list-answereds ((folder elmo-multi-folder))
278   (let ((cur-number 0)
279         answereds)
280     (dolist (child (elmo-multi-folder-children-internal folder))
281       (setq cur-number (+ cur-number 1))
282       (setq answereds
283             (nconc
284              answereds
285              (mapcar (lambda (x)
286                        (+ x (* cur-number
287                                (elmo-multi-folder-divide-number-internal
288                                 folder))))
289                      (elmo-folder-list-answereds child)))))
290     answereds))
291
292 (luna-define-method elmo-folder-list-importants ((folder elmo-multi-folder))
293   (let ((cur-number 0)
294         importants)
295     (dolist (child (elmo-multi-folder-children-internal folder))
296       (setq cur-number (+ cur-number 1))
297       (setq importants
298             (nconc
299              importants
300              (mapcar (lambda (x)
301                        (+ x (* cur-number
302                                (elmo-multi-folder-divide-number-internal
303                                 folder))))
304                      (elmo-folder-list-importants child)))))
305     (elmo-uniq-list
306      (nconc importants
307             (elmo-folder-list-messages-with-global-mark
308              folder elmo-msgdb-important-mark)))))
309
310 (luna-define-method elmo-folder-list-messages
311   ((folder elmo-multi-folder) &optional visible-only in-msgdb)
312   (let* ((flds (elmo-multi-folder-children-internal folder))
313          (cur-number 0)
314          list numbers)
315     (while flds
316       (setq cur-number (+ cur-number 1))
317       (setq list (elmo-folder-list-messages (car flds) visible-only in-msgdb))
318       (setq numbers
319             (nconc
320              numbers
321              (mapcar
322               (function
323                (lambda (x)
324                  (+
325                   (* (elmo-multi-folder-divide-number-internal
326                       folder) cur-number) x)))
327               list)))
328       (setq flds (cdr flds)))
329     numbers))
330
331 (luna-define-method elmo-folder-exists-p ((folder elmo-multi-folder))
332   (let ((flds (elmo-multi-folder-children-internal folder)))
333     (catch 'exists
334       (while flds
335         (unless (elmo-folder-exists-p (car flds))
336           (throw 'exists nil))
337         (setq flds (cdr flds)))
338       t)))
339
340 (luna-define-method elmo-folder-creatable-p ((folder elmo-multi-folder))
341   (let ((flds (elmo-multi-folder-children-internal folder)))
342     (catch 'creatable
343       (while flds
344         (when (and (elmo-folder-creatable-p (car flds))
345                    (not (elmo-folder-exists-p (car flds))))
346           ;; If folder already exists, don't to `creatable'.
347           ;; Because this function is called, when folder doesn't exists.
348           (throw 'creatable t))
349         (setq flds (cdr flds)))
350       nil)))
351
352 (luna-define-method elmo-folder-create ((folder elmo-multi-folder))
353   (let ((flds (elmo-multi-folder-children-internal folder)))
354     (catch 'create
355       (while flds
356         (unless (or (elmo-folder-exists-p (car flds))
357                     (elmo-folder-create (car flds)))
358           (throw 'create nil))
359         (setq flds (cdr flds)))
360       t)))
361
362 (luna-define-method elmo-folder-search ((folder elmo-multi-folder)
363                                         condition &optional numlist)
364   (let* ((flds (elmo-multi-folder-children-internal folder))
365          (cur-number 0)
366          numlist-list cur-numlist ; for filtered search.
367          ret-val)
368     (if numlist
369         (setq numlist-list
370               (elmo-multi-split-numbers folder numlist t)))
371     (while flds
372       (setq cur-number (+ cur-number 1))
373       (when numlist
374         (setq cur-numlist (car numlist-list))
375         (if (null cur-numlist)
376             ;; t means filter all.
377             (setq cur-numlist t)))
378       (setq ret-val (append
379                      ret-val
380                      (elmo-list-filter
381                       cur-numlist
382                       (mapcar
383                        (function
384                         (lambda (x)
385                           (+
386                            (* (elmo-multi-folder-divide-number-internal
387                                folder) cur-number) x)))
388                        (elmo-folder-search
389                         (car flds) condition)))))
390       (when numlist
391         (setq numlist-list (cdr numlist-list)))
392       (setq flds (cdr flds)))
393     ret-val))
394
395 (luna-define-method elmo-message-use-cache-p ((folder elmo-multi-folder)
396                                               number)
397   (let ((pair (elmo-multi-real-folder-number folder number)))
398     (elmo-message-use-cache-p (car pair) (cdr pair))))
399
400 (luna-define-method elmo-message-file-p ((folder elmo-multi-folder) number)
401   (let ((pair (elmo-multi-real-folder-number folder number)))
402     (elmo-message-file-p (car pair) (cdr pair))))
403
404 (luna-define-method elmo-message-file-name ((folder elmo-multi-folder) number)
405   (let ((pair (elmo-multi-real-folder-number folder number)))
406     (elmo-message-file-name (car pair) (cdr pair))))
407
408 (luna-define-method elmo-folder-plugged-p ((folder elmo-multi-folder))
409   (let ((flds (elmo-multi-folder-children-internal folder)))
410     (catch 'plugged
411       (while flds
412         (unless (elmo-folder-plugged-p (car flds))
413           (throw 'plugged nil))
414         (setq flds (cdr flds)))
415       t)))
416
417 (luna-define-method elmo-folder-set-plugged ((folder elmo-multi-folder)
418                                              plugged add)
419   (let ((flds  (elmo-multi-folder-children-internal folder)))
420     (dolist (fld flds)
421       (elmo-folder-set-plugged fld plugged add))))
422
423 (defun elmo-multi-folder-numbers-list-assoc (folder folder-numbers)
424   (let (ent)
425     (while folder-numbers
426       (when (string= (elmo-folder-name-internal (car (car folder-numbers)))
427                      (elmo-folder-name-internal folder))
428         (setq ent (car folder-numbers)
429               folder-numbers nil))
430       (setq folder-numbers (cdr folder-numbers)))
431     ent))
432
433 (defun elmo-multi-make-folder-numbers-list (folder msgs)
434   (let ((msg-list msgs)
435         pair fld-list
436         ret-val)
437     (while msg-list
438       (when (and (numberp (car msg-list))
439                  (> (car msg-list) 0))
440         (setq pair (elmo-multi-real-folder-number folder (car msg-list)))
441         (if (setq fld-list (elmo-multi-folder-numbers-list-assoc
442                             (car pair)
443                             ret-val))
444             (setcdr fld-list (cons (cdr pair) (cdr fld-list)))
445           (setq ret-val (cons (cons (car pair) (list (cdr pair))) ret-val))))
446       (setq msg-list (cdr msg-list)))
447     ret-val))
448
449 (luna-define-method elmo-folder-mark-as-important ((folder
450                                                     elmo-multi-folder)
451                                                    numbers
452                                                    &optional
453                                                    ignore-flags)
454   (dolist (folder-numbers (elmo-multi-make-folder-numbers-list folder numbers))
455     (elmo-folder-mark-as-important (car folder-numbers)
456                                    (cdr folder-numbers)
457                                    ignore-flags)))
458
459 (luna-define-method elmo-folder-unmark-important ((folder
460                                                    elmo-multi-folder)
461                                                   numbers
462                                                   &optional
463                                                   ignore-flags)
464   (dolist (folder-numbers (elmo-multi-make-folder-numbers-list folder numbers))
465     (elmo-folder-unmark-important (car folder-numbers)
466                                   (cdr folder-numbers)
467                                   ignore-flags)))
468
469 (luna-define-method elmo-folder-mark-as-read ((folder
470                                                elmo-multi-folder)
471                                               numbers
472                                               &optional ignore-flag)
473   (dolist (folder-numbers (elmo-multi-make-folder-numbers-list folder numbers))
474     (elmo-folder-mark-as-read (car folder-numbers)
475                               (cdr folder-numbers)
476                               ignore-flag)))
477
478 (luna-define-method elmo-folder-unmark-read ((folder
479                                               elmo-multi-folder)
480                                              numbers
481                                              &optional ignore-flag)
482   (dolist (folder-numbers (elmo-multi-make-folder-numbers-list folder numbers))
483     (elmo-folder-unmark-read (car folder-numbers)
484                              (cdr folder-numbers)
485                              ignore-flag)))
486
487 (luna-define-method elmo-folder-mark-as-answered ((folder
488                                                    elmo-multi-folder)
489                                                   numbers)
490   (dolist (folder-numbers (elmo-multi-make-folder-numbers-list folder numbers))
491     (elmo-folder-mark-as-answered (car folder-numbers)
492                                   (cdr folder-numbers))))
493
494 (luna-define-method elmo-folder-unmark-answered ((folder
495                                                   elmo-multi-folder)
496                                                  numbers)
497   (dolist (folder-numbers (elmo-multi-make-folder-numbers-list folder numbers))
498     (elmo-folder-unmark-answered (car folder-numbers)
499                                  (cdr folder-numbers))))
500
501 (luna-define-method elmo-folder-list-flagged ((folder elmo-multi-folder)
502                                               flag
503                                               &optional in-msgdb)
504   (let ((cur-number 0)
505         numbers)
506     (dolist (child (elmo-multi-folder-children-internal folder))
507       (setq cur-number (+ cur-number 1)
508             numbers
509             (nconc
510              numbers
511              (mapcar
512               (function
513                (lambda (x)
514                  (+
515                   (* (elmo-multi-folder-divide-number-internal folder)
516                      cur-number) x)))
517               (elmo-folder-list-flagged child flag in-msgdb)))))
518     numbers))
519
520 (luna-define-method elmo-folder-commit ((folder elmo-multi-folder))
521   (dolist (child (elmo-multi-folder-children-internal folder))
522     (elmo-folder-commit child)))
523
524 (luna-define-method elmo-folder-length ((folder elmo-multi-folder))
525   (let ((sum 0))
526     (dolist (child (elmo-multi-folder-children-internal folder))
527       (setq sum (+ sum (elmo-folder-length child))))
528     sum))
529
530 (luna-define-method elmo-folder-count-flags ((folder elmo-multi-folder))
531   (let ((new 0)
532         (unreads 0)
533         (answered 0)
534         flags)
535     (dolist (child (elmo-multi-folder-children-internal folder))
536       (setq flags (elmo-folder-count-flags child))
537       (setq new (+ new (nth 0 flags)))
538       (setq unreads (+ unreads (nth 1 flags)))
539       (setq answered (+ answered (nth 2 flags))))
540     (list new unreads answered)))
541
542 (require 'product)
543 (product-provide (provide 'elmo-multi) (require 'elmo-version))
544
545 ;;; elmo-multi.el ends here