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))
42 (defun elmo-load-msgdb (path)
43 "Load the MSGDB from PATH."
44 (let ((inhibit-quit t))
45 (elmo-make-msgdb (elmo-msgdb-overview-load path)
46 (elmo-msgdb-number-load path)
47 (elmo-msgdb-mark-load path))))
49 (defun elmo-make-msgdb (&optional overview number-alist mark-alist)
51 (let ((msgdb (list overview number-alist mark-alist nil)))
52 (elmo-msgdb-make-index msgdb)
55 (defsubst elmo-msgdb-get-mark (msgdb number)
56 "Get mark string from MSGDB which corresponds to the message with NUMBER."
57 (cadr (elmo-get-hash-val (format "#%d" number)
58 (elmo-msgdb-get-mark-hashtb msgdb))))
60 (defsubst elmo-msgdb-set-mark (msgdb number mark)
61 "Set MARK of the message with NUMBER in the MSGDB.
62 if MARK is nil, mark is removed."
63 (elmo-msgdb-set-mark-alist
65 (elmo-msgdb-mark-alist-set (elmo-msgdb-get-mark-alist msgdb)
69 (elmo-clear-hash-val (format "#%d" number)
70 (elmo-msgdb-get-mark-hashtb msgdb))))
72 (defsubst elmo-msgdb-count-marks (msgdb new-mark unread-marks)
75 (dolist (elem (elmo-msgdb-get-mark-alist msgdb))
77 ((string= (cadr elem) new-mark)
79 ((member (cadr elem) unread-marks)
83 (defsubst elmo-msgdb-get-number (msgdb message-id)
84 "Get number of the message which corrensponds to MESSAGE-ID from MSGDB."
85 (elmo-msgdb-overview-entity-get-number
86 (elmo-msgdb-overview-get-entity message-id msgdb)))
88 (defsubst elmo-msgdb-get-field (msgdb number field)
89 "Get FIELD value of the message with NUMBER from MSGDB."
91 (message-id (elmo-msgdb-overview-entity-get-id
92 (elmo-msgdb-overview-get-entity
94 (subject (elmo-msgdb-overview-entity-get-subject
95 (elmo-msgdb-overview-get-entity
97 (size (elmo-msgdb-overview-entity-get-size
98 (elmo-msgdb-overview-get-entity
100 (date (elmo-msgdb-overview-entity-get-date
101 (elmo-msgdb-overview-get-entity
103 (to (elmo-msgdb-overview-entity-get-to
104 (elmo-msgdb-overview-get-entity
106 (cc (elmo-msgdb-overview-entity-get-cc
107 (elmo-msgdb-overview-get-entity
110 (defsubst elmo-msgdb-append (msgdb msgdb-append)
112 (nconc (car msgdb) (car msgdb-append))
113 (nconc (cadr msgdb) (cadr msgdb-append))
114 (nconc (caddr msgdb) (caddr msgdb-append))
115 (elmo-msgdb-make-index
117 (elmo-msgdb-get-overview msgdb-append)
118 (elmo-msgdb-get-mark-alist msgdb-append))))
120 (defsubst elmo-msgdb-clear (&optional msgdb)
124 (setcar (cdr msgdb) nil)
125 (setcar (cddr msgdb) nil)
126 (setcar (nthcdr 3 msgdb) nil))
127 (list nil nil nil nil)))
129 (defun elmo-msgdb-delete-msgs (msgdb msgs)
130 "Delete MSGS from MSGDB
131 content of MSGDB is changed."
132 (let* ((overview (car msgdb))
133 (number-alist (cadr msgdb))
134 (mark-alist (caddr msgdb))
135 (index (elmo-msgdb-get-index msgdb))
136 (newmsgdb (list overview number-alist mark-alist index))
138 ;; remove from current database.
143 (elmo-msgdb-overview-get-entity (car msgs) newmsgdb))
145 (setq number-alist (delq (assq (car msgs) number-alist) number-alist))
146 (setq mark-alist (delq (assq (car msgs) mark-alist) mark-alist))
148 (when index (elmo-msgdb-clear-index msgdb ov-entity))
149 (setq msgs (cdr msgs)))
150 (setcar msgdb overview)
151 (setcar (cdr msgdb) number-alist)
152 (setcar (cddr msgdb) mark-alist)
153 (setcar (nthcdr 3 msgdb) index)
156 (defun elmo-msgdb-sort-by-date (msgdb)
157 (message "Sorting...")
158 (let ((overview (elmo-msgdb-get-overview msgdb)))
159 (setq overview (elmo-msgdb-overview-sort-by-date overview))
160 (message "Sorting...done")
161 (list overview (nth 1 msgdb)(nth 2 msgdb))))
163 (defun elmo-msgdb-make-entity (&rest args)
164 "Make an msgdb entity."
165 (cons (plist-get args :message-id)
166 (vector (plist-get args :number)
167 (plist-get args :references)
168 (plist-get args :from)
169 (plist-get args :subject)
170 (plist-get args :date)
173 (plist-get args :size)
174 (plist-get args :extra))))
177 (defsubst elmo-msgdb-append-element (list element)
179 ;;; (append list (list element))
180 (nconc list (list element))
184 (defsubst elmo-msgdb-get-overview (msgdb)
186 (defsubst elmo-msgdb-get-number-alist (msgdb)
188 (defsubst elmo-msgdb-get-mark-alist (msgdb)
190 ;(defsubst elmo-msgdb-get-location (msgdb)
193 (defsubst elmo-msgdb-get-index (msgdb)
196 (defsubst elmo-msgdb-get-entity-hashtb (msgdb)
199 (defsubst elmo-msgdb-get-mark-hashtb (msgdb)
203 ;; number <-> Message-ID handling
205 (defsubst elmo-msgdb-number-add (alist number id)
206 (let ((ret-val alist))
208 (elmo-msgdb-append-element ret-val (cons number id)))
212 ;; parsistent mark handling
215 (defvar elmo-msgdb-global-mark-alist nil)
217 (defun elmo-msgdb-global-mark-delete (msgid)
218 (let* ((path (expand-file-name
219 elmo-msgdb-global-mark-filename
220 elmo-msgdb-directory))
221 (malist (or elmo-msgdb-global-mark-alist
222 (setq elmo-msgdb-global-mark-alist
223 (elmo-object-load path))))
225 (when (setq match (assoc msgid malist))
226 (setq elmo-msgdb-global-mark-alist
227 (delete match elmo-msgdb-global-mark-alist))
228 (elmo-object-save path elmo-msgdb-global-mark-alist))))
230 (defun elmo-msgdb-global-mark-set (msgid mark)
231 (let* ((path (expand-file-name
232 elmo-msgdb-global-mark-filename
233 elmo-msgdb-directory))
234 (malist (or elmo-msgdb-global-mark-alist
235 (setq elmo-msgdb-global-mark-alist
236 (elmo-object-load path))))
238 (if (setq match (assoc msgid malist))
240 (setq elmo-msgdb-global-mark-alist
241 (nconc elmo-msgdb-global-mark-alist
242 (list (cons msgid mark)))))
243 (elmo-object-save path elmo-msgdb-global-mark-alist)))
245 (defun elmo-msgdb-global-mark-get (msgid)
246 (cdr (assoc msgid (or elmo-msgdb-global-mark-alist
247 (setq elmo-msgdb-global-mark-alist
250 elmo-msgdb-global-mark-filename
251 elmo-msgdb-directory)))))))
254 ;; persistent mark handling
256 (defun elmo-msgdb-mark-alist-set (alist id mark msgdb)
257 (let ((ret-val alist)
259 (setq entity (assq id alist))
262 ;; delete this entity
263 (setq ret-val (delq entity alist))
265 (setcar (cdr entity) mark))
267 (setq ret-val (elmo-msgdb-append-element ret-val
270 (elmo-set-hash-val (format "#%d" id) entity
271 (elmo-msgdb-get-mark-hashtb msgdb))))
274 (defun elmo-msgdb-mark-append (alist id mark)
276 (setq alist (elmo-msgdb-append-element alist
279 (defun elmo-msgdb-seen-list (msgdb seen-marks)
280 "Get SEEN-MSGID-LIST from MSGDB."
281 (let ((ov (elmo-msgdb-get-overview msgdb))
284 (if (setq mark (elmo-msgdb-get-mark
286 (elmo-msgdb-overview-entity-get-number (car ov))))
287 (if (and mark (member mark seen-marks))
288 (setq seen-list (cons
289 (elmo-msgdb-overview-entity-get-id (car ov))
291 (setq seen-list (cons
292 (elmo-msgdb-overview-entity-get-id (car ov))
300 (defvar elmo-msgdb-decoded-cache-hashtb nil)
301 (make-variable-buffer-local 'elmo-msgdb-decoded-cache-hashtb)
303 (defsubst elmo-msgdb-get-decoded-cache (string)
304 (if elmo-use-decoded-cache
305 (let ((hashtb (or elmo-msgdb-decoded-cache-hashtb
306 (setq elmo-msgdb-decoded-cache-hashtb
307 (elmo-make-hash 2048))))
309 (or (elmo-get-hash-val string hashtb)
314 (decode-mime-charset-string string elmo-mime-charset))
317 (decode-mime-charset-string string elmo-mime-charset)))
323 (defsubst elmo-msgdb-get-field-value (field-name beg end buffer)
327 (narrow-to-region beg end)
328 (elmo-field-body field-name))))
330 (defun elmo-multiple-field-body (name &optional boundary)
333 (std11-narrow-to-header boundary)
334 (goto-char (point-min))
335 (let ((case-fold-search t)
337 (while (re-search-forward (concat "^" name ":[ \t]*") nil t)
340 (list (buffer-substring-no-properties
341 (match-end 0) (std11-field-end))))))
344 (defun elmo-multiple-fields-body-list (field-names &optional boundary)
345 "Return list of each field-bodies of FIELD-NAMES of the message header
346 in current buffer. If BOUNDARY is not nil, it is used as message
350 (std11-narrow-to-header boundary)
351 (let* ((case-fold-search t)
353 field-name field-body)
354 (while (setq field-name (car s-rest))
355 (goto-char (point-min))
356 (while (re-search-forward (concat "^" field-name ":[ \t]*") nil t)
359 (list (buffer-substring-no-properties
360 (match-end 0) (std11-field-end))))))
361 (setq s-rest (cdr s-rest)))
364 (defsubst elmo-msgdb-remove-field-string (string)
365 (if (string-match (concat std11-field-head-regexp "[ \t]*") string)
366 (substring string (match-end 0))
369 (defsubst elmo-msgdb-get-last-message-id (string)
375 (goto-char (point-max))
376 (when (search-backward "<" nil t)
378 (if (search-forward ">" nil t)
379 (elmo-replace-in-string
380 (buffer-substring beg (point)) "\n[ \t]*" ""))))))))
382 (defun elmo-msgdb-number-load (dir)
384 (expand-file-name elmo-msgdb-number-filename dir)))
386 (defun elmo-msgdb-overview-load (dir)
388 (expand-file-name elmo-msgdb-overview-filename dir)))
390 (defun elmo-msgdb-mark-load (dir)
392 (expand-file-name elmo-msgdb-mark-filename dir)))
394 (defsubst elmo-msgdb-seen-load (dir)
395 (elmo-object-load (expand-file-name
396 elmo-msgdb-seen-filename
399 (defun elmo-msgdb-number-save (dir obj)
401 (expand-file-name elmo-msgdb-number-filename dir)
404 (defun elmo-msgdb-mark-save (dir obj)
406 (expand-file-name elmo-msgdb-mark-filename dir)
409 (defun elmo-msgdb-change-mark (msgdb before after)
410 "Set the BEFORE marks to AFTER."
411 (let ((mark-alist (elmo-msgdb-get-mark-alist msgdb))
414 (setq entity (car mark-alist))
415 (when (string= (cadr entity) before)
416 (setcar (cdr entity) after))
417 (setq mark-alist (cdr mark-alist)))))
419 (defsubst elmo-msgdb-seen-save (dir obj)
421 (expand-file-name elmo-msgdb-seen-filename dir)
424 (defsubst elmo-msgdb-overview-save (dir overview)
426 (expand-file-name elmo-msgdb-overview-filename dir)
429 (defun elmo-msgdb-match-condition-primitive (condition entity numbers)
431 (let ((key (elmo-filter-key condition))
435 ((string= key "last")
436 (setq result (<= (length (memq
437 (elmo-msgdb-overview-entity-get-number
440 (string-to-int (elmo-filter-value condition)))))
441 ((string= key "first")
445 (elmo-msgdb-overview-entity-get-number
448 (string-to-int (elmo-filter-value condition)))))
449 ((string= key "from")
450 (setq result (string-match
451 (elmo-filter-value condition)
452 (elmo-msgdb-overview-entity-get-from entity))))
453 ((string= key "subject")
454 (setq result (string-match
455 (elmo-filter-value condition)
456 (elmo-msgdb-overview-entity-get-subject entity))))
458 (setq result (string-match
459 (elmo-filter-value condition)
460 (elmo-msgdb-overview-entity-get-to entity))))
462 (setq result (string-match
463 (elmo-filter-value condition)
464 (elmo-msgdb-overview-entity-get-cc entity))))
465 ((or (string= key "since")
466 (string= key "before"))
467 (let ((field-date (elmo-date-make-sortable-string
469 (elmo-msgdb-overview-entity-get-date entity)
470 (current-time-zone) nil)))
472 (elmo-date-make-sortable-string
473 (elmo-date-get-datevec
474 (elmo-filter-value condition)))))
475 (setq result (if (string= key "since")
476 (or (string= specified-date field-date)
477 (string< specified-date field-date))
478 (string< field-date specified-date)))))
479 ((member key elmo-msgdb-extra-fields)
480 (let ((extval (elmo-msgdb-overview-entity-get-extra-field entity key)))
481 (when (stringp extval)
482 (setq result (string-match
483 (elmo-filter-value condition)
486 (throw 'unresolved condition)))
487 (if (eq (elmo-filter-type condition) 'unmatch)
491 (defun elmo-msgdb-match-condition (condition entity numbers)
494 (elmo-msgdb-match-condition-primitive condition entity numbers))
495 ((eq (car condition) 'and)
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)
507 (elmo-msgdb-match-condition (nth 2 condition)
509 ((eq (car condition) 'or)
510 (let ((lhs (elmo-msgdb-match-condition (nth 1 condition)
513 ((elmo-filter-condition-p lhs)
514 (let ((rhs (elmo-msgdb-match-condition (nth 2 condition)
516 (cond ((elmo-filter-condition-p rhs)
525 (elmo-msgdb-match-condition (nth 2 condition)
526 entity numbers)))))))
528 (defsubst elmo-msgdb-set-overview (msgdb overview)
529 (setcar msgdb overview))
531 (defsubst elmo-msgdb-set-number-alist (msgdb number-alist)
532 (setcar (cdr msgdb) number-alist))
534 (defsubst elmo-msgdb-set-mark-alist (msgdb mark-alist)
535 (setcar (cddr msgdb) mark-alist))
537 (defsubst elmo-msgdb-set-index (msgdb index)
538 (setcar (cdddr msgdb) index))
540 (defsubst elmo-msgdb-overview-entity-get-references (entity)
541 (and entity (aref (cdr entity) 1)))
543 (defsubst elmo-msgdb-overview-entity-set-references (entity references)
544 (and entity (aset (cdr entity) 1 references))
547 ;; entity -> parent-entity
548 (defsubst elmo-msgdb-overview-get-parent-entity (entity database)
549 (setq entity (elmo-msgdb-overview-entity-get-references entity))
550 ;; entity is parent-id.
551 (and entity (assoc entity database)))
553 (defsubst elmo-msgdb-get-parent-entity (entity msgdb)
554 (setq entity (elmo-msgdb-overview-entity-get-references entity))
555 ;; entity is parent-id.
556 (and entity (elmo-msgdb-overview-get-entity entity msgdb)))
558 (defsubst elmo-msgdb-overview-entity-get-number (entity)
559 (and entity (aref (cdr entity) 0)))
561 (defsubst elmo-msgdb-overview-entity-get-from-no-decode (entity)
562 (and entity (aref (cdr entity) 2)))
564 (defsubst elmo-msgdb-overview-entity-get-from (entity)
566 (aref (cdr entity) 2)
567 (elmo-msgdb-get-decoded-cache (aref (cdr entity) 2))))
569 (defsubst elmo-msgdb-overview-entity-set-number (entity number)
570 (and entity (aset (cdr entity) 0 number))
572 ;;;(setcar (cadr entity) number) entity)
574 (defsubst elmo-msgdb-overview-entity-set-from (entity from)
575 (and entity (aset (cdr entity) 2 from))
578 (defsubst elmo-msgdb-overview-entity-get-subject (entity)
580 (aref (cdr entity) 3)
581 (elmo-msgdb-get-decoded-cache (aref (cdr entity) 3))))
583 (defsubst elmo-msgdb-overview-entity-get-subject-no-decode (entity)
584 (and entity (aref (cdr entity) 3)))
586 (defsubst elmo-msgdb-overview-entity-set-subject (entity subject)
587 (and entity (aset (cdr entity) 3 subject))
590 (defsubst elmo-msgdb-overview-entity-get-date (entity)
591 (and entity (aref (cdr entity) 4)))
593 (defsubst elmo-msgdb-overview-entity-set-date (entity date)
594 (and entity (aset (cdr entity) 4 date))
597 (defsubst elmo-msgdb-overview-entity-get-to (entity)
598 (and entity (aref (cdr entity) 5)))
600 (defsubst elmo-msgdb-overview-entity-get-cc (entity)
601 (and entity (aref (cdr entity) 6)))
603 (defsubst elmo-msgdb-overview-entity-get-size (entity)
604 (and entity (aref (cdr entity) 7)))
606 (defsubst elmo-msgdb-overview-entity-set-size (entity size)
607 (and entity (aset (cdr entity) 7 size))
610 (defsubst elmo-msgdb-overview-entity-get-id (entity)
611 (and entity (car entity)))
613 (defsubst elmo-msgdb-overview-entity-get-extra-field (entity field-name)
614 (let ((extra (and entity (aref (cdr entity) 8))))
616 (cdr (assoc field-name extra)))))
618 (defsubst elmo-msgdb-overview-entity-set-extra-field (entity field-name value)
619 (let ((extras (and entity (aref (cdr entity) 8)))
621 (if (setq extra (assoc field-name extras))
623 (elmo-msgdb-overview-entity-set-extra
625 (cons (cons field-name value) extras)))))
627 (defsubst elmo-msgdb-overview-entity-get-extra (entity)
628 (and entity (aref (cdr entity) 8)))
630 (defsubst elmo-msgdb-overview-entity-set-extra (entity extra)
631 (and entity (aset (cdr entity) 8 extra))
634 (defun elmo-msgdb-overview-get-entity-by-number (database number)
639 (if (eq (elmo-msgdb-overview-entity-get-number (car db)) number)
640 (setq entity (car db)
645 (defun elmo-msgdb-overview-get-entity (id msgdb)
647 (let ((ht (elmo-msgdb-get-entity-hashtb msgdb)))
649 (if (stringp id) ;; ID is message-id
650 (elmo-get-hash-val id ht)
651 (elmo-get-hash-val (format "#%d" id) ht))))))
654 ;; deleted message handling
656 (defun elmo-msgdb-killed-list-load (dir)
658 (expand-file-name elmo-msgdb-killed-filename dir)
661 (defun elmo-msgdb-killed-list-save (dir killed-list)
663 (expand-file-name elmo-msgdb-killed-filename dir)
666 (defun elmo-msgdb-killed-message-p (killed-list msg)
667 (elmo-number-set-member msg killed-list))
669 (defun elmo-msgdb-set-as-killed (killed-list msg)
670 (elmo-number-set-append killed-list msg))
672 (defun elmo-msgdb-append-to-killed-list (folder msgs)
673 (elmo-folder-set-killed-list-internal
675 (elmo-number-set-append-list
676 (elmo-folder-killed-list-internal folder)
679 (defun elmo-msgdb-killed-list-length (killed-list)
680 (let ((killed killed-list)
683 (if (consp (car killed))
684 (setq ret-val (+ ret-val 1 (- (cdar killed) (caar killed))))
685 (setq ret-val (+ ret-val 1)))
686 (setq killed (cdr killed)))
689 (defun elmo-msgdb-max-of-killed (killed-list)
690 (let ((klist killed-list)
696 (if (consp (car klist))
700 (setq klist (cdr klist)))
703 (defun elmo-living-messages (messages killed-list)
706 (mapcar (lambda (number)
707 (unless (elmo-number-set-member number killed-list)
712 (defun elmo-msgdb-finfo-load ()
713 (elmo-object-load (expand-file-name
714 elmo-msgdb-finfo-filename
715 elmo-msgdb-directory)
716 elmo-mime-charset t))
718 (defun elmo-msgdb-finfo-save (finfo)
719 (elmo-object-save (expand-file-name
720 elmo-msgdb-finfo-filename
721 elmo-msgdb-directory)
722 finfo elmo-mime-charset))
724 (defun elmo-msgdb-flist-load (fname)
725 (let ((flist-file (expand-file-name
726 elmo-msgdb-flist-filename
728 (elmo-safe-filename fname)
729 (expand-file-name "folder" elmo-msgdb-directory)))))
730 (elmo-object-load flist-file elmo-mime-charset t)))
732 (defun elmo-msgdb-flist-save (fname flist)
733 (let ((flist-file (expand-file-name
734 elmo-msgdb-flist-filename
736 (elmo-safe-filename fname)
737 (expand-file-name "folder" elmo-msgdb-directory)))))
738 (elmo-object-save flist-file flist elmo-mime-charset)))
740 (defun elmo-crosspost-alist-load ()
741 (elmo-object-load (expand-file-name
742 elmo-crosspost-alist-filename
743 elmo-msgdb-directory)
746 (defun elmo-crosspost-alist-save (alist)
747 (elmo-object-save (expand-file-name
748 elmo-crosspost-alist-filename
749 elmo-msgdb-directory)
752 (defun elmo-msgdb-add-msgs-to-seen-list (msgs msgdb unread-marks seen-list)
756 (if (setq mark (elmo-msgdb-get-mark msgdb (car msgs)))
757 (unless (member mark unread-marks) ;; not unread mark
760 (elmo-msgdb-get-field msgdb (car msgs) 'message-id)
762 ;; no mark ... seen...
765 (elmo-msgdb-get-field msgdb (car msgs) 'message-id)
767 (setq msgs (cdr msgs)))
770 (defun elmo-msgdb-get-message-id-from-buffer ()
771 (or (elmo-field-body "message-id")
772 ;; no message-id, so put dummy msgid.
773 (concat "<" (timezone-make-date-sortable
774 (elmo-field-body "date"))
775 (nth 1 (eword-extract-address-components
776 (or (elmo-field-body "from") "nobody"))) ">")))
778 (defsubst elmo-msgdb-create-overview-from-buffer (number &optional size time)
779 "Create overview entity from current buffer.
780 Header region is supposed to be narrowed."
782 (let ((extras elmo-msgdb-extra-fields)
783 (default-mime-charset default-mime-charset)
784 message-id references from subject to cc date
785 extra field-body charset)
786 (elmo-set-buffer-multibyte default-enable-multibyte-characters)
787 (setq message-id (elmo-msgdb-get-message-id-from-buffer))
788 (and (setq charset (cdr (assoc "charset" (mime-read-Content-Type))))
789 (setq charset (intern-soft charset))
790 (setq default-mime-charset charset))
792 (or (elmo-msgdb-get-last-message-id
793 (elmo-field-body "in-reply-to"))
794 (elmo-msgdb-get-last-message-id
795 (elmo-field-body "references"))))
796 (setq from (elmo-replace-in-string
797 (elmo-mime-string (or (elmo-field-body "from")
800 subject (elmo-replace-in-string
801 (elmo-mime-string (or (elmo-field-body "subject")
804 (setq date (or (elmo-field-body "date") time))
805 (setq to (mapconcat 'identity (elmo-multiple-field-body "to") ","))
806 (setq cc (mapconcat 'identity (elmo-multiple-field-body "cc") ","))
808 (if (setq size (elmo-field-body "content-length"))
809 (setq size (string-to-int size))
810 (setq size 0)));; No mean...
812 (if (setq field-body (elmo-field-body (car extras)))
813 (setq extra (cons (cons (downcase (car extras))
815 (setq extras (cdr extras)))
816 (cons message-id (vector number references
817 from subject date to cc
821 (defun elmo-msgdb-copy-overview-entity (entity)
823 (copy-sequence (cdr entity))))
825 (defsubst elmo-msgdb-insert-file-header (file)
826 "Insert the header of the article."
828 insert-file-contents-pre-hook ; To avoid autoconv-xmas...
829 insert-file-contents-post-hook
831 (when (file-exists-p file)
832 ;; Read until header separator is found.
833 (while (and (eq elmo-msgdb-file-header-chop-length
835 (insert-file-contents-as-binary
837 (incf beg elmo-msgdb-file-header-chop-length))))
838 (prog1 (not (search-forward "\n\n" nil t))
839 (goto-char (point-max))))))))
841 (defsubst elmo-msgdb-create-overview-entity-from-file (number file)
842 (let (insert-file-contents-pre-hook ; To avoid autoconv-xmas...
843 insert-file-contents-post-hook header-end
844 (attrib (file-attributes file))
847 (if (not (file-exists-p file))
849 (setq size (nth 7 attrib))
850 (setq mtime (timezone-make-date-arpa-standard
851 (current-time-string (nth 5 attrib)) (current-time-zone)))
852 ;; insert header from file.
855 (elmo-msgdb-insert-file-header file)
856 (error (throw 'done nil)))
857 (goto-char (point-min))
859 (if (re-search-forward "\\(^--.*$\\)\\|\\(\n\n\\)" nil t)
862 (narrow-to-region (point-min) header-end)
863 (elmo-msgdb-create-overview-from-buffer number size mtime))))))
865 (defun elmo-msgdb-overview-sort-by-date (overview)
871 (timezone-make-date-sortable
872 (elmo-msgdb-overview-entity-get-date x))
873 (timezone-make-date-sortable
874 (elmo-msgdb-overview-entity-get-date y)))
877 (defun elmo-msgdb-clear-index (msgdb entity)
878 (let ((ehash (elmo-msgdb-get-entity-hashtb msgdb))
879 (mhash (elmo-msgdb-get-mark-hashtb msgdb))
881 (when (and entity ehash)
882 (and (setq number (elmo-msgdb-overview-entity-get-number entity))
883 (elmo-clear-hash-val (format "#%d" number) ehash))
884 (and (car entity) ;; message-id
885 (elmo-clear-hash-val (car entity) ehash)))
886 (when (and entity mhash)
887 (and (setq number (elmo-msgdb-overview-entity-get-number entity))
888 (elmo-clear-hash-val (format "#%d" number) mhash)))))
890 (defun elmo-msgdb-make-index (msgdb &optional overview mark-alist)
891 "Append OVERVIEW and MARK-ALIST to the index of MSGDB.
892 If OVERVIEW and MARK-ALIST are nil, make index for current MSGDB.
893 Return the updated INDEX."
895 (let* ((overview (or overview (elmo-msgdb-get-overview msgdb)))
896 (mark-alist (or mark-alist (elmo-msgdb-get-mark-alist msgdb)))
897 (index (elmo-msgdb-get-index msgdb))
898 (ehash (or (car index) ;; append
899 (elmo-make-hash (length overview))))
900 (mhash (or (cdr index) ;; append
901 (elmo-make-hash (length overview)))))
905 (elmo-set-hash-val (caar overview) (car overview) ehash))
909 (elmo-msgdb-overview-entity-get-number (car overview)))
910 (car overview) ehash)
911 (setq overview (cdr overview)))
915 (format "#%d" (car (car mark-alist)))
916 (car mark-alist) mhash)
917 (setq mark-alist (cdr mark-alist)))
918 (setq index (or index (cons ehash mhash)))
919 (elmo-msgdb-set-index msgdb index)
922 (defsubst elmo-folder-get-info (folder &optional hashtb)
923 (elmo-get-hash-val folder
924 (or hashtb elmo-folder-info-hashtb)))
926 (defun elmo-folder-get-info-max (folder)
927 "Get folder info from cache."
928 (nth 3 (elmo-folder-get-info folder)))
930 (defun elmo-folder-get-info-length (folder)
931 (nth 2 (elmo-folder-get-info folder)))
933 (defun elmo-folder-get-info-unread (folder)
934 (nth 1 (elmo-folder-get-info folder)))
936 (defsubst elmo-msgdb-location-load (dir)
939 elmo-msgdb-location-filename
942 (defsubst elmo-msgdb-location-add (alist number location)
943 (let ((ret-val alist))
945 (elmo-msgdb-append-element ret-val (cons number location)))
948 (defsubst elmo-msgdb-location-save (dir alist)
951 elmo-msgdb-location-filename
954 (put 'elmo-msgdb-do-each-entity 'lisp-indent-function '1)
955 (def-edebug-spec elmo-msgdb-do-each-entity
956 ((symbolp form &rest form) &rest form))
957 (defmacro elmo-msgdb-do-each-entity (spec &rest form)
958 `(dolist (,(car spec) (elmo-msgdb-get-overview ,(car (cdr spec))))
962 (product-provide (provide 'elmo-msgdb) (require 'elmo-version))
964 ;;; elmo-msgdb.el ends here