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 (defcustom elmo-msgdb-new-mark "N"
42 "Mark for new message."
43 :type '(string :tag "Mark")
46 (defcustom elmo-msgdb-unread-uncached-mark "U"
47 "Mark for unread and uncached message."
48 :type '(string :tag "Mark")
51 (defcustom elmo-msgdb-unread-cached-mark "!"
52 "Mark for unread but already cached message."
53 :type '(string :tag "Mark")
56 (defcustom elmo-msgdb-read-uncached-mark "u"
57 "Mark for read but uncached message."
58 :type '(string :tag "Mark")
61 ;; Not implemented yet.
62 (defcustom elmo-msgdb-answered-cached-mark "&"
63 "Mark for answered and cached message."
64 :type '(string :tag "Mark")
67 (defcustom elmo-msgdb-answered-uncached-mark "A"
68 "Mark for answered but cached message."
69 :type '(string :tag "Mark")
72 (defcustom elmo-msgdb-important-mark"$"
73 "Mark for important message."
74 :type '(string :tag "Mark")
79 ;; MSGDB elmo-load-msgdb PATH
80 ;; MARK elmo-msgdb-get-mark MSGDB NUMBER
82 ;; CACHED elmo-msgdb-get-cached MSGDB NUMBER
83 ;; VOID elmo-msgdb-set-cached MSGDB NUMBER CACHED USE-CACHE
84 ;; VOID elmo-msgdb-set-flag MSGDB FOLDER NUMBER FLAG
85 ;; VOID elmo-msgdb-unset-flag MSGDB FOLDER NUMBER FLAG
87 ;; LIST-OF-NUMBERS elmo-msgdb-count-marks MSGDB
88 ;; NUMBER elmo-msgdb-get-number MSGDB MESSAGE-ID
89 ;; FIELD-VALUE elmo-msgdb-get-field MSGDB NUMBER FIELD
90 ;; MSGDB elmo-msgdb-append MSGDB MSGDB-APPEND
91 ;; MSGDB elmo-msgdb-clear MSGDB
92 ;; elmo-msgdb-delete-msgs MSGDB NUMBERS
93 ;; elmo-msgdb-sort-by-date MSGDB
96 ;; LIST-OF-NUMBERS elmo-msgdb-list-messages MSGDB
98 ;; elmo-flag-table-load
99 ;; elmo-flag-table-set
100 ;; elmo-flag-table-get
101 ;; elmo-flag-table-save
103 ;; elmo-msgdb-append-entity
104 ;; msgdb entity flag-table
106 ;; ENTITY elmo-msgdb-make-entity ARGS
107 ;; VALUE elmo-msgdb-entity-field ENTITY
110 ;; OVERVIEW elmo-msgdb-get-overview MSGDB
111 ;; NUMBER-ALIST elmo-msgdb-get-number-alist MSGDB
112 ;; MARK-ALIST elmo-msgdb-get-mark-alist MSGDB
113 ;; elmo-msgdb-change-mark MSGDB BEFORE AFTER
115 ;; (for internal use?)
116 ;; LIST-OF-MARKS elmo-msgdb-unread-marks
117 ;; LIST-OF-MARKS elmo-msgdb-answered-marks
118 ;; LIST-OF-MARKS elmo-msgdb-uncached-marks
119 ;; elmo-msgdb-overview-save DIR OBJ
121 ;; elmo-msgdb-message-entity MSGDB KEY
124 ;; elmo-msgdb-overview-entity-get-references ENTITY
125 ;; elmo-msgdb-overview-entity-set-references ENTITY
126 ;; elmo-msgdb-get-parent-entity ENTITY MSGDB
127 ;; elmo-msgdb-overview-enitty-get-number ENTITY
128 ;; elmo-msgdb-overview-enitty-get-from-no-decode ENTITY
129 ;; elmo-msgdb-overview-enitty-get-from ENTITY
130 ;; elmo-msgdb-overview-enitty-get-subject-no-decode ENTITY
131 ;; elmo-msgdb-overview-enitty-get-subject ENTITY
132 ;; elmo-msgdb-overview-enitty-get-date ENTITY
133 ;; elmo-msgdb-overview-enitty-get-to ENTITY
134 ;; elmo-msgdb-overview-enitty-get-cc ENTITY
135 ;; elmo-msgdb-overview-enitty-get-size ENTITY
136 ;; elmo-msgdb-overview-enitty-get-id ENTITY
137 ;; elmo-msgdb-overview-enitty-get-extra-field ENTITY
138 ;; elmo-msgdb-overview-enitty-get-extra ENTITY
139 ;; elmo-msgdb-overview-get-entity ID MSGDB
141 ;; elmo-msgdb-killed-list-load DIR
142 ;; elmo-msgdb-killed-list-save DIR
143 ;; elmo-msgdb-append-to-killed-list FOLDER MSG
144 ;; elmo-msgdb-killed-list-length KILLED-LIST
145 ;; elmo-msgdb-max-of-killed KILLED-LIST
146 ;; elmo-msgdb-killed-message-p KILLED-LIST MSG
147 ;; elmo-living-messages MESSAGES KILLED-LIST
148 ;; elmo-msgdb-finfo-load
149 ;; elmo-msgdb-finfo-save
150 ;; elmo-msgdb-flist-load
151 ;; elmo-msgdb-flist-save
153 ;; elmo-crosspost-alist-load
154 ;; elmo-crosspost-alist-save
156 ;; elmo-msgdb-create-overview-from-buffer NUMBER SIZE TIME
157 ;; elmo-msgdb-copy-overview-entity ENTITY
158 ;; elmo-msgdb-create-overview-entity-from-file NUMBER FILE
159 ;; elmo-msgdb-overview-sort-by-date OVERVIEW
160 ;; elmo-msgdb-clear-index
162 ;; elmo-folder-get-info
163 ;; elmo-folder-get-info-max
164 ;; elmo-folder-get-info-length
165 ;; elmo-folder-get-info-unread
167 ;; elmo-msgdb-list-flagged MSGDB FLAG
168 ;; (MACRO) elmo-msgdb-do-each-entity
170 (defun elmo-load-msgdb (path)
171 "Load the MSGDB from PATH."
172 (let ((inhibit-quit t))
173 (elmo-make-msgdb (elmo-msgdb-overview-load path)
174 (elmo-msgdb-number-load path)
175 (elmo-msgdb-mark-load path)
178 (defun elmo-make-msgdb (&optional overview number-alist mark-alist path)
180 (let ((msgdb (list overview number-alist mark-alist nil path)))
181 (elmo-msgdb-make-index msgdb)
184 (defun elmo-msgdb-list-messages (msgdb-or-path)
185 "Return a list of message numbers in the msgdb.
186 If MSGDB-OR-PATH is a msgdb structure, use it as a msgdb.
187 If argument is a string, use it as a path to load message entities."
188 (mapcar 'elmo-msgdb-overview-entity-get-number
189 (if (stringp msgdb-or-path)
190 (elmo-msgdb-overview-load msgdb-or-path)
191 (elmo-msgdb-get-overview msgdb-or-path))))
193 (defsubst elmo-msgdb-get-mark (msgdb number)
194 "Get mark string from MSGDB which corresponds to the message with NUMBER."
195 (cadr (elmo-get-hash-val (format "#%d" number)
196 (elmo-msgdb-get-mark-hashtb msgdb))))
198 (defsubst elmo-msgdb-set-mark (msgdb number mark)
199 "Set MARK of the message with NUMBER in the MSGDB.
200 if MARK is nil, mark is removed."
201 (let ((elem (elmo-get-hash-val (format "#%d" number)
202 (elmo-msgdb-get-mark-hashtb msgdb))))
205 ;; Set mark of the elem
206 (setcar (cdr elem) mark)
207 ;; Delete elem from mark-alist
208 (elmo-msgdb-set-mark-alist
210 (delq elem (elmo-msgdb-get-mark-alist msgdb)))
211 (elmo-clear-hash-val (format "#%d" number)
212 (elmo-msgdb-get-mark-hashtb msgdb)))
214 ;; Append new element.
215 (elmo-msgdb-set-mark-alist
218 (elmo-msgdb-get-mark-alist msgdb)
219 (list (setq elem (list number mark)))))
220 (elmo-set-hash-val (format "#%d" number) elem
221 (elmo-msgdb-get-mark-hashtb msgdb))))
225 (defun elmo-msgdb-get-cached (msgdb number)
226 "Return non-nil if message is cached."
227 (not (member (elmo-msgdb-get-mark msgdb number)
228 (elmo-msgdb-uncached-marks))))
230 (defun elmo-msgdb-set-cached (msgdb number cached use-cache)
231 "Set message cache status.
232 If mark is changed, return non-nil."
233 (let* ((cur-mark (elmo-msgdb-get-mark msgdb number))
235 ((string= cur-mark elmo-msgdb-important-mark)
237 ((member cur-mark (elmo-msgdb-answered-marks))
239 ((not (member cur-mark (elmo-msgdb-unread-marks)))
241 (cur-cached (elmo-file-cache-exists-p
242 (elmo-msgdb-get-field msgdb number 'message-id))))
243 (unless (eq cached cur-cached)
246 (elmo-msgdb-set-mark msgdb number
247 (if (and use-cache (not cached))
248 elmo-msgdb-read-uncached-mark)))
251 (elmo-msgdb-set-mark msgdb number
253 elmo-msgdb-answered-cached-mark
254 elmo-msgdb-answered-uncached-mark)))
256 (elmo-msgdb-set-mark msgdb number
258 elmo-msgdb-unread-cached-mark
259 elmo-msgdb-unread-uncached-mark)))))))
261 (defun elmo-msgdb-set-flag (msgdb folder number flag)
263 MSGDB is the ELMO msgdb.
264 FOLDER is a ELMO folder structure.
265 NUMBER is a message number to set flag.
266 FLAG is a symbol which is one of the following:
267 `read' ... Messages which are already read.
268 `important' ... Messages which are marked as important.
269 `answered' ... Messages which are marked as answered."
270 (let* ((cur-mark (elmo-msgdb-get-mark msgdb number))
271 (use-cache (elmo-message-use-cache-p folder number))
273 ((string= cur-mark elmo-msgdb-important-mark)
275 ((member cur-mark (elmo-msgdb-answered-marks))
277 ((not (member cur-mark (elmo-msgdb-unread-marks)))
279 (cur-cached (elmo-file-cache-exists-p
280 (elmo-msgdb-get-field msgdb number 'message-id)))
285 ((read important)) ; answered mark is overriden.
286 (t (elmo-msgdb-set-mark msgdb number
287 (if (and use-cache (not cur-cached))
288 elmo-msgdb-read-uncached-mark))
289 (setq mark-modified t))))
291 (unless (eq cur-flag 'important)
292 (elmo-msgdb-set-mark msgdb number elmo-msgdb-important-mark)
293 (setq mark-modified t)))
295 (unless (or (eq cur-flag 'answered) (eq cur-flag 'important))
296 (elmo-msgdb-set-mark msgdb number
298 elmo-msgdb-answered-cached-mark
299 elmo-msgdb-answered-uncached-mark)))
300 (setq mark-modified t)))
301 (if mark-modified (elmo-folder-set-mark-modified-internal folder t))))
303 (defun elmo-msgdb-unset-flag (msgdb folder number flag)
305 MSGDB is the ELMO msgdb.
306 FOLDER is a ELMO folder structure.
307 NUMBER is a message number to be set flag.
308 FLAG is a symbol which is one of the following:
309 `read' ... Messages which are already read.
310 `important' ... Messages which are marked as important.
311 `answered' ... Messages which are marked as answered."
312 (let* ((cur-mark (elmo-msgdb-get-mark msgdb number))
313 (use-cache (elmo-message-use-cache-p folder number))
315 ((string= cur-mark elmo-msgdb-important-mark)
317 ((member cur-mark (elmo-msgdb-answered-marks))
319 ((not (member cur-mark (elmo-msgdb-unread-marks)))
321 (cur-cached (elmo-file-cache-exists-p
322 (elmo-msgdb-get-field msgdb number 'message-id)))
326 (when (or (eq cur-flag 'read) (eq cur-flag 'answered))
327 (elmo-msgdb-set-mark msgdb number
329 elmo-msgdb-unread-cached-mark
330 elmo-msgdb-unread-uncached-mark))
331 (setq mark-modified t)))
333 (when (eq cur-flag 'important)
334 (elmo-msgdb-set-mark msgdb number nil)
335 (setq mark-modified t)))
337 (when (eq cur-flag 'answered)
338 (elmo-msgdb-set-mark msgdb number
339 (if (and use-cache (not cur-cached))
340 elmo-msgdb-read-uncached-mark))
341 (setq mark-modified t))))
342 (if mark-modified (elmo-folder-set-mark-modified-internal folder t))))
344 (defvar elmo-msgdb-unread-marks-internal nil)
345 (defsubst elmo-msgdb-unread-marks ()
346 "Return an unread mark list"
347 (or elmo-msgdb-unread-marks-internal
348 (setq elmo-msgdb-unread-marks-internal
349 (list elmo-msgdb-new-mark
350 elmo-msgdb-unread-uncached-mark
351 elmo-msgdb-unread-cached-mark))))
353 (defvar elmo-msgdb-answered-marks-internal nil)
354 (defsubst elmo-msgdb-answered-marks ()
355 "Return an answered mark list"
356 (or elmo-msgdb-answered-marks-internal
357 (setq elmo-msgdb-answered-marks-internal
358 (list elmo-msgdb-answered-cached-mark
359 elmo-msgdb-answered-uncached-mark))))
361 (defvar elmo-msgdb-uncached-marks-internal nil)
362 (defsubst elmo-msgdb-uncached-marks ()
363 (or elmo-msgdb-uncached-marks-internal
364 (setq elmo-msgdb-uncached-marks-internal
365 (list elmo-msgdb-new-mark
366 elmo-msgdb-answered-uncached-mark
367 elmo-msgdb-unread-uncached-mark
368 elmo-msgdb-read-uncached-mark))))
370 (defsubst elmo-msgdb-get-number (msgdb message-id)
371 "Get number of the message which corrensponds to MESSAGE-ID from MSGDB."
372 (elmo-msgdb-overview-entity-get-number
373 (elmo-msgdb-overview-get-entity message-id msgdb)))
375 (defsubst elmo-msgdb-get-field (msgdb number field)
376 "Get FIELD value of the message with NUMBER from MSGDB."
378 (message-id (elmo-msgdb-overview-entity-get-id
379 (elmo-msgdb-overview-get-entity
381 (subject (elmo-msgdb-overview-entity-get-subject
382 (elmo-msgdb-overview-get-entity
384 (size (elmo-msgdb-overview-entity-get-size
385 (elmo-msgdb-overview-get-entity
387 (date (elmo-msgdb-overview-entity-get-date
388 (elmo-msgdb-overview-get-entity
390 (to (elmo-msgdb-overview-entity-get-to
391 (elmo-msgdb-overview-get-entity
393 (cc (elmo-msgdb-overview-entity-get-cc
394 (elmo-msgdb-overview-get-entity
397 (defsubst elmo-msgdb-append (msgdb msgdb-append)
399 (nconc (car msgdb) (car msgdb-append))
400 (nconc (cadr msgdb) (cadr msgdb-append))
401 (nconc (caddr msgdb) (caddr msgdb-append))
402 (elmo-msgdb-make-index-return
404 (elmo-msgdb-get-overview msgdb-append)
405 (elmo-msgdb-get-mark-alist msgdb-append))
408 (defun elmo-msgdb-merge (folder msgdb-merge)
409 "Return a list of messages which have duplicated message-id."
410 (let (msgdb duplicates)
411 (setq msgdb (or (elmo-folder-msgdb-internal folder)
412 (elmo-make-msgdb nil nil nil
413 (elmo-folder-msgdb-path folder))))
414 (elmo-msgdb-set-overview
416 (nconc (elmo-msgdb-get-overview msgdb)
417 (elmo-msgdb-get-overview msgdb-merge)))
418 (elmo-msgdb-set-number-alist
420 (nconc (elmo-msgdb-get-number-alist msgdb)
421 (elmo-msgdb-get-number-alist msgdb-merge)))
422 (elmo-msgdb-set-mark-alist
424 (nconc (elmo-msgdb-get-mark-alist msgdb)
425 (elmo-msgdb-get-mark-alist msgdb-merge)))
426 (setq duplicates (elmo-msgdb-make-index
428 (elmo-msgdb-get-overview msgdb-merge)
429 (elmo-msgdb-get-mark-alist msgdb-merge)))
432 (or (elmo-msgdb-get-path msgdb)
433 (elmo-msgdb-get-path msgdb-merge)))
434 (elmo-folder-set-msgdb-internal folder msgdb)
437 (defsubst elmo-msgdb-clear (&optional msgdb)
441 (setcar (cdr msgdb) nil)
442 (setcar (cddr msgdb) nil)
443 (setcar (nthcdr 3 msgdb) nil)
444 (setcar (nthcdr 4 msgdb) nil))
445 (list nil nil nil nil nil)))
447 (defun elmo-msgdb-delete-msgs (msgdb msgs)
448 "Delete MSGS from MSGDB
449 content of MSGDB is changed."
450 (let* ((overview (car msgdb))
451 (number-alist (cadr msgdb))
452 (mark-alist (caddr msgdb))
453 (index (elmo-msgdb-get-index msgdb))
454 (newmsgdb (list overview number-alist mark-alist index
457 ;; remove from current database.
462 (elmo-msgdb-overview-get-entity (car msgs) newmsgdb))
464 (setq number-alist (delq (assq (car msgs) number-alist) number-alist))
465 (setq mark-alist (delq (assq (car msgs) mark-alist) mark-alist))
467 (when index (elmo-msgdb-clear-index msgdb ov-entity))
468 (setq msgs (cdr msgs)))
469 (setcar msgdb overview)
470 (setcar (cdr msgdb) number-alist)
471 (setcar (cddr msgdb) mark-alist)
472 (setcar (nthcdr 3 msgdb) index)
475 (defun elmo-msgdb-sort-by-date (msgdb)
476 (message "Sorting...")
477 (let ((overview (elmo-msgdb-get-overview msgdb)))
478 (setq overview (elmo-msgdb-overview-sort-by-date overview))
479 (message "Sorting...done")
480 (list overview (nth 1 msgdb)(nth 2 msgdb))))
483 (defsubst elmo-msgdb-append-element (list element)
485 ;;; (append list (list element))
486 (nconc list (list element))
490 (defsubst elmo-msgdb-get-overview (msgdb)
492 (defsubst elmo-msgdb-get-number-alist (msgdb)
494 (defsubst elmo-msgdb-get-mark-alist (msgdb)
496 ;(defsubst elmo-msgdb-get-location (msgdb)
499 (defsubst elmo-msgdb-get-index (msgdb)
502 (defsubst elmo-msgdb-get-entity-hashtb (msgdb)
505 (defsubst elmo-msgdb-get-mark-hashtb (msgdb)
508 (defsubst elmo-msgdb-get-path (msgdb)
512 ;; number <-> Message-ID handling
514 (defsubst elmo-msgdb-number-add (alist number id)
515 (let ((ret-val alist))
517 (elmo-msgdb-append-element ret-val (cons number id)))
522 (defvar elmo-flag-table-filename "flag-table")
523 (defun elmo-flag-table-load (dir)
524 "Load flag hashtable for MSGDB."
525 (let ((table (elmo-make-hash))
526 ;; For backward compatibility
527 (seen-file (expand-file-name elmo-msgdb-seen-filename dir))
529 (when (file-exists-p seen-file)
530 (setq seen-list (elmo-object-load seen-file))
531 (delete-file seen-file))
532 (dolist (msgid seen-list)
533 (elmo-set-hash-val msgid 'read table))
534 (dolist (pair (elmo-object-load
535 (expand-file-name elmo-flag-table-filename dir)))
536 (elmo-set-hash-val (car pair) (cdr pair) table))
539 (defun elmo-flag-table-set (flag-table msg-id flag)
540 (elmo-set-hash-val msg-id flag flag-table))
542 (defun elmo-flag-table-get (flag-table msg-id)
543 (elmo-get-hash-val msg-id flag-table))
545 (defun elmo-flag-table-save (dir flag-table)
547 (expand-file-name elmo-flag-table-filename dir)
550 (mapatoms (lambda (atom)
551 (setq list (cons (cons (symbol-name atom)
557 ;; persistent mark handling
560 (defun elmo-msgdb-mark-append (alist id mark)
562 (setq alist (elmo-msgdb-append-element alist
565 (defsubst elmo-msgdb-length (msgdb)
566 (length (elmo-msgdb-get-overview msgdb)))
568 (defun elmo-msgdb-flag-table (msgdb &optional flag-table)
569 ;; Make a table of msgid flag (read, answered)
570 (let ((flag-table (or flag-table (elmo-make-hash (elmo-msgdb-length msgdb))))
572 (dolist (ov (elmo-msgdb-get-overview msgdb))
573 (setq mark (elmo-msgdb-get-mark
575 (elmo-msgdb-overview-entity-get-number ov)))
579 (elmo-msgdb-overview-entity-get-id ov)
582 ((and mark (member mark (elmo-msgdb-answered-marks)))
584 (elmo-msgdb-overview-entity-get-id ov)
587 ((and mark (not (member mark
588 (elmo-msgdb-unread-marks))))
590 (elmo-msgdb-overview-entity-get-id ov)
598 (defvar elmo-msgdb-decoded-cache-hashtb nil)
599 (make-variable-buffer-local 'elmo-msgdb-decoded-cache-hashtb)
601 (defsubst elmo-msgdb-get-decoded-cache (string)
602 (if elmo-use-decoded-cache
603 (let ((hashtb (or elmo-msgdb-decoded-cache-hashtb
604 (setq elmo-msgdb-decoded-cache-hashtb
605 (elmo-make-hash 2048))))
607 (or (elmo-get-hash-val string hashtb)
612 (decode-mime-charset-string string elmo-mime-charset))
615 (decode-mime-charset-string string elmo-mime-charset)))
620 (defun elmo-multiple-field-body (name &optional boundary)
623 (std11-narrow-to-header boundary)
624 (goto-char (point-min))
625 (let ((case-fold-search t)
627 (while (re-search-forward (concat "^" name ":[ \t]*") nil t)
630 (list (buffer-substring-no-properties
631 (match-end 0) (std11-field-end))))))
634 (defun elmo-multiple-fields-body-list (field-names &optional boundary)
635 "Return list of each field-bodies of FIELD-NAMES of the message header
636 in current buffer. If BOUNDARY is not nil, it is used as message
640 (std11-narrow-to-header boundary)
641 (let* ((case-fold-search t)
643 field-name field-body)
644 (while (setq field-name (car s-rest))
645 (goto-char (point-min))
646 (while (re-search-forward (concat "^" field-name ":[ \t]*") nil t)
649 (list (buffer-substring-no-properties
650 (match-end 0) (std11-field-end))))))
651 (setq s-rest (cdr s-rest)))
654 (defsubst elmo-msgdb-remove-field-string (string)
655 (if (string-match (concat std11-field-head-regexp "[ \t]*") string)
656 (substring string (match-end 0))
659 (defsubst elmo-msgdb-get-last-message-id (string)
665 (goto-char (point-max))
666 (when (search-backward "<" nil t)
668 (if (search-forward ">" nil t)
669 (elmo-replace-in-string
670 (buffer-substring beg (point)) "\n[ \t]*" ""))))))))
672 (defun elmo-msgdb-number-load (dir)
674 (expand-file-name elmo-msgdb-number-filename dir)))
676 (defun elmo-msgdb-overview-load (dir)
678 (expand-file-name elmo-msgdb-overview-filename dir)))
680 (defun elmo-msgdb-mark-load (dir)
682 (expand-file-name elmo-msgdb-mark-filename dir)))
684 (defsubst elmo-msgdb-seen-load (dir)
685 (elmo-object-load (expand-file-name
686 elmo-msgdb-seen-filename
689 (defun elmo-msgdb-number-save (dir obj)
691 (expand-file-name elmo-msgdb-number-filename dir)
694 (defun elmo-msgdb-mark-save (dir obj)
696 (expand-file-name elmo-msgdb-mark-filename dir)
699 (defun elmo-msgdb-change-mark (msgdb before after)
700 "Set the BEFORE marks to AFTER."
701 (let ((mark-alist (elmo-msgdb-get-mark-alist msgdb))
704 (setq entity (car mark-alist))
705 (when (string= (cadr entity) before)
706 (setcar (cdr entity) after))
707 (setq mark-alist (cdr mark-alist)))))
709 (defsubst elmo-msgdb-mark (flag cached &optional new)
715 elmo-msgdb-read-uncached-mark))
717 elmo-msgdb-important-mark)
720 elmo-msgdb-answered-cached-mark
721 elmo-msgdb-answered-uncached-mark))
724 elmo-msgdb-unread-cached-mark
725 elmo-msgdb-new-mark)))
729 elmo-msgdb-unread-cached-mark
730 elmo-msgdb-unread-uncached-mark))
732 elmo-msgdb-important-mark)
735 elmo-msgdb-answered-cached-mark
736 elmo-msgdb-answered-uncached-mark)))))
738 (defsubst elmo-msgdb-overview-save (dir overview)
740 (expand-file-name elmo-msgdb-overview-filename dir)
743 (defun elmo-msgdb-match-condition-primitive (condition mark entity numbers)
745 (let ((key (elmo-filter-key condition))
749 ((string= key "last")
750 (setq result (<= (length (memq
751 (elmo-msgdb-overview-entity-get-number
754 (string-to-int (elmo-filter-value condition)))))
755 ((string= key "first")
759 (elmo-msgdb-overview-entity-get-number
762 (string-to-int (elmo-filter-value condition)))))
763 ((string= key "flag")
766 ((string= (elmo-filter-value condition) "any")
768 (string= mark elmo-msgdb-read-uncached-mark))))
769 ((string= (elmo-filter-value condition) "digest")
771 (string= mark elmo-msgdb-read-uncached-mark)
772 (string= mark elmo-msgdb-answered-cached-mark)
773 (string= mark elmo-msgdb-answered-uncached-mark))))
774 ;; (member mark (append (elmo-msgdb-answered-marks)
775 ;; (list elmo-msgdb-important-mark)
776 ;; (elmo-msgdb-unread-marks))))
777 ((string= (elmo-filter-value condition) "unread")
778 (member mark (elmo-msgdb-unread-marks)))
779 ((string= (elmo-filter-value condition) "important")
780 (string= mark elmo-msgdb-important-mark))
781 ((string= (elmo-filter-value condition) "answered")
782 (member mark (elmo-msgdb-answered-marks))))))
783 ((string= key "from")
784 (setq result (string-match
785 (elmo-filter-value condition)
786 (elmo-msgdb-overview-entity-get-from entity))))
787 ((string= key "subject")
788 (setq result (string-match
789 (elmo-filter-value condition)
790 (elmo-msgdb-overview-entity-get-subject entity))))
792 (setq result (string-match
793 (elmo-filter-value condition)
794 (elmo-msgdb-overview-entity-get-to entity))))
796 (setq result (string-match
797 (elmo-filter-value condition)
798 (elmo-msgdb-overview-entity-get-cc entity))))
799 ((or (string= key "since")
800 (string= key "before"))
801 (let ((field-date (elmo-date-make-sortable-string
803 (elmo-msgdb-overview-entity-get-date entity)
804 (current-time-zone) nil)))
806 (elmo-date-make-sortable-string
807 (elmo-date-get-datevec
808 (elmo-filter-value condition)))))
809 (setq result (if (string= key "since")
810 (or (string= specified-date field-date)
811 (string< specified-date field-date))
812 (string< field-date specified-date)))))
813 ((member key elmo-msgdb-extra-fields)
814 (let ((extval (elmo-msgdb-overview-entity-get-extra-field entity key)))
815 (when (stringp extval)
816 (setq result (string-match
817 (elmo-filter-value condition)
820 (throw 'unresolved condition)))
821 (if (eq (elmo-filter-type condition) 'unmatch)
825 (defun elmo-msgdb-match-condition-internal (condition mark entity numbers)
828 (elmo-msgdb-match-condition-primitive condition mark entity numbers))
829 ((eq (car condition) 'and)
830 (let ((lhs (elmo-msgdb-match-condition-internal (nth 1 condition)
831 mark entity numbers)))
833 ((elmo-filter-condition-p lhs)
834 (let ((rhs (elmo-msgdb-match-condition-internal
835 (nth 2 condition) mark entity numbers)))
836 (cond ((elmo-filter-condition-p rhs)
841 (elmo-msgdb-match-condition-internal (nth 2 condition)
842 mark entity numbers)))))
843 ((eq (car condition) 'or)
844 (let ((lhs (elmo-msgdb-match-condition-internal (nth 1 condition)
845 mark entity numbers)))
847 ((elmo-filter-condition-p lhs)
848 (let ((rhs (elmo-msgdb-match-condition-internal (nth 2 condition)
849 mark entity numbers)))
850 (cond ((elmo-filter-condition-p rhs)
859 (elmo-msgdb-match-condition-internal (nth 2 condition)
860 mark entity numbers)))))))
862 (defun elmo-msgdb-match-condition (msgdb condition number numbers)
863 "Check whether the condition of the message is satisfied or not.
864 MSGDB is the msgdb to search from.
865 CONDITION is the search condition.
866 NUMBER is the message number to check.
867 NUMBERS is the target message number list.
868 Return CONDITION itself if no entity exists in msgdb."
869 (let ((entity (elmo-msgdb-overview-get-entity number msgdb)))
871 (elmo-msgdb-match-condition-internal condition
872 (elmo-msgdb-get-mark msgdb number)
876 (defsubst elmo-msgdb-set-overview (msgdb overview)
877 (setcar msgdb overview))
879 (defsubst elmo-msgdb-set-number-alist (msgdb number-alist)
880 (setcar (cdr msgdb) number-alist))
882 (defsubst elmo-msgdb-set-mark-alist (msgdb mark-alist)
883 (setcar (cddr msgdb) mark-alist))
885 (defsubst elmo-msgdb-set-index (msgdb index)
886 (setcar (cdddr msgdb) index))
888 (defsubst elmo-msgdb-set-path (msgdb path)
889 (setcar (cddddr msgdb) path))
891 (defsubst elmo-msgdb-overview-entity-get-references (entity)
892 (and entity (aref (cdr entity) 1)))
894 (defsubst elmo-msgdb-overview-entity-set-references (entity references)
895 (and entity (aset (cdr entity) 1 references))
898 ;; entity -> parent-entity
899 (defsubst elmo-msgdb-overview-get-parent-entity (entity database)
900 (setq entity (elmo-msgdb-overview-entity-get-references entity))
901 ;; entity is parent-id.
902 (and entity (assoc entity database)))
904 (defsubst elmo-msgdb-get-parent-entity (entity msgdb)
905 (setq entity (elmo-msgdb-overview-entity-get-references entity))
906 ;; entity is parent-id.
907 (and entity (elmo-msgdb-overview-get-entity entity msgdb)))
909 (defsubst elmo-msgdb-overview-entity-get-number (entity)
910 (and entity (aref (cdr entity) 0)))
912 (defsubst elmo-msgdb-overview-entity-get-from-no-decode (entity)
913 (and entity (aref (cdr entity) 2)))
915 (defsubst elmo-msgdb-overview-entity-get-from (entity)
917 (aref (cdr entity) 2)
918 (elmo-msgdb-get-decoded-cache (aref (cdr entity) 2))))
920 (defsubst elmo-msgdb-overview-entity-set-number (entity number)
921 (and entity (aset (cdr entity) 0 number))
923 ;;;(setcar (cadr entity) number) entity)
925 (defsubst elmo-msgdb-overview-entity-set-from (entity from)
926 (and entity (aset (cdr entity) 2 from))
929 (defsubst elmo-msgdb-overview-entity-get-subject (entity)
931 (aref (cdr entity) 3)
932 (elmo-msgdb-get-decoded-cache (aref (cdr entity) 3))))
934 (defsubst elmo-msgdb-overview-entity-get-subject-no-decode (entity)
935 (and entity (aref (cdr entity) 3)))
937 (defsubst elmo-msgdb-overview-entity-set-subject (entity subject)
938 (and entity (aset (cdr entity) 3 subject))
941 (defsubst elmo-msgdb-overview-entity-get-date (entity)
942 (and entity (aref (cdr entity) 4)))
944 (defsubst elmo-msgdb-overview-entity-set-date (entity date)
945 (and entity (aset (cdr entity) 4 date))
948 (defsubst elmo-msgdb-overview-entity-get-to (entity)
949 (and entity (aref (cdr entity) 5)))
951 (defsubst elmo-msgdb-overview-entity-get-cc (entity)
952 (and entity (aref (cdr entity) 6)))
954 (defsubst elmo-msgdb-overview-entity-get-size (entity)
955 (and entity (aref (cdr entity) 7)))
957 (defsubst elmo-msgdb-overview-entity-set-size (entity size)
958 (and entity (aset (cdr entity) 7 size))
961 (defsubst elmo-msgdb-overview-entity-get-id (entity)
962 (and entity (car entity)))
964 (defsubst elmo-msgdb-overview-entity-get-extra-field (entity field-name)
965 (let ((field-name (downcase field-name))
966 (extra (and entity (aref (cdr entity) 8))))
968 (cdr (assoc field-name extra)))))
970 (defsubst elmo-msgdb-overview-entity-set-extra-field (entity field-name value)
971 (let ((field-name (downcase field-name))
972 (extras (and entity (aref (cdr entity) 8)))
974 (if (setq extra (assoc field-name extras))
976 (elmo-msgdb-overview-entity-set-extra
978 (cons (cons field-name value) extras)))))
980 (defsubst elmo-msgdb-overview-entity-get-extra (entity)
981 (and entity (aref (cdr entity) 8)))
983 (defsubst elmo-msgdb-overview-entity-set-extra (entity extra)
984 (and entity (aset (cdr entity) 8 extra))
988 (defsubst elmo-msgdb-message-entity (msgdb key)
990 (cond ((stringp key) key)
991 ((numberp key) (format "#%d" key)))
992 (elmo-msgdb-get-entity-hashtb msgdb)))
994 (defun elmo-msgdb-make-message-entity (&rest args)
995 "Make an message entity."
996 (cons (plist-get args :message-id)
997 (vector (plist-get args :number)
998 (plist-get args :references)
999 (plist-get args :from)
1000 (plist-get args :subject)
1001 (plist-get args :date)
1002 (plist-get args :to)
1003 (plist-get args :cc)
1004 (plist-get args :size)
1005 (plist-get args :extra))))
1007 (defsubst elmo-msgdb-message-entity-field (entity field &optional decode)
1011 (to (aref (cdr entity) 5))
1012 (cc (aref (cdr entity) 6))
1013 (date (aref (cdr entity) 4))
1014 (subject (aref (cdr entity) 3))
1015 (from (aref (cdr entity) 2))
1016 (message-id (car entity))
1017 (references (aref (cdr entity) 1))
1018 (size (aref (cdr entity) 7))
1019 (t (cdr (assoc (symbol-name field) (aref (cdr entity) 8)))))))
1021 (elmo-msgdb-get-decoded-cache field-value)
1024 (defsubst elmo-msgdb-message-entity-set-field (entity field value)
1027 (to (aset (cdr entity) 5 value))
1028 (cc (aset (cdr entity) 6 value))
1029 (date (aset (cdr entity) 4 value))
1030 (subject (aset (cdr entity) 3 value))
1031 (from (aset (cdr entity) 2 value))
1032 (message-id (setcar entity value))
1033 (references (aset (cdr entity) 1 value))
1034 (size (aset (cdr entity) 7 value))
1036 (let ((extras (and entity (aref (cdr entity) 8)))
1038 (if (setq extra (assoc field extras))
1039 (setcdr extra value)
1040 (aset (cdr entity) 8 (cons (cons (symbol-name field)
1041 value) extras))))))))
1044 (defun elmo-msgdb-overview-get-entity (id msgdb)
1046 (let ((ht (elmo-msgdb-get-entity-hashtb msgdb)))
1048 (if (stringp id) ;; ID is message-id
1049 (elmo-get-hash-val id ht)
1050 (elmo-get-hash-val (format "#%d" id) ht))))))
1053 ;; deleted message handling
1055 (defun elmo-msgdb-killed-list-load (dir)
1057 (expand-file-name elmo-msgdb-killed-filename dir)
1060 (defun elmo-msgdb-killed-list-save (dir killed-list)
1062 (expand-file-name elmo-msgdb-killed-filename dir)
1065 (defun elmo-msgdb-killed-message-p (killed-list msg)
1066 (elmo-number-set-member msg killed-list))
1068 (defun elmo-msgdb-set-as-killed (killed-list msg)
1069 (elmo-number-set-append killed-list msg))
1071 (defun elmo-msgdb-killed-list-length (killed-list)
1072 (let ((killed killed-list)
1075 (if (consp (car killed))
1076 (setq ret-val (+ ret-val 1 (- (cdar killed) (caar killed))))
1077 (setq ret-val (+ ret-val 1)))
1078 (setq killed (cdr killed)))
1081 (defun elmo-msgdb-max-of-killed (killed-list)
1082 (let ((klist killed-list)
1088 (if (consp (car klist))
1092 (setq klist (cdr klist)))
1095 (defun elmo-living-messages (messages killed-list)
1098 (mapcar (lambda (number)
1099 (unless (elmo-number-set-member number killed-list)
1104 (defun elmo-msgdb-finfo-load ()
1105 (elmo-object-load (expand-file-name
1106 elmo-msgdb-finfo-filename
1107 elmo-msgdb-directory)
1108 elmo-mime-charset t))
1110 (defun elmo-msgdb-finfo-save (finfo)
1111 (elmo-object-save (expand-file-name
1112 elmo-msgdb-finfo-filename
1113 elmo-msgdb-directory)
1114 finfo elmo-mime-charset))
1116 (defun elmo-msgdb-flist-load (fname)
1117 (let ((flist-file (expand-file-name
1118 elmo-msgdb-flist-filename
1120 (elmo-safe-filename fname)
1121 (expand-file-name "folder" elmo-msgdb-directory)))))
1122 (elmo-object-load flist-file elmo-mime-charset t)))
1124 (defun elmo-msgdb-flist-save (fname flist)
1125 (let ((flist-file (expand-file-name
1126 elmo-msgdb-flist-filename
1128 (elmo-safe-filename fname)
1129 (expand-file-name "folder" elmo-msgdb-directory)))))
1130 (elmo-object-save flist-file flist elmo-mime-charset)))
1132 (defun elmo-crosspost-alist-load ()
1133 (elmo-object-load (expand-file-name
1134 elmo-crosspost-alist-filename
1135 elmo-msgdb-directory)
1138 (defun elmo-crosspost-alist-save (alist)
1139 (elmo-object-save (expand-file-name
1140 elmo-crosspost-alist-filename
1141 elmo-msgdb-directory)
1144 (defun elmo-msgdb-get-message-id-from-buffer ()
1145 (let ((msgid (elmo-field-body "message-id")))
1147 (if (string-match "<\\(.+\\)>$" msgid)
1149 (concat "<" msgid ">")) ; Invaild message-id.
1150 ;; no message-id, so put dummy msgid.
1151 (concat "<" (timezone-make-date-sortable
1152 (elmo-field-body "date"))
1153 (nth 1 (eword-extract-address-components
1154 (or (elmo-field-body "from") "nobody"))) ">"))))
1156 (defsubst elmo-msgdb-create-overview-from-buffer (number &optional size time)
1157 "Create overview entity from current buffer.
1158 Header region is supposed to be narrowed."
1160 (let ((extras elmo-msgdb-extra-fields)
1161 (default-mime-charset default-mime-charset)
1162 message-id references from subject to cc date
1163 extra field-body charset)
1164 (elmo-set-buffer-multibyte default-enable-multibyte-characters)
1165 (setq message-id (elmo-msgdb-get-message-id-from-buffer))
1166 (and (setq charset (cdr (assoc "charset" (mime-read-Content-Type))))
1167 (setq charset (intern-soft charset))
1168 (setq default-mime-charset charset))
1170 (or (elmo-msgdb-get-last-message-id
1171 (elmo-field-body "in-reply-to"))
1172 (elmo-msgdb-get-last-message-id
1173 (elmo-field-body "references"))))
1174 (setq from (elmo-replace-in-string
1175 (elmo-mime-string (or (elmo-field-body "from")
1178 subject (elmo-replace-in-string
1179 (elmo-mime-string (or (elmo-field-body "subject")
1182 (setq date (or (elmo-field-body "date") time))
1183 (setq to (mapconcat 'identity (elmo-multiple-field-body "to") ","))
1184 (setq cc (mapconcat 'identity (elmo-multiple-field-body "cc") ","))
1186 (if (setq size (elmo-field-body "content-length"))
1187 (setq size (string-to-int size))
1188 (setq size 0)));; No mean...
1190 (if (setq field-body (elmo-field-body (car extras)))
1191 (setq extra (cons (cons (downcase (car extras))
1192 field-body) extra)))
1193 (setq extras (cdr extras)))
1194 (cons message-id (vector number references
1195 from subject date to cc
1199 (defun elmo-msgdb-copy-overview-entity (entity)
1201 (copy-sequence (cdr entity))))
1203 (defsubst elmo-msgdb-insert-file-header (file)
1204 "Insert the header of the article."
1206 insert-file-contents-pre-hook ; To avoid autoconv-xmas...
1207 insert-file-contents-post-hook
1209 (when (file-exists-p file)
1210 ;; Read until header separator is found.
1211 (while (and (eq elmo-msgdb-file-header-chop-length
1213 (insert-file-contents-as-binary
1215 (incf beg elmo-msgdb-file-header-chop-length))))
1216 (prog1 (not (search-forward "\n\n" nil t))
1217 (goto-char (point-max))))))))
1219 (defsubst elmo-msgdb-create-overview-entity-from-file (number file)
1220 (let (insert-file-contents-pre-hook ; To avoid autoconv-xmas...
1221 insert-file-contents-post-hook header-end
1222 (attrib (file-attributes file))
1225 (if (not (file-exists-p file))
1227 (setq size (nth 7 attrib))
1228 (setq mtime (timezone-make-date-arpa-standard
1229 (current-time-string (nth 5 attrib)) (current-time-zone)))
1230 ;; insert header from file.
1233 (elmo-msgdb-insert-file-header file)
1234 (error (throw 'done nil)))
1235 (goto-char (point-min))
1237 (if (re-search-forward "\\(^--.*$\\)\\|\\(\n\n\\)" nil t)
1240 (narrow-to-region (point-min) header-end)
1241 (elmo-msgdb-create-overview-from-buffer number size mtime))))))
1243 (defun elmo-msgdb-overview-sort-by-date (overview)
1249 (timezone-make-date-sortable
1250 (elmo-msgdb-overview-entity-get-date x))
1251 (timezone-make-date-sortable
1252 (elmo-msgdb-overview-entity-get-date y)))
1255 (defun elmo-msgdb-clear-index (msgdb entity)
1256 (let ((ehash (elmo-msgdb-get-entity-hashtb msgdb))
1257 (mhash (elmo-msgdb-get-mark-hashtb msgdb))
1259 (when (and entity ehash)
1260 (and (setq number (elmo-msgdb-overview-entity-get-number entity))
1261 (elmo-clear-hash-val (format "#%d" number) ehash))
1262 (and (car entity) ;; message-id
1263 (elmo-clear-hash-val (car entity) ehash)))
1264 (when (and entity mhash)
1265 (and (setq number (elmo-msgdb-overview-entity-get-number entity))
1266 (elmo-clear-hash-val (format "#%d" number) mhash)))))
1268 (defun elmo-msgdb-make-index-return (msgdb &optional overview mark-alist)
1269 "Append OVERVIEW and MARK-ALIST to the index of MSGDB.
1270 If OVERVIEW and MARK-ALIST are nil, make index for current MSGDB.
1271 Return the updated INDEX."
1273 (let* ((overview (or overview (elmo-msgdb-get-overview msgdb)))
1274 (mark-alist (or mark-alist (elmo-msgdb-get-mark-alist msgdb)))
1275 (index (elmo-msgdb-get-index msgdb))
1276 (ehash (or (car index) ;; append
1277 (elmo-make-hash (length overview))))
1278 (mhash (or (cdr index) ;; append
1279 (elmo-make-hash (length overview)))))
1281 ;; key is message-id
1283 (elmo-set-hash-val (caar overview) (car overview) ehash))
1287 (elmo-msgdb-overview-entity-get-number (car overview)))
1288 (car overview) ehash)
1289 (setq overview (cdr overview)))
1293 (format "#%d" (car (car mark-alist)))
1294 (car mark-alist) mhash)
1295 (setq mark-alist (cdr mark-alist)))
1296 (setq index (or index (cons ehash mhash)))
1297 (elmo-msgdb-set-index msgdb index)
1300 (defun elmo-msgdb-make-index (msgdb &optional overview mark-alist)
1301 "Append OVERVIEW and MARK-ALIST to the index of MSGDB.
1302 If OVERVIEW and MARK-ALIST are nil, make index for current MSGDB.
1303 Return a list of message numbers which have duplicated message-ids."
1305 (let* ((overview (or overview (elmo-msgdb-get-overview msgdb)))
1306 (mark-alist (or mark-alist (elmo-msgdb-get-mark-alist msgdb)))
1307 (index (elmo-msgdb-get-index msgdb))
1308 (ehash (or (car index) ;; append
1309 (elmo-make-hash (length overview))))
1310 (mhash (or (cdr index) ;; append
1311 (elmo-make-hash (length overview))))
1314 ;; key is message-id
1315 (if (elmo-get-hash-val (caar overview) ehash) ; duplicated.
1316 (setq duplicates (cons
1317 (elmo-msgdb-overview-entity-get-number
1321 (elmo-set-hash-val (caar overview) (car overview) ehash))
1325 (elmo-msgdb-overview-entity-get-number (car overview)))
1326 (car overview) ehash)
1327 (setq overview (cdr overview)))
1331 (format "#%d" (car (car mark-alist)))
1332 (car mark-alist) mhash)
1333 (setq mark-alist (cdr mark-alist)))
1334 (setq index (or index (cons ehash mhash)))
1335 (elmo-msgdb-set-index msgdb index)
1338 (defsubst elmo-folder-get-info (folder &optional hashtb)
1339 (elmo-get-hash-val folder
1340 (or hashtb elmo-folder-info-hashtb)))
1342 (defun elmo-folder-get-info-max (folder)
1343 "Get folder info from cache."
1344 (nth 3 (elmo-folder-get-info folder)))
1346 (defun elmo-folder-get-info-length (folder)
1347 (nth 2 (elmo-folder-get-info folder)))
1349 (defun elmo-folder-get-info-unread (folder)
1350 (nth 1 (elmo-folder-get-info folder)))
1352 (defsubst elmo-msgdb-location-load (dir)
1355 elmo-msgdb-location-filename
1358 (defsubst elmo-msgdb-location-add (alist number location)
1359 (let ((ret-val alist))
1361 (elmo-msgdb-append-element ret-val (cons number location)))
1364 (defsubst elmo-msgdb-location-save (dir alist)
1367 elmo-msgdb-location-filename
1370 (defun elmo-msgdb-list-flagged (msgdb flag)
1371 (let ((case-fold-search nil)
1372 mark-regexp matched)
1375 (setq mark-regexp (regexp-quote elmo-msgdb-new-mark)))
1377 (setq mark-regexp (elmo-regexp-opt (elmo-msgdb-unread-marks))))
1379 (setq mark-regexp (elmo-regexp-opt (elmo-msgdb-answered-marks))))
1381 (setq mark-regexp (regexp-quote elmo-msgdb-important-mark)))
1383 (setq mark-regexp (elmo-regexp-opt (elmo-msgdb-unread-marks))))
1385 (setq mark-regexp (elmo-regexp-opt
1386 (append (elmo-msgdb-unread-marks)
1387 (list elmo-msgdb-important-mark)))))
1389 (setq mark-regexp (elmo-regexp-opt
1391 (elmo-msgdb-unread-marks)
1392 (elmo-msgdb-answered-marks)
1393 (list elmo-msgdb-important-mark))))))
1396 (dolist (number (elmo-msgdb-list-messages msgdb))
1397 (let ((mark (elmo-msgdb-get-mark msgdb number)))
1398 (unless (and mark (string-match mark-regexp mark))
1399 (setq matched (cons number matched)))))
1400 (dolist (elem (elmo-msgdb-get-mark-alist msgdb))
1401 (if (string-match mark-regexp (cadr elem))
1402 (setq matched (cons (car elem) matched))))))
1406 (product-provide (provide 'elmo-msgdb) (require 'elmo-version))
1408 ;;; elmo-msgdb.el ends here