f6aa4fff959a6e1a954d49e0d9e9ec2a13469f1c
[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-unflag-important (folder locations)
66   "")
67
68 (luna-define-generic elmo-map-folder-flag-as-important (folder locations)
69   "")
70
71 (luna-define-generic elmo-map-folder-unflag-read (folder locations)
72   "")
73
74 (luna-define-generic elmo-map-folder-flag-as-read (folder locations)
75   "")
76
77 (luna-define-generic elmo-map-folder-unflag-answered (folder locations)
78   "")
79
80 (luna-define-generic elmo-map-folder-flag-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          (numbers (sort (elmo-folder-list-messages folder nil 'in-msgdb) '<))
142          (new-msgdb (elmo-make-msgdb (elmo-folder-msgdb-path folder)))
143          (number 1)
144          total location entity)
145     (setq total (length numbers))
146     (elmo-with-progress-display (> total elmo-display-progress-threshold)
147         (elmo-folder-pack-numbers total "Packing...")
148       (dolist (old-number numbers)
149         (setq entity (elmo-msgdb-message-entity msgdb old-number))
150         (elmo-msgdb-overview-entity-set-number entity number)
151         (elmo-msgdb-append-entity new-msgdb entity
152                                   (elmo-msgdb-flags msgdb old-number))
153         (setq location
154               (cons (cons number
155                           (elmo-map-message-location folder old-number))
156                     location))
157         (setq number (1+ number))))
158     (message "Packing...done")
159     (elmo-map-folder-location-setup folder (nreverse location))
160     (elmo-folder-set-msgdb-internal folder new-msgdb)))
161
162 (defun elmo-map-folder-location-setup (folder locations)
163   (elmo-map-folder-set-location-alist-internal
164    folder
165    locations)
166   (elmo-map-folder-set-location-hash-internal
167    folder (elmo-make-hash
168            (* 2 (length locations))))
169   (elmo-map-folder-set-number-max-internal folder 0)
170   ;; Set number-max and hashtables.
171   (dolist (location-cons locations)
172     (if (< (elmo-map-folder-number-max-internal folder)
173            (car location-cons))
174         (elmo-map-folder-set-number-max-internal folder (car location-cons)))
175     (elmo-set-hash-val (cdr location-cons)
176                        location-cons
177                        (elmo-map-folder-location-hash-internal folder))
178     (elmo-set-hash-val (concat "#" (int-to-string (car location-cons)))
179                        location-cons
180                        (elmo-map-folder-location-hash-internal folder))))
181
182 (defun elmo-map-folder-update-locations (folder locations)
183   ;; A subroutine to make location-alist.
184   ;; location-alist is existing location-alist.
185   ;; locations is the newest locations.
186   (let* ((location-alist (elmo-map-folder-location-alist-internal folder))
187          (locations-in-db (mapcar 'cdr location-alist))
188          new-locs new-alist deleted-locs pair i)
189     (setq new-locs
190           (elmo-delete-if (function
191                            (lambda (x) (member x locations-in-db)))
192                           locations))
193     (setq deleted-locs
194           (elmo-delete-if (function
195                            (lambda (x) (member x locations)))
196                           locations-in-db))
197     (dolist (location deleted-locs)
198       (setq location-alist
199             (delq (setq pair
200                         (elmo-get-hash-val
201                          location
202                          (elmo-map-folder-location-hash-internal
203                           folder)))
204                   location-alist))
205       (when pair
206         (elmo-clear-hash-val (concat "#" (int-to-string (car pair)))
207                              (elmo-map-folder-location-hash-internal
208                               folder))
209         (elmo-clear-hash-val location
210                              (elmo-map-folder-location-hash-internal
211                               folder))))
212     (setq i (elmo-map-folder-number-max-internal folder))
213     (dolist (location new-locs)
214       (setq i (1+ i))
215       (elmo-map-folder-set-number-max-internal folder i)
216       (setq new-alist (cons (setq pair (cons i location)) new-alist))
217       (setq new-alist (nreverse new-alist))
218       (elmo-set-hash-val (concat "#" (int-to-string i))
219                          pair
220                          (elmo-map-folder-location-hash-internal
221                           folder))
222       (elmo-set-hash-val location
223                          pair
224                          (elmo-map-folder-location-hash-internal
225                           folder)))
226     (setq location-alist
227           (sort (nconc location-alist new-alist)
228                 (lambda (x y) (< (car x) (car y)))))
229     (elmo-map-folder-set-location-alist-internal folder location-alist)))
230
231 (luna-define-method elmo-folder-open-internal ((folder elmo-map-folder))
232   (elmo-map-folder-location-setup
233    folder 
234    (elmo-msgdb-location-load (elmo-folder-msgdb-path folder)))
235   (if (elmo-folder-plugged-p folder)
236       (elmo-map-folder-update-locations
237        folder
238        (elmo-map-folder-list-message-locations folder))))
239
240 (luna-define-method elmo-folder-commit :after ((folder elmo-map-folder))
241   (when (elmo-folder-persistent-p folder)
242     (elmo-msgdb-location-save (elmo-folder-msgdb-path folder)
243                               (elmo-map-folder-location-alist-internal
244                                folder))))
245
246 (luna-define-method elmo-folder-close-internal ((folder elmo-map-folder))
247   (elmo-map-folder-set-location-alist-internal folder nil)
248   (elmo-map-folder-set-location-hash-internal folder nil))
249   
250 (luna-define-method elmo-folder-check ((folder elmo-map-folder))
251   (elmo-map-folder-update-locations
252    folder
253    (elmo-map-folder-list-message-locations folder)))
254
255 (luna-define-method elmo-folder-clear :around ((folder elmo-map-folder)
256                                                &optional keep-killed)
257   (unless keep-killed
258     (elmo-map-folder-set-number-max-internal folder 0)
259     (elmo-map-folder-set-location-alist-internal folder nil)
260     ;; clear hashtable.
261     (elmo-map-folder-set-location-hash-internal folder (elmo-make-hash)))
262   (luna-call-next-method))
263
264 (luna-define-method elmo-folder-list-messages-internal
265   ((folder elmo-map-folder) &optional nohide)
266   (mapcar 'car (elmo-map-folder-location-alist-internal folder)))
267
268 (luna-define-method elmo-folder-unflag-important :before ((folder
269                                                            elmo-map-folder)
270                                                           numbers
271                                                           &optional
272                                                           is-local)
273   (unless is-local
274     (elmo-map-folder-unflag-important
275      folder
276      (elmo-map-folder-numbers-to-locations folder numbers))))
277
278 (luna-define-method elmo-folder-flag-as-important :before ((folder
279                                                             elmo-map-folder)
280                                                            numbers
281                                                            &optional
282                                                            is-local)
283   (unless is-local
284     (elmo-map-folder-flag-as-important
285      folder
286      (elmo-map-folder-numbers-to-locations folder numbers))))
287
288 (luna-define-method elmo-folder-unflag-read :before ((folder elmo-map-folder)
289                                                      numbers
290                                                      &optional is-local)
291   (unless is-local
292     (elmo-map-folder-unflag-read
293      folder
294      (elmo-map-folder-numbers-to-locations folder numbers))))
295
296 (luna-define-method elmo-folder-flag-as-read :before ((folder
297                                                        elmo-map-folder)
298                                                       numbers
299                                                       &optional is-local)
300   (unless is-local
301     (elmo-map-folder-flag-as-read
302      folder
303      (elmo-map-folder-numbers-to-locations folder numbers))))
304
305 (luna-define-method elmo-folder-unflag-answered :before ((folder
306                                                           elmo-map-folder)
307                                                          numbers)
308   (elmo-map-folder-unflag-answered
309    folder
310    (elmo-map-folder-numbers-to-locations folder numbers)))
311
312 (luna-define-method elmo-folder-flag-as-answered :before ((folder
313                                                           elmo-map-folder)
314                                                          numbers)
315   (elmo-map-folder-flag-as-answered
316    folder
317    (elmo-map-folder-numbers-to-locations folder numbers)))
318
319 (luna-define-method elmo-message-fetch-internal ((folder elmo-map-folder)
320                                                  number strategy
321                                                  &optional section unread)
322   (elmo-map-message-fetch
323    folder
324    (elmo-map-message-location folder number)
325    strategy section unread))
326
327 (luna-define-method elmo-folder-list-unreads :around ((folder elmo-map-folder))
328   (let ((locations (elmo-map-folder-list-unreads folder)))
329     (if (listp locations)
330         (elmo-map-folder-locations-to-numbers folder locations)
331       (luna-call-next-method))))
332
333 (luna-define-method elmo-folder-list-importants :around ((folder
334                                                           elmo-map-folder))
335   (let ((locations (elmo-map-folder-list-importants folder)))
336     (if (listp locations)
337         (elmo-map-folder-locations-to-numbers folder locations)
338       (luna-call-next-method))))
339
340 (luna-define-method elmo-folder-list-answereds :around ((folder
341                                                          elmo-map-folder))
342   (let ((locations (elmo-map-folder-list-answereds folder)))
343     (if (listp locations)
344         (elmo-map-folder-locations-to-numbers folder locations)
345       (luna-call-next-method))))
346
347 (luna-define-method elmo-folder-delete-messages ((folder elmo-map-folder)
348                                                  numbers)
349   (elmo-map-folder-delete-messages
350    folder
351    (elmo-map-folder-numbers-to-locations folder numbers))
352   (dolist (number numbers)
353     (elmo-map-folder-set-location-alist-internal
354      folder
355      (delq (elmo-get-hash-val
356             (concat "#" (int-to-string number))
357             (elmo-map-folder-location-hash-internal
358              folder))
359            (elmo-map-folder-location-alist-internal folder))))
360   t) ; success
361
362 (require 'product)
363 (product-provide (provide 'elmo-map) (require 'elmo-version))
364
365 ;;; elmo-map.el ends here