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))
39 (eval-and-compile (luna-define-class modb-entity-handler))
41 (defcustom modb-entity-default-handler 'modb-legacy-entity-handler
42 "Default entity handler."
46 (defvar modb-entity-default-cache-internal nil)
48 (defun elmo-message-entity-handler (&optional entity)
49 "Get modb entity handler instance which corresponds to the ENTITY."
52 (not (eq (car entity) t))
53 (not (stringp (car entity))))
55 (or modb-entity-default-cache-internal
56 (setq modb-entity-default-cache-internal
57 (luna-make-entity modb-entity-default-handler)))))
59 (luna-define-generic elmo-msgdb-make-message-entity (handler &rest args)
60 "Make a message entity using HANDLER.")
62 (luna-define-generic elmo-msgdb-message-entity-number (handler entity)
63 "Number of the ENTITY.")
65 (luna-define-generic elmo-msgdb-message-entity-set-number (handler
67 "Set number of the ENTITY.")
69 (luna-define-generic elmo-msgdb-message-entity-field (handler
72 "Retrieve field value of the message entity.
73 HANDLER is the message entity handler.
74 ENTITY is the message entity structure.
75 FIELD is a symbol of the field.
76 If optional DECODE is no-nil, the field value is decoded.")
78 (luna-define-generic elmo-msgdb-message-entity-set-field (handler
80 "Set the field value of the message entity.
81 HANDLER is the message entity handler.
82 ENTITY is the message entity structure.
83 FIELD is a symbol of the field.
84 VALUE is the field value to set.")
86 (luna-define-generic elmo-msgdb-copy-message-entity (handler entity)
88 HANDLER is the message entity handler.
89 ENTITY is the message entity structure.")
91 (luna-define-generic elmo-msgdb-create-message-entity-from-file (handler
94 "Create message entity from file.
95 HANDLER is the message entity handler.
96 NUMBER is the number of the newly created message entity.
97 FILE is the message file.")
99 (luna-define-generic elmo-msgdb-create-message-entity-from-buffer (handler
102 "Create message entity from current buffer.
103 HANDLER is the message entity handler.
104 NUMBER is the number of the newly created message entity.
105 Rest of the ARGS is a plist of message entity field for initial value.
106 Header region is supposed to be narrowed.")
108 ;; Transitional interface.
109 (luna-define-generic elmo-msgdb-message-match-condition (handler
114 "Return non-nil when the entity matches the condition.")
116 ;; Generic implementation.
117 (luna-define-method elmo-msgdb-create-message-entity-from-file
118 ((handler modb-entity-handler) number file)
119 (let (insert-file-contents-pre-hook ; To avoid autoconv-xmas...
120 insert-file-contents-post-hook header-end
121 (attrib (file-attributes file))
124 (if (not (file-exists-p file))
126 (setq size (nth 7 attrib))
127 (setq mtime (timezone-make-date-arpa-standard
128 (current-time-string (nth 5 attrib)) (current-time-zone)))
129 ;; insert header from file.
132 (elmo-msgdb-insert-file-header file)
133 (error (throw 'done nil)))
134 (goto-char (point-min))
136 (if (re-search-forward "\\(^--.*$\\)\\|\\(\n\n\\)" nil t)
139 (narrow-to-region (point-min) header-end)
140 (elmo-msgdb-create-message-entity-from-buffer
141 handler number :size size :date mtime))))))
143 (luna-define-method elmo-msgdb-make-message-entity ((handler
148 (luna-define-method elmo-msgdb-message-entity-field ((handler
152 (plist-get (cdr entity) (intern (concat ":" (symbol-name field)))))
154 (luna-define-method elmo-msgdb-message-entity-number ((handler
157 (plist-get (cdr entity) :number))
159 ;; Legacy implementation.
160 (eval-and-compile (luna-define-class modb-legacy-entity-handler
161 (modb-entity-handler)))
166 (defvar elmo-msgdb-decoded-cache-hashtb nil)
167 (make-variable-buffer-local 'elmo-msgdb-decoded-cache-hashtb)
169 (defsubst elmo-msgdb-get-decoded-cache (string)
170 (if elmo-use-decoded-cache
171 (let ((hashtb (or elmo-msgdb-decoded-cache-hashtb
172 (setq elmo-msgdb-decoded-cache-hashtb
173 (elmo-make-hash 2048))))
175 (or (elmo-get-hash-val string hashtb)
180 (decode-mime-charset-string string elmo-mime-charset))
183 (decode-mime-charset-string string elmo-mime-charset)))
185 (defsubst modb-legacy-make-message-entity (args)
186 "Make an message entity."
187 (cons (plist-get args :message-id)
188 (vector (plist-get args :number)
189 (plist-get args :references)
190 (plist-get args :from)
191 (plist-get args :subject)
192 (plist-get args :date)
195 (plist-get args :size)
196 (plist-get args :extra))))
198 (luna-define-method elmo-msgdb-make-message-entity
199 ((handler modb-legacy-entity-handler) args)
200 (modb-legacy-make-message-entity args))
202 (luna-define-method elmo-msgdb-create-message-entity-from-buffer
203 ((handler modb-legacy-entity-handler) number args)
204 (let ((extras elmo-msgdb-extra-fields)
205 (default-mime-charset default-mime-charset)
206 entity message-id references from subject to cc date
207 extra field-body charset size)
209 (setq entity (modb-legacy-make-message-entity args))
210 (set-buffer-multibyte default-enable-multibyte-characters)
211 (setq message-id (elmo-msgdb-get-message-id-from-buffer))
212 (and (setq charset (cdr (assoc "charset" (mime-read-Content-Type))))
213 (setq charset (intern-soft charset))
214 (setq default-mime-charset charset))
216 (or (elmo-msgdb-get-last-message-id
217 (elmo-field-body "in-reply-to"))
218 (elmo-msgdb-get-last-message-id
219 (elmo-field-body "references")))
220 from (elmo-replace-in-string
221 (elmo-mime-string (or (elmo-field-body "from")
224 subject (elmo-replace-in-string
225 (elmo-mime-string (or (elmo-field-body "subject")
228 date (elmo-unfold-field-body "date")
229 to (mapconcat 'identity (elmo-multiple-field-body "to") ",")
230 cc (mapconcat 'identity (elmo-multiple-field-body "cc") ","))
231 (unless (elmo-msgdb-message-entity-field handler entity 'size)
232 (if (setq size (elmo-field-body "content-length"))
233 (setq size (string-to-int size))
236 (if (setq field-body (elmo-field-body (car extras)))
237 (elmo-msgdb-message-entity-set-field
238 handler entity (intern (downcase (car extras))) field-body))
239 (setq extras (cdr extras)))
240 (dolist (field '(message-id number references from subject
242 (when (symbol-value field)
243 (elmo-msgdb-message-entity-set-field
244 handler entity field (symbol-value field))))
247 (luna-define-method elmo-msgdb-message-entity-number
248 ((handler modb-legacy-entity-handler) entity)
249 (and entity (aref (cdr entity) 0)))
251 (luna-define-method elmo-msgdb-message-entity-set-number
252 ((handler modb-legacy-entity-handler) entity number)
253 (and entity (aset (cdr entity) 0 number))
256 (luna-define-method elmo-msgdb-message-entity-field
257 ((handler modb-legacy-entity-handler) entity field &optional decode)
261 (to (aref (cdr entity) 5))
262 (cc (aref (cdr entity) 6))
263 (date (aref (cdr entity) 4))
264 (subject (aref (cdr entity) 3))
265 (from (aref (cdr entity) 2))
266 (message-id (car entity))
267 (references (aref (cdr entity) 1))
268 (size (aref (cdr entity) 7))
269 (t (cdr (assoc (symbol-name field) (aref (cdr entity) 8)))))))
270 (if (and decode (memq field '(from subject)))
271 (elmo-msgdb-get-decoded-cache field-value)
274 (luna-define-method elmo-msgdb-message-entity-set-field
275 ((handler modb-legacy-entity-handler) entity field value)
278 (number (aset (cdr entity) 0 value))
279 (to (aset (cdr entity) 5 value))
280 (cc (aset (cdr entity) 6 value))
281 (date (aset (cdr entity) 4 value))
282 (subject (aset (cdr entity) 3 value))
283 (from (aset (cdr entity) 2 value))
284 (message-id (setcar entity value))
285 (references (aset (cdr entity) 1 value))
286 (size (aset (cdr entity) 7 value))
288 (let ((extras (and entity (aref (cdr entity) 8)))
290 (if (setq extra (assoc (symbol-name field) extras))
292 (aset (cdr entity) 8 (cons (cons (symbol-name field)
293 value) extras))))))))
295 (luna-define-method elmo-msgdb-copy-message-entity
296 ((handler modb-legacy-entity-handler) entity)
298 (copy-sequence (cdr entity))))
300 (luna-define-method elmo-msgdb-message-match-condition
301 ((handler modb-legacy-entity-handler) condition entity flags numbers)
304 (elmo-msgdb-match-condition-primitive handler condition
305 entity flags numbers))
306 ((eq (car condition) 'and)
307 (let ((lhs (elmo-msgdb-message-match-condition handler
309 entity flags numbers)))
311 ((elmo-filter-condition-p lhs)
312 (let ((rhs (elmo-msgdb-message-match-condition
313 handler (nth 2 condition) entity flags numbers)))
314 (cond ((elmo-filter-condition-p rhs)
319 (elmo-msgdb-message-match-condition handler (nth 2 condition)
320 entity flags numbers)))))
321 ((eq (car condition) 'or)
322 (let ((lhs (elmo-msgdb-message-match-condition handler (nth 1 condition)
323 entity flags numbers)))
325 ((elmo-filter-condition-p lhs)
326 (let ((rhs (elmo-msgdb-message-match-condition handler
328 entity flags numbers)))
329 (cond ((elmo-filter-condition-p rhs)
338 (elmo-msgdb-message-match-condition handler
340 entity flags numbers)))))))
343 (defun elmo-msgdb-match-condition-primitive (handler
349 (let ((key (elmo-filter-key condition))
353 ((string= key "last")
354 (setq result (<= (length (memq
355 (elmo-msgdb-message-entity-number
358 (string-to-int (elmo-filter-value condition)))))
359 ((string= key "first")
363 (elmo-msgdb-message-entity-number
366 (string-to-int (elmo-filter-value condition)))))
367 ((string= key "flag")
370 ((string= (elmo-filter-value condition) "any")
371 (or (memq 'important flags)
372 (memq 'answered flags)
373 (memq 'unread flags)))
374 ((string= (elmo-filter-value condition) "digest")
375 (or (memq 'important flags)
376 (memq 'unread flags)))
377 ((string= (elmo-filter-value condition) "unread")
378 (memq 'unread flags))
379 ((string= (elmo-filter-value condition) "important")
380 (memq 'important flags))
381 ((string= (elmo-filter-value condition) "answered")
382 (memq 'answered flags)))))
383 ((string= key "from")
384 (setq result (string-match
385 (elmo-filter-value condition)
386 (elmo-msgdb-message-entity-field
387 handler entity 'from t))))
388 ((string= key "subject")
389 (setq result (string-match
390 (elmo-filter-value condition)
391 (elmo-msgdb-message-entity-field
392 handler entity 'subject t))))
394 (setq result (string-match
395 (elmo-filter-value condition)
396 (elmo-msgdb-message-entity-field
397 handler entity 'to))))
399 (setq result (string-match
400 (elmo-filter-value condition)
401 (elmo-msgdb-message-entity-field
402 handler entity 'cc))))
403 ((or (string= key "since")
404 (string= key "before"))
405 (let ((field-date (elmo-date-make-sortable-string
407 (elmo-msgdb-message-entity-field
408 handler entity 'date)
409 (current-time-zone) nil)))
411 (elmo-date-make-sortable-string
412 (elmo-date-get-datevec
413 (elmo-filter-value condition)))))
414 (setq result (if (string= key "since")
415 (or (string= specified-date field-date)
416 (string< specified-date field-date))
417 (string< field-date specified-date)))))
418 ((member key elmo-msgdb-extra-fields)
419 (let ((extval (elmo-msgdb-message-entity-field handler
422 (when (stringp extval)
423 (setq result (string-match
424 (elmo-filter-value condition)
427 (throw 'unresolved condition)))
428 (if (eq (elmo-filter-type condition) 'unmatch)
433 (product-provide (provide 'modb-entity) (require 'elmo-version))
435 ;;; modb-entity.el ends here