1 ;;; elmo-map.el --- A ELMO folder class with message number mapping.
3 ;; Copyright (C) 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.
27 ;; Folders which do not have unique message numbers but unique message names
28 ;; should inherit this folder.
35 (eval-when-compile (require 'cl))
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))
44 (defun elmo-map-folder-numbers-to-locations (folder numbers)
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)))
53 (defun elmo-map-folder-locations-to-numbers (folder locations)
55 (dolist (location locations)
56 (if (setq pair (elmo-get-hash-val
58 (elmo-map-folder-location-hash-internal folder)))
59 (setq numbers (cons (car pair) numbers))))
62 (luna-define-generic elmo-map-folder-list-message-locations (folder)
63 "Return a location list of the FOLDER.")
65 (luna-define-generic elmo-map-folder-unflag-important (folder locations)
68 (luna-define-generic elmo-map-folder-flag-as-important (folder locations)
71 (luna-define-generic elmo-map-folder-unflag-read (folder locations)
74 (luna-define-generic elmo-map-folder-flag-as-read (folder locations)
77 (luna-define-generic elmo-map-folder-unflag-answered (folder locations)
80 (luna-define-generic elmo-map-folder-flag-as-answered (folder locations)
83 (luna-define-generic elmo-map-message-fetch (folder location
90 (luna-define-generic elmo-map-folder-list-unreads (folder)
93 (luna-define-method elmo-map-folder-list-unreads ((folder elmo-map-folder))
96 (luna-define-generic elmo-map-folder-list-importants (folder)
99 (luna-define-method elmo-map-folder-list-importants ((folder elmo-map-folder))
102 (luna-define-generic elmo-map-folder-list-answereds (folder)
105 (luna-define-method elmo-map-folder-list-answereds ((folder elmo-map-folder))
108 (luna-define-generic elmo-map-folder-delete-messages (folder locations)
111 (luna-define-method elmo-folder-status ((folder elmo-map-folder))
112 (elmo-folder-open-internal folder)
113 (elmo-folder-set-killed-list-internal
115 (elmo-msgdb-killed-list-load (elmo-folder-msgdb-path folder)))
116 (let ((numbers (mapcar
118 (elmo-map-folder-location-alist-internal folder))))
119 (setq numbers (elmo-living-messages
121 (elmo-folder-killed-list-internal folder)))
123 (cons (elmo-max-of-list numbers)
125 ;; Don't close after status.
126 (unless (elmo-folder-reserve-status-p folder)
127 (elmo-folder-close-internal folder)))))
129 (defun elmo-map-message-number (folder location)
130 "Return number of the message in the FOLDER with LOCATION."
131 (car (elmo-get-hash-val
133 (elmo-map-folder-location-hash-internal folder))))
135 (defun elmo-map-message-location (folder number)
136 "Return location of the message in the FOLDER with NUMBER."
137 (cdr (elmo-get-hash-val
138 (concat "#" (int-to-string number))
139 (elmo-map-folder-location-hash-internal folder))))
141 (luna-define-method elmo-folder-pack-numbers ((folder elmo-map-folder))
142 (let* ((msgdb (elmo-folder-msgdb folder))
143 (numbers (sort (elmo-folder-list-messages folder nil 'in-msgdb) '<))
144 (new-msgdb (elmo-make-msgdb (elmo-folder-msgdb-path folder)))
146 total location entity)
147 (setq total (length numbers))
148 (elmo-with-progress-display (> total elmo-display-progress-threshold)
149 (elmo-folder-pack-numbers total "Packing...")
150 (dolist (old-number numbers)
151 (setq entity (elmo-msgdb-message-entity msgdb old-number))
152 (elmo-message-entity-set-number entity number)
153 (elmo-msgdb-append-entity new-msgdb entity
154 (elmo-msgdb-flags msgdb old-number))
157 (elmo-map-message-location folder old-number))
159 (setq number (1+ number))))
160 (message "Packing...done")
161 (elmo-map-folder-location-setup folder (nreverse location))
162 (elmo-folder-set-msgdb-internal folder new-msgdb)))
164 (defun elmo-map-folder-location-setup (folder locations)
165 (elmo-map-folder-set-location-alist-internal
168 (elmo-map-folder-set-location-hash-internal
169 folder (elmo-make-hash
170 (* 2 (length locations))))
171 (elmo-map-folder-set-number-max-internal folder 0)
172 ;; Set number-max and hashtables.
173 (dolist (location-cons locations)
174 (if (< (elmo-map-folder-number-max-internal folder)
176 (elmo-map-folder-set-number-max-internal folder (car location-cons)))
177 (elmo-set-hash-val (cdr location-cons)
179 (elmo-map-folder-location-hash-internal folder))
180 (elmo-set-hash-val (concat "#" (int-to-string (car location-cons)))
182 (elmo-map-folder-location-hash-internal folder))))
184 (defun elmo-map-folder-update-locations (folder locations)
185 ;; A subroutine to make location-alist.
186 ;; location-alist is existing location-alist.
187 ;; locations is the newest locations.
188 (let* ((location-alist (elmo-map-folder-location-alist-internal folder))
189 (locations-in-db (mapcar 'cdr location-alist))
190 new-locs new-alist deleted-locs pair i)
192 (elmo-delete-if (function
193 (lambda (x) (member x locations-in-db)))
196 (elmo-delete-if (function
197 (lambda (x) (member x locations)))
199 (dolist (location deleted-locs)
204 (elmo-map-folder-location-hash-internal
208 (elmo-clear-hash-val (concat "#" (int-to-string (car pair)))
209 (elmo-map-folder-location-hash-internal
211 (elmo-clear-hash-val location
212 (elmo-map-folder-location-hash-internal
214 (setq i (elmo-map-folder-number-max-internal folder))
215 (dolist (location new-locs)
217 (elmo-map-folder-set-number-max-internal folder i)
218 (setq new-alist (cons (setq pair (cons i location)) new-alist))
219 (setq new-alist (nreverse new-alist))
220 (elmo-set-hash-val (concat "#" (int-to-string i))
222 (elmo-map-folder-location-hash-internal
224 (elmo-set-hash-val location
226 (elmo-map-folder-location-hash-internal
229 (sort (nconc location-alist new-alist)
230 (lambda (x y) (< (car x) (car y)))))
231 (elmo-map-folder-set-location-alist-internal folder location-alist)))
233 (luna-define-method elmo-folder-open-internal ((folder elmo-map-folder))
234 (elmo-map-folder-location-setup
236 (elmo-msgdb-location-load (elmo-folder-msgdb-path folder)))
237 (if (elmo-folder-plugged-p folder)
238 (elmo-map-folder-update-locations
240 (elmo-map-folder-list-message-locations folder))))
242 (luna-define-method elmo-folder-commit :after ((folder elmo-map-folder))
243 (when (elmo-folder-persistent-p folder)
244 (elmo-msgdb-location-save (elmo-folder-msgdb-path folder)
245 (elmo-map-folder-location-alist-internal
248 (luna-define-method elmo-folder-close-internal ((folder elmo-map-folder))
249 (elmo-map-folder-set-location-alist-internal folder nil)
250 (elmo-map-folder-set-location-hash-internal folder nil))
252 (luna-define-method elmo-folder-check ((folder elmo-map-folder))
253 (elmo-map-folder-update-locations
255 (elmo-map-folder-list-message-locations folder)))
257 (luna-define-method elmo-folder-next-message-number ((folder elmo-map-folder))
258 (1+ (elmo-map-folder-number-max-internal folder)))
260 (luna-define-method elmo-folder-clear :around ((folder elmo-map-folder)
261 &optional keep-killed)
263 (elmo-map-folder-set-number-max-internal folder 0)
264 (elmo-map-folder-set-location-alist-internal folder nil)
266 (elmo-map-folder-set-location-hash-internal folder (elmo-make-hash)))
267 (luna-call-next-method))
269 (luna-define-method elmo-folder-list-messages-internal
270 ((folder elmo-map-folder) &optional nohide)
271 (mapcar 'car (elmo-map-folder-location-alist-internal folder)))
273 (luna-define-method elmo-folder-unflag-important :before ((folder
279 (elmo-map-folder-unflag-important
281 (elmo-map-folder-numbers-to-locations folder numbers))))
283 (luna-define-method elmo-folder-flag-as-important :before ((folder
289 (elmo-map-folder-flag-as-important
291 (elmo-map-folder-numbers-to-locations folder numbers))))
293 (luna-define-method elmo-folder-unflag-read :before ((folder elmo-map-folder)
297 (elmo-map-folder-unflag-read
299 (elmo-map-folder-numbers-to-locations folder numbers))))
301 (luna-define-method elmo-folder-flag-as-read :before ((folder
306 (elmo-map-folder-flag-as-read
308 (elmo-map-folder-numbers-to-locations folder numbers))))
310 (luna-define-method elmo-folder-unflag-answered :before ((folder
314 (elmo-map-folder-unflag-answered
316 (elmo-map-folder-numbers-to-locations folder numbers)))
318 (luna-define-method elmo-folder-flag-as-answered :before ((folder
322 (elmo-map-folder-flag-as-answered
324 (elmo-map-folder-numbers-to-locations folder numbers)))
326 (luna-define-method elmo-message-fetch-internal ((folder elmo-map-folder)
328 &optional section unread)
329 (elmo-map-message-fetch
331 (elmo-map-message-location folder number)
332 strategy section unread))
334 (luna-define-method elmo-folder-list-unreads :around ((folder elmo-map-folder))
335 (let ((locations (elmo-map-folder-list-unreads folder)))
336 (if (listp locations)
337 (elmo-map-folder-locations-to-numbers folder locations)
338 (luna-call-next-method))))
340 (luna-define-method elmo-folder-list-importants :around ((folder
342 (let ((locations (elmo-map-folder-list-importants folder)))
343 (if (listp locations)
344 (elmo-map-folder-locations-to-numbers folder locations)
345 (luna-call-next-method))))
347 (luna-define-method elmo-folder-list-answereds :around ((folder
349 (let ((locations (elmo-map-folder-list-answereds folder)))
350 (if (listp locations)
351 (elmo-map-folder-locations-to-numbers folder locations)
352 (luna-call-next-method))))
354 (luna-define-method elmo-folder-delete-messages ((folder elmo-map-folder)
356 (elmo-map-folder-delete-messages
358 (elmo-map-folder-numbers-to-locations folder numbers))
359 (dolist (number numbers)
360 (elmo-map-folder-set-location-alist-internal
362 (delq (elmo-get-hash-val
363 (concat "#" (int-to-string number))
364 (elmo-map-folder-location-hash-internal
366 (elmo-map-folder-location-alist-internal folder)))
367 (elmo-clear-hash-val (concat "#" (int-to-string number))
368 (elmo-map-folder-location-hash-internal
373 (product-provide (provide 'elmo-map) (require 'elmo-version))
375 ;;; elmo-map.el ends here