delete->dispose (summary mark operation)
[elisp/wanderlust.git] / elmo / elmo-map.el
1 ;;; elmo-map.el --- A ELMO folder class with message number mapping.
2
3 ;; Copyright (C) 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 ;; Folders which do not have unique message numbers but unique message names
28 ;; should inherit this folder.
29
30 ;;; Code:
31 ;;
32 (require 'elmo)
33 (require 'elmo-msgdb)
34
35 (eval-when-compile (require 'cl))
36
37 (eval-and-compile
38   ;; location-hash: location->number mapping
39   ;; number-hash:   number->location mapping
40   (luna-define-class elmo-map-folder (elmo-folder)
41                      (location-alist number-max location-hash))
42   (luna-define-internal-accessors 'elmo-map-folder))
43
44 (defun elmo-map-folder-numbers-to-locations (folder numbers)
45   (let (locations pair)
46     (dolist (number numbers)
47       (if (setq pair (elmo-get-hash-val
48                       (concat "#" (int-to-string number))
49                       (elmo-map-folder-location-hash-internal folder)))
50           (setq locations (cons (cdr pair) locations))))
51     (nreverse locations)))
52
53 (defun elmo-map-folder-locations-to-numbers (folder locations)
54   (let (numbers pair)
55     (dolist (location locations)
56       (if (setq pair (elmo-get-hash-val
57                       location
58                       (elmo-map-folder-location-hash-internal folder)))
59           (setq numbers (cons (car pair) numbers))))
60     (nreverse numbers)))
61
62 (luna-define-generic elmo-map-folder-list-message-locations (folder)
63   "Return a location list of the FOLDER.")
64
65 (luna-define-generic elmo-map-folder-unmark-important (folder locations)
66   "")
67
68 (luna-define-generic elmo-map-folder-mark-as-important (folder locations)
69   "")
70
71 (luna-define-generic elmo-map-folder-unmark-read (folder locations)
72   "")
73
74 (luna-define-generic elmo-map-folder-mark-as-read (folder locations)
75   "")
76
77 (luna-define-generic elmo-map-folder-unmark-answered (folder locations)
78   "")
79
80 (luna-define-generic elmo-map-folder-mark-as-answered (folder locations)
81   "")
82
83 (luna-define-generic elmo-map-message-fetch (folder location
84                                                     strategy
85                                                     &optional
86                                                     section
87                                                     unseen)
88   "")
89
90 (luna-define-generic elmo-map-folder-list-unreads (folder)
91   "")
92
93 (luna-define-method elmo-map-folder-list-unreads ((folder elmo-map-folder))
94   t)
95
96 (luna-define-generic elmo-map-folder-list-importants (folder)
97   "")
98
99 (luna-define-method elmo-map-folder-list-importants ((folder elmo-map-folder))
100   t)
101
102 (luna-define-generic elmo-map-folder-list-answereds (folder)
103   "")
104
105 (luna-define-method elmo-map-folder-list-answereds ((folder elmo-map-folder))
106   t)
107
108 (luna-define-generic elmo-map-folder-delete-messages (folder locations)
109   "")
110
111 (luna-define-method elmo-folder-status ((folder elmo-map-folder))
112   (elmo-folder-open-internal folder)
113   (elmo-folder-set-killed-list-internal
114    folder
115    (elmo-msgdb-killed-list-load (elmo-folder-msgdb-path folder)))
116   (let ((numbers (mapcar
117                   'car
118                   (elmo-map-folder-location-alist-internal folder))))
119     (setq numbers (elmo-living-messages numbers (elmo-folder-killed-list-internal folder)))
120     (prog1
121         (cons (elmo-max-of-list numbers)
122               (length numbers))
123       ;; Don't close after status.
124       (unless (elmo-folder-reserve-status-p folder)
125         (elmo-folder-close-internal folder)))))
126
127 (defun elmo-map-message-number (folder location)
128   "Return number of the message in the FOLDER with LOCATION."
129   (car (elmo-get-hash-val
130         location
131         (elmo-map-folder-location-hash-internal folder))))
132
133 (defun elmo-map-message-location (folder number)
134   "Return location of the message in the FOLDER with NUMBER."
135   (cdr (elmo-get-hash-val
136         (concat "#" (int-to-string number))
137         (elmo-map-folder-location-hash-internal folder))))
138
139 (luna-define-method elmo-folder-pack-numbers ((folder elmo-map-folder))
140   (let* ((msgdb (elmo-folder-msgdb folder))
141          (old-number-alist (elmo-msgdb-get-number-alist msgdb))
142          (old-overview (elmo-msgdb-get-overview msgdb))
143          (old-mark-alist (elmo-msgdb-get-mark-alist msgdb))
144          (old-location (elmo-map-folder-location-alist-internal folder))
145          old-number overview number-alist mark-alist location
146          mark (number 1))
147     (setq overview old-overview)
148     (while old-overview
149       (setq old-number
150             (elmo-msgdb-overview-entity-get-number (car old-overview)))
151       (elmo-msgdb-overview-entity-set-number (car old-overview) number)
152       (setq number-alist
153             (cons (cons number (cdr (assq old-number old-number-alist)))
154                   number-alist))
155       (when (setq mark (cadr (assq old-number old-mark-alist)))
156         (setq mark-alist
157               (elmo-msgdb-mark-append
158                mark-alist number mark)))
159       (setq location
160             (cons (cons number
161                         (elmo-map-message-location folder old-number))
162                   location))
163       (setq number (1+ number))
164       (setq old-overview (cdr old-overview)))
165     (elmo-map-folder-location-setup folder (nreverse location))
166     (elmo-folder-set-msgdb-internal
167      folder
168      (elmo-make-msgdb overview
169                       (nreverse number-alist)
170                       (nreverse mark-alist)))))
171
172 (defun elmo-map-folder-location-setup (folder locations)
173   (elmo-map-folder-set-location-alist-internal
174    folder
175    locations)
176   (elmo-map-folder-set-location-hash-internal
177    folder (elmo-make-hash
178            (* 2 (length locations))))
179   (elmo-map-folder-set-number-max-internal folder 0)
180   ;; Set number-max and hashtables.
181   (dolist (location-cons locations)
182     (if (< (elmo-map-folder-number-max-internal folder)
183            (car location-cons))
184         (elmo-map-folder-set-number-max-internal folder (car location-cons)))
185     (elmo-set-hash-val (cdr location-cons)
186                        location-cons
187                        (elmo-map-folder-location-hash-internal folder))
188     (elmo-set-hash-val (concat "#" (int-to-string (car location-cons)))
189                        location-cons
190                        (elmo-map-folder-location-hash-internal folder))))
191
192 (defun elmo-map-folder-update-locations (folder locations)
193   ;; A subroutine to make location-alist.
194   ;; location-alist is existing location-alist.
195   ;; locations is the newest locations.
196   (let* ((location-alist (elmo-map-folder-location-alist-internal folder))
197          (locations-in-db (mapcar 'cdr location-alist))
198          new-locs new-alist deleted-locs pair i)
199     (setq new-locs
200           (elmo-delete-if (function
201                            (lambda (x) (member x locations-in-db)))
202                           locations))
203     (setq deleted-locs
204           (elmo-delete-if (function
205                            (lambda (x) (member x locations)))
206                           locations-in-db))
207     (dolist (location deleted-locs)
208       (setq location-alist
209             (delq (setq pair
210                         (elmo-get-hash-val
211                          location
212                          (elmo-map-folder-location-hash-internal
213                           folder)))
214                   location-alist))
215       (when pair
216         (elmo-clear-hash-val (concat "#" (int-to-string (car pair)))
217                              (elmo-map-folder-location-hash-internal
218                               folder))
219         (elmo-clear-hash-val location
220                              (elmo-map-folder-location-hash-internal
221                               folder))))
222     (setq i (elmo-map-folder-number-max-internal folder))
223     (dolist (location new-locs)
224       (setq i (1+ i))
225       (elmo-map-folder-set-number-max-internal folder i)
226       (setq new-alist (cons (setq pair (cons i location)) new-alist))
227       (setq new-alist (nreverse new-alist))
228       (elmo-set-hash-val (concat "#" (int-to-string i))
229                          pair
230                          (elmo-map-folder-location-hash-internal
231                           folder))
232       (elmo-set-hash-val location
233                          pair
234                          (elmo-map-folder-location-hash-internal
235                           folder)))
236     (setq location-alist
237           (sort (nconc location-alist new-alist)
238                 (lambda (x y) (< (car x) (car y)))))
239     (elmo-map-folder-set-location-alist-internal folder location-alist)))
240
241 (luna-define-method elmo-folder-open-internal ((folder elmo-map-folder))
242   (elmo-map-folder-location-setup
243    folder 
244    (elmo-msgdb-location-load (elmo-folder-msgdb-path folder)))
245   (if (elmo-folder-plugged-p folder)
246       (elmo-map-folder-update-locations
247        folder
248        (elmo-map-folder-list-message-locations folder))))
249
250 (luna-define-method elmo-folder-commit :after ((folder elmo-map-folder))
251   (when (elmo-folder-persistent-p folder)
252     (elmo-msgdb-location-save (elmo-folder-msgdb-path folder)
253                               (elmo-map-folder-location-alist-internal
254                                folder))))
255
256 (luna-define-method elmo-folder-close-internal ((folder elmo-map-folder))
257   (elmo-map-folder-set-location-alist-internal folder nil)
258   (elmo-map-folder-set-location-hash-internal folder nil))
259   
260 (luna-define-method elmo-folder-check ((folder elmo-map-folder))
261   (elmo-map-folder-update-locations
262    folder
263    (elmo-map-folder-list-message-locations folder)))
264
265 (luna-define-method elmo-folder-clear :around ((folder elmo-map-folder)
266                                                &optional keep-killed)
267   (unless keep-killed
268     (elmo-map-folder-set-number-max-internal folder 0)
269     (elmo-map-folder-set-location-alist-internal folder nil)
270     ;; clear hashtable.
271     (elmo-map-folder-set-location-hash-internal folder (elmo-make-hash)))
272   (luna-call-next-method))
273
274 (luna-define-method elmo-folder-list-messages-internal
275   ((folder elmo-map-folder) &optional nohide)
276   (mapcar 'car (elmo-map-folder-location-alist-internal folder)))
277
278 (luna-define-method elmo-folder-unmark-important :before ((folder
279                                                            elmo-map-folder)
280                                                           numbers
281                                                           &optional
282                                                           ignore-flags)
283   (unless ignore-flags
284     (elmo-map-folder-unmark-important
285      folder
286      (elmo-map-folder-numbers-to-locations folder numbers))))
287
288 (luna-define-method elmo-folder-mark-as-important :before ((folder
289                                                             elmo-map-folder)
290                                                            numbers
291                                                            &optional
292                                                            ignore-flags)
293   (unless ignore-flags
294     (elmo-map-folder-mark-as-important
295      folder
296      (elmo-map-folder-numbers-to-locations folder numbers))))
297
298 (luna-define-method elmo-folder-unmark-read :before ((folder elmo-map-folder)
299                                                      numbers
300                                                      &optional ignore-flags)
301   (unless ignore-flags
302     (elmo-map-folder-unmark-read
303      folder
304      (elmo-map-folder-numbers-to-locations folder numbers))))
305
306 (luna-define-method elmo-folder-mark-as-read :before ((folder
307                                                        elmo-map-folder)
308                                                       numbers
309                                                       &optional ignore-flags)
310   (unless ignore-flags
311     (elmo-map-folder-mark-as-read
312      folder
313      (elmo-map-folder-numbers-to-locations folder numbers))))
314
315 (luna-define-method elmo-folder-unmark-answered :before ((folder
316                                                           elmo-map-folder)
317                                                          numbers)
318   (elmo-map-folder-unmark-answered
319    folder
320    (elmo-map-folder-numbers-to-locations folder numbers)))
321
322 (luna-define-method elmo-folder-mark-as-answered :before ((folder
323                                                           elmo-map-folder)
324                                                          numbers)
325   (elmo-map-folder-mark-as-answered
326    folder
327    (elmo-map-folder-numbers-to-locations folder numbers)))
328
329 (luna-define-method elmo-message-fetch-internal ((folder elmo-map-folder)
330                                                  number strategy
331                                                  &optional section unread)
332   (elmo-map-message-fetch
333    folder
334    (elmo-map-message-location folder number)
335    strategy section unread))
336
337 (luna-define-method elmo-folder-list-unreads :around ((folder elmo-map-folder))
338   (let ((locations (elmo-map-folder-list-unreads folder)))
339     (if (listp locations)
340         (elmo-map-folder-locations-to-numbers folder locations)
341       (luna-call-next-method))))
342
343 (luna-define-method elmo-folder-list-importants :around ((folder
344                                                           elmo-map-folder))
345   (let ((locations (elmo-map-folder-list-importants folder)))
346     (if (listp locations)
347         (elmo-map-folder-locations-to-numbers folder locations)
348       (luna-call-next-method))))
349
350 (luna-define-method elmo-folder-list-answereds :around ((folder
351                                                          elmo-map-folder))
352   (let ((locations (elmo-map-folder-list-answereds folder)))
353     (if (listp locations)
354         (elmo-map-folder-locations-to-numbers folder locations)
355       (luna-call-next-method))))
356
357 (luna-define-method elmo-folder-delete-messages ((folder elmo-map-folder)
358                                                  numbers)
359   (elmo-map-folder-delete-messages
360    folder
361    (elmo-map-folder-numbers-to-locations folder numbers))
362   (dolist (number numbers)
363     (elmo-map-folder-set-location-alist-internal
364      folder
365      (delq (elmo-get-hash-val
366             (concat "#" (int-to-string number))
367             (elmo-map-folder-location-hash-internal
368              folder))
369            (elmo-map-folder-location-alist-internal folder))))
370   t) ; success
371
372 (require 'product)
373 (product-provide (provide 'elmo-map) (require 'elmo-version))
374
375 ;;; elmo-map.el ends here