1 ;;; elmo-msgdb.el --- Message Database for ELMO.
3 ;; Copyright (C) 1998,1999,2000 Yuuichi Teranishi <teranisi@gohome.org>
4 ;; Copyright (C) 2000 Masahiro MURATA <muse@ba2.so-net.ne.jp>
6 ;; Author: Yuuichi Teranishi <teranisi@gohome.org>
7 ;; Masahiro MURATA <muse@ba2.so-net.ne.jp>
8 ;; Keywords: mail, net news
10 ;; This file is part of ELMO (Elisp Library for Message Orchestration).
12 ;; This program is free software; you can redistribute it and/or modify
13 ;; it under the terms of the GNU General Public License as published by
14 ;; the Free Software Foundation; either version 2, or (at your option)
17 ;; This program is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 ;; GNU General Public License for more details.
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING. If not, write to the
24 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 ;; Boston, MA 02111-1307, USA.
34 (eval-when-compile (require 'cl))
41 (defconst elmo-msgdb-new-mark "N"
42 "Mark for new message.")
44 (defconst elmo-msgdb-unread-uncached-mark "U"
45 "Mark for unread and uncached message.")
47 (defconst elmo-msgdb-unread-cached-mark "!"
48 "Mark for unread but already cached message.")
50 (defconst elmo-msgdb-read-uncached-mark "u"
51 "Mark for read but uncached message.")
53 (defconst elmo-msgdb-answered-cached-mark "&"
54 "Mark for answered and cached message.")
56 (defconst elmo-msgdb-answered-uncached-mark "A"
57 "Mark for answered but cached message.")
59 (defconst elmo-msgdb-important-mark "$"
60 "Mark for important message.")
64 ;; MSGDB elmo-load-msgdb PATH
65 ;; MARK elmo-msgdb-get-mark MSGDB NUMBER
67 ;; CACHED elmo-msgdb-get-cached MSGDB NUMBER
68 ;; VOID elmo-msgdb-set-cached MSGDB NUMBER CACHED USE-CACHE
69 ;; VOID elmo-msgdb-set-flag MSGDB FOLDER NUMBER FLAG
70 ;; VOID elmo-msgdb-unset-flag MSGDB FOLDER NUMBER FLAG
72 ;; LIST-OF-NUMBERS elmo-msgdb-count-marks MSGDB
73 ;; NUMBER elmo-msgdb-get-number MSGDB MESSAGE-ID
74 ;; FIELD-VALUE elmo-msgdb-get-field MSGDB NUMBER FIELD
75 ;; MSGDB elmo-msgdb-append MSGDB MSGDB-APPEND
76 ;; MSGDB elmo-msgdb-clear MSGDB
77 ;; elmo-msgdb-delete-messages MSGDB NUMBERS
78 ;; elmo-msgdb-sort-by-date MSGDB
81 ;; LIST-OF-NUMBERS elmo-msgdb-list-messages MSGDB
83 ;; elmo-flag-table-load
84 ;; elmo-flag-table-set
85 ;; elmo-flag-table-get
86 ;; elmo-flag-table-save
88 ;; elmo-msgdb-append-entity MSGDB ENTITY MARK-OR-FLAGS
90 ;; ENTITY elmo-msgdb-make-entity ARGS
91 ;; VALUE elmo-msgdb-entity-field ENTITY
94 ;; OVERVIEW elmo-msgdb-get-overview MSGDB
95 ;; NUMBER-ALIST elmo-msgdb-get-number-alist MSGDB
96 ;; MARK-ALIST elmo-msgdb-get-mark-alist MSGDB
97 ;; elmo-msgdb-change-mark MSGDB BEFORE AFTER
99 ;; (for internal use?)
100 ;; LIST-OF-MARKS elmo-msgdb-unread-marks
101 ;; LIST-OF-MARKS elmo-msgdb-answered-marks
102 ;; LIST-OF-MARKS elmo-msgdb-uncached-marks
103 ;; elmo-msgdb-overview-save DIR OBJ
105 ;; elmo-msgdb-message-entity MSGDB KEY
108 ;; elmo-msgdb-overview-entity-get-references ENTITY
109 ;; elmo-msgdb-overview-entity-set-references ENTITY
110 ;; elmo-msgdb-get-parent-entity ENTITY MSGDB
111 ;; elmo-msgdb-overview-enitty-get-number ENTITY
112 ;; elmo-msgdb-overview-enitty-get-from-no-decode ENTITY
113 ;; elmo-msgdb-overview-enitty-get-from ENTITY
114 ;; elmo-msgdb-overview-enitty-get-subject-no-decode ENTITY
115 ;; elmo-msgdb-overview-enitty-get-subject ENTITY
116 ;; elmo-msgdb-overview-enitty-get-date ENTITY
117 ;; elmo-msgdb-overview-enitty-get-to ENTITY
118 ;; elmo-msgdb-overview-enitty-get-cc ENTITY
119 ;; elmo-msgdb-overview-enitty-get-size ENTITY
120 ;; elmo-msgdb-overview-enitty-get-id ENTITY
121 ;; elmo-msgdb-overview-enitty-get-extra-field ENTITY
122 ;; elmo-msgdb-overview-enitty-get-extra ENTITY
123 ;; elmo-msgdb-overview-get-entity ID MSGDB
125 ;; elmo-msgdb-killed-list-load DIR
126 ;; elmo-msgdb-killed-list-save DIR
127 ;; elmo-msgdb-append-to-killed-list FOLDER MSG
128 ;; elmo-msgdb-killed-list-length KILLED-LIST
129 ;; elmo-msgdb-max-of-killed KILLED-LIST
130 ;; elmo-msgdb-killed-message-p KILLED-LIST MSG
131 ;; elmo-living-messages MESSAGES KILLED-LIST
132 ;; elmo-msgdb-finfo-load
133 ;; elmo-msgdb-finfo-save
134 ;; elmo-msgdb-flist-load
135 ;; elmo-msgdb-flist-save
137 ;; elmo-crosspost-alist-load
138 ;; elmo-crosspost-alist-save
140 ;; elmo-msgdb-create-overview-from-buffer NUMBER SIZE TIME
141 ;; elmo-msgdb-copy-overview-entity ENTITY
142 ;; elmo-msgdb-create-overview-entity-from-file NUMBER FILE
143 ;; elmo-msgdb-clear-index
145 ;; elmo-folder-get-info
146 ;; elmo-folder-get-info-max
147 ;; elmo-folder-get-info-length
148 ;; elmo-folder-get-info-unread
150 ;; elmo-msgdb-list-flagged MSGDB FLAG
151 ;; (MACRO) elmo-msgdb-do-each-entity
156 (luna-define-class elmo-msgdb () (location ; location for save.
157 message-modified ; message is modified.
158 flag-modified ; flag is modified.
160 (luna-define-internal-accessors 'elmo-msgdb))
162 (luna-define-generic elmo-msgdb-load (msgdb)
165 (luna-define-generic elmo-msgdb-save (msgdb)
168 (luna-define-generic elmo-msgdb-location (msgdb)
169 "Return the location of MSGDB.")
171 (luna-define-generic elmo-msgdb-message-modified-p (msgdb)
172 "Return non-nil if message is modified.")
174 (luna-define-generic elmo-msgdb-flag-modified-p (msgdb)
175 "Return non-nil if flag is modified.")
177 (luna-define-generic elmo-msgdb-append (msgdb msgdb-append)
178 "Append the MSGDB-APPEND to the MSGDB.
179 Return a list of messages which have duplicated message-id.")
181 (luna-define-generic elmo-msgdb-clear (msgdb)
182 "Clear the MSGDB structure.")
184 (luna-define-generic elmo-msgdb-flags (msgdb number)
185 "Return a list of flag which corresponds to the message with NUMBER.")
187 (luna-define-generic elmo-msgdb-set-flag (msgdb number flag)
189 MSGDB is the ELMO msgdb.
190 NUMBER is a message number to set flag.
191 FLAG is a symbol which is one of the following:
192 `new' ... Message which is new.
193 `read' ... Message which is already read.
194 `important' ... Message which is marked as important.
195 `answered' ... Message which is marked as answered.
196 `cached' ... Message which is cached.")
198 (luna-define-generic elmo-msgdb-unset-flag (msgdb number flag)
200 MSGDB is the ELMO msgdb.
201 NUMBER is a message number to set flag.
202 FLAG is a symbol which is one of the following:
203 `new' ... Message which is new.
204 `read' ... Message which is already read.
205 `important' ... Message which is marked as important.
206 `answered' ... Message which is marked as answered.
207 `cached' ... Message which is cached.")
209 (luna-define-generic elmo-msgdb-list-messages (msgdb)
210 "Return a list of message numbers in the MSGDB.")
212 (luna-define-generic elmo-msgdb-list-flagged (msgdb flag)
213 "Return a list of message numbers which is set FLAG in the MSGDB.")
215 ;;; (luna-define-generic elmo-msgdb-search (msgdb condition &optional numbers)
216 ;;; "Search and return list of message numbers.
217 ;;; MSGDB is the ELMO msgdb structure.
218 ;;; CONDITION is a condition structure for searching.
219 ;;; If optional argument NUMBERS is specified and is a list of message numbers,
220 ;;; messages are searched from the list.")
222 (luna-define-generic elmo-msgdb-append-entity (msgdb entity &optional flags)
223 "Append a ENTITY with FLAGS into the MSGDB.
224 Return non-nil if message-id of entity is duplicated.")
226 (luna-define-generic elmo-msgdb-delete-messages (msgdb numbers)
227 "Delete messages which are contained NUMBERS from MSGDB.")
229 (luna-define-generic elmo-msgdb-sort-entities (msgdb predicate &optional app-data)
230 "Sort entities of MSGDB, comparing with PREDICATE.
231 PREDICATE is called with two entities and APP-DATA.
232 Should return non-nil if the first entity is \"less\" than the second.")
234 (luna-define-generic elmo-msgdb-message-entity (msgdb key)
235 "Return the message-entity structure which matches to the KEY.
236 KEY is a number or a string.
237 A number is for message number in the MSGDB.
238 A string is for message-id of the message.")
240 ;;; generic implement
242 (luna-define-method elmo-msgdb-location ((msgdb elmo-msgdb))
243 (elmo-msgdb-location-internal msgdb))
245 (luna-define-method elmo-msgdb-message-modified-p ((msgdb elmo-msgdb))
246 (elmo-msgdb-message-modified-internal msgdb))
248 (luna-define-method elmo-msgdb-flag-modified-p ((msgdb elmo-msgdb))
249 (elmo-msgdb-flag-modified-internal msgdb))
251 (luna-define-method elmo-msgdb-clear ((msgdb elmo-msgdb))
252 (elmo-msgdb-set-message-modified-internal msgdb nil)
253 (elmo-msgdb-set-flag-modified-internal msgdb nil))
255 (luna-define-method elmo-msgdb-append ((msgdb elmo-msgdb) msgdb-append)
257 (dolist (number (elmo-msgdb-list-messages msgdb-append))
258 (when (elmo-msgdb-append-entity
260 (elmo-msgdb-message-entity msgdb-append number)
261 (elmo-msgdb-flags msgdb-append number))
262 (setq duplicates (cons number duplicates))))
269 (luna-define-class elmo-msgdb-legacy (elmo-msgdb)
270 (overview number-alist mark-alist index))
271 (luna-define-internal-accessors 'elmo-msgdb-legacy))
273 ;; for internal use only
274 (defsubst elmo-msgdb-get-overview (msgdb)
275 (elmo-msgdb-legacy-overview-internal msgdb))
277 (defsubst elmo-msgdb-get-number-alist (msgdb)
278 (elmo-msgdb-legacy-number-alist-internal msgdb))
280 (defsubst elmo-msgdb-get-mark-alist (msgdb)
281 (elmo-msgdb-legacy-mark-alist-internal msgdb))
283 (defsubst elmo-msgdb-get-index (msgdb)
284 (elmo-msgdb-legacy-index-internal msgdb))
286 (defsubst elmo-msgdb-get-entity-hashtb (msgdb)
287 (car (elmo-msgdb-legacy-index-internal msgdb)))
289 (defsubst elmo-msgdb-get-mark-hashtb (msgdb)
290 (cdr (elmo-msgdb-legacy-index-internal msgdb)))
292 (defsubst elmo-msgdb-get-path (msgdb)
293 (elmo-msgdb-location msgdb))
295 (defsubst elmo-msgdb-set-overview (msgdb overview)
296 (elmo-msgdb-legacy-set-overview-internal msgdb overview))
298 (defsubst elmo-msgdb-set-number-alist (msgdb number-alist)
299 (elmo-msgdb-legacy-set-number-alist-internal msgdb number-alist))
301 (defsubst elmo-msgdb-set-mark-alist (msgdb mark-alist)
302 (elmo-msgdb-legacy-set-mark-alist-internal msgdb mark-alist))
304 (defsubst elmo-msgdb-set-index (msgdb index)
305 (elmo-msgdb-legacy-set-index-internal msgdb index))
307 (defsubst elmo-msgdb-set-path (msgdb path)
308 (elmo-msgdb-set-location-internal msgdb path))
312 (luna-define-method elmo-msgdb-load ((msgdb elmo-msgdb-legacy))
313 (let ((inhibit-quit t)
314 (path (elmo-msgdb-location msgdb)))
315 (when (file-exists-p (expand-file-name elmo-msgdb-mark-filename path))
316 (elmo-msgdb-legacy-set-overview-internal
318 (elmo-msgdb-overview-load path))
319 (elmo-msgdb-legacy-set-number-alist-internal
321 (elmo-msgdb-number-load path))
322 (elmo-msgdb-legacy-set-mark-alist-internal
324 (elmo-msgdb-mark-load path))
325 (elmo-msgdb-make-index msgdb)
328 (luna-define-method elmo-msgdb-save ((msgdb elmo-msgdb-legacy))
329 (let ((path (elmo-msgdb-location msgdb)))
330 (when (elmo-msgdb-message-modified-p msgdb)
331 (elmo-msgdb-overview-save
333 (elmo-msgdb-legacy-overview-internal msgdb))
334 (elmo-msgdb-number-save
336 (elmo-msgdb-legacy-number-alist-internal msgdb))
337 (elmo-msgdb-set-message-modified-internal msgdb nil))
338 (when (elmo-msgdb-flag-modified-p msgdb)
339 (elmo-msgdb-mark-save
341 (elmo-msgdb-legacy-mark-alist-internal msgdb))
342 (elmo-msgdb-set-flag-modified-internal msgdb nil))))
344 (defun elmo-load-msgdb (location)
345 "Load the MSGDB from PATH."
346 (let ((msgdb (elmo-make-msgdb location)))
347 (elmo-msgdb-load msgdb)
350 (defun elmo-make-msgdb (&optional location)
352 (luna-make-entity 'elmo-msgdb-legacy :location location))
354 (luna-define-method elmo-msgdb-list-messages ((msgdb elmo-msgdb-legacy))
355 (mapcar 'elmo-msgdb-overview-entity-get-number
356 (elmo-msgdb-get-overview msgdb)))
358 (defsubst elmo-msgdb-mark-to-flags (mark)
360 (and (string= mark elmo-msgdb-new-mark)
362 (and (string= mark elmo-msgdb-important-mark)
364 (and (member mark (elmo-msgdb-unread-marks))
366 (and (member mark (elmo-msgdb-answered-marks))
368 (and (not (member mark (elmo-msgdb-uncached-marks)))
371 (defsubst elmo-msgdb-flags-to-mark (flags)
372 (cond ((memq 'new flags)
374 ((memq 'important flags)
375 elmo-msgdb-important-mark)
376 ((memq 'answered flags)
377 (if (memq 'cached flags)
378 elmo-msgdb-answered-cached-mark
379 elmo-msgdb-answered-uncached-mark))
380 ((memq 'unread flags)
381 (if (memq 'cached flags)
382 elmo-msgdb-unread-cached-mark
383 elmo-msgdb-unread-uncached-mark))
385 (if (memq 'cached flags)
387 elmo-msgdb-read-uncached-mark))))
389 (defsubst elmo-msgdb-get-mark (msgdb number)
390 "Get mark string from MSGDB which corresponds to the message with NUMBER."
391 (cadr (elmo-get-hash-val (format "#%d" number)
392 (elmo-msgdb-get-mark-hashtb msgdb))))
394 (defsubst elmo-msgdb-set-mark (msgdb number mark)
395 "Set MARK of the message with NUMBER in the MSGDB.
396 if MARK is nil, mark is removed."
397 (let ((elem (elmo-get-hash-val (format "#%d" number)
398 (elmo-msgdb-get-mark-hashtb msgdb))))
401 ;; Set mark of the elem
402 (setcar (cdr elem) mark)
403 ;; Delete elem from mark-alist
404 (elmo-msgdb-set-mark-alist
406 (delq elem (elmo-msgdb-get-mark-alist msgdb)))
407 (elmo-clear-hash-val (format "#%d" number)
408 (elmo-msgdb-get-mark-hashtb msgdb)))
410 ;; Append new element.
411 (elmo-msgdb-set-mark-alist
414 (elmo-msgdb-get-mark-alist msgdb)
415 (list (setq elem (list number mark)))))
416 (elmo-set-hash-val (format "#%d" number) elem
417 (elmo-msgdb-get-mark-hashtb msgdb))))
418 (elmo-msgdb-set-flag-modified-internal msgdb t)
422 (defun elmo-msgdb-get-cached (msgdb number)
423 "Return non-nil if message is cached."
424 (not (member (elmo-msgdb-get-mark msgdb number)
425 (elmo-msgdb-uncached-marks))))
427 (defun elmo-msgdb-set-cached (msgdb number cached use-cache)
428 "Set message cache status.
429 If mark is changed, return non-nil."
430 (let* ((cur-mark (elmo-msgdb-get-mark msgdb number))
432 ((string= cur-mark elmo-msgdb-important-mark)
434 ((member cur-mark (elmo-msgdb-answered-marks))
436 ((not (member cur-mark (elmo-msgdb-unread-marks)))
438 (cur-cached (elmo-file-cache-exists-p
439 (elmo-msgdb-get-field msgdb number 'message-id))))
440 (unless (eq cached cur-cached)
443 (elmo-msgdb-set-mark msgdb number
444 (if (and use-cache (not cached))
445 elmo-msgdb-read-uncached-mark)))
448 (elmo-msgdb-set-mark msgdb number
450 elmo-msgdb-answered-cached-mark
451 elmo-msgdb-answered-uncached-mark)))
453 (elmo-msgdb-set-mark msgdb number
455 elmo-msgdb-unread-cached-mark
456 elmo-msgdb-unread-uncached-mark)))))))
458 (luna-define-method elmo-msgdb-flags ((msgdb elmo-msgdb-legacy) number)
459 (elmo-msgdb-mark-to-flags (elmo-msgdb-get-mark msgdb number)))
461 (luna-define-method elmo-msgdb-set-flag ((msgdb elmo-msgdb-legacy)
463 (let* ((cur-mark (elmo-msgdb-get-mark msgdb number))
465 ((string= cur-mark elmo-msgdb-important-mark)
467 ((member cur-mark (elmo-msgdb-answered-marks))
469 ((not (member cur-mark (elmo-msgdb-unread-marks)))
471 (cur-cached (elmo-file-cache-exists-p
472 (elmo-msgdb-get-field msgdb number 'message-id))))
476 ((read important)) ; answered mark is overriden.
477 (t (elmo-msgdb-set-mark msgdb number
479 elmo-msgdb-read-uncached-mark)))))
481 (unless (eq cur-flag 'important)
482 (elmo-msgdb-set-mark msgdb number elmo-msgdb-important-mark)))
484 (unless (or (eq cur-flag 'answered) (eq cur-flag 'important))
485 (elmo-msgdb-set-mark msgdb number
487 elmo-msgdb-answered-cached-mark
488 elmo-msgdb-answered-uncached-mark)))))))
490 (luna-define-method elmo-msgdb-unset-flag ((msgdb elmo-msgdb-legacy)
492 (let* ((cur-mark (elmo-msgdb-get-mark msgdb number))
494 ((string= cur-mark elmo-msgdb-important-mark)
496 ((member cur-mark (elmo-msgdb-answered-marks))
498 ((not (member cur-mark (elmo-msgdb-unread-marks)))
500 (cur-cached (elmo-file-cache-exists-p
501 (elmo-msgdb-get-field msgdb number 'message-id))))
504 (when (or (eq cur-flag 'read) (eq cur-flag 'answered))
505 (elmo-msgdb-set-mark msgdb number
507 elmo-msgdb-unread-cached-mark
508 elmo-msgdb-unread-uncached-mark))))
510 (when (eq cur-flag 'important)
511 (elmo-msgdb-set-mark msgdb number nil)))
513 (when (eq cur-flag 'answered)
514 (elmo-msgdb-set-mark msgdb number
516 elmo-msgdb-read-uncached-mark)))))))
518 (defvar elmo-msgdb-unread-marks-internal nil)
519 (defsubst elmo-msgdb-unread-marks ()
520 "Return an unread mark list"
521 (or elmo-msgdb-unread-marks-internal
522 (setq elmo-msgdb-unread-marks-internal
523 (list elmo-msgdb-new-mark
524 elmo-msgdb-unread-uncached-mark
525 elmo-msgdb-unread-cached-mark))))
527 (defvar elmo-msgdb-answered-marks-internal nil)
528 (defsubst elmo-msgdb-answered-marks ()
529 "Return an answered mark list"
530 (or elmo-msgdb-answered-marks-internal
531 (setq elmo-msgdb-answered-marks-internal
532 (list elmo-msgdb-answered-cached-mark
533 elmo-msgdb-answered-uncached-mark))))
535 (defvar elmo-msgdb-uncached-marks-internal nil)
536 (defsubst elmo-msgdb-uncached-marks ()
537 (or elmo-msgdb-uncached-marks-internal
538 (setq elmo-msgdb-uncached-marks-internal
539 (list elmo-msgdb-new-mark
540 elmo-msgdb-answered-uncached-mark
541 elmo-msgdb-unread-uncached-mark
542 elmo-msgdb-read-uncached-mark))))
544 (luna-define-method elmo-msgdb-append-entity ((msgdb elmo-msgdb-legacy)
545 entity &optional flags)
547 (let ((number (elmo-msgdb-overview-entity-get-number entity))
548 (message-id (elmo-msgdb-overview-entity-get-id entity))
550 (elmo-msgdb-set-overview
552 (nconc (elmo-msgdb-get-overview msgdb)
554 (elmo-msgdb-set-number-alist
556 (nconc (elmo-msgdb-get-number-alist msgdb)
557 (list (cons number message-id))))
558 (elmo-msgdb-set-message-modified-internal msgdb t)
559 (when (setq mark (elmo-msgdb-flags-to-mark flags))
560 (elmo-msgdb-set-mark-alist
562 (nconc (elmo-msgdb-get-mark-alist msgdb)
563 (list (list number mark))))
564 (elmo-msgdb-set-flag-modified-internal msgdb t))
565 (elmo-msgdb-make-index
568 (list (list number mark))))))
570 (defsubst elmo-msgdb-get-number (msgdb message-id)
571 "Get number of the message which corrensponds to MESSAGE-ID from MSGDB."
572 (elmo-msgdb-overview-entity-get-number
573 (elmo-msgdb-overview-get-entity message-id msgdb)))
575 (defsubst elmo-msgdb-get-field (msgdb number field)
576 "Get FIELD value of the message with NUMBER from MSGDB."
578 (message-id (elmo-msgdb-overview-entity-get-id
579 (elmo-msgdb-overview-get-entity
581 (subject (elmo-msgdb-overview-entity-get-subject
582 (elmo-msgdb-overview-get-entity
584 (size (elmo-msgdb-overview-entity-get-size
585 (elmo-msgdb-overview-get-entity
587 (date (elmo-msgdb-overview-entity-get-date
588 (elmo-msgdb-overview-get-entity
590 (to (elmo-msgdb-overview-entity-get-to
591 (elmo-msgdb-overview-get-entity
593 (cc (elmo-msgdb-overview-entity-get-cc
594 (elmo-msgdb-overview-get-entity
597 (luna-define-method elmo-msgdb-append :around ((msgdb elmo-msgdb-legacy)
599 (if (eq (luna-class-name msgdb-append)
602 (elmo-msgdb-set-overview
604 (nconc (elmo-msgdb-get-overview msgdb)
605 (elmo-msgdb-get-overview msgdb-append)))
606 (elmo-msgdb-set-number-alist
608 (nconc (elmo-msgdb-get-number-alist msgdb)
609 (elmo-msgdb-get-number-alist msgdb-append)))
610 (elmo-msgdb-set-mark-alist
612 (nconc (elmo-msgdb-get-mark-alist msgdb)
613 (elmo-msgdb-get-mark-alist msgdb-append)))
614 (setq duplicates (elmo-msgdb-make-index
616 (elmo-msgdb-get-overview msgdb-append)
617 (elmo-msgdb-get-mark-alist msgdb-append)))
620 (or (elmo-msgdb-get-path msgdb)
621 (elmo-msgdb-get-path msgdb-append)))
622 (elmo-msgdb-set-message-modified-internal msgdb t)
623 (elmo-msgdb-set-flag-modified-internal msgdb t)
625 (luna-call-next-method)))
627 (defun elmo-msgdb-merge (folder msgdb-merge)
628 "Return a list of messages which have duplicated message-id."
629 (let (msgdb duplicates)
630 (setq msgdb (or (elmo-folder-msgdb-internal folder)
631 (elmo-make-msgdb (elmo-folder-msgdb-path folder))))
632 (setq duplicates (elmo-msgdb-append msgdb msgdb-merge))
633 (elmo-folder-set-msgdb-internal folder msgdb)
636 (luna-define-method elmo-msgdb-clear :after ((msgdb elmo-msgdb-legacy))
637 (elmo-msgdb-set-overview msgdb nil)
638 (elmo-msgdb-set-number-alist msgdb nil)
639 (elmo-msgdb-set-mark-alist msgdb nil)
640 (elmo-msgdb-set-index msgdb nil))
642 (luna-define-method elmo-msgdb-delete-messages ((msgdb elmo-msgdb-legacy)
644 (let* ((overview (elmo-msgdb-get-overview msgdb))
645 (number-alist (elmo-msgdb-get-number-alist msgdb))
646 (mark-alist (elmo-msgdb-get-mark-alist msgdb))
647 (index (elmo-msgdb-get-index msgdb))
649 ;; remove from current database.
650 (dolist (number numbers)
654 (elmo-msgdb-overview-get-entity number msgdb))
656 (setq number-alist (delq (assq number number-alist) number-alist))
657 (setq mark-alist (delq (assq number mark-alist) mark-alist))
659 (when index (elmo-msgdb-clear-index msgdb ov-entity)))
660 (elmo-msgdb-set-overview msgdb overview)
661 (elmo-msgdb-set-number-alist msgdb number-alist)
662 (elmo-msgdb-set-mark-alist msgdb mark-alist)
663 (elmo-msgdb-set-index msgdb index)
664 (elmo-msgdb-set-message-modified-internal msgdb t)
665 (elmo-msgdb-set-flag-modified-internal msgdb t)
668 (luna-define-method elmo-msgdb-sort-entities ((msgdb elmo-msgdb-legacy)
669 predicate &optional app-data)
670 (message "Sorting...")
671 (let ((overview (elmo-msgdb-get-overview msgdb)))
672 (elmo-msgdb-set-overview
674 (sort overview (lambda (a b) (funcall predicate a b app-data))))
675 (message "Sorting...done")
678 (defun elmo-msgdb-sort-by-date (msgdb)
679 (elmo-msgdb-sort-entities
681 (lambda (x y app-data)
684 (timezone-make-date-sortable
685 (elmo-msgdb-overview-entity-get-date x))
686 (timezone-make-date-sortable
687 (elmo-msgdb-overview-entity-get-date y)))
691 (defsubst elmo-msgdb-append-element (list element)
693 ;;; (append list (list element))
694 (nconc list (list element))
699 ;; number <-> Message-ID handling
701 (defsubst elmo-msgdb-number-add (alist number id)
702 (let ((ret-val alist))
704 (elmo-msgdb-append-element ret-val (cons number id)))
709 (defvar elmo-flag-table-filename "flag-table")
710 (defun elmo-flag-table-load (dir)
711 "Load flag hashtable for MSGDB."
712 (let ((table (elmo-make-hash))
713 ;; For backward compatibility
714 (seen-file (expand-file-name elmo-msgdb-seen-filename dir))
716 (when (file-exists-p seen-file)
717 (dolist (msgid (elmo-object-load seen-file))
718 (elmo-set-hash-val msgid '(read) table))
719 (delete-file seen-file))
720 (dolist (pair (elmo-object-load
721 (expand-file-name elmo-flag-table-filename dir)))
722 (setq value (cdr pair))
723 (elmo-set-hash-val (car pair)
726 ;; Following cases for backward compatibility.
734 (defun elmo-flag-table-set (flag-table msg-id flags)
735 (elmo-set-hash-val msg-id (or flags '(read)) flag-table))
737 (defun elmo-flag-table-get (flag-table msg-id)
738 (let ((flags (elmo-get-hash-val msg-id flag-table)))
741 (and (elmo-msgdb-global-mark-get msg-id)
743 (and (elmo-file-cache-exists-p msg-id)
745 (elmo-list-delete '(important cached read)
746 (copy-sequence flags)
750 (defun elmo-flag-table-save (dir flag-table)
752 (expand-file-name elmo-flag-table-filename dir)
755 (mapatoms (lambda (atom)
756 (setq list (cons (cons (symbol-name atom)
762 ;; persistent mark handling
765 (defun elmo-msgdb-mark-append (alist id mark)
767 (setq alist (elmo-msgdb-append-element alist
770 (defsubst elmo-msgdb-length (msgdb)
771 (length (elmo-msgdb-get-overview msgdb)))
773 (defun elmo-msgdb-flag-table (msgdb &optional flag-table)
774 ;; Make a table of msgid flag (read, answered)
775 (let ((flag-table (or flag-table
776 (elmo-make-hash (elmo-msgdb-length msgdb))))
778 (dolist (number (elmo-msgdb-list-messages msgdb))
779 (setq entity (elmo-msgdb-message-entity msgdb number))
782 (elmo-msgdb-overview-entity-get-id entity)
783 (elmo-msgdb-flags msgdb number)))
789 (defvar elmo-msgdb-decoded-cache-hashtb nil)
790 (make-variable-buffer-local 'elmo-msgdb-decoded-cache-hashtb)
792 (defsubst elmo-msgdb-get-decoded-cache (string)
793 (if elmo-use-decoded-cache
794 (let ((hashtb (or elmo-msgdb-decoded-cache-hashtb
795 (setq elmo-msgdb-decoded-cache-hashtb
796 (elmo-make-hash 2048))))
798 (or (elmo-get-hash-val string hashtb)
803 (decode-mime-charset-string string elmo-mime-charset))
806 (decode-mime-charset-string string elmo-mime-charset)))
811 (defun elmo-multiple-field-body (name &optional boundary)
814 (std11-narrow-to-header boundary)
815 (goto-char (point-min))
816 (let ((case-fold-search t)
818 (while (re-search-forward (concat "^" name ":[ \t]*") nil t)
821 (list (buffer-substring-no-properties
822 (match-end 0) (std11-field-end))))))
825 (defun elmo-multiple-fields-body-list (field-names &optional boundary)
826 "Return list of each field-bodies of FIELD-NAMES of the message header
827 in current buffer. If BOUNDARY is not nil, it is used as message
831 (std11-narrow-to-header boundary)
832 (let* ((case-fold-search t)
834 field-name field-body)
835 (while (setq field-name (car s-rest))
836 (goto-char (point-min))
837 (while (re-search-forward (concat "^" field-name ":[ \t]*") nil t)
840 (list (buffer-substring-no-properties
841 (match-end 0) (std11-field-end))))))
842 (setq s-rest (cdr s-rest)))
845 (defsubst elmo-msgdb-remove-field-string (string)
846 (if (string-match (concat std11-field-head-regexp "[ \t]*") string)
847 (substring string (match-end 0))
850 (defsubst elmo-msgdb-get-last-message-id (string)
856 (goto-char (point-max))
857 (when (search-backward "<" nil t)
859 (if (search-forward ">" nil t)
860 (elmo-replace-in-string
861 (buffer-substring beg (point)) "\n[ \t]*" ""))))))))
863 (defun elmo-msgdb-number-load (dir)
865 (expand-file-name elmo-msgdb-number-filename dir)))
867 (defun elmo-msgdb-overview-load (dir)
869 (expand-file-name elmo-msgdb-overview-filename dir)))
871 (defun elmo-msgdb-mark-load (dir)
873 (expand-file-name elmo-msgdb-mark-filename dir)))
875 (defsubst elmo-msgdb-seen-load (dir)
876 (elmo-object-load (expand-file-name
877 elmo-msgdb-seen-filename
880 (defun elmo-msgdb-number-save (dir obj)
882 (expand-file-name elmo-msgdb-number-filename dir)
885 (defun elmo-msgdb-mark-save (dir obj)
887 (expand-file-name elmo-msgdb-mark-filename dir)
890 (defun elmo-msgdb-change-mark (msgdb before after)
891 "Set the BEFORE marks to AFTER."
892 (let ((mark-alist (elmo-msgdb-get-mark-alist msgdb))
895 (setq entity (car mark-alist))
896 (when (string= (cadr entity) before)
897 (setcar (cdr entity) after))
898 (setq mark-alist (cdr mark-alist)))))
900 (defsubst elmo-msgdb-out-of-date-messages (msgdb)
901 (elmo-msgdb-change-mark msgdb
903 elmo-msgdb-unread-uncached-mark))
905 (defsubst elmo-msgdb-overview-save (dir overview)
907 (expand-file-name elmo-msgdb-overview-filename dir)
910 (defun elmo-msgdb-match-condition-primitive (condition mark entity numbers)
912 (let ((key (elmo-filter-key condition))
916 ((string= key "last")
917 (setq result (<= (length (memq
918 (elmo-msgdb-overview-entity-get-number
921 (string-to-int (elmo-filter-value condition)))))
922 ((string= key "first")
926 (elmo-msgdb-overview-entity-get-number
929 (string-to-int (elmo-filter-value condition)))))
930 ((string= key "flag")
933 ((string= (elmo-filter-value condition) "any")
935 (string= mark elmo-msgdb-read-uncached-mark))))
936 ((string= (elmo-filter-value condition) "digest")
938 (string= mark elmo-msgdb-read-uncached-mark)
939 (string= mark elmo-msgdb-answered-cached-mark)
940 (string= mark elmo-msgdb-answered-uncached-mark))))
941 ;; (member mark (append (elmo-msgdb-answered-marks)
942 ;; (list elmo-msgdb-important-mark)
943 ;; (elmo-msgdb-unread-marks))))
944 ((string= (elmo-filter-value condition) "unread")
945 (member mark (elmo-msgdb-unread-marks)))
946 ((string= (elmo-filter-value condition) "important")
947 (string= mark elmo-msgdb-important-mark))
948 ((string= (elmo-filter-value condition) "answered")
949 (member mark (elmo-msgdb-answered-marks))))))
950 ((string= key "from")
951 (setq result (string-match
952 (elmo-filter-value condition)
953 (elmo-msgdb-overview-entity-get-from entity))))
954 ((string= key "subject")
955 (setq result (string-match
956 (elmo-filter-value condition)
957 (elmo-msgdb-overview-entity-get-subject entity))))
959 (setq result (string-match
960 (elmo-filter-value condition)
961 (elmo-msgdb-overview-entity-get-to entity))))
963 (setq result (string-match
964 (elmo-filter-value condition)
965 (elmo-msgdb-overview-entity-get-cc entity))))
966 ((or (string= key "since")
967 (string= key "before"))
968 (let ((field-date (elmo-date-make-sortable-string
970 (elmo-msgdb-overview-entity-get-date entity)
971 (current-time-zone) nil)))
973 (elmo-date-make-sortable-string
974 (elmo-date-get-datevec
975 (elmo-filter-value condition)))))
976 (setq result (if (string= key "since")
977 (or (string= specified-date field-date)
978 (string< specified-date field-date))
979 (string< field-date specified-date)))))
980 ((member key elmo-msgdb-extra-fields)
981 (let ((extval (elmo-msgdb-overview-entity-get-extra-field entity key)))
982 (when (stringp extval)
983 (setq result (string-match
984 (elmo-filter-value condition)
987 (throw 'unresolved condition)))
988 (if (eq (elmo-filter-type condition) 'unmatch)
992 (defun elmo-msgdb-match-condition-internal (condition mark entity numbers)
995 (elmo-msgdb-match-condition-primitive condition mark entity numbers))
996 ((eq (car condition) 'and)
997 (let ((lhs (elmo-msgdb-match-condition-internal (nth 1 condition)
998 mark entity numbers)))
1000 ((elmo-filter-condition-p lhs)
1001 (let ((rhs (elmo-msgdb-match-condition-internal
1002 (nth 2 condition) mark entity numbers)))
1003 (cond ((elmo-filter-condition-p rhs)
1004 (list 'and lhs rhs))
1008 (elmo-msgdb-match-condition-internal (nth 2 condition)
1009 mark entity numbers)))))
1010 ((eq (car condition) 'or)
1011 (let ((lhs (elmo-msgdb-match-condition-internal (nth 1 condition)
1012 mark entity numbers)))
1014 ((elmo-filter-condition-p lhs)
1015 (let ((rhs (elmo-msgdb-match-condition-internal (nth 2 condition)
1016 mark entity numbers)))
1017 (cond ((elmo-filter-condition-p rhs)
1026 (elmo-msgdb-match-condition-internal (nth 2 condition)
1027 mark entity numbers)))))))
1029 (defun elmo-msgdb-match-condition (msgdb condition number numbers)
1030 "Check whether the condition of the message is satisfied or not.
1031 MSGDB is the msgdb to search from.
1032 CONDITION is the search condition.
1033 NUMBER is the message number to check.
1034 NUMBERS is the target message number list.
1035 Return CONDITION itself if no entity exists in msgdb."
1036 (let ((entity (elmo-msgdb-overview-get-entity number msgdb)))
1038 (elmo-msgdb-match-condition-internal condition
1039 (elmo-msgdb-get-mark msgdb number)
1043 (defsubst elmo-msgdb-overview-entity-get-references (entity)
1044 (and entity (aref (cdr entity) 1)))
1046 (defsubst elmo-msgdb-overview-entity-set-references (entity references)
1047 (and entity (aset (cdr entity) 1 references))
1050 ;; entity -> parent-entity
1051 (defsubst elmo-msgdb-overview-get-parent-entity (entity database)
1052 (setq entity (elmo-msgdb-overview-entity-get-references entity))
1053 ;; entity is parent-id.
1054 (and entity (assoc entity database)))
1056 (defsubst elmo-msgdb-get-parent-entity (entity msgdb)
1057 (setq entity (elmo-msgdb-overview-entity-get-references entity))
1058 ;; entity is parent-id.
1059 (and entity (elmo-msgdb-overview-get-entity entity msgdb)))
1061 (defsubst elmo-msgdb-overview-entity-get-number (entity)
1062 (and entity (aref (cdr entity) 0)))
1064 (defsubst elmo-msgdb-overview-entity-get-from-no-decode (entity)
1065 (and entity (aref (cdr entity) 2)))
1067 (defsubst elmo-msgdb-overview-entity-get-from (entity)
1069 (aref (cdr entity) 2)
1070 (elmo-msgdb-get-decoded-cache (aref (cdr entity) 2))))
1072 (defsubst elmo-msgdb-overview-entity-set-number (entity number)
1073 (and entity (aset (cdr entity) 0 number))
1075 ;;;(setcar (cadr entity) number) entity)
1077 (defsubst elmo-msgdb-overview-entity-set-from (entity from)
1078 (and entity (aset (cdr entity) 2 from))
1081 (defsubst elmo-msgdb-overview-entity-get-subject (entity)
1083 (aref (cdr entity) 3)
1084 (elmo-msgdb-get-decoded-cache (aref (cdr entity) 3))))
1086 (defsubst elmo-msgdb-overview-entity-get-subject-no-decode (entity)
1087 (and entity (aref (cdr entity) 3)))
1089 (defsubst elmo-msgdb-overview-entity-set-subject (entity subject)
1090 (and entity (aset (cdr entity) 3 subject))
1093 (defsubst elmo-msgdb-overview-entity-get-date (entity)
1094 (and entity (aref (cdr entity) 4)))
1096 (defsubst elmo-msgdb-overview-entity-set-date (entity date)
1097 (and entity (aset (cdr entity) 4 date))
1100 (defsubst elmo-msgdb-overview-entity-get-to (entity)
1101 (and entity (aref (cdr entity) 5)))
1103 (defsubst elmo-msgdb-overview-entity-get-cc (entity)
1104 (and entity (aref (cdr entity) 6)))
1106 (defsubst elmo-msgdb-overview-entity-get-size (entity)
1107 (and entity (aref (cdr entity) 7)))
1109 (defsubst elmo-msgdb-overview-entity-set-size (entity size)
1110 (and entity (aset (cdr entity) 7 size))
1113 (defsubst elmo-msgdb-overview-entity-get-id (entity)
1114 (and entity (car entity)))
1116 (defsubst elmo-msgdb-overview-entity-get-extra-field (entity field-name)
1117 (let ((field-name (downcase field-name))
1118 (extra (and entity (aref (cdr entity) 8))))
1120 (cdr (assoc field-name extra)))))
1122 (defsubst elmo-msgdb-overview-entity-set-extra-field (entity field-name value)
1123 (let ((field-name (downcase field-name))
1124 (extras (and entity (aref (cdr entity) 8)))
1126 (if (setq extra (assoc field-name extras))
1127 (setcdr extra value)
1128 (elmo-msgdb-overview-entity-set-extra
1130 (cons (cons field-name value) extras)))))
1132 (defsubst elmo-msgdb-overview-entity-get-extra (entity)
1133 (and entity (aref (cdr entity) 8)))
1135 (defsubst elmo-msgdb-overview-entity-set-extra (entity extra)
1136 (and entity (aset (cdr entity) 8 extra))
1140 (luna-define-method elmo-msgdb-message-entity ((msgdb elmo-msgdb-legacy) key)
1142 (cond ((stringp key) key)
1143 ((numberp key) (format "#%d" key)))
1144 (elmo-msgdb-get-entity-hashtb msgdb)))
1146 (defun elmo-msgdb-make-message-entity (&rest args)
1147 "Make an message entity."
1148 (cons (plist-get args :message-id)
1149 (vector (plist-get args :number)
1150 (plist-get args :references)
1151 (plist-get args :from)
1152 (plist-get args :subject)
1153 (plist-get args :date)
1154 (plist-get args :to)
1155 (plist-get args :cc)
1156 (plist-get args :size)
1157 (plist-get args :extra))))
1159 (defsubst elmo-msgdb-message-entity-field (entity field &optional decode)
1163 (to (aref (cdr entity) 5))
1164 (cc (aref (cdr entity) 6))
1165 (date (aref (cdr entity) 4))
1166 (subject (aref (cdr entity) 3))
1167 (from (aref (cdr entity) 2))
1168 (message-id (car entity))
1169 (references (aref (cdr entity) 1))
1170 (size (aref (cdr entity) 7))
1171 (t (cdr (assoc (symbol-name field) (aref (cdr entity) 8)))))))
1172 (if (and decode (memq field '(from subject)))
1173 (elmo-msgdb-get-decoded-cache field-value)
1176 (defsubst elmo-msgdb-message-entity-set-field (entity field value)
1179 (to (aset (cdr entity) 5 value))
1180 (cc (aset (cdr entity) 6 value))
1181 (date (aset (cdr entity) 4 value))
1182 (subject (aset (cdr entity) 3 value))
1183 (from (aset (cdr entity) 2 value))
1184 (message-id (setcar entity value))
1185 (references (aset (cdr entity) 1 value))
1186 (size (aset (cdr entity) 7 value))
1188 (let ((extras (and entity (aref (cdr entity) 8)))
1190 (if (setq extra (assoc field extras))
1191 (setcdr extra value)
1192 (aset (cdr entity) 8 (cons (cons (symbol-name field)
1193 value) extras))))))))
1196 (defun elmo-msgdb-overview-get-entity (id msgdb)
1197 (elmo-msgdb-message-entity msgdb id))
1200 ;; deleted message handling
1202 (defun elmo-msgdb-killed-list-load (dir)
1204 (expand-file-name elmo-msgdb-killed-filename dir)
1207 (defun elmo-msgdb-killed-list-save (dir killed-list)
1209 (expand-file-name elmo-msgdb-killed-filename dir)
1212 (defun elmo-msgdb-killed-message-p (killed-list msg)
1213 (elmo-number-set-member msg killed-list))
1215 (defun elmo-msgdb-set-as-killed (killed-list msg)
1216 (elmo-number-set-append killed-list msg))
1218 (defun elmo-msgdb-killed-list-length (killed-list)
1219 (let ((killed killed-list)
1222 (if (consp (car killed))
1223 (setq ret-val (+ ret-val 1 (- (cdar killed) (caar killed))))
1224 (setq ret-val (+ ret-val 1)))
1225 (setq killed (cdr killed)))
1228 (defun elmo-msgdb-max-of-killed (killed-list)
1229 (let ((klist killed-list)
1235 (if (consp (car klist))
1239 (setq klist (cdr klist)))
1242 (defun elmo-living-messages (messages killed-list)
1245 (mapcar (lambda (number)
1246 (unless (elmo-number-set-member number killed-list)
1251 (defun elmo-msgdb-finfo-load ()
1252 (elmo-object-load (expand-file-name
1253 elmo-msgdb-finfo-filename
1254 elmo-msgdb-directory)
1255 elmo-mime-charset t))
1257 (defun elmo-msgdb-finfo-save (finfo)
1258 (elmo-object-save (expand-file-name
1259 elmo-msgdb-finfo-filename
1260 elmo-msgdb-directory)
1261 finfo elmo-mime-charset))
1263 (defun elmo-msgdb-flist-load (fname)
1264 (let ((flist-file (expand-file-name
1265 elmo-msgdb-flist-filename
1267 (elmo-safe-filename fname)
1268 (expand-file-name "folder" elmo-msgdb-directory)))))
1269 (elmo-object-load flist-file elmo-mime-charset t)))
1271 (defun elmo-msgdb-flist-save (fname flist)
1272 (let ((flist-file (expand-file-name
1273 elmo-msgdb-flist-filename
1275 (elmo-safe-filename fname)
1276 (expand-file-name "folder" elmo-msgdb-directory)))))
1277 (elmo-object-save flist-file flist elmo-mime-charset)))
1279 (defun elmo-crosspost-alist-load ()
1280 (elmo-object-load (expand-file-name
1281 elmo-crosspost-alist-filename
1282 elmo-msgdb-directory)
1285 (defun elmo-crosspost-alist-save (alist)
1286 (elmo-object-save (expand-file-name
1287 elmo-crosspost-alist-filename
1288 elmo-msgdb-directory)
1291 (defun elmo-msgdb-get-message-id-from-buffer ()
1292 (let ((msgid (elmo-field-body "message-id")))
1294 (if (string-match "<\\(.+\\)>$" msgid)
1296 (concat "<" msgid ">")) ; Invaild message-id.
1297 ;; no message-id, so put dummy msgid.
1298 (concat "<" (timezone-make-date-sortable
1299 (elmo-field-body "date"))
1300 (nth 1 (eword-extract-address-components
1301 (or (elmo-field-body "from") "nobody"))) ">"))))
1303 (defsubst elmo-msgdb-create-overview-from-buffer (number &optional size time)
1304 "Create overview entity from current buffer.
1305 Header region is supposed to be narrowed."
1307 (let ((extras elmo-msgdb-extra-fields)
1308 (default-mime-charset default-mime-charset)
1309 message-id references from subject to cc date
1310 extra field-body charset)
1311 (elmo-set-buffer-multibyte default-enable-multibyte-characters)
1312 (setq message-id (elmo-msgdb-get-message-id-from-buffer))
1313 (and (setq charset (cdr (assoc "charset" (mime-read-Content-Type))))
1314 (setq charset (intern-soft charset))
1315 (setq default-mime-charset charset))
1317 (or (elmo-msgdb-get-last-message-id
1318 (elmo-field-body "in-reply-to"))
1319 (elmo-msgdb-get-last-message-id
1320 (elmo-field-body "references"))))
1321 (setq from (elmo-replace-in-string
1322 (elmo-mime-string (or (elmo-field-body "from")
1325 subject (elmo-replace-in-string
1326 (elmo-mime-string (or (elmo-field-body "subject")
1329 (setq date (or (elmo-field-body "date") time))
1330 (setq to (mapconcat 'identity (elmo-multiple-field-body "to") ","))
1331 (setq cc (mapconcat 'identity (elmo-multiple-field-body "cc") ","))
1333 (if (setq size (elmo-field-body "content-length"))
1334 (setq size (string-to-int size))
1335 (setq size 0)));; No mean...
1337 (if (setq field-body (elmo-field-body (car extras)))
1338 (setq extra (cons (cons (downcase (car extras))
1339 field-body) extra)))
1340 (setq extras (cdr extras)))
1341 (cons message-id (vector number references
1342 from subject date to cc
1346 (defun elmo-msgdb-copy-overview-entity (entity)
1348 (copy-sequence (cdr entity))))
1350 (defsubst elmo-msgdb-insert-file-header (file)
1351 "Insert the header of the article."
1353 insert-file-contents-pre-hook ; To avoid autoconv-xmas...
1354 insert-file-contents-post-hook
1356 (when (file-exists-p file)
1357 ;; Read until header separator is found.
1358 (while (and (eq elmo-msgdb-file-header-chop-length
1360 (insert-file-contents-as-binary
1362 (incf beg elmo-msgdb-file-header-chop-length))))
1363 (prog1 (not (search-forward "\n\n" nil t))
1364 (goto-char (point-max))))))))
1366 (defsubst elmo-msgdb-create-overview-entity-from-file (number file)
1367 (let (insert-file-contents-pre-hook ; To avoid autoconv-xmas...
1368 insert-file-contents-post-hook header-end
1369 (attrib (file-attributes file))
1372 (if (not (file-exists-p file))
1374 (setq size (nth 7 attrib))
1375 (setq mtime (timezone-make-date-arpa-standard
1376 (current-time-string (nth 5 attrib)) (current-time-zone)))
1377 ;; insert header from file.
1380 (elmo-msgdb-insert-file-header file)
1381 (error (throw 'done nil)))
1382 (goto-char (point-min))
1384 (if (re-search-forward "\\(^--.*$\\)\\|\\(\n\n\\)" nil t)
1387 (narrow-to-region (point-min) header-end)
1388 (elmo-msgdb-create-overview-from-buffer number size mtime))))))
1390 (defun elmo-msgdb-clear-index (msgdb entity)
1391 (let ((ehash (elmo-msgdb-get-entity-hashtb msgdb))
1392 (mhash (elmo-msgdb-get-mark-hashtb msgdb))
1394 (when (and entity ehash)
1395 (and (setq number (elmo-msgdb-overview-entity-get-number entity))
1396 (elmo-clear-hash-val (format "#%d" number) ehash))
1397 (and (car entity) ;; message-id
1398 (elmo-clear-hash-val (car entity) ehash)))
1399 (when (and entity mhash)
1400 (and (setq number (elmo-msgdb-overview-entity-get-number entity))
1401 (elmo-clear-hash-val (format "#%d" number) mhash)))))
1403 (defun elmo-msgdb-make-index (msgdb &optional overview mark-alist)
1404 "Append OVERVIEW and MARK-ALIST to the index of MSGDB.
1405 If OVERVIEW and MARK-ALIST are nil, make index for current MSGDB.
1406 Return a list of message numbers which have duplicated message-ids."
1408 (let* ((overview (or overview (elmo-msgdb-get-overview msgdb)))
1409 (mark-alist (or mark-alist (elmo-msgdb-get-mark-alist msgdb)))
1410 (index (elmo-msgdb-get-index msgdb))
1411 (ehash (or (car index) ;; append
1412 (elmo-make-hash (length overview))))
1413 (mhash (or (cdr index) ;; append
1414 (elmo-make-hash (length overview))))
1417 ;; key is message-id
1418 (if (elmo-get-hash-val (caar overview) ehash) ; duplicated.
1419 (setq duplicates (cons
1420 (elmo-msgdb-overview-entity-get-number
1424 (elmo-set-hash-val (caar overview) (car overview) ehash))
1428 (elmo-msgdb-overview-entity-get-number (car overview)))
1429 (car overview) ehash)
1430 (setq overview (cdr overview)))
1434 (format "#%d" (car (car mark-alist)))
1435 (car mark-alist) mhash)
1436 (setq mark-alist (cdr mark-alist)))
1437 (setq index (or index (cons ehash mhash)))
1438 (elmo-msgdb-set-index msgdb index)
1441 (defsubst elmo-folder-get-info (folder &optional hashtb)
1442 (elmo-get-hash-val folder
1443 (or hashtb elmo-folder-info-hashtb)))
1445 (defun elmo-folder-get-info-max (folder)
1446 "Get folder info from cache."
1447 (nth 3 (elmo-folder-get-info folder)))
1449 (defun elmo-folder-get-info-length (folder)
1450 (nth 2 (elmo-folder-get-info folder)))
1452 (defun elmo-folder-get-info-unread (folder)
1453 (nth 1 (elmo-folder-get-info folder)))
1455 (defsubst elmo-msgdb-location-load (dir)
1458 elmo-msgdb-location-filename
1461 (defsubst elmo-msgdb-location-add (alist number location)
1462 (let ((ret-val alist))
1464 (elmo-msgdb-append-element ret-val (cons number location)))
1467 (defsubst elmo-msgdb-location-save (dir alist)
1470 elmo-msgdb-location-filename
1473 (luna-define-method elmo-msgdb-list-flagged ((msgdb elmo-msgdb-legacy) flag)
1474 (let ((case-fold-search nil)
1475 mark-regexp matched)
1478 (setq mark-regexp (regexp-quote elmo-msgdb-new-mark)))
1480 (setq mark-regexp (elmo-regexp-opt (elmo-msgdb-unread-marks))))
1482 (setq mark-regexp (elmo-regexp-opt (elmo-msgdb-answered-marks))))
1484 (setq mark-regexp (regexp-quote elmo-msgdb-important-mark)))
1486 (setq mark-regexp (elmo-regexp-opt (elmo-msgdb-unread-marks))))
1488 (setq mark-regexp (elmo-regexp-opt
1489 (append (elmo-msgdb-unread-marks)
1490 (list elmo-msgdb-important-mark)))))
1492 (setq mark-regexp (elmo-regexp-opt
1494 (elmo-msgdb-unread-marks)
1495 (elmo-msgdb-answered-marks)
1496 (list elmo-msgdb-important-mark))))))
1499 (dolist (number (elmo-msgdb-list-messages msgdb))
1500 (let ((mark (elmo-msgdb-get-mark msgdb number)))
1501 (unless (and mark (string-match mark-regexp mark))
1502 (setq matched (cons number matched)))))
1503 (dolist (elem (elmo-msgdb-get-mark-alist msgdb))
1504 (if (string-match mark-regexp (cadr elem))
1505 (setq matched (cons (car elem) matched))))))
1509 (product-provide (provide 'elmo-msgdb) (require 'elmo-version))
1511 ;;; elmo-msgdb.el ends here