Remove empty entity files from modb cache.
[elisp/wanderlust.git] / elmo / modb-standard.el
1 ;;; modb-standard.el --- Standartd Implement of MODB.
2
3 ;; Copyright (C) 2003 Yuuichi Teranishi <teranisi@gohome.org>
4
5 ;; Author: Yuuichi Teranishi <teranisi@gohome.org>
6 ;;      Hiroya Murata <lapis-lazuli@pop06.odn.ne.jp>
7 ;; Keywords: mail, net news
8
9 ;; This file is part of ELMO (Elisp Library for Message Orchestration).
10
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)
14 ;; any later version.
15 ;;
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.
20 ;;
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.
25 ;;
26
27 ;;; Commentary:
28 ;;
29
30 ;;; Code:
31 ;;
32 (eval-when-compile (require 'cl))
33
34 (require 'elmo-util)
35 (require 'modb)
36
37 (defcustom modb-standard-divide-number 500
38   "*Standard modb divide entity number."
39   :type '(choice (const :tag "Not divide" nil)
40                  number)
41   :group 'elmo)
42
43 (defvar modb-standard-entity-filename "entity"
44   "Message entity database.")
45
46 (defvar modb-standard-flag-filename "flag"
47   "Message number <=> Flag status database.")
48
49 (defvar modb-standard-msgid-filename "msgid"
50   "Message number <=> Message-Id database.")
51
52 (eval-and-compile
53   (luna-define-class modb-standard (modb-generic)
54                      (number-list       ; sorted list of message numbers.
55                       entity-map        ; number, msg-id -> entity mapping.
56                       flag-map          ; number -> flag-list mapping
57                       flag-count        ; list of (FLAG . COUNT)
58                       overview-handler  ; instance of modb-entity-handler.
59                       ))
60   (luna-define-internal-accessors 'modb-standard))
61
62 ;; for internal use only
63 (defsubst modb-standard-key (number)
64   (concat "#" (number-to-string number)))
65
66 (defsubst modb-standard-entity-id (entity)
67   (if (eq 'autoload (car-safe entity))
68       (cddr entity)
69     (elmo-msgdb-message-entity-field
70      (elmo-message-entity-handler entity)
71      entity 'message-id)))
72
73 (defsubst modb-standard-entity-map (modb)
74   (or (modb-standard-entity-map-internal modb)
75       (modb-standard-set-entity-map-internal
76        modb
77        (elmo-make-hash (elmo-msgdb-length modb)))))
78
79 (defsubst modb-standard-flag-map (modb)
80   (or (modb-standard-flag-map-internal modb)
81       (modb-standard-set-flag-map-internal
82        modb
83        (elmo-make-hash (elmo-msgdb-length modb)))))
84
85 (defsubst modb-standard-set-message-modified (modb number)
86   (if modb-standard-divide-number
87       (let ((section (/ number modb-standard-divide-number))
88             (modified (modb-generic-message-modified-internal modb)))
89         (unless (memq section modified)
90           (modb-generic-set-message-modified-internal
91            modb (cons section modified))))
92     (modb-generic-set-message-modified-internal modb t)))
93
94 (defsubst modb-standard-set-flag-modified (modb number)
95   (modb-generic-set-flag-modified-internal modb t))
96
97 (defsubst modb-standard-message-flags (modb number)
98   (cdr (elmo-get-hash-val (modb-standard-key number)
99                           (modb-standard-flag-map-internal modb))))
100
101 (defsubst modb-standard-match-flags (check-flags flags)
102   (catch 'done
103     (while check-flags
104       (when (memq (car check-flags) flags)
105         (throw 'done t))
106       (setq check-flags (cdr check-flags)))))
107
108 (defsubst modb-standard-countup-flags (modb flags &optional delta)
109   (let ((flag-count (modb-standard-flag-count-internal modb))
110         (delta (or delta 1))
111         elem)
112     (dolist (flag flags)
113       (if (setq elem (assq flag flag-count))
114           (setcdr elem (+ (cdr elem) delta))
115         (setq flag-count (cons (cons flag delta) flag-count))))
116     (modb-standard-set-flag-count-internal modb flag-count)))
117
118 ;; save and load functions
119 (defun modb-standard-load-msgid (modb path)
120   (let* ((alist (elmo-object-load
121                  (expand-file-name modb-standard-msgid-filename path)))
122          (table (or (modb-standard-entity-map-internal modb)
123                     (elmo-make-hash (length alist))))
124          numbers info)
125     (dolist (pair alist)
126       (setq info (cons 'autoload pair))
127       (elmo-set-hash-val (modb-standard-key (car pair)) info table)
128       (elmo-set-hash-val (cdr pair) info table)
129       (setq numbers (cons (car pair) numbers)))
130     (modb-standard-set-number-list-internal modb (nreverse numbers))
131     (modb-standard-set-entity-map-internal modb table)))
132
133 (defun modb-standard-save-msgid (modb path)
134   (let ((table (modb-standard-entity-map-internal modb))
135         entity alist)
136     (dolist (number (modb-standard-number-list-internal modb))
137       (setq entity (elmo-get-hash-val (modb-standard-key number) table))
138       (setq alist (cons (cons number (modb-standard-entity-id entity))
139                         alist)))
140     (elmo-object-save
141      (expand-file-name modb-standard-msgid-filename path)
142      (nreverse alist))))
143
144 (defun modb-standard-load-flag (modb path)
145   (let ((table (or (modb-standard-flag-map-internal modb)
146                    (elmo-make-hash (elmo-msgdb-length modb)))))
147     (dolist (info (elmo-object-load
148                    (expand-file-name modb-standard-flag-filename path)))
149       (modb-standard-countup-flags modb (cdr info))
150       (elmo-set-hash-val (modb-standard-key (car info)) info table))
151     (modb-standard-set-flag-map-internal modb table)))
152
153 (defun modb-standard-save-flag (modb path)
154   (let (table flist info)
155     (when (setq table (modb-standard-flag-map-internal modb))
156       (mapatoms
157        (lambda (atom)
158          (setq info (symbol-value atom))
159          (when (cdr info)
160            (setq flist (cons info flist))))
161        table))
162     (elmo-object-save
163      (expand-file-name modb-standard-flag-filename path)
164      flist)))
165
166 (defsubst modb-standard-entity-filename (section)
167   (if section
168       (concat modb-standard-entity-filename
169               "-"
170               (number-to-string section))
171     modb-standard-entity-filename))
172
173 (defsubst modb-standard-loaded-message-id (msgdb number)
174   "Get message-id for autoloaded entity."
175   (let ((ret (elmo-get-hash-val
176               (modb-standard-key number)
177               (modb-standard-entity-map-internal msgdb))))
178     (cond
179      ((null ret)
180       ;; Garbage entity.
181       (elmo-clear-hash-val (modb-standard-key number)
182                            (modb-standard-entity-map-internal msgdb))
183       nil)                              ; return nil.
184      ((eq (car-safe ret) 'autoload)
185       (cdr (cdr ret)))                  ; message-id.
186      ((elmo-msgdb-message-entity-field (elmo-message-entity-handler ret)
187                                        ret 'message-id)) ; Already loaded.
188      (t (error "Internal error: invalid msgdb status")))))
189
190 (defun modb-standard-load-entity (modb path &optional section)
191   (let ((table (or (modb-standard-entity-map-internal modb)
192                    (elmo-make-hash (elmo-msgdb-length modb))))
193         (objects (elmo-object-load
194                   (expand-file-name
195                    (modb-standard-entity-filename section)
196                    path)))
197         number msgid)
198     (cond ((eq (car objects) 'modb-standard-entity-handler)
199            ;; (standard PARAMETERS ENTITY*)
200            (let ((handler (apply #'luna-make-entity
201                                  (car objects)
202                                  (car (cdr objects))))
203                  entity)
204              (dolist (element (cdr (cdr objects)))
205                (setq entity (cons handler (cons nil element))
206                      number (elmo-msgdb-message-entity-number handler entity)
207                      msgid  (modb-standard-loaded-message-id modb number))
208                (when msgid
209                  (elmo-msgdb-message-entity-set-field
210                   handler entity 'message-id msgid)
211                  (elmo-set-hash-val (modb-standard-key number) entity table)
212                  (elmo-set-hash-val msgid entity table)))))
213           (t
214            ;; legacy format
215            (dolist (entity objects)
216              (setq number (elmo-msgdb-message-entity-number
217                            (elmo-message-entity-handler entity)
218                            entity)
219                    msgid (modb-standard-loaded-message-id modb number))
220              (when msgid
221                (setcar entity msgid)
222                (elmo-set-hash-val (modb-standard-key number) entity table)
223                (elmo-set-hash-val msgid entity table)))))
224     (modb-standard-set-entity-map-internal modb table)))
225
226 (defsubst modb-standard-save-entity-1 (modb path &optional section)
227   (let ((table (modb-standard-entity-map-internal modb))
228         (filename (expand-file-name
229                    (modb-standard-entity-filename (car section)) path))
230         (handler (elmo-msgdb-message-entity-handler modb))
231         entity entities)
232     (dolist (number (or (cdr section)
233                         (modb-standard-number-list-internal modb)))
234       (when (setq entity (elmo-msgdb-message-entity modb number))
235         (unless (modb-entity-handler-equal-p
236                  handler
237                  (elmo-message-entity-handler entity))
238           (setq entity (elmo-msgdb-copy-message-entity
239                         (elmo-message-entity-handler entity)
240                         entity handler)))
241         (setq entities (cons (cdr (cdr entity)) entities))))
242     (if entities
243         (elmo-object-save filename
244                           (nconc
245                            (list (luna-class-name handler)
246                                  (modb-entity-handler-dump-parameters handler))
247                            entities))
248       (ignore-errors (delete-file filename)))))
249
250 (defun modb-standard-cleanup-stale-entities (modb path)
251   (message "Removing stale entities...")
252   (let* ((entity-regex
253           (concat "^" modb-standard-entity-filename "-\\([0-9]+\\)"))
254          (entities (elmo-uniq-list
255                     (mapcar
256                      (lambda (x) (/ x modb-standard-divide-number))
257                      (modb-standard-number-list-internal modb))))
258          (files (mapcar (lambda(x)
259                           (when (string-match entity-regex x)
260                             (string-to-number (match-string 1 x))))
261                         (directory-files path nil entity-regex))))
262     (dolist (entity (car (elmo-list-diff-nonsortable files entities)))
263       (ignore-errors (delete-file
264                       (expand-file-name
265                        (modb-standard-entity-filename entity) path))))))
266
267 (defun modb-standard-save-entity (modb path)
268   (let ((modified (modb-generic-message-modified-internal modb)))
269     (cond ((listp modified)
270            (let ((sections (mapcar 'list modified))
271                  section)
272              (dolist (number (modb-standard-number-list-internal modb))
273                (when (setq section (assq (/ number modb-standard-divide-number)
274                                          sections))
275                  (nconc section (list number))))
276              (dolist (section sections)
277                (modb-standard-save-entity-1 modb path section))))
278           (modified
279            (modb-standard-cleanup-stale-entities modb path)))))
280
281 ;;; Implement
282 ;;
283 (luna-define-method elmo-msgdb-load ((msgdb modb-standard))
284   (let ((inhibit-quit t)
285         (path (elmo-msgdb-location msgdb)))
286     (when (file-exists-p (expand-file-name modb-standard-flag-filename path))
287       (modb-standard-load-msgid msgdb path)
288       (modb-standard-load-flag msgdb path)
289       (unless modb-standard-divide-number
290         (modb-standard-load-entity msgdb path))
291       t)))
292
293 (luna-define-method elmo-msgdb-save ((msgdb modb-standard))
294   (let ((path (elmo-msgdb-location msgdb))
295         (inhibit-quit t))
296     (when (elmo-msgdb-message-modified-p msgdb)
297       (modb-standard-save-msgid  msgdb path)
298       (modb-standard-save-entity msgdb path)
299       (modb-generic-set-message-modified-internal msgdb nil))
300     (when (elmo-msgdb-flag-modified-p msgdb)
301       (modb-standard-save-flag msgdb path)
302       (modb-generic-set-flag-modified-internal msgdb nil))))
303
304 (luna-define-method elmo-msgdb-append :around ((msgdb modb-standard)
305                                                msgdb-append)
306   (when (> (elmo-msgdb-length msgdb-append) 0)
307     (if (eq (luna-class-name msgdb-append) 'modb-standard)
308         (let ((numbers (modb-standard-number-list-internal msgdb-append))
309               duplicates)
310           ;; number-list
311           (modb-standard-set-number-list-internal
312            msgdb
313            (nconc (modb-standard-number-list-internal msgdb)
314                   numbers))
315           ;; entity-map
316           (let ((table (modb-standard-entity-map msgdb))
317                 entity msg-id)
318             (dolist (number numbers)
319               (setq entity (elmo-msgdb-message-entity msgdb-append number)
320                     msg-id (modb-standard-entity-id entity))
321               (if (elmo-get-hash-val msg-id table)
322                   (setq duplicates (cons number duplicates))
323                 (elmo-set-hash-val msg-id entity table))
324               (elmo-set-hash-val (modb-standard-key number)
325                                  entity
326                                  table)))
327           ;; flag-map
328           (let ((table (modb-standard-flag-map msgdb)))
329             (mapatoms
330              (lambda (atom)
331                (elmo-set-hash-val (symbol-name atom)
332                                   (symbol-value atom)
333                                   table))
334              (modb-standard-flag-map msgdb-append)))
335           ;; flag-count
336           (dolist (pair (modb-standard-flag-count-internal msgdb-append))
337             (modb-standard-countup-flags msgdb (list (car pair)) (cdr pair)))
338           ;; modification flags
339           (dolist (number (modb-standard-number-list-internal msgdb-append))
340             (modb-standard-set-message-modified msgdb number)
341             (modb-standard-set-flag-modified msgdb number))
342           duplicates)
343       (luna-call-next-method))))
344
345 (luna-define-method elmo-msgdb-clear :after ((msgdb modb-standard))
346   (modb-standard-set-number-list-internal msgdb nil)
347   (modb-standard-set-entity-map-internal msgdb nil)
348   (modb-standard-set-flag-map-internal msgdb nil)
349   (modb-standard-set-flag-count-internal msgdb nil))
350
351 (luna-define-method elmo-msgdb-length ((msgdb modb-standard))
352   (length (modb-standard-number-list-internal msgdb)))
353
354 (luna-define-method elmo-msgdb-flag-available-p ((msgdb modb-standard) flag)
355   t)
356
357 (luna-define-method elmo-msgdb-flags ((msgdb modb-standard) number)
358   (modb-standard-message-flags msgdb number))
359
360 (luna-define-method elmo-msgdb-set-flag ((msgdb modb-standard)
361                                          number flag)
362   (case flag
363     (read
364      (elmo-msgdb-unset-flag msgdb number 'unread))
365     (uncached
366      (elmo-msgdb-unset-flag msgdb number 'cached))
367     (t
368      (let ((cur-flags (modb-standard-message-flags msgdb number))
369            new-flags diff)
370        (unless (memq flag cur-flags)
371          (setq new-flags (cons flag cur-flags))
372          (setq diff (elmo-list-diff-nonsortable new-flags cur-flags))
373          (modb-standard-countup-flags msgdb (car diff))
374          (modb-standard-countup-flags msgdb (cadr diff) -1)
375          (elmo-set-hash-val (modb-standard-key number)
376                             (cons number new-flags)
377                             (modb-standard-flag-map msgdb))
378          (modb-standard-set-flag-modified msgdb number))))))
379
380 (luna-define-method elmo-msgdb-unset-flag ((msgdb modb-standard)
381                                            number flag)
382   (case flag
383     (read
384      (elmo-msgdb-set-flag msgdb number 'unread))
385     (uncached
386      (elmo-msgdb-set-flag msgdb number 'cached))
387     (all
388      (modb-standard-countup-flags msgdb
389                                   (modb-standard-message-flags msgdb number)
390                                   -1)
391      (elmo-clear-hash-val (modb-standard-key number)
392                           (modb-standard-flag-map msgdb)))
393     (t
394      (let ((cur-flags (modb-standard-message-flags msgdb number))
395            (inhibit-quit t)
396            new-flags diff)
397        (when (memq flag cur-flags)
398          (setq new-flags (delq flag (copy-sequence cur-flags)))
399          (setq diff (elmo-list-diff-nonsortable new-flags cur-flags))
400          (modb-standard-countup-flags msgdb (car diff))
401          (modb-standard-countup-flags msgdb (cadr diff) -1)
402          (elmo-set-hash-val (modb-standard-key number)
403                             (cons number new-flags)
404                             (modb-standard-flag-map msgdb))
405          (modb-standard-set-flag-modified msgdb number))
406        (when (eq flag 'unread)
407          (elmo-msgdb-unset-flag msgdb number 'new))))))
408
409 (luna-define-method elmo-msgdb-flag-count ((msgdb modb-standard))
410   (modb-standard-flag-count-internal msgdb))
411
412 (luna-define-method elmo-msgdb-list-messages ((msgdb modb-standard))
413   (copy-sequence
414    (modb-standard-number-list-internal msgdb)))
415
416 (luna-define-method elmo-msgdb-list-flagged ((msgdb modb-standard) flag)
417   (let (entry matched)
418     (case flag
419       (read
420        (dolist (number (modb-standard-number-list-internal msgdb))
421          (unless (memq 'unread (modb-standard-message-flags msgdb number))
422            (setq matched (cons number matched)))))
423       (uncached
424        (dolist (number (modb-standard-number-list-internal msgdb))
425          (unless (memq 'cached (modb-standard-message-flags msgdb number))
426            (setq matched (cons number matched)))))
427       (any
428        (mapatoms
429         (lambda (atom)
430           (setq entry (symbol-value atom))
431           (unless (and (eq (length (cdr entry)) 1)
432                        (eq (car (cdr entry)) 'cached))
433             ;; If there is a flag other than cached, then the message
434             ;; matches to `any'.
435             (setq matched (cons (car entry) matched))))
436         (modb-standard-flag-map msgdb)))
437       (digest
438        (let ((flags (append elmo-digest-flags
439                             (elmo-get-global-flags t t))))
440          (mapatoms
441           (lambda (atom)
442             (setq entry (symbol-value atom))
443             (when (modb-standard-match-flags flags (cdr entry))
444               (setq matched (cons (car entry) matched))))
445           (modb-standard-flag-map msgdb))))
446       (t
447        (mapatoms
448         (lambda (atom)
449           (setq entry (symbol-value atom))
450           (when (memq flag (cdr entry))
451             (setq matched (cons (car entry) matched))))
452         (modb-standard-flag-map msgdb))))
453     matched))
454
455 (luna-define-method elmo-msgdb-search ((msgdb modb-standard)
456                                        condition &optional numbers)
457   (if (vectorp condition)
458       (let ((key (elmo-filter-key condition))
459             results)
460         (cond
461          ((and (string= key "flag")
462                (eq (elmo-filter-type condition) 'match))
463           (setq results (elmo-msgdb-list-flagged
464                          msgdb
465                          (intern (elmo-filter-value condition))))
466           (if numbers
467               (elmo-list-filter numbers results)
468             results))
469          ((member key '("first" "last"))
470           (let* ((numbers (or numbers
471                               (modb-standard-number-list-internal msgdb)))
472                  (len (length numbers))
473                  (lastp (string= key "last"))
474                  (value (string-to-number (elmo-filter-value condition))))
475             (when (eq (elmo-filter-type condition) 'unmatch)
476               (setq lastp (not lastp)
477                     value (- len value)))
478             (if lastp
479                 (nthcdr (max (- len value) 0) numbers)
480               (when (> value 0)
481                 (let* ((numbers (copy-sequence numbers))
482                        (last (nthcdr (1- value) numbers)))
483                   (when last
484                     (setcdr last nil))
485                   numbers)))))
486          (t
487           t)))
488     t))
489
490 (luna-define-method elmo-msgdb-append-entity ((msgdb modb-standard)
491                                               entity &optional flags)
492   (when entity
493     (let ((number (elmo-msgdb-message-entity-number
494                    (elmo-message-entity-handler entity) entity))
495           (msg-id (elmo-msgdb-message-entity-field
496                    (elmo-message-entity-handler entity) entity 'message-id))
497           duplicate)
498       (when (and number msg-id)
499         ;; number-list
500         (modb-standard-set-number-list-internal
501          msgdb
502          (nconc (modb-standard-number-list-internal msgdb)
503                 (list number)))
504         ;; entity-map
505         (let ((table (modb-standard-entity-map msgdb)))
506           (setq duplicate (elmo-get-hash-val msg-id table))
507           (elmo-set-hash-val (modb-standard-key number) entity table)
508           (elmo-set-hash-val msg-id entity table))
509         ;; modification flags
510         (modb-standard-set-message-modified msgdb number)
511         ;; flag-map
512         (when flags
513           (elmo-set-hash-val
514            (modb-standard-key number)
515            (cons number flags)
516            (modb-standard-flag-map msgdb))
517           (modb-standard-countup-flags msgdb flags)
518           (modb-standard-set-flag-modified msgdb number))
519         duplicate))))
520
521 (luna-define-method elmo-msgdb-update-entity ((msgdb modb-standard)
522                                               entity values)
523   (let ((handler (elmo-message-entity-handler entity)))
524     (when (elmo-msgdb-message-entity-update-fields handler entity values)
525       (modb-standard-set-message-modified
526        msgdb
527        (elmo-msgdb-message-entity-number handler entity))
528       t)))
529
530 (luna-define-method elmo-msgdb-delete-messages ((msgdb modb-standard)
531                                                 numbers)
532   (let ((number-list (modb-standard-number-list-internal msgdb))
533         (entity-map (modb-standard-entity-map-internal msgdb))
534         (flag-map (modb-standard-flag-map-internal msgdb))
535         key entity)
536     (dolist (number numbers)
537       (setq key (modb-standard-key number)
538             entity (elmo-get-hash-val key entity-map))
539       (when entity
540         ;; number-list
541         (setq number-list (delq number number-list))
542         ;; entity-map
543         (elmo-clear-hash-val key entity-map)
544         (elmo-clear-hash-val (modb-standard-entity-id entity) entity-map)
545         ;; flag-count (must be BEFORE flag-map)
546         (modb-standard-countup-flags
547          msgdb
548          (modb-standard-message-flags msgdb number)
549          -1)
550         ;; flag-map
551         (elmo-clear-hash-val key flag-map)
552         (modb-standard-set-message-modified msgdb number)
553         (modb-standard-set-flag-modified msgdb number)))
554     (modb-standard-set-number-list-internal msgdb number-list)
555     (modb-standard-set-entity-map-internal msgdb entity-map)
556     (modb-standard-set-flag-map-internal msgdb flag-map)
557     t))
558
559 (luna-define-method elmo-msgdb-sort-entities ((msgdb modb-standard)
560                                               predicate &optional app-data)
561   (message "Sorting...")
562   (let ((numbers (modb-standard-number-list-internal msgdb)))
563     (modb-standard-set-number-list-internal
564      msgdb
565      (sort numbers (lambda (a b)
566                      (funcall predicate
567                               (elmo-msgdb-message-entity msgdb a)
568                               (elmo-msgdb-message-entity msgdb b)
569                               app-data))))
570     (message "Sorting...done")
571     msgdb))
572
573 (defun modb-standard-message-entity (msgdb key load)
574   (let ((ret (elmo-get-hash-val
575               key
576               (modb-standard-entity-map-internal msgdb)))
577         (inhibit-quit t))
578     (if (eq 'autoload (car-safe ret))
579         (when (and load modb-standard-divide-number)
580           (modb-standard-load-entity
581            msgdb
582            (elmo-msgdb-location msgdb)
583            (/ (nth 1 ret) modb-standard-divide-number))
584           (modb-standard-message-entity msgdb key nil))
585       ret)))
586
587 (luna-define-method elmo-msgdb-message-number ((msgdb modb-standard)
588                                                message-id)
589   (let ((ret (elmo-get-hash-val
590               message-id
591               (modb-standard-entity-map-internal msgdb))))
592     (if (eq 'autoload (car-safe ret))
593         ;; Not loaded yet but can return number.
594         (nth 1 ret)
595       (elmo-message-entity-number ret))))
596
597 (luna-define-method elmo-msgdb-message-field ((msgdb modb-standard)
598                                               number field &optional type)
599   (let ((ret (elmo-get-hash-val
600               (modb-standard-key number)
601               (modb-standard-entity-map-internal msgdb))))
602     (if (and (eq 'autoload (car-safe ret)) (eq field 'message-id))
603         ;; Not loaded yet but can return message-id
604         (cdr (cdr ret))
605       (elmo-message-entity-field (elmo-msgdb-message-entity
606                                   msgdb (modb-standard-key number))
607                                  field type))))
608
609 (luna-define-method elmo-msgdb-message-entity ((msgdb modb-standard) key)
610   (when key
611     (modb-standard-message-entity
612      msgdb
613      (cond ((stringp key) key)
614            ((numberp key) (modb-standard-key key)))
615      'autoload)))
616
617 (luna-define-method elmo-msgdb-message-entity-handler ((msgdb modb-standard))
618   (or (modb-standard-overview-handler-internal msgdb)
619       (modb-standard-set-overview-handler-internal
620        msgdb
621        (luna-make-entity 'modb-standard-entity-handler
622                          :mime-charset
623                          (modb-generic-mime-charset-internal msgdb)))))
624
625 (require 'product)
626 (product-provide (provide 'modb-standard) (require 'elmo-version))
627
628 ;;; modb-standard.el ends here