1 ;;; modb-legacy.el --- Legacy 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.
33 (eval-when-compile (require 'cl))
41 (defconst modb-legacy-new-mark "N"
42 "Mark for new message.")
44 (defconst modb-legacy-unread-uncached-mark "U"
45 "Mark for unread and uncached message.")
47 (defconst modb-legacy-unread-cached-mark "!"
48 "Mark for unread but already cached message.")
50 (defconst modb-legacy-read-uncached-mark "u"
51 "Mark for read but uncached message.")
53 (defconst modb-legacy-answered-cached-mark "&"
54 "Mark for answered and cached message.")
56 (defconst modb-legacy-answered-uncached-mark "A"
57 "Mark for answered but cached message.")
59 (defconst modb-legacy-important-mark "$"
60 "Mark for important message.")
63 (luna-define-class modb-legacy (modb-generic)
64 (overview number-alist mark-alist index))
65 (luna-define-internal-accessors 'modb-legacy))
67 ;; for internal use only
68 (defsubst elmo-msgdb-get-overview (msgdb)
69 (modb-legacy-overview-internal msgdb))
71 (defsubst elmo-msgdb-get-number-alist (msgdb)
72 (modb-legacy-number-alist-internal msgdb))
74 (defsubst elmo-msgdb-get-mark-alist (msgdb)
75 (modb-legacy-mark-alist-internal msgdb))
77 (defsubst elmo-msgdb-get-index (msgdb)
78 (modb-legacy-index-internal msgdb))
80 (defsubst elmo-msgdb-get-entity-hashtb (msgdb)
81 (car (modb-legacy-index-internal msgdb)))
83 (defsubst elmo-msgdb-get-mark-hashtb (msgdb)
84 (cdr (modb-legacy-index-internal msgdb)))
86 (defsubst elmo-msgdb-get-path (msgdb)
87 (elmo-msgdb-location msgdb))
89 (defsubst elmo-msgdb-set-overview (msgdb overview)
90 (modb-legacy-set-overview-internal msgdb overview))
92 (defsubst elmo-msgdb-set-number-alist (msgdb number-alist)
93 (modb-legacy-set-number-alist-internal msgdb number-alist))
95 (defsubst elmo-msgdb-set-mark-alist (msgdb mark-alist)
96 (modb-legacy-set-mark-alist-internal msgdb mark-alist))
98 (defsubst elmo-msgdb-set-index (msgdb index)
99 (modb-legacy-set-index-internal msgdb index))
101 (defsubst elmo-msgdb-set-path (msgdb path)
102 (modb-generic-set-location-internal msgdb path))
105 ;; Internal use only (obsolete interface)
107 (defsubst elmo-msgdb-overview-entity-get-id (entity)
108 (and entity (car entity)))
110 (defsubst elmo-msgdb-overview-entity-get-number (entity)
111 (and entity (aref (cdr entity) 0)))
113 (defsubst elmo-msgdb-overview-entity-set-number (entity number)
114 (and entity (aset (cdr entity) 0 number))
117 (defsubst elmo-msgdb-overview-entity-get-references (entity)
118 (and entity (aref (cdr entity) 1)))
120 (defsubst elmo-msgdb-overview-entity-set-references (entity references)
121 (and entity (aset (cdr entity) 1 references))
124 (defsubst elmo-msgdb-overview-entity-get-from-no-decode (entity)
125 (and entity (aref (cdr entity) 2)))
127 (defsubst elmo-msgdb-overview-entity-get-from (entity)
129 (aref (cdr entity) 2)
130 (elmo-msgdb-get-decoded-cache (aref (cdr entity) 2))))
132 (defsubst elmo-msgdb-overview-entity-set-from (entity from)
133 (and entity (aset (cdr entity) 2 from))
136 (defsubst elmo-msgdb-overview-entity-get-subject (entity)
138 (aref (cdr entity) 3)
139 (elmo-msgdb-get-decoded-cache (aref (cdr entity) 3))))
141 (defsubst elmo-msgdb-overview-entity-get-subject-no-decode (entity)
142 (and entity (aref (cdr entity) 3)))
144 (defsubst elmo-msgdb-overview-entity-set-subject (entity subject)
145 (and entity (aset (cdr entity) 3 subject))
148 (defsubst elmo-msgdb-overview-entity-get-date (entity)
149 (and entity (aref (cdr entity) 4)))
151 (defsubst elmo-msgdb-overview-entity-set-date (entity date)
152 (and entity (aset (cdr entity) 4 date))
155 (defsubst elmo-msgdb-overview-entity-get-to (entity)
156 (and entity (aref (cdr entity) 5)))
158 (defsubst elmo-msgdb-overview-entity-get-cc (entity)
159 (and entity (aref (cdr entity) 6)))
161 (defsubst elmo-msgdb-overview-entity-get-size (entity)
162 (and entity (aref (cdr entity) 7)))
164 (defsubst elmo-msgdb-overview-entity-set-size (entity size)
165 (and entity (aset (cdr entity) 7 size))
168 (defsubst elmo-msgdb-overview-entity-get-extra (entity)
169 (and entity (aref (cdr entity) 8)))
171 (defsubst elmo-msgdb-overview-entity-set-extra (entity extra)
172 (and entity (aset (cdr entity) 8 extra))
175 (defsubst elmo-msgdb-overview-entity-get-extra-field (entity field-name)
176 (let ((field-name (downcase field-name))
177 (extra (and entity (aref (cdr entity) 8))))
179 (cdr (assoc field-name extra)))))
181 (defsubst elmo-msgdb-overview-entity-set-extra-field (entity field-name value)
182 (let ((field-name (downcase field-name))
183 (extras (and entity (aref (cdr entity) 8)))
185 (if (setq extra (assoc field-name extras))
187 (elmo-msgdb-overview-entity-set-extra
189 (cons (cons field-name value) extras)))))
192 (defun elmo-msgdb-number-load (dir)
194 (expand-file-name elmo-msgdb-number-filename dir)))
196 (defun elmo-msgdb-overview-load (dir)
198 (expand-file-name elmo-msgdb-overview-filename dir)))
200 (defun elmo-msgdb-mark-load (dir)
202 (expand-file-name elmo-msgdb-mark-filename dir)))
204 (defun elmo-msgdb-number-save (dir obj)
206 (expand-file-name elmo-msgdb-number-filename dir)
209 (defun elmo-msgdb-mark-save (dir obj)
211 (expand-file-name elmo-msgdb-mark-filename dir)
214 (defsubst elmo-msgdb-overview-save (dir overview)
216 (expand-file-name elmo-msgdb-overview-filename dir)
222 (defvar modb-legacy-unread-marks-internal nil)
223 (defsubst modb-legacy-unread-marks ()
224 "Return an unread mark list"
225 (or modb-legacy-unread-marks-internal
226 (setq modb-legacy-unread-marks-internal
227 (list modb-legacy-new-mark
228 modb-legacy-unread-uncached-mark
229 modb-legacy-unread-cached-mark))))
231 (defvar modb-legacy-answered-marks-internal nil)
232 (defsubst modb-legacy-answered-marks ()
233 "Return an answered mark list"
234 (or modb-legacy-answered-marks-internal
235 (setq modb-legacy-answered-marks-internal
236 (list modb-legacy-answered-cached-mark
237 modb-legacy-answered-uncached-mark))))
239 (defvar modb-legacy-uncached-marks-internal nil)
240 (defsubst modb-legacy-uncached-marks ()
241 (or modb-legacy-uncached-marks-internal
242 (setq modb-legacy-uncached-marks-internal
243 (list modb-legacy-new-mark
244 modb-legacy-answered-uncached-mark
245 modb-legacy-unread-uncached-mark
246 modb-legacy-read-uncached-mark))))
248 (defsubst modb-legacy-mark-to-flags (mark)
250 (and (string= mark modb-legacy-new-mark)
252 (and (string= mark modb-legacy-important-mark)
254 (and (member mark (modb-legacy-unread-marks))
256 (and (member mark (modb-legacy-answered-marks))
258 (and (not (member mark (modb-legacy-uncached-marks)))
261 (defsubst modb-legacy-flags-to-mark (flags)
262 (cond ((memq 'new flags)
263 modb-legacy-new-mark)
264 ((memq 'important flags)
265 modb-legacy-important-mark)
266 ((memq 'answered flags)
267 (if (memq 'cached flags)
268 modb-legacy-answered-cached-mark
269 modb-legacy-answered-uncached-mark))
270 ((memq 'unread flags)
271 (if (memq 'cached flags)
272 modb-legacy-unread-cached-mark
273 modb-legacy-unread-uncached-mark))
275 (if (memq 'cached flags)
277 modb-legacy-read-uncached-mark))))
279 (defsubst elmo-msgdb-get-mark (msgdb number)
280 "Get mark string from MSGDB which corresponds to the message with NUMBER."
281 (cadr (elmo-get-hash-val (format "#%d" number)
282 (elmo-msgdb-get-mark-hashtb msgdb))))
284 (defsubst elmo-msgdb-set-mark (msgdb number mark)
285 "Set MARK of the message with NUMBER in the MSGDB.
286 if MARK is nil, mark is removed."
287 (let ((elem (elmo-get-hash-val (format "#%d" number)
288 (elmo-msgdb-get-mark-hashtb msgdb))))
291 ;; Set mark of the elem
292 (setcar (cdr elem) mark)
293 ;; Delete elem from mark-alist
294 (elmo-msgdb-set-mark-alist
296 (delq elem (elmo-msgdb-get-mark-alist msgdb)))
297 (elmo-clear-hash-val (format "#%d" number)
298 (elmo-msgdb-get-mark-hashtb msgdb)))
300 ;; Append new element.
301 (elmo-msgdb-set-mark-alist
304 (elmo-msgdb-get-mark-alist msgdb)
305 (list (setq elem (list number mark)))))
306 (elmo-set-hash-val (format "#%d" number) elem
307 (elmo-msgdb-get-mark-hashtb msgdb))))
308 (modb-generic-set-flag-modified-internal msgdb t)
312 (defun elmo-msgdb-make-index (msgdb &optional overview mark-alist)
313 "Append OVERVIEW and MARK-ALIST to the index of MSGDB.
314 If OVERVIEW and MARK-ALIST are nil, make index for current MSGDB.
315 Return a list of message numbers which have duplicated message-ids."
317 (let* ((overview (or overview (elmo-msgdb-get-overview msgdb)))
318 (mark-alist (or mark-alist (elmo-msgdb-get-mark-alist msgdb)))
319 (index (elmo-msgdb-get-index msgdb))
320 (ehash (or (car index) ;; append
321 (elmo-make-hash (length overview))))
322 (mhash (or (cdr index) ;; append
323 (elmo-make-hash (length overview))))
327 (if (elmo-get-hash-val (caar overview) ehash) ; duplicated.
328 (setq duplicates (cons
329 (elmo-msgdb-overview-entity-get-number
333 (elmo-set-hash-val (caar overview) (car overview) ehash))
337 (elmo-msgdb-overview-entity-get-number (car overview)))
338 (car overview) ehash)
339 (setq overview (cdr overview)))
343 (format "#%d" (car (car mark-alist)))
344 (car mark-alist) mhash)
345 (setq mark-alist (cdr mark-alist)))
346 (setq index (or index (cons ehash mhash)))
347 (elmo-msgdb-set-index msgdb index)
350 (defun elmo-msgdb-clear-index (msgdb entity)
351 (let ((ehash (elmo-msgdb-get-entity-hashtb msgdb))
352 (mhash (elmo-msgdb-get-mark-hashtb msgdb))
354 (when (and entity ehash)
355 (and (setq number (elmo-msgdb-overview-entity-get-number entity))
356 (elmo-clear-hash-val (format "#%d" number) ehash))
357 (and (car entity) ;; message-id
358 (elmo-clear-hash-val (car entity) ehash)))
359 (when (and entity mhash)
360 (and (setq number (elmo-msgdb-overview-entity-get-number entity))
361 (elmo-clear-hash-val (format "#%d" number) mhash)))))
365 (luna-define-method elmo-msgdb-load ((msgdb modb-legacy))
366 (let ((inhibit-quit t)
367 (path (elmo-msgdb-location msgdb)))
368 (when (file-exists-p (expand-file-name elmo-msgdb-mark-filename path))
369 (modb-legacy-set-overview-internal
371 (elmo-msgdb-overview-load path))
372 (modb-legacy-set-number-alist-internal
374 (elmo-msgdb-number-load path))
375 (modb-legacy-set-mark-alist-internal
377 (elmo-msgdb-mark-load path))
378 (elmo-msgdb-make-index msgdb)
381 (luna-define-method elmo-msgdb-save ((msgdb modb-legacy))
382 (let ((path (elmo-msgdb-location msgdb)))
383 (when (elmo-msgdb-message-modified-p msgdb)
384 (elmo-msgdb-overview-save
386 (modb-legacy-overview-internal msgdb))
387 (elmo-msgdb-number-save
389 (modb-legacy-number-alist-internal msgdb))
390 (modb-generic-set-message-modified-internal msgdb nil))
391 (when (elmo-msgdb-flag-modified-p msgdb)
392 (elmo-msgdb-mark-save
394 (modb-legacy-mark-alist-internal msgdb))
395 (modb-generic-set-flag-modified-internal msgdb nil))))
397 (luna-define-method elmo-msgdb-append :around ((msgdb modb-legacy)
399 (if (eq (luna-class-name msgdb-append)
402 (elmo-msgdb-set-overview
404 (nconc (elmo-msgdb-get-overview msgdb)
405 (elmo-msgdb-get-overview msgdb-append)))
406 (elmo-msgdb-set-number-alist
408 (nconc (elmo-msgdb-get-number-alist msgdb)
409 (elmo-msgdb-get-number-alist msgdb-append)))
410 (elmo-msgdb-set-mark-alist
412 (nconc (elmo-msgdb-get-mark-alist msgdb)
413 (elmo-msgdb-get-mark-alist msgdb-append)))
414 (setq duplicates (elmo-msgdb-make-index
416 (elmo-msgdb-get-overview msgdb-append)
417 (elmo-msgdb-get-mark-alist msgdb-append)))
420 (or (elmo-msgdb-get-path msgdb)
421 (elmo-msgdb-get-path msgdb-append)))
422 (modb-generic-set-message-modified-internal msgdb t)
423 (modb-generic-set-flag-modified-internal msgdb t)
425 (luna-call-next-method)))
427 (luna-define-method elmo-msgdb-clear :after ((msgdb modb-legacy))
428 (elmo-msgdb-set-overview msgdb nil)
429 (elmo-msgdb-set-number-alist msgdb nil)
430 (elmo-msgdb-set-mark-alist msgdb nil)
431 (elmo-msgdb-set-index msgdb nil))
433 (luna-define-method elmo-msgdb-length ((msgdb modb-legacy))
434 (length (modb-legacy-overview-internal msgdb)))
436 (luna-define-method elmo-msgdb-flags ((msgdb modb-legacy) number)
437 (modb-legacy-mark-to-flags (elmo-msgdb-get-mark msgdb number)))
439 (luna-define-method elmo-msgdb-set-flag ((msgdb modb-legacy)
443 (elmo-msgdb-unset-flag msgdb number 'unread))
445 (elmo-msgdb-unset-flag msgdb number 'cached))
447 (let* ((cur-mark (elmo-msgdb-get-mark msgdb number))
448 (flags (modb-legacy-mark-to-flags cur-mark))
450 (and (memq 'new flags)
451 (setq flags (delq 'new flags)))
452 (or (memq flag flags)
453 (setq flags (cons flag flags)))
454 (when (and (eq flag 'unread)
455 (memq 'answered flags))
456 (setq flags (delq 'answered flags)))
457 (setq new-mark (modb-legacy-flags-to-mark flags))
458 (unless (string= new-mark cur-mark)
459 (elmo-msgdb-set-mark msgdb number new-mark))))))
461 (luna-define-method elmo-msgdb-unset-flag ((msgdb modb-legacy)
465 (elmo-msgdb-set-flag msgdb number 'unread))
467 (elmo-msgdb-set-flag msgdb number 'cached))
469 (let* ((cur-mark (elmo-msgdb-get-mark msgdb number))
470 (flags (modb-legacy-mark-to-flags cur-mark))
472 (and (memq 'new flags)
473 (setq flags (delq 'new flags)))
474 (and (memq flag flags)
475 (setq flags (delq flag flags)))
476 (when (and (eq flag 'unread)
477 (memq 'answered flags))
478 (setq flags (delq 'answered flags)))
479 (setq new-mark (modb-legacy-flags-to-mark flags))
480 (unless (string= new-mark cur-mark)
481 (elmo-msgdb-set-mark msgdb number new-mark))))))
483 (luna-define-method elmo-msgdb-list-messages ((msgdb modb-legacy))
484 (mapcar 'elmo-msgdb-overview-entity-get-number
485 (elmo-msgdb-get-overview msgdb)))
487 (luna-define-method elmo-msgdb-list-flagged ((msgdb modb-legacy) flag)
488 (let ((case-fold-search nil)
492 (setq mark-regexp (regexp-quote modb-legacy-new-mark)))
494 (setq mark-regexp (elmo-regexp-opt (modb-legacy-unread-marks))))
496 (setq mark-regexp (elmo-regexp-opt (modb-legacy-answered-marks))))
498 (setq mark-regexp (regexp-quote modb-legacy-important-mark)))
500 (setq mark-regexp (elmo-regexp-opt (modb-legacy-unread-marks))))
502 (setq mark-regexp (elmo-regexp-opt
503 (append (modb-legacy-unread-marks)
504 (list modb-legacy-important-mark)))))
506 (setq mark-regexp (elmo-regexp-opt
508 (modb-legacy-unread-marks)
509 (modb-legacy-answered-marks)
510 (list modb-legacy-important-mark))))))
513 (dolist (number (elmo-msgdb-list-messages msgdb))
514 (let ((mark (elmo-msgdb-get-mark msgdb number)))
515 (unless (and mark (string-match mark-regexp mark))
516 (setq matched (cons number matched)))))
517 (dolist (elem (elmo-msgdb-get-mark-alist msgdb))
518 (if (string-match mark-regexp (cadr elem))
519 (setq matched (cons (car elem) matched))))))
522 (luna-define-method elmo-msgdb-append-entity ((msgdb modb-legacy)
523 entity &optional flags)
525 (let ((number (elmo-msgdb-overview-entity-get-number entity))
526 (message-id (elmo-msgdb-overview-entity-get-id entity))
528 (elmo-msgdb-set-overview
530 (nconc (elmo-msgdb-get-overview msgdb)
532 (elmo-msgdb-set-number-alist
534 (nconc (elmo-msgdb-get-number-alist msgdb)
535 (list (cons number message-id))))
536 (modb-generic-set-message-modified-internal msgdb t)
537 (when (setq mark (modb-legacy-flags-to-mark flags))
538 (elmo-msgdb-set-mark-alist
540 (nconc (elmo-msgdb-get-mark-alist msgdb)
541 (list (list number mark))))
542 (modb-generic-set-flag-modified-internal msgdb t))
543 (elmo-msgdb-make-index
546 (list (list number mark))))))
548 (luna-define-method elmo-msgdb-delete-messages ((msgdb modb-legacy)
550 (let* ((overview (elmo-msgdb-get-overview msgdb))
551 (number-alist (elmo-msgdb-get-number-alist msgdb))
552 (mark-alist (elmo-msgdb-get-mark-alist msgdb))
553 (index (elmo-msgdb-get-index msgdb))
555 ;; remove from current database.
556 (dolist (number numbers)
560 (elmo-msgdb-message-entity msgdb number))
562 (setq number-alist (delq (assq number number-alist) number-alist))
563 (setq mark-alist (delq (assq number mark-alist) mark-alist))
565 (when index (elmo-msgdb-clear-index msgdb ov-entity)))
566 (elmo-msgdb-set-overview msgdb overview)
567 (elmo-msgdb-set-number-alist msgdb number-alist)
568 (elmo-msgdb-set-mark-alist msgdb mark-alist)
569 (elmo-msgdb-set-index msgdb index)
570 (modb-generic-set-message-modified-internal msgdb t)
571 (modb-generic-set-flag-modified-internal msgdb t)
574 (luna-define-method elmo-msgdb-sort-entities ((msgdb modb-legacy)
575 predicate &optional app-data)
576 (message "Sorting...")
577 (let ((overview (elmo-msgdb-get-overview msgdb)))
578 (elmo-msgdb-set-overview
580 (sort overview (lambda (a b) (funcall predicate a b app-data))))
581 (message "Sorting...done")
584 (luna-define-method elmo-msgdb-message-entity ((msgdb modb-legacy) key)
586 (cond ((stringp key) key)
587 ((numberp key) (format "#%d" key)))
588 (elmo-msgdb-get-entity-hashtb msgdb)))
591 (product-provide (provide 'modb-legacy) (require 'elmo-version))
593 ;;; modb-legacy.el ends here