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 (defun elmo-load-msgdb (path)
42 "Load the MSGDB from PATH."
43 (let ((inhibit-quit t))
44 (elmo-make-msgdb (elmo-msgdb-overview-load path)
45 (elmo-msgdb-number-load path)
46 (elmo-msgdb-mark-load path))))
48 (defun elmo-make-msgdb (&optional overview number-alist mark-alist)
50 (let ((msgdb (list overview number-alist mark-alist nil)))
51 (elmo-msgdb-make-index msgdb)
54 (defsubst elmo-msgdb-get-mark (msgdb number)
55 "Get mark string from MSGDB which corresponds to the message with NUMBER."
56 (cadr (elmo-get-hash-val (format "#%d" number)
57 (elmo-msgdb-get-mark-hashtb msgdb))))
59 (defsubst elmo-msgdb-set-mark (msgdb number mark)
60 "Set MARK of the message with NUMBER in the MSGDB.
61 if MARK is nil, mark is removed."
62 (elmo-msgdb-set-mark-alist
64 (elmo-msgdb-mark-alist-set (elmo-msgdb-get-mark-alist msgdb)
68 (elmo-clear-hash-val (format "#%d" number)
69 (elmo-msgdb-get-mark-hashtb msgdb))))
71 (defsubst elmo-msgdb-count-marks (msgdb new-mark unread-marks)
74 (dolist (elem (elmo-msgdb-get-mark-alist msgdb))
76 ((string= (cadr elem) new-mark)
78 ((member (cadr elem) unread-marks)
82 (defsubst elmo-msgdb-get-number (msgdb message-id)
83 "Get number of the message which corrensponds to MESSAGE-ID from MSGDB."
84 (elmo-msgdb-overview-entity-get-number
85 (elmo-msgdb-overview-get-entity message-id msgdb)))
87 (defsubst elmo-msgdb-get-field (msgdb number field)
88 "Get FIELD value of the message with NUMBER from MSGDB."
90 (message-id (elmo-msgdb-overview-entity-get-id
91 (elmo-msgdb-overview-get-entity
93 (subject (elmo-msgdb-overview-entity-get-subject
94 (elmo-msgdb-overview-get-entity
96 (size (elmo-msgdb-overview-entity-get-size
97 (elmo-msgdb-overview-get-entity
99 (date (elmo-msgdb-overview-entity-get-date
100 (elmo-msgdb-overview-get-entity
102 (to (elmo-msgdb-overview-entity-get-to
103 (elmo-msgdb-overview-get-entity
105 (cc (elmo-msgdb-overview-entity-get-cc
106 (elmo-msgdb-overview-get-entity
109 (defsubst elmo-msgdb-append (msgdb msgdb-append)
111 (nconc (car msgdb) (car msgdb-append))
112 (nconc (cadr msgdb) (cadr msgdb-append))
113 (nconc (caddr msgdb) (caddr msgdb-append))
114 (elmo-msgdb-make-index
116 (elmo-msgdb-get-overview msgdb-append)
117 (elmo-msgdb-get-mark-alist msgdb-append))))
119 (defsubst elmo-msgdb-clear (&optional msgdb)
123 (setcar (cdr msgdb) nil)
124 (setcar (cddr msgdb) nil)
125 (setcar (nthcdr 3 msgdb) nil))
126 (list nil nil nil nil)))
128 (defun elmo-msgdb-delete-msgs (msgdb msgs)
129 "Delete MSGS from MSGDB
130 content of MSGDB is changed."
131 (let* ((overview (car msgdb))
132 (number-alist (cadr msgdb))
133 (mark-alist (caddr msgdb))
134 (index (elmo-msgdb-get-index msgdb))
135 (newmsgdb (list overview number-alist mark-alist index))
137 ;; remove from current database.
142 (elmo-msgdb-overview-get-entity (car msgs) newmsgdb))
144 (setq number-alist (delq (assq (car msgs) number-alist) number-alist))
145 (setq mark-alist (delq (assq (car msgs) mark-alist) mark-alist))
147 (when index (elmo-msgdb-clear-index msgdb ov-entity))
148 (setq msgs (cdr msgs)))
149 (setcar msgdb overview)
150 (setcar (cdr msgdb) number-alist)
151 (setcar (cddr msgdb) mark-alist)
152 (setcar (nthcdr 3 msgdb) index)
155 (defun elmo-msgdb-sort-by-date (msgdb)
156 (message "Sorting...")
157 (let ((overview (elmo-msgdb-get-overview msgdb)))
158 (setq overview (elmo-msgdb-overview-sort-by-date overview))
159 (message "Sorting...done")
160 (list overview (nth 1 msgdb)(nth 2 msgdb))))
163 (defsubst elmo-msgdb-append-element (list element)
165 ;;; (append list (list element))
166 (nconc list (list element))
170 (defsubst elmo-msgdb-get-overview (msgdb)
172 (defsubst elmo-msgdb-get-number-alist (msgdb)
174 (defsubst elmo-msgdb-get-mark-alist (msgdb)
176 ;(defsubst elmo-msgdb-get-location (msgdb)
179 (defsubst elmo-msgdb-get-index (msgdb)
182 (defsubst elmo-msgdb-get-entity-hashtb (msgdb)
185 (defsubst elmo-msgdb-get-mark-hashtb (msgdb)
189 ;; number <-> Message-ID handling
191 (defsubst elmo-msgdb-number-add (alist number id)
192 (let ((ret-val alist))
194 (elmo-msgdb-append-element ret-val (cons number id)))
198 ;; parsistent mark handling
201 (defvar elmo-msgdb-global-mark-alist nil)
203 (defun elmo-msgdb-global-mark-delete (msgid)
204 (let* ((path (expand-file-name
205 elmo-msgdb-global-mark-filename
206 elmo-msgdb-directory))
207 (malist (or elmo-msgdb-global-mark-alist
208 (setq elmo-msgdb-global-mark-alist
209 (elmo-object-load path))))
211 (when (setq match (assoc msgid malist))
212 (setq elmo-msgdb-global-mark-alist
213 (delete match elmo-msgdb-global-mark-alist))
214 (elmo-object-save path elmo-msgdb-global-mark-alist))))
216 (defun elmo-msgdb-global-mark-set (msgid mark)
217 (let* ((path (expand-file-name
218 elmo-msgdb-global-mark-filename
219 elmo-msgdb-directory))
220 (malist (or elmo-msgdb-global-mark-alist
221 (setq elmo-msgdb-global-mark-alist
222 (elmo-object-load path))))
224 (if (setq match (assoc msgid malist))
226 (setq elmo-msgdb-global-mark-alist
227 (nconc elmo-msgdb-global-mark-alist
228 (list (cons msgid mark)))))
229 (elmo-object-save path elmo-msgdb-global-mark-alist)))
231 (defun elmo-msgdb-global-mark-get (msgid)
232 (cdr (assoc msgid (or elmo-msgdb-global-mark-alist
233 (setq elmo-msgdb-global-mark-alist
236 elmo-msgdb-global-mark-filename
237 elmo-msgdb-directory)))))))
240 ;; persistent mark handling
242 (defun elmo-msgdb-mark-alist-set (alist id mark msgdb)
243 (let ((ret-val alist)
245 (setq entity (assq id alist))
248 ;; delete this entity
249 (setq ret-val (delq entity alist))
251 (setcar (cdr entity) mark))
253 (setq ret-val (elmo-msgdb-append-element ret-val
256 (elmo-set-hash-val (format "#%d" id) entity
257 (elmo-msgdb-get-mark-hashtb msgdb))))
260 (defun elmo-msgdb-mark-append (alist id mark)
262 (setq alist (elmo-msgdb-append-element alist
265 (defun elmo-msgdb-seen-list (msgdb seen-marks)
266 "Get SEEN-MSGID-LIST from MSGDB."
267 (let ((ov (elmo-msgdb-get-overview msgdb))
270 (if (setq mark (elmo-msgdb-get-mark
272 (elmo-msgdb-overview-entity-get-number (car ov))))
273 (if (and mark (member mark seen-marks))
274 (setq seen-list (cons
275 (elmo-msgdb-overview-entity-get-id (car ov))
277 (setq seen-list (cons
278 (elmo-msgdb-overview-entity-get-id (car ov))
286 (defvar elmo-msgdb-decoded-cache-hashtb nil)
287 (make-variable-buffer-local 'elmo-msgdb-decoded-cache-hashtb)
289 (defsubst elmo-msgdb-get-decoded-cache (string)
290 (if elmo-use-decoded-cache
291 (let ((hashtb (or elmo-msgdb-decoded-cache-hashtb
292 (setq elmo-msgdb-decoded-cache-hashtb
293 (elmo-make-hash 2048))))
295 (or (elmo-get-hash-val string hashtb)
300 (decode-mime-charset-string string elmo-mime-charset))
303 (decode-mime-charset-string string elmo-mime-charset)))
309 (defsubst elmo-msgdb-get-field-value (field-name beg end buffer)
313 (narrow-to-region beg end)
314 (elmo-field-body field-name))))
316 (defun elmo-multiple-field-body (name &optional boundary)
319 (std11-narrow-to-header boundary)
320 (goto-char (point-min))
321 (let ((case-fold-search t)
323 (while (re-search-forward (concat "^" name ":[ \t]*") nil t)
326 (list (buffer-substring-no-properties
327 (match-end 0) (std11-field-end))))))
330 (defun elmo-multiple-fields-body-list (field-names &optional boundary)
331 "Return list of each field-bodies of FIELD-NAMES of the message header
332 in current buffer. If BOUNDARY is not nil, it is used as message
336 (std11-narrow-to-header boundary)
337 (let* ((case-fold-search t)
339 field-name field-body)
340 (while (setq field-name (car s-rest))
341 (goto-char (point-min))
342 (while (re-search-forward (concat "^" field-name ":[ \t]*") nil t)
345 (list (buffer-substring-no-properties
346 (match-end 0) (std11-field-end))))))
347 (setq s-rest (cdr s-rest)))
350 (defsubst elmo-msgdb-remove-field-string (string)
351 (if (string-match (concat std11-field-head-regexp "[ \t]*") string)
352 (substring string (match-end 0))
355 (defsubst elmo-msgdb-get-last-message-id (string)
361 (goto-char (point-max))
362 (when (search-backward "<" nil t)
364 (if (search-forward ">" nil t)
365 (elmo-replace-in-string
366 (buffer-substring beg (point)) "\n[ \t]*" ""))))))))
368 (defun elmo-msgdb-number-load (dir)
370 (expand-file-name elmo-msgdb-number-filename dir)))
372 (defun elmo-msgdb-overview-load (dir)
374 (expand-file-name elmo-msgdb-overview-filename dir)))
376 (defun elmo-msgdb-mark-load (dir)
378 (expand-file-name elmo-msgdb-mark-filename dir)))
380 (defsubst elmo-msgdb-seen-load (dir)
381 (elmo-object-load (expand-file-name
382 elmo-msgdb-seen-filename
385 (defun elmo-msgdb-number-save (dir obj)
387 (expand-file-name elmo-msgdb-number-filename dir)
390 (defun elmo-msgdb-mark-save (dir obj)
392 (expand-file-name elmo-msgdb-mark-filename dir)
395 (defun elmo-msgdb-change-mark (msgdb before after)
396 "Set the BEFORE marks to AFTER."
397 (let ((mark-alist (elmo-msgdb-get-mark-alist msgdb))
400 (setq entity (car mark-alist))
401 (when (string= (cadr entity) before)
402 (setcar (cdr entity) after))
403 (setq mark-alist (cdr mark-alist)))))
405 (defsubst elmo-msgdb-seen-save (dir obj)
407 (expand-file-name elmo-msgdb-seen-filename dir)
410 (defsubst elmo-msgdb-overview-save (dir overview)
412 (expand-file-name elmo-msgdb-overview-filename dir)
415 (defun elmo-msgdb-match-condition-primitive (condition entity numbers)
417 (let ((key (elmo-filter-key condition))
421 ((string= key "last")
422 (setq result (<= (length (memq
423 (elmo-msgdb-overview-entity-get-number
426 (string-to-int (elmo-filter-value condition)))))
427 ((string= key "first")
431 (elmo-msgdb-overview-entity-get-number
434 (string-to-int (elmo-filter-value condition)))))
435 ((string= key "from")
436 (setq result (string-match
437 (elmo-filter-value condition)
438 (elmo-msgdb-overview-entity-get-from entity))))
439 ((string= key "subject")
440 (setq result (string-match
441 (elmo-filter-value condition)
442 (elmo-msgdb-overview-entity-get-subject entity))))
444 (setq result (string-match
445 (elmo-filter-value condition)
446 (elmo-msgdb-overview-entity-get-to entity))))
448 (setq result (string-match
449 (elmo-filter-value condition)
450 (elmo-msgdb-overview-entity-get-cc entity))))
451 ((or (string= key "since")
452 (string= key "before"))
453 (let ((field-date (elmo-date-make-sortable-string
455 (elmo-msgdb-overview-entity-get-date entity)
456 (current-time-zone) nil)))
458 (elmo-date-make-sortable-string
459 (elmo-date-get-datevec
460 (elmo-filter-value condition)))))
461 (setq result (if (string= key "since")
462 (or (string= specified-date field-date)
463 (string< specified-date field-date))
464 (string< field-date specified-date)))))
465 ((member key elmo-msgdb-extra-fields)
466 (let ((extval (elmo-msgdb-overview-entity-get-extra-field entity key)))
467 (when (stringp extval)
468 (setq result (string-match
469 (elmo-filter-value condition)
472 (throw 'unresolved condition)))
473 (if (eq (elmo-filter-type condition) 'unmatch)
477 (defun elmo-msgdb-match-condition (condition entity numbers)
480 (elmo-msgdb-match-condition-primitive condition entity numbers))
481 ((eq (car condition) 'and)
482 (let ((lhs (elmo-msgdb-match-condition (nth 1 condition)
485 ((elmo-filter-condition-p lhs)
486 (let ((rhs (elmo-msgdb-match-condition (nth 2 condition)
488 (cond ((elmo-filter-condition-p rhs)
493 (elmo-msgdb-match-condition (nth 2 condition)
495 ((eq (car condition) 'or)
496 (let ((lhs (elmo-msgdb-match-condition (nth 1 condition)
499 ((elmo-filter-condition-p lhs)
500 (let ((rhs (elmo-msgdb-match-condition (nth 2 condition)
502 (cond ((elmo-filter-condition-p rhs)
511 (elmo-msgdb-match-condition (nth 2 condition)
512 entity numbers)))))))
514 (defsubst elmo-msgdb-set-overview (msgdb overview)
515 (setcar msgdb overview))
517 (defsubst elmo-msgdb-set-number-alist (msgdb number-alist)
518 (setcar (cdr msgdb) number-alist))
520 (defsubst elmo-msgdb-set-mark-alist (msgdb mark-alist)
521 (setcar (cddr msgdb) mark-alist))
523 (defsubst elmo-msgdb-set-index (msgdb index)
524 (setcar (cdddr msgdb) index))
526 (defsubst elmo-msgdb-overview-entity-get-references (entity)
527 (and entity (aref (cdr entity) 1)))
529 (defsubst elmo-msgdb-overview-entity-set-references (entity references)
530 (and entity (aset (cdr entity) 1 references))
533 ;; entity -> parent-entity
534 (defsubst elmo-msgdb-overview-get-parent-entity (entity database)
535 (setq entity (elmo-msgdb-overview-entity-get-references entity))
536 ;; entity is parent-id.
537 (and entity (assoc entity database)))
539 (defsubst elmo-msgdb-get-parent-entity (entity msgdb)
540 (setq entity (elmo-msgdb-overview-entity-get-references entity))
541 ;; entity is parent-id.
542 (and entity (elmo-msgdb-overview-get-entity entity msgdb)))
544 (defsubst elmo-msgdb-overview-entity-get-number (entity)
545 (and entity (aref (cdr entity) 0)))
547 (defsubst elmo-msgdb-overview-entity-get-from-no-decode (entity)
548 (and entity (aref (cdr entity) 2)))
550 (defsubst elmo-msgdb-overview-entity-get-from (entity)
552 (aref (cdr entity) 2)
553 (elmo-msgdb-get-decoded-cache (aref (cdr entity) 2))))
555 (defsubst elmo-msgdb-overview-entity-set-number (entity number)
556 (and entity (aset (cdr entity) 0 number))
558 ;;;(setcar (cadr entity) number) entity)
560 (defsubst elmo-msgdb-overview-entity-set-from (entity from)
561 (and entity (aset (cdr entity) 2 from))
564 (defsubst elmo-msgdb-overview-entity-get-subject (entity)
566 (aref (cdr entity) 3)
567 (elmo-msgdb-get-decoded-cache (aref (cdr entity) 3))))
569 (defsubst elmo-msgdb-overview-entity-get-subject-no-decode (entity)
570 (and entity (aref (cdr entity) 3)))
572 (defsubst elmo-msgdb-overview-entity-set-subject (entity subject)
573 (and entity (aset (cdr entity) 3 subject))
576 (defsubst elmo-msgdb-overview-entity-get-date (entity)
577 (and entity (aref (cdr entity) 4)))
579 (defsubst elmo-msgdb-overview-entity-set-date (entity date)
580 (and entity (aset (cdr entity) 4 date))
583 (defsubst elmo-msgdb-overview-entity-get-to (entity)
584 (and entity (aref (cdr entity) 5)))
586 (defsubst elmo-msgdb-overview-entity-get-cc (entity)
587 (and entity (aref (cdr entity) 6)))
589 (defsubst elmo-msgdb-overview-entity-get-size (entity)
590 (and entity (aref (cdr entity) 7)))
592 (defsubst elmo-msgdb-overview-entity-set-size (entity size)
593 (and entity (aset (cdr entity) 7 size))
596 (defsubst elmo-msgdb-overview-entity-get-id (entity)
597 (and entity (car entity)))
599 (defsubst elmo-msgdb-overview-entity-get-extra-field (entity field-name)
600 (let ((extra (and entity (aref (cdr entity) 8))))
602 (cdr (assoc field-name extra)))))
604 (defsubst elmo-msgdb-overview-entity-set-extra-field (entity field-name value)
605 (let ((extras (and entity (aref (cdr entity) 8)))
607 (if (setq extra (assoc field-name extras))
609 (elmo-msgdb-overview-entity-set-extra
611 (cons (cons field-name value) extras)))))
613 (defsubst elmo-msgdb-overview-entity-get-extra (entity)
614 (and entity (aref (cdr entity) 8)))
616 (defsubst elmo-msgdb-overview-entity-set-extra (entity extra)
617 (and entity (aset (cdr entity) 8 extra))
620 (defun elmo-msgdb-overview-get-entity-by-number (database number)
625 (if (eq (elmo-msgdb-overview-entity-get-number (car db)) number)
626 (setq entity (car db)
631 (defun elmo-msgdb-overview-get-entity (id msgdb)
633 (let ((ht (elmo-msgdb-get-entity-hashtb msgdb)))
635 (if (stringp id) ;; ID is message-id
636 (elmo-get-hash-val id ht)
637 (elmo-get-hash-val (format "#%d" id) ht))))))
640 ;; deleted message handling
642 (defun elmo-msgdb-killed-list-load (dir)
644 (expand-file-name elmo-msgdb-killed-filename dir)
647 (defun elmo-msgdb-killed-list-save (dir killed-list)
649 (expand-file-name elmo-msgdb-killed-filename dir)
652 (defun elmo-msgdb-killed-message-p (killed-list msg)
653 (elmo-number-set-member msg killed-list))
655 (defun elmo-msgdb-set-as-killed (killed-list msg)
656 (elmo-number-set-append killed-list msg))
658 (defun elmo-msgdb-append-to-killed-list (folder msgs)
659 (elmo-folder-set-killed-list-internal
661 (elmo-number-set-append-list
662 (elmo-folder-killed-list-internal folder)
665 (defun elmo-msgdb-killed-list-length (killed-list)
666 (let ((killed killed-list)
669 (if (consp (car killed))
670 (setq ret-val (+ ret-val 1 (- (cdar killed) (caar killed))))
671 (setq ret-val (+ ret-val 1)))
672 (setq killed (cdr killed)))
675 (defun elmo-msgdb-max-of-killed (killed-list)
676 (let ((klist killed-list)
682 (if (consp (car klist))
686 (setq klist (cdr klist)))
689 (defun elmo-living-messages (messages killed-list)
692 (mapcar (lambda (number)
693 (unless (elmo-number-set-member number killed-list)
698 (defun elmo-msgdb-finfo-load ()
699 (elmo-object-load (expand-file-name
700 elmo-msgdb-finfo-filename
701 elmo-msgdb-directory)
702 elmo-mime-charset t))
704 (defun elmo-msgdb-finfo-save (finfo)
705 (elmo-object-save (expand-file-name
706 elmo-msgdb-finfo-filename
707 elmo-msgdb-directory)
708 finfo elmo-mime-charset))
710 (defun elmo-msgdb-flist-load (fname)
711 (let ((flist-file (expand-file-name
712 elmo-msgdb-flist-filename
714 (elmo-safe-filename fname)
715 (expand-file-name "folder" elmo-msgdb-directory)))))
716 (elmo-object-load flist-file elmo-mime-charset t)))
718 (defun elmo-msgdb-flist-save (fname flist)
719 (let ((flist-file (expand-file-name
720 elmo-msgdb-flist-filename
722 (elmo-safe-filename fname)
723 (expand-file-name "folder" elmo-msgdb-directory)))))
724 (elmo-object-save flist-file flist elmo-mime-charset)))
726 (defun elmo-crosspost-alist-load ()
727 (elmo-object-load (expand-file-name
728 elmo-crosspost-alist-filename
729 elmo-msgdb-directory)
732 (defun elmo-crosspost-alist-save (alist)
733 (elmo-object-save (expand-file-name
734 elmo-crosspost-alist-filename
735 elmo-msgdb-directory)
738 (defun elmo-msgdb-add-msgs-to-seen-list (msgs msgdb unread-marks seen-list)
742 (if (setq mark (elmo-msgdb-get-mark msgdb (car msgs)))
743 (unless (member mark unread-marks) ;; not unread mark
746 (elmo-msgdb-get-field msgdb (car msgs) 'message-id)
748 ;; no mark ... seen...
751 (elmo-msgdb-get-field msgdb (car msgs) 'message-id)
753 (setq msgs (cdr msgs)))
756 (defun elmo-msgdb-get-message-id-from-buffer ()
757 (or (elmo-field-body "message-id")
758 ;; no message-id, so put dummy msgid.
759 (concat (timezone-make-date-sortable
760 (elmo-field-body "date"))
761 (nth 1 (eword-extract-address-components
762 (or (elmo-field-body "from") "nobody"))))))
764 (defsubst elmo-msgdb-create-overview-from-buffer (number &optional size time)
765 "Create overview entity from current buffer.
766 Header region is supposed to be narrowed."
768 (let ((extras elmo-msgdb-extra-fields)
769 message-id references from subject to cc date
771 (elmo-set-buffer-multibyte default-enable-multibyte-characters)
772 (setq message-id (elmo-msgdb-get-message-id-from-buffer))
774 (or (elmo-msgdb-get-last-message-id
775 (elmo-field-body "in-reply-to"))
776 (elmo-msgdb-get-last-message-id
777 (elmo-field-body "references"))))
778 (setq from (elmo-mime-string (elmo-delete-char
781 (elmo-field-body "from")
783 (setq subject (elmo-mime-string (or (elmo-field-body "subject")
785 (setq date (or (elmo-field-body "date") time))
786 (setq to (mapconcat 'identity (elmo-multiple-field-body "to") ","))
787 (setq cc (mapconcat 'identity (elmo-multiple-field-body "cc") ","))
789 (if (setq size (elmo-field-body "content-length"))
790 (setq size (string-to-int size))
791 (setq size 0)));; No mean...
793 (if (setq field-body (elmo-field-body (car extras)))
794 (setq extra (cons (cons (downcase (car extras))
796 (setq extras (cdr extras)))
797 (cons message-id (vector number references
798 from subject date to cc
802 (defun elmo-msgdb-copy-overview-entity (entity)
804 (copy-sequence (cdr entity))))
806 (defsubst elmo-msgdb-insert-file-header (file)
807 "Insert the header of the article."
809 insert-file-contents-pre-hook ; To avoid autoconv-xmas...
810 insert-file-contents-post-hook
812 (when (file-exists-p file)
813 ;; Read until header separator is found.
814 (while (and (eq elmo-msgdb-file-header-chop-length
816 (insert-file-contents-as-binary
818 (incf beg elmo-msgdb-file-header-chop-length))))
819 (prog1 (not (search-forward "\n\n" nil t))
820 (goto-char (point-max))))))))
822 (defsubst elmo-msgdb-create-overview-entity-from-file (number file)
823 (let (insert-file-contents-pre-hook ; To avoid autoconv-xmas...
824 insert-file-contents-post-hook header-end
825 (attrib (file-attributes file))
828 (if (not (file-exists-p file))
830 (setq size (nth 7 attrib))
831 (setq mtime (timezone-make-date-arpa-standard
832 (current-time-string (nth 5 attrib)) (current-time-zone)))
833 ;; insert header from file.
836 (elmo-msgdb-insert-file-header file)
837 (error (throw 'done nil)))
838 (goto-char (point-min))
840 (if (re-search-forward "\\(^--.*$\\)\\|\\(\n\n\\)" nil t)
843 (narrow-to-region (point-min) header-end)
844 (elmo-msgdb-create-overview-from-buffer number size mtime))))))
846 (defun elmo-msgdb-overview-sort-by-date (overview)
852 (timezone-make-date-sortable
853 (elmo-msgdb-overview-entity-get-date x))
854 (timezone-make-date-sortable
855 (elmo-msgdb-overview-entity-get-date y)))
858 (defun elmo-msgdb-clear-index (msgdb entity)
859 (let ((ehash (elmo-msgdb-get-entity-hashtb msgdb))
860 (mhash (elmo-msgdb-get-mark-hashtb msgdb))
862 (when (and entity ehash)
863 (and (setq number (elmo-msgdb-overview-entity-get-number entity))
864 (elmo-clear-hash-val (format "#%d" number) ehash))
865 (and (car entity) ;; message-id
866 (elmo-clear-hash-val (car entity) ehash)))
867 (when (and entity mhash)
868 (and (setq number (elmo-msgdb-overview-entity-get-number entity))
869 (elmo-clear-hash-val (format "#%d" number) mhash)))))
871 (defun elmo-msgdb-make-index (msgdb &optional overview mark-alist)
872 "Append OVERVIEW and MARK-ALIST to the index of MSGDB.
873 If OVERVIEW and MARK-ALIST are nil, make index for current MSGDB.
874 Return the updated INDEX."
876 (let* ((overview (or overview (elmo-msgdb-get-overview msgdb)))
877 (mark-alist (or mark-alist (elmo-msgdb-get-mark-alist msgdb)))
878 (index (elmo-msgdb-get-index msgdb))
879 (ehash (or (car index) ;; append
880 (elmo-make-hash (length overview))))
881 (mhash (or (cdr index) ;; append
882 (elmo-make-hash (length overview)))))
886 (elmo-set-hash-val (caar overview) (car overview) ehash))
890 (elmo-msgdb-overview-entity-get-number (car overview)))
891 (car overview) ehash)
892 (setq overview (cdr overview)))
896 (format "#%d" (car (car mark-alist)))
897 (car mark-alist) mhash)
898 (setq mark-alist (cdr mark-alist)))
899 (setq index (or index (cons ehash mhash)))
900 (elmo-msgdb-set-index msgdb index)
903 (defsubst elmo-folder-get-info (folder &optional hashtb)
904 (elmo-get-hash-val folder
905 (or hashtb elmo-folder-info-hashtb)))
907 (defun elmo-folder-get-info-max (folder)
908 "Get folder info from cache."
909 (nth 3 (elmo-folder-get-info folder)))
911 (defun elmo-folder-get-info-length (folder)
912 (nth 2 (elmo-folder-get-info folder)))
914 (defun elmo-folder-get-info-unread (folder)
915 (nth 1 (elmo-folder-get-info folder)))
917 (defsubst elmo-msgdb-location-load (dir)
920 elmo-msgdb-location-filename
923 (defsubst elmo-msgdb-location-add (alist number location)
924 (let ((ret-val alist))
926 (elmo-msgdb-append-element ret-val (cons number location)))
929 (defsubst elmo-msgdb-location-save (dir alist)
932 elmo-msgdb-location-filename
936 (product-provide (provide 'elmo-msgdb) (require 'elmo-version))
938 ;;; elmo-msgdb.el ends here