1 ;;; modb-entity.el --- Message Entity Interface.
3 ;; Copyright (C) 2003 Yuuichi Teranishi <teranisi@gohome.org>
5 ;; Author: Yuuichi Teranishi <teranisi@gohome.org>
6 ;; Hiroya Murata <lapis-lazuli@pop06.odn.ne.jp>
7 ;; Keywords: mail, net news
9 ;; This file is part of ELMO (Elisp Library for Message Orchestration).
11 ;; This program is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 2, or (at your option)
16 ;; This program is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING. If not, write to the
23 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 ;; Boston, MA 02111-1307, USA.
29 ;; Message entity handling.
33 (eval-when-compile (require 'cl))
40 (luna-define-class modb-entity-handler () (mime-charset))
41 (luna-define-internal-accessors 'modb-entity-handler))
43 (defcustom modb-entity-default-handler 'modb-legacy-entity-handler
44 "Default entity handler."
48 (defcustom modb-entity-field-extractor-alist
49 '((ml-info . modb-entity-extract-mailing-list-info))
50 "*An alist of field name and function to extract field body from buffer."
51 :type '(repeat (cons (symbol :tag "Field Name")
52 (function :tag "Function")))
55 (defvar modb-entity-default-cache-internal nil)
57 (defun elmo-message-entity-handler (&optional entity)
58 "Get modb entity handler instance which corresponds to the ENTITY."
61 (not (eq (car entity) t))
62 (not (stringp (car entity))))
64 (or modb-entity-default-cache-internal
65 (setq modb-entity-default-cache-internal
66 (luna-make-entity modb-entity-default-handler)))))
68 (luna-define-generic modb-entity-handler-list-parameters (handler)
69 "Return a parameter list of HANDLER.")
71 (luna-define-generic elmo-msgdb-make-message-entity (handler &rest args)
72 "Make a message entity using HANDLER.")
74 (luna-define-generic elmo-msgdb-message-entity-number (handler entity)
75 "Number of the ENTITY.")
77 (luna-define-generic elmo-msgdb-message-entity-set-number (handler
79 "Set number of the ENTITY.")
81 (luna-define-generic elmo-msgdb-message-entity-field (handler entity field
83 "Retrieve field value of the message entity.
84 HANDLER is the message entity handler.
85 ENTITY is the message entity structure.
86 FIELD is a symbol of the field.
87 If optional argument TYPE is specified, return converted value.")
89 (luna-define-generic elmo-msgdb-message-entity-set-field (handler
91 "Set the field value of the message entity.
92 HANDLER is the message entity handler.
93 ENTITY is the message entity structure.
94 FIELD is a symbol of the field.
95 VALUE is the field value to set.")
97 (luna-define-generic elmo-msgdb-message-entity-update-fields (handler
99 "Update message entity by VALUES.
100 HANDLER is the message entity handler.
101 ENTITY is the message entity structure.
102 VALUES is an alist of field-name and field-value.")
104 (luna-define-generic elmo-msgdb-copy-message-entity (handler entity
107 "Copy message entity.
108 HANDLER is the message entity handler.
109 ENTITY is the message entity structure.
110 If optional argument MAKE-HANDLER is specified, use it to make new entity.")
112 (luna-define-generic elmo-msgdb-create-message-entity-from-file (handler
115 "Create message entity from file.
116 HANDLER is the message entity handler.
117 NUMBER is the number of the newly created message entity.
118 FILE is the message file.")
120 (luna-define-generic elmo-msgdb-create-message-entity-from-buffer (handler
123 "Create message entity from current buffer.
124 HANDLER is the message entity handler.
125 NUMBER is the number of the newly created message entity.
126 Rest of the ARGS is a plist of message entity field for initial value.
127 Header region is supposed to be narrowed.")
129 ;; Transitional interface.
130 (luna-define-generic elmo-msgdb-message-match-condition (handler
135 "Return non-nil when the entity matches the condition.")
137 ;; Generic implementation.
138 (luna-define-method modb-entity-handler-list-parameters
139 ((handler modb-entity-handler))
140 (list 'mime-charset))
142 (luna-define-method elmo-msgdb-create-message-entity-from-file
143 ((handler modb-entity-handler) number file)
144 (let (insert-file-contents-pre-hook ; To avoid autoconv-xmas...
145 insert-file-contents-post-hook header-end
146 (attrib (file-attributes file))
149 (if (not (file-exists-p file))
151 (setq size (nth 7 attrib))
152 (setq mtime (timezone-make-date-arpa-standard
153 (current-time-string (nth 5 attrib)) (current-time-zone)))
154 ;; insert header from file.
157 (elmo-msgdb-insert-file-header file)
158 (error (throw 'done nil)))
159 (goto-char (point-min))
161 (if (re-search-forward "\\(^--.*$\\)\\|\\(\n\n\\)" nil t)
164 (narrow-to-region (point-min) header-end)
165 (elmo-msgdb-create-message-entity-from-buffer
166 handler number :size size :date mtime))))))
168 (luna-define-method elmo-msgdb-make-message-entity ((handler
173 (luna-define-method elmo-msgdb-message-entity-field ((handler
177 (plist-get (cdr entity) (intern (concat ":" (symbol-name field)))))
179 (luna-define-method elmo-msgdb-message-entity-number ((handler
182 (plist-get (cdr entity) :number))
184 (luna-define-method elmo-msgdb-message-entity-update-fields
185 ((handler modb-entity-handler) entity values)
187 (dolist (pair values)
190 (elmo-msgdb-message-entity-field handler entity (car pair)))
191 (elmo-msgdb-message-entity-set-field handler entity
192 (car pair) (cdr pair))
196 (defun modb-entity-handler-equal-p (handler other)
197 "Return non-nil, if OTHER hanlder is equal this HANDLER."
198 (and (eq (luna-class-name handler)
199 (luna-class-name other))
201 (dolist (slot (modb-entity-handler-list-parameters handler))
202 (when (not (equal (luna-slot-value handler slot)
203 (luna-slot-value other slot)))
204 (throw 'mismatch nil)))
207 (defun modb-entity-handler-dump-parameters (handler)
208 "Return parameters for reconstruct HANDLER as plist."
210 (mapcar (lambda (slot)
211 (let ((value (luna-slot-value handler slot)))
213 (list (intern (concat ":" (symbol-name slot)))
215 (modb-entity-handler-list-parameters handler))))
217 ;; field in/out converter
218 (defun modb-set-field-converter (converter type &rest specs)
219 "Set convert function of TYPE into CONVERTER.
220 SPECS must be like `FIELD1 FUNCTION1 FIELD2 FUNCTION2 ...'.
221 If each field is t, function is set as default converter."
223 (let ((alist (symbol-value converter))
226 (let ((field (pop specs))
227 (function (pop specs))
229 (if (setq cell (assq type alist))
230 (setcdr cell (put-alist field function (cdr cell)))
231 (setq cell (cons type (list (cons field function)))
232 alist (cons cell alist)))
233 ;; support colon keyword (syntax sugar).
234 (unless (or (eq field t)
235 (string-match "^:" (symbol-name field)))
236 (setcdr cell (put-alist (intern (concat ":" (symbol-name field)))
239 (set converter alist))))
240 (put 'modb-set-field-converter 'lisp-indent-function 2)
242 (defsubst modb-convert-field-value (converter field value &optional type)
244 (let* ((alist (cdr (assq (or type t) converter)))
245 (function (cdr (or (assq field alist)
248 (funcall function field value)
252 (defvar elmo-msgdb-decoded-cache-hashtb nil)
253 (make-variable-buffer-local 'elmo-msgdb-decoded-cache-hashtb)
255 (defsubst elmo-msgdb-get-decoded-cache (string)
256 (if elmo-use-decoded-cache
257 (let ((hashtb (or elmo-msgdb-decoded-cache-hashtb
258 (setq elmo-msgdb-decoded-cache-hashtb
259 (elmo-make-hash 2048))))
261 (or (elmo-get-hash-val string hashtb)
264 (elmo-with-enable-multibyte
265 (decode-mime-charset-string string elmo-mime-charset)))
266 (elmo-set-hash-val string decoded hashtb))))
267 (elmo-with-enable-multibyte
268 (decode-mime-charset-string string elmo-mime-charset))))
270 (defun modb-entity-string-decoder (field value)
271 (elmo-msgdb-get-decoded-cache value))
273 (defun modb-entity-string-encoder (field value)
274 (elmo-with-enable-multibyte
275 (encode-mime-charset-string value elmo-mime-charset)))
277 (defun modb-entity-parse-date-string (field value)
279 (elmo-time-parse-date-string value)
282 (defun modb-entity-make-date-string (field value)
285 (elmo-time-make-date-string value)))
287 (defun modb-entity-mime-decoder (field value)
288 (mime-decode-field-body value (symbol-name field) 'summary))
290 (defun modb-entity-mime-encoder (field value)
291 (mime-encode-field-body value (symbol-name field)))
293 (defun modb-entity-address-list-decoder (field value)
295 (mapcar (lambda (address)
296 (mime-decode-field-body address (symbol-name field)))
297 (elmo-parse-addresses value))
300 (defun modb-entity-address-list-encoder (field value)
303 (mime-encode-field-body (mapconcat 'identity value ", ")
304 (symbol-name field))))
306 (defun modb-entity-parse-address-string (field value)
307 (modb-entity-encode-string-recursive
310 (elmo-parse-addresses value)
313 (defun modb-entity-make-address-string (field value)
314 (let ((value (modb-entity-decode-string-recursive field value)))
317 (mapconcat 'identity value ", "))))
319 (defun modb-entity-decode-string-recursive (field value)
320 (cond ((stringp value)
321 (elmo-msgdb-get-decoded-cache value))
323 (setcar value (modb-entity-decode-string-recursive field (car value)))
324 (setcdr value (modb-entity-decode-string-recursive field (cdr value)))
329 (defun modb-entity-encode-string-recursive (field value)
330 (cond ((stringp value)
331 (elmo-with-enable-multibyte
332 (encode-mime-charset-string value elmo-mime-charset)))
334 (setcar value (modb-entity-encode-string-recursive field (car value)))
335 (setcdr value (modb-entity-encode-string-recursive field (cdr value)))
341 (defun modb-entity-create-field-indices (slots)
345 (setq indices (cons (cons (car slots) index) indices)
350 (mapcar (lambda (cell)
351 (cons (intern (concat ":" (symbol-name (car cell))))
356 ;; Legacy implementation.
358 (luna-define-class modb-legacy-entity-handler (modb-entity-handler)))
360 (defconst modb-legacy-entity-field-slots
371 (defconst modb-legacy-entity-field-indices
372 (modb-entity-create-field-indices modb-legacy-entity-field-slots))
374 (defvar modb-legacy-entity-normalizer nil)
375 (modb-set-field-converter 'modb-legacy-entity-normalizer nil
379 'from #'modb-entity-string-encoder
380 'subject #'modb-entity-string-encoder
381 'date #'modb-entity-make-date-string
382 'to #'modb-entity-address-list-encoder
383 'cc #'modb-entity-address-list-encoder
385 t #'modb-entity-mime-encoder)
387 (defvar modb-legacy-entity-specializer nil)
389 (modb-set-field-converter 'modb-legacy-entity-specializer nil
393 'from #'modb-entity-string-decoder
394 'subject #'modb-entity-string-decoder
395 'date #'modb-entity-parse-date-string
396 'to #'modb-entity-address-list-decoder
397 'cc #'modb-entity-address-list-decoder
399 t #'modb-entity-mime-decoder)
401 (modb-set-field-converter 'modb-legacy-entity-specializer 'string
403 'number nil ; not supported
405 'from #'modb-entity-string-decoder
406 'subject #'modb-entity-string-decoder
408 'size nil ; not supported
409 t #'modb-entity-mime-decoder)
412 (defmacro modb-legacy-entity-field-index (field)
413 `(cdr (assq ,field modb-legacy-entity-field-indices)))
415 (defsubst modb-legacy-entity-set-field (entity field value &optional as-is)
419 (setq value (modb-convert-field-value
420 modb-legacy-entity-normalizer
422 (cond ((memq field '(message-id :message-id))
423 (setcar entity value))
424 ((setq index (modb-legacy-entity-field-index field))
425 (aset (cdr entity) index value))
427 (setq index (modb-legacy-entity-field-index :extra))
428 (let ((extras (and entity (aref (cdr entity) index)))
430 (if (setq extra (assoc (symbol-name field) extras))
432 (aset (cdr entity) index (cons (cons (symbol-name field)
433 value) extras)))))))))
435 (defsubst modb-legacy-make-message-entity (args)
436 "Make an message entity."
437 (let ((entity (cons nil (make-vector 9 nil)))
440 (setq field (pop args)
443 (modb-legacy-entity-set-field entity field value)))
446 (luna-define-method elmo-msgdb-make-message-entity
447 ((handler modb-legacy-entity-handler) args)
448 (modb-legacy-make-message-entity args))
450 (luna-define-method elmo-msgdb-create-message-entity-from-buffer
451 ((handler modb-legacy-entity-handler) number args)
452 (let ((extras elmo-msgdb-extra-fields)
453 (default-mime-charset default-mime-charset)
454 entity message-id references from subject to cc date
455 extra field-body charset size)
457 (setq entity (modb-legacy-make-message-entity args))
458 (set-buffer-multibyte default-enable-multibyte-characters)
459 (setq message-id (elmo-msgdb-get-message-id-from-buffer))
460 (and (setq charset (cdr (assoc "charset" (mime-read-Content-Type))))
461 (setq charset (intern-soft charset))
462 (setq default-mime-charset charset))
464 (elmo-msgdb-get-references-from-buffer)
465 from (elmo-replace-in-string
466 (elmo-mime-string (or (elmo-field-body "from")
469 subject (elmo-replace-in-string
470 (elmo-mime-string (or (elmo-field-body "subject")
473 date (elmo-decoded-field-body "date")
474 to (mapconcat 'identity (elmo-multiple-field-body "to") ",")
475 cc (mapconcat 'identity (elmo-multiple-field-body "cc") ","))
476 (unless (elmo-msgdb-message-entity-field handler entity 'size)
477 (if (setq size (elmo-field-body "content-length"))
478 (setq size (string-to-int size))
481 (if (setq field-body (elmo-field-body (car extras)))
482 (modb-legacy-entity-set-field
483 entity (intern (downcase (car extras))) field-body 'as-is))
484 (setq extras (cdr extras)))
485 (dolist (field '(message-id number references from subject
487 (when (symbol-value field)
488 (modb-legacy-entity-set-field
489 entity field (symbol-value field) 'as-is)))
492 (luna-define-method elmo-msgdb-message-entity-number
493 ((handler modb-legacy-entity-handler) entity)
494 (and entity (aref (cdr entity) 0)))
496 (luna-define-method elmo-msgdb-message-entity-set-number
497 ((handler modb-legacy-entity-handler) entity number)
498 (and entity (aset (cdr entity) 0 number))
501 (luna-define-method elmo-msgdb-message-entity-field
502 ((handler modb-legacy-entity-handler) entity field &optional type)
505 (modb-convert-field-value
506 modb-legacy-entity-specializer
508 (cond ((memq field '(message-id :message-id))
510 ((setq index (modb-legacy-entity-field-index field))
511 (aref (cdr entity) index))
513 (setq index (modb-legacy-entity-field-index :extra))
514 (cdr (assoc (symbol-name field)
515 (aref (cdr entity) index)))))
518 (luna-define-method elmo-msgdb-message-entity-set-field
519 ((handler modb-legacy-entity-handler) entity field value)
520 (modb-legacy-entity-set-field entity field value))
522 (luna-define-method elmo-msgdb-copy-message-entity
523 ((handler modb-legacy-entity-handler) entity &optional make-handler)
525 (let ((copy (elmo-msgdb-make-message-entity make-handler)))
526 (dolist (field (append '(message-id number references from subject
528 (mapcar (lambda (extra) (intern (car extra)))
529 (aref (cdr entity) 8))))
530 (elmo-msgdb-message-entity-set-field
531 make-handler copy field
532 (elmo-msgdb-message-entity-field handler entity field)))
535 (copy-sequence (cdr entity)))))
537 (luna-define-method elmo-msgdb-message-match-condition
538 ((handler modb-entity-handler) condition entity flags numbers)
541 (elmo-msgdb-match-condition-primitive handler condition
542 entity flags numbers))
543 ((eq (car condition) 'and)
544 (let ((lhs (elmo-msgdb-message-match-condition handler
546 entity flags numbers)))
548 ((elmo-filter-condition-p lhs)
549 (let ((rhs (elmo-msgdb-message-match-condition
550 handler (nth 2 condition) entity flags numbers)))
551 (cond ((elmo-filter-condition-p rhs)
556 (elmo-msgdb-message-match-condition handler (nth 2 condition)
557 entity flags numbers)))))
558 ((eq (car condition) 'or)
559 (let ((lhs (elmo-msgdb-message-match-condition handler (nth 1 condition)
560 entity flags numbers)))
562 ((elmo-filter-condition-p lhs)
563 (let ((rhs (elmo-msgdb-message-match-condition handler
565 entity flags numbers)))
566 (cond ((elmo-filter-condition-p rhs)
575 (elmo-msgdb-message-match-condition handler
577 entity flags numbers)))))))
580 (defun elmo-msgdb-match-condition-primitive (handler
586 (let ((key (elmo-filter-key condition))
590 ((string= key "last")
591 (setq result (<= (length (memq
592 (elmo-msgdb-message-entity-number
595 (string-to-int (elmo-filter-value condition)))))
596 ((string= key "first")
600 (elmo-msgdb-message-entity-number
603 (string-to-int (elmo-filter-value condition)))))
604 ((string= key "flag")
607 ((string= (elmo-filter-value condition) "any")
608 (or (memq 'important flags)
609 (memq 'answered flags)
610 (memq 'unread flags)))
611 ((string= (elmo-filter-value condition) "digest")
612 (or (memq 'important flags)
613 (memq 'unread flags)))
614 ((string= (elmo-filter-value condition) "unread")
615 (memq 'unread flags))
616 ((string= (elmo-filter-value condition) "important")
617 (memq 'important flags))
618 ((string= (elmo-filter-value condition) "answered")
619 (memq 'answered flags)))))
620 ((string= key "from")
621 (setq result (string-match
622 (elmo-filter-value condition)
623 (elmo-msgdb-message-entity-field
624 handler entity 'from))))
625 ((string= key "subject")
626 (setq result (string-match
627 (elmo-filter-value condition)
628 (elmo-msgdb-message-entity-field
629 handler entity 'subject))))
631 (setq result (string-match
632 (elmo-filter-value condition)
633 (elmo-msgdb-message-entity-field
634 handler entity 'to 'string))))
636 (setq result (string-match
637 (elmo-filter-value condition)
638 (elmo-msgdb-message-entity-field
639 handler entity 'cc 'string))))
640 ((or (string= key "since")
641 (string= key "before"))
642 (let ((field-date (elmo-msgdb-message-entity-field
643 handler entity 'date))
645 (elmo-datevec-to-time
646 (elmo-date-get-datevec
647 (elmo-filter-value condition)))))
648 (setq result (if (string= key "since")
649 (not (elmo-time< field-date specified-date))
650 (elmo-time< field-date specified-date)))))
651 ((member key elmo-msgdb-extra-fields)
652 (let ((extval (elmo-msgdb-message-entity-field handler
656 (when (stringp extval)
657 (setq result (string-match
658 (elmo-filter-value condition)
661 (throw 'unresolved condition)))
662 (if (eq (elmo-filter-type condition) 'unmatch)
667 ;; Standard implementation.
669 (luna-define-class modb-standard-entity-handler (modb-entity-handler)))
671 (defconst modb-standard-entity-field-slots
684 (defconst modb-standard-entity-field-indices
685 (modb-entity-create-field-indices modb-standard-entity-field-slots))
687 (defvar modb-standard-entity-normalizer nil)
688 (modb-set-field-converter 'modb-standard-entity-normalizer nil
691 'date #'modb-entity-parse-date-string
692 'to #'modb-entity-parse-address-string
693 'cc #'modb-entity-parse-address-string
697 t #'modb-entity-encode-string-recursive)
699 (defvar modb-standard-entity-specializer nil)
700 (modb-set-field-converter 'modb-standard-entity-specializer nil
707 t #'modb-entity-decode-string-recursive)
708 (modb-set-field-converter 'modb-standard-entity-specializer 'string
711 'date #'modb-entity-make-date-string
712 'to #'modb-entity-make-address-string
713 'cc #'modb-entity-make-address-string
717 'ml-info #'modb-entity-make-mailing-list-info-string
718 t #'modb-entity-decode-string-recursive)
720 (defmacro modb-standard-entity-field-index (field)
721 `(cdr (assq ,field modb-standard-entity-field-indices)))
723 (defsubst modb-standard-entity-set-field (entity field value &optional as-is)
727 (let ((elmo-mime-charset
728 (or (modb-entity-handler-mime-charset-internal (car entity))
730 (setq value (modb-convert-field-value modb-standard-entity-normalizer
732 (cond ((memq field '(message-id :message-id))
733 (setcar (cdr entity) value))
734 ((setq index (modb-standard-entity-field-index field))
735 (aset (cdr (cdr entity)) index value))
737 (setq index (modb-standard-entity-field-index :extra))
738 (let ((extras (aref (cdr (cdr entity)) index))
740 (if (setq cell (assq field extras))
742 (aset (cdr (cdr entity))
744 (cons (cons field value) extras)))))))))
746 (defsubst modb-standard-make-message-entity (handler args)
747 (let ((entity (cons handler
750 (length modb-standard-entity-field-slots)
754 (setq field (pop args)
757 (modb-standard-entity-set-field entity field value)))
760 (luna-define-method elmo-msgdb-make-message-entity
761 ((handler modb-standard-entity-handler) args)
762 (modb-standard-make-message-entity handler args))
764 (luna-define-method elmo-msgdb-message-entity-number
765 ((handler modb-standard-entity-handler) entity)
766 (and entity (aref (cdr (cdr entity)) 0)))
768 (luna-define-method elmo-msgdb-message-entity-set-number
769 ((handler modb-standard-entity-handler) entity number)
770 (and entity (aset (cdr (cdr entity)) 0 number)))
772 (luna-define-method elmo-msgdb-message-entity-field
773 ((handler modb-standard-entity-handler) entity field &optional type)
775 (let ((elmo-mime-charset
776 (or (modb-entity-handler-mime-charset-internal handler)
779 (modb-convert-field-value
780 modb-standard-entity-specializer
782 (cond ((memq field '(message-id :message-id))
784 ((setq index (modb-standard-entity-field-index field))
785 (aref (cdr (cdr entity)) index))
787 (setq index (modb-standard-entity-field-index :extra))
788 (cdr (assq field (aref (cdr (cdr entity)) index)))))
791 (luna-define-method elmo-msgdb-message-entity-set-field
792 ((handler modb-standard-entity-handler) entity field value)
793 (modb-standard-entity-set-field entity field value))
795 (luna-define-method elmo-msgdb-copy-message-entity
796 ((handler modb-standard-entity-handler) entity &optional make-handler)
798 (let ((copy (elmo-msgdb-make-message-entity make-handler)))
799 (dolist (field (nconc
801 (copy-sequence modb-standard-entity-field-slots))
805 (modb-standard-entity-field-index :extra)))
807 (elmo-msgdb-message-entity-set-field
808 make-handler copy field
809 (elmo-msgdb-message-entity-field handler entity field)))
812 (cons (car (cdr entity))
813 (copy-sequence (cdr (cdr entity)))))))
815 (luna-define-method elmo-msgdb-create-message-entity-from-buffer
816 ((handler modb-standard-entity-handler) number args)
817 (let ((default-mime-charset default-mime-charset)
818 entity content-type charset)
820 (set-buffer-multibyte default-enable-multibyte-characters)
821 (and (setq content-type (elmo-decoded-field-body
822 "content-type" 'summary))
823 (setq charset (mime-content-type-parameter
824 (mime-parse-Content-Type content-type) "charset"))
825 (setq charset (intern-soft charset))
826 (mime-charset-p charset)
827 (setq default-mime-charset charset))
829 (modb-standard-make-message-entity
837 (elmo-msgdb-get-message-id-from-buffer)
839 (elmo-msgdb-get-references-from-buffer)
841 (elmo-replace-in-string
842 (or (elmo-decoded-field-body "from" 'summary)
846 (elmo-replace-in-string
847 (or (elmo-decoded-field-body "subject" 'summary)
851 (elmo-decoded-field-body "date" 'summary)
855 (mime-decode-field-body field-body "to" 'summary))
856 (elmo-multiple-field-body "to") ",")
860 (mime-decode-field-body field-body "cc" 'summary))
861 (elmo-multiple-field-body "cc") ",")
865 (let ((size (elmo-field-body "content-length")))
868 (or (plist-get args :size) 0)))))))
869 (let (field-name field-body extractor)
870 (dolist (extra (cons "newsgroups" elmo-msgdb-extra-fields))
871 (setq field-name (intern (downcase extra))
872 extractor (cdr (assq field-name
873 modb-entity-field-extractor-alist))
874 field-body (if extractor
875 (funcall extractor field-name)
876 (elmo-decoded-field-body extra 'summary)))
878 (modb-standard-entity-set-field entity field-name field-body))))
882 ;; mailing list info handling
883 (defun modb-entity-extract-ml-info-from-x-sequence ()
884 (let ((sequence (elmo-decoded-field-body "x-sequence" 'summary))
887 (elmo-set-list '(name count) (split-string sequence " "))
890 (defun modb-entity-extract-ml-info-from-subject ()
891 (let ((subject (elmo-decoded-field-body "subject" 'summary)))
893 (string-match "^\\s(\\(\\S)+\\)[ :]\\([0-9]+\\)\\s)[ \t]*"
895 (cons (match-string 1 subject) (match-string 2 subject)))))
897 (defun modb-entity-extract-ml-info-from-return-path ()
898 (let ((return-path (elmo-decoded-field-body "return-path" 'summary)))
899 (when (and return-path
900 (string-match "^<\\([^@>]+\\)-return-\\([0-9]+\\)-"
902 (cons (match-string 1 return-path)
903 (match-string 2 return-path)))))
905 (defun modb-entity-extract-ml-info-from-delivered-to ()
906 (let ((delivered-to (elmo-decoded-field-body "delivered-to" 'summary)))
907 (when (and delivered-to
908 (string-match "^mailing list \\([^@]+\\)@" delivered-to))
909 (cons (match-string 1 delivered-to) nil))))
911 (defun modb-entity-extract-ml-info-from-mailing-list ()
912 (let ((mailing-list (elmo-decoded-field-body "mailing-list" 'summary)))
913 ;; *-help@, *-owner@, etc.
914 (when (and mailing-list
915 (string-match "\\(^\\|; \\)contact \\([^@]+\\)-[^-@]+@"
917 (cons (match-string 2 mailing-list) nil))))
919 (defvar modb-entity-extract-mailing-list-info-functions
920 '(modb-entity-extract-ml-info-from-x-sequence
921 modb-entity-extract-ml-info-from-subject
922 modb-entity-extract-ml-info-from-return-path
923 modb-entity-extract-ml-info-from-delivered-to
924 modb-entity-extract-ml-info-from-mailing-list))
926 (defun modb-entity-extract-mailing-list-info (field)
927 (let ((ml-name (elmo-decoded-field-body "x-ml-name" 'summary))
928 (ml-count (or (elmo-decoded-field-body "x-mail-count" 'summary)
929 (elmo-decoded-field-body "x-ml-count" 'summary)))
930 (functions modb-entity-extract-mailing-list-info-functions)
932 (while (and functions
933 (or (null ml-name) (null ml-count)))
934 (when (setq result (funcall (car functions)))
936 (setq ml-name (car result)))
938 (setq ml-count (cdr result))))
939 (setq functions (cdr functions)))
940 (when (or ml-name ml-count)
941 (cons (and ml-name (car (split-string ml-name " ")))
942 (and ml-count (string-to-int ml-count))))))
944 (defun modb-entity-make-mailing-list-info-string (field value)
946 (format (if (cdr value) "(%s %05.0f)" "(%s)")
947 (elmo-msgdb-get-decoded-cache (car value))
951 (product-provide (provide 'modb-entity) (require 'elmo-version))
953 ;;; modb-entity.el ends here