1 ;;; modb-standard.el --- Standartd Implement of MODB.
3 ;; Copyright (C) 2003 Yuuichi Teranishi <teranisi@gohome.org>
5 ;; Author: Yuuichi Teranishi <teranisi@gohome.org>
6 ;; Hiroya Murata <lapis-lazuli@pop06.odn.ne.jp>
7 ;; Keywords: mail, net news
9 ;; This file is part of ELMO (Elisp Library for Message Orchestration).
11 ;; This program is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 2, or (at your option)
16 ;; This program is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING. If not, write to the
23 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 ;; Boston, MA 02111-1307, USA.
32 (eval-when-compile (require 'cl))
38 (defcustom modb-standard-divide-number 500
39 "*Standard modb divide entity number."
40 :type '(choice (const :tag "Not divide" nil)
44 (defvar modb-standard-entity-filename "entity"
45 "Message entity database.")
47 (defvar modb-standard-flag-filename "flag"
48 "Message number <=> Flag status database.")
50 (defvar modb-standard-msgid-filename "msgid"
51 "Message number <=> Message-Id database.")
54 (luna-define-class modb-standard (modb-generic)
55 (number-list ; sorted list of message numbers.
56 entity-map ; number, msg-id -> entity mapping.
57 flag-map ; number -> flag-list mapping
58 flag-count ; list of (FLAG . COUNT)
60 (luna-define-internal-accessors 'modb-standard))
62 ;; for internal use only
63 (defsubst modb-standard-key (number)
64 (concat "#" (number-to-string number)))
66 (defsubst modb-standard-entity-id (entity)
67 (if (eq 'autoload (car-safe entity))
69 (elmo-msgdb-message-entity-field
70 (elmo-message-entity-handler entity)
73 (defsubst modb-standard-entity-map (modb)
74 (or (modb-standard-entity-map-internal modb)
75 (modb-standard-set-entity-map-internal
77 (elmo-make-hash (elmo-msgdb-length modb)))))
79 (defsubst modb-standard-flag-map (modb)
80 (or (modb-standard-flag-map-internal modb)
81 (modb-standard-set-flag-map-internal
83 (elmo-make-hash (elmo-msgdb-length modb)))))
85 (defsubst modb-standard-set-message-modified (modb number)
86 (if modb-standard-divide-number
87 (let ((section (/ number modb-standard-divide-number))
88 (modified (modb-generic-message-modified-internal modb)))
89 (unless (memq section modified)
90 (modb-generic-set-message-modified-internal
91 modb (cons section modified))))
92 (modb-generic-set-message-modified-internal modb t)))
94 (defsubst modb-standard-set-flag-modified (modb number)
95 (modb-generic-set-flag-modified-internal modb t))
97 (defsubst modb-standard-message-flags (modb number)
98 (cdr (elmo-get-hash-val (modb-standard-key number)
99 (modb-standard-flag-map-internal modb))))
101 (defsubst modb-standard-match-flags (check-flags flags)
104 (when (memq (car check-flags) flags)
106 (setq check-flags (cdr check-flags)))))
108 (defsubst modb-standard-countup-flags (modb flags &optional delta)
109 (let ((flag-count (modb-standard-flag-count-internal modb))
113 (if (setq elem (assq flag flag-count))
114 (setcdr elem (+ (cdr elem) delta))
115 (setq flag-count (cons (cons flag delta) flag-count))))
116 (modb-standard-set-flag-count-internal modb flag-count)))
118 ;; save and load functions
119 (defun modb-standard-load-msgid (modb path)
120 (let* ((alist (elmo-object-load
121 (expand-file-name modb-standard-msgid-filename path)))
122 (table (or (modb-standard-entity-map-internal modb)
123 (elmo-make-hash (length alist))))
126 (setq info (cons 'autoload pair))
127 (elmo-set-hash-val (modb-standard-key (car pair)) info table)
128 (elmo-set-hash-val (cdr pair) info table)
129 (setq numbers (cons (car pair) numbers)))
130 (modb-standard-set-number-list-internal modb (nreverse numbers))
131 (modb-standard-set-entity-map-internal modb table)))
133 (defun modb-standard-save-msgid (modb path)
134 (let ((table (modb-standard-entity-map-internal modb))
136 (dolist (number (modb-standard-number-list-internal modb))
137 (setq entity (elmo-get-hash-val (modb-standard-key number) table))
138 (setq alist (cons (cons number (modb-standard-entity-id entity))
141 (expand-file-name modb-standard-msgid-filename path)
144 (defun modb-standard-load-flag (modb path)
145 (let ((table (or (modb-standard-flag-map-internal modb)
146 (elmo-make-hash (elmo-msgdb-length modb)))))
147 (dolist (info (elmo-object-load
148 (expand-file-name modb-standard-flag-filename path)))
149 (modb-standard-countup-flags modb (cdr info))
150 (elmo-set-hash-val (modb-standard-key (car info)) info table))
151 (modb-standard-set-flag-map-internal modb table)))
153 (defun modb-standard-save-flag (modb path)
154 (let (table flist info)
155 (when (setq table (modb-standard-flag-map-internal modb))
158 (setq info (symbol-value atom))
160 (setq flist (cons info flist))))
163 (expand-file-name modb-standard-flag-filename path)
166 (defsubst modb-standard-entity-filename (section)
168 (concat modb-standard-entity-filename
170 (number-to-string section))
171 modb-standard-entity-filename))
173 (defun modb-standard-load-entity (modb path &optional section)
174 (let ((table (or (modb-standard-entity-map-internal modb)
175 (elmo-make-hash (elmo-msgdb-length modb)))))
176 (dolist (entity (elmo-object-load
178 (modb-standard-entity-filename section)
180 (elmo-set-hash-val (modb-standard-key
181 (elmo-msgdb-message-entity-number
182 (elmo-message-entity-handler entity)
186 (elmo-set-hash-val (elmo-msgdb-message-entity-field
187 (elmo-message-entity-handler entity)
191 (modb-standard-set-entity-map-internal modb table)))
193 (defsubst modb-standard-save-entity-1 (modb path &optional section)
194 (let ((table (modb-standard-entity-map-internal modb))
195 (filename (expand-file-name
196 (modb-standard-entity-filename section) path))
198 (dolist (number (modb-standard-number-list-internal modb))
199 (when (and (or (null section)
200 (= section (/ number modb-standard-divide-number)))
201 (setq entity (elmo-msgdb-message-entity modb number)))
202 (setq entities (cons entity entities))))
204 (elmo-object-save filename entities)
205 (ignore-errors (delete-file filename)))))
207 (defun modb-standard-save-entity (modb path)
208 (let ((sections (modb-generic-message-modified-internal modb)))
209 (cond ((listp sections)
210 (dolist (section sections)
211 (modb-standard-save-entity-1 modb path section)))
213 (modb-standard-save-entity-1 modb path)))))
217 (luna-define-method elmo-msgdb-load ((msgdb modb-standard))
218 (let ((inhibit-quit t)
219 (path (elmo-msgdb-location msgdb)))
220 (when (file-exists-p (expand-file-name modb-standard-flag-filename path))
221 (modb-standard-load-msgid msgdb path)
222 (modb-standard-load-flag msgdb path)
223 (unless modb-standard-divide-number
224 (modb-standard-load-entity msgdb path))
227 (luna-define-method elmo-msgdb-save ((msgdb modb-standard))
228 (let ((path (elmo-msgdb-location msgdb)))
229 (when (elmo-msgdb-message-modified-p msgdb)
230 (modb-standard-save-msgid msgdb path)
231 (modb-standard-save-entity msgdb path)
232 (modb-generic-set-message-modified-internal msgdb nil))
233 (when (elmo-msgdb-flag-modified-p msgdb)
234 (modb-standard-save-flag msgdb path)
235 (modb-generic-set-flag-modified-internal msgdb nil))))
237 (luna-define-method elmo-msgdb-append :around ((msgdb modb-standard)
239 (when (> (elmo-msgdb-length msgdb-append) 0)
240 (if (eq (luna-class-name msgdb-append) 'modb-standard)
241 (let ((numbers (modb-standard-number-list-internal msgdb-append))
244 (modb-standard-set-number-list-internal
246 (nconc (modb-standard-number-list-internal msgdb)
249 (let ((table (modb-standard-entity-map msgdb))
251 (dolist (number numbers)
252 (setq entity (elmo-msgdb-message-entity msgdb-append number)
253 msg-id (modb-standard-entity-id entity))
254 (if (elmo-get-hash-val msg-id table)
255 (setq duplicates (cons number duplicates))
256 (elmo-set-hash-val msg-id entity table))
257 (elmo-set-hash-val (modb-standard-key number)
261 (let ((table (modb-standard-flag-map msgdb)))
264 (elmo-set-hash-val (symbol-name atom)
267 (modb-standard-flag-map msgdb-append)))
269 (dolist (pair (modb-standard-flag-count-internal msgdb-append))
270 (modb-standard-countup-flags msgdb (list (car pair)) (cdr pair)))
271 ;; modification flags
272 (dolist (number (modb-standard-number-list-internal msgdb-append))
273 (modb-standard-set-message-modified msgdb number)
274 (modb-standard-set-flag-modified msgdb number))
276 (luna-call-next-method))))
278 (luna-define-method elmo-msgdb-clear :after ((msgdb modb-standard))
279 (modb-standard-set-number-list-internal msgdb nil)
280 (modb-standard-set-entity-map-internal msgdb nil)
281 (modb-standard-set-flag-map-internal msgdb nil)
282 (modb-standard-set-flag-count-internal msgdb nil))
284 (luna-define-method elmo-msgdb-length ((msgdb modb-standard))
285 (length (modb-standard-number-list-internal msgdb)))
287 (luna-define-method elmo-msgdb-flags ((msgdb modb-standard) number)
288 (modb-standard-message-flags msgdb number))
290 (luna-define-method elmo-msgdb-set-flag ((msgdb modb-standard)
294 (elmo-msgdb-unset-flag msgdb number 'unread))
296 (elmo-msgdb-unset-flag msgdb number 'cached))
298 (let* ((cur-flags (modb-standard-message-flags msgdb number))
299 (new-flags (copy-sequence cur-flags))
301 (and (memq 'new new-flags)
302 (setq new-flags (delq 'new new-flags)))
303 (or (memq flag new-flags)
304 (setq new-flags (cons flag new-flags)))
305 (when (and (eq flag 'unread)
306 (memq 'answered new-flags))
307 (setq new-flags (delq 'answered new-flags)))
308 (unless (equal new-flags cur-flags)
309 (setq diff (elmo-list-diff new-flags cur-flags))
310 (modb-standard-countup-flags msgdb (car diff))
311 (modb-standard-countup-flags msgdb (cadr diff) -1)
312 (elmo-set-hash-val (modb-standard-key number)
313 (cons number new-flags)
314 (modb-standard-flag-map msgdb))
315 (modb-standard-set-flag-modified msgdb number))))))
317 (luna-define-method elmo-msgdb-unset-flag ((msgdb modb-standard)
321 (elmo-msgdb-set-flag msgdb number 'unread))
323 (elmo-msgdb-set-flag msgdb number 'cached))
325 (modb-standard-countup-flags msgdb
326 (modb-standard-message-flags msgdb number)
328 (elmo-clear-hash-val (modb-standard-key number)
329 (modb-standard-flag-map msgdb)))
331 (let* ((cur-flags (modb-standard-message-flags msgdb number))
332 (new-flags (copy-sequence cur-flags))
334 (and (memq 'new new-flags)
335 (setq new-flags (delq 'new new-flags)))
336 (and (memq flag new-flags)
337 (setq new-flags (delq flag new-flags)))
338 (when (and (eq flag 'unread)
339 (memq 'answered new-flags))
340 (setq new-flags (delq 'answered new-flags)))
341 (unless (equal new-flags cur-flags)
342 (setq diff (elmo-list-diff new-flags cur-flags))
343 (modb-standard-countup-flags msgdb (car diff))
344 (modb-standard-countup-flags msgdb (cadr diff) -1)
345 (elmo-set-hash-val (modb-standard-key number)
346 (cons number new-flags)
347 (modb-standard-flag-map msgdb))
348 (modb-standard-set-flag-modified msgdb number))))))
350 (luna-define-method elmo-msgdb-flag-count ((msgdb modb-standard))
351 (modb-standard-flag-count-internal msgdb))
353 (luna-define-method elmo-msgdb-list-messages ((msgdb modb-standard))
355 (modb-standard-number-list-internal msgdb)))
357 (luna-define-method elmo-msgdb-list-flagged ((msgdb modb-standard) flag)
361 (dolist (number (modb-standard-number-list-internal msgdb))
362 (unless (memq 'unread (modb-standard-message-flags msgdb number))
363 (setq matched (cons number matched)))))
367 (setq entry (symbol-value atom))
368 (when (modb-standard-match-flags '(unread important)
370 (setq matched (cons (car entry) matched))))
371 (modb-standard-flag-map msgdb)))
375 (setq entry (symbol-value atom))
376 (when (modb-standard-match-flags '(unread important answered)
378 (setq matched (cons (car entry) matched))))
379 (modb-standard-flag-map msgdb)))
383 (setq entry (symbol-value atom))
384 (when (memq flag (cdr entry))
385 (setq matched (cons (car entry) matched))))
386 (modb-standard-flag-map msgdb))))
389 (luna-define-method elmo-msgdb-search ((msgdb modb-standard)
390 condition &optional numbers)
391 (if (vectorp condition)
392 (let ((key (elmo-filter-key condition))
395 ((and (string= key "flag")
396 (eq (elmo-filter-type condition) 'match))
397 (setq results (elmo-msgdb-list-flagged
399 (intern (elmo-filter-value condition))))
401 (elmo-list-filter numbers results)
403 ((member key '("first" "last"))
404 (let* ((numbers (or numbers
405 (modb-standard-number-list-internal msgdb)))
406 (len (length numbers))
407 (lastp (string= key "last"))
408 (value (string-to-number (elmo-filter-value condition))))
409 (when (eq (elmo-filter-type condition) 'unmatch)
410 (setq lastp (not lastp)
411 value (- len value)))
413 (nthcdr (max (- len value) 0) numbers)
415 (let* ((numbers (copy-sequence numbers))
416 (last (nthcdr (1- value) numbers)))
424 (luna-define-method elmo-msgdb-append-entity ((msgdb modb-standard)
425 entity &optional flags)
426 (let ((number (elmo-msgdb-message-entity-number
427 (elmo-message-entity-handler entity) entity))
428 (msg-id (elmo-msgdb-message-entity-field
429 (elmo-message-entity-handler entity) entity 'message-id))
432 (modb-standard-set-number-list-internal
434 (nconc (modb-standard-number-list-internal msgdb)
437 (let ((table (modb-standard-entity-map msgdb)))
438 (setq duplicate (elmo-get-hash-val msg-id table))
439 (elmo-set-hash-val (modb-standard-key number) entity table)
440 (elmo-set-hash-val msg-id entity table))
441 ;; modification flags
442 (modb-standard-set-message-modified msgdb number)
446 (modb-standard-key number)
448 (modb-standard-flag-map msgdb))
449 (modb-standard-countup-flags msgdb flags)
450 (modb-standard-set-flag-modified msgdb number))
453 (luna-define-method elmo-msgdb-delete-messages ((msgdb modb-standard)
455 (let ((number-list (modb-standard-number-list-internal msgdb))
456 (entity-map (modb-standard-entity-map-internal msgdb))
457 (flag-map (modb-standard-flag-map-internal msgdb))
459 (dolist (number numbers)
460 (setq key (modb-standard-key number)
461 entity (elmo-get-hash-val key entity-map))
463 (setq number-list (delq number number-list))
465 (elmo-clear-hash-val key entity-map)
466 (elmo-clear-hash-val (modb-standard-entity-id entity) entity-map)
467 ;; flag-count (must be BEFORE flag-map)
468 (modb-standard-countup-flags
470 (modb-standard-message-flags msgdb number)
473 (elmo-clear-hash-val key flag-map)
474 (modb-standard-set-message-modified msgdb number)
475 (modb-standard-set-flag-modified msgdb number))
476 (modb-standard-set-number-list-internal msgdb number-list)
477 (modb-standard-set-entity-map-internal msgdb entity-map)
478 (modb-standard-set-flag-map-internal msgdb flag-map)))
480 (luna-define-method elmo-msgdb-sort-entities ((msgdb modb-standard)
481 predicate &optional app-data)
482 (message "Sorting...")
483 (let ((numbers (modb-standard-number-list-internal msgdb)))
484 (modb-standard-set-number-list-internal
486 (sort numbers (lambda (a b)
488 (elmo-msgdb-message-entity msgdb a)
489 (elmo-msgdb-message-entity msgdb b)
491 (message "Sorting...done")
494 (luna-define-method elmo-msgdb-message-entity ((msgdb modb-standard) key)
495 (let ((ret (elmo-get-hash-val
496 (cond ((stringp key) key)
497 ((numberp key) (modb-standard-key key)))
498 (modb-standard-entity-map-internal msgdb))))
499 (if (eq 'autoload (car-safe ret))
500 (when modb-standard-divide-number
501 (modb-standard-load-entity
503 (elmo-msgdb-location msgdb)
504 (/ (nth 1 ret) modb-standard-divide-number))
506 (cond ((stringp key) key)
507 ((numberp key) (modb-standard-key key)))
508 (modb-standard-entity-map-internal msgdb)))
512 (product-provide (provide 'modb-standard) (require 'elmo-version))
514 ;;; modb-standard.el ends here