* wl-summary.el (wl-summary-detect-mark-position): Use
[elisp/wanderlust.git] / elmo / modb-legacy.el
1 ;;; modb-legacy.el --- Legacy 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
33 (eval-when-compile (require 'cl))
34
35 (require 'elmo-util)
36 (require 'modb)
37
38 ;;; legacy implement
39 ;;
40
41 (defconst modb-legacy-new-mark "N"
42   "Mark for new message.")
43
44 (defconst modb-legacy-unread-uncached-mark "U"
45   "Mark for unread and uncached message.")
46
47 (defconst modb-legacy-unread-cached-mark "!"
48   "Mark for unread but already cached message.")
49
50 (defconst modb-legacy-read-uncached-mark "u"
51   "Mark for read but uncached message.")
52
53 (defconst modb-legacy-answered-cached-mark "&"
54   "Mark for answered and cached message.")
55
56 (defconst modb-legacy-answered-uncached-mark "A"
57   "Mark for answered but cached message.")
58
59 (defconst modb-legacy-important-mark "$"
60   "Mark for important message.")
61
62 (eval-and-compile
63   (luna-define-class modb-legacy (modb-generic)
64                      (overview number-alist mark-alist index))
65   (luna-define-internal-accessors 'modb-legacy))
66
67 ;; for internal use only
68 (defsubst elmo-msgdb-get-overview (msgdb)
69   (modb-legacy-overview-internal msgdb))
70
71 (defsubst elmo-msgdb-get-number-alist (msgdb)
72   (modb-legacy-number-alist-internal msgdb))
73
74 (defsubst elmo-msgdb-get-mark-alist (msgdb)
75   (modb-legacy-mark-alist-internal msgdb))
76
77 (defsubst elmo-msgdb-get-index (msgdb)
78   (modb-legacy-index-internal msgdb))
79
80 (defsubst elmo-msgdb-get-entity-hashtb (msgdb)
81   (car (modb-legacy-index-internal msgdb)))
82
83 (defsubst elmo-msgdb-get-mark-hashtb (msgdb)
84   (cdr (modb-legacy-index-internal msgdb)))
85
86 (defsubst elmo-msgdb-get-path (msgdb)
87   (elmo-msgdb-location msgdb))
88
89 (defsubst elmo-msgdb-set-overview (msgdb overview)
90   (modb-legacy-set-overview-internal msgdb overview))
91
92 (defsubst elmo-msgdb-set-number-alist (msgdb number-alist)
93   (modb-legacy-set-number-alist-internal msgdb number-alist))
94
95 (defsubst elmo-msgdb-set-mark-alist (msgdb mark-alist)
96   (modb-legacy-set-mark-alist-internal msgdb mark-alist))
97
98 (defsubst elmo-msgdb-set-index (msgdb index)
99   (modb-legacy-set-index-internal msgdb index))
100
101 (defsubst elmo-msgdb-set-path (msgdb path)
102   (modb-generic-set-location-internal msgdb path))
103
104 ;;;
105 ;; Internal use only (obsolete interface)
106 ;;
107 (defsubst elmo-msgdb-overview-entity-get-id (entity)
108   (and entity (car entity)))
109
110 (defsubst elmo-msgdb-overview-entity-get-number (entity)
111   (and entity (aref (cdr entity) 0)))
112
113 (defsubst elmo-msgdb-overview-entity-set-number (entity number)
114   (and entity (aset (cdr entity) 0 number))
115   entity)
116
117 (defsubst elmo-msgdb-overview-entity-get-references (entity)
118   (and entity (aref (cdr entity) 1)))
119
120 (defsubst elmo-msgdb-overview-entity-set-references (entity references)
121   (and entity (aset (cdr entity) 1 references))
122   entity)
123
124 (defsubst elmo-msgdb-overview-entity-get-from-no-decode (entity)
125   (and entity (aref (cdr entity) 2)))
126
127 (defsubst elmo-msgdb-overview-entity-get-from (entity)
128   (and entity
129        (aref (cdr entity) 2)
130        (elmo-msgdb-get-decoded-cache (aref (cdr entity) 2))))
131
132 (defsubst elmo-msgdb-overview-entity-set-from (entity from)
133   (and entity (aset (cdr entity) 2 from))
134   entity)
135
136 (defsubst elmo-msgdb-overview-entity-get-subject (entity)
137   (and entity
138        (aref (cdr entity) 3)
139        (elmo-msgdb-get-decoded-cache (aref (cdr entity) 3))))
140
141 (defsubst elmo-msgdb-overview-entity-get-subject-no-decode (entity)
142   (and entity (aref (cdr entity) 3)))
143
144 (defsubst elmo-msgdb-overview-entity-set-subject (entity subject)
145   (and entity (aset (cdr entity) 3 subject))
146   entity)
147
148 (defsubst elmo-msgdb-overview-entity-get-date (entity)
149   (and entity (aref (cdr entity) 4)))
150
151 (defsubst elmo-msgdb-overview-entity-set-date (entity date)
152   (and entity (aset (cdr entity) 4 date))
153   entity)
154
155 (defsubst elmo-msgdb-overview-entity-get-to (entity)
156   (and entity (aref (cdr entity) 5)))
157
158 (defsubst elmo-msgdb-overview-entity-get-cc (entity)
159   (and entity (aref (cdr entity) 6)))
160
161 (defsubst elmo-msgdb-overview-entity-get-size (entity)
162   (and entity (aref (cdr entity) 7)))
163
164 (defsubst elmo-msgdb-overview-entity-set-size (entity size)
165   (and entity (aset (cdr entity) 7 size))
166   entity)
167
168 (defsubst elmo-msgdb-overview-entity-get-extra (entity)
169   (and entity (aref (cdr entity) 8)))
170
171 (defsubst elmo-msgdb-overview-entity-set-extra (entity extra)
172   (and entity (aset (cdr entity) 8 extra))
173   entity)
174
175 (defsubst elmo-msgdb-overview-entity-get-extra-field (entity field-name)
176   (let ((field-name (downcase field-name))
177         (extra (and entity (aref (cdr entity) 8))))
178     (and extra
179          (cdr (assoc field-name extra)))))
180
181 (defsubst elmo-msgdb-overview-entity-set-extra-field (entity field-name value)
182   (let ((field-name (downcase field-name))
183         (extras (and entity (aref (cdr entity) 8)))
184         extra)
185     (if (setq extra (assoc field-name extras))
186         (setcdr extra value)
187       (elmo-msgdb-overview-entity-set-extra
188        entity
189        (cons (cons field-name value) extras)))))
190
191 ;;; load & save
192 (defun elmo-msgdb-number-load (dir)
193   (elmo-object-load
194    (expand-file-name elmo-msgdb-number-filename dir)))
195
196 (defun elmo-msgdb-overview-load (dir)
197   (elmo-object-load
198    (expand-file-name elmo-msgdb-overview-filename dir)))
199
200 (defun elmo-msgdb-mark-load (dir)
201   (elmo-object-load
202    (expand-file-name elmo-msgdb-mark-filename dir)))
203
204 (defun elmo-msgdb-number-save (dir obj)
205   (elmo-object-save
206    (expand-file-name elmo-msgdb-number-filename dir)
207    obj))
208
209 (defun elmo-msgdb-mark-save (dir obj)
210   (elmo-object-save
211    (expand-file-name elmo-msgdb-mark-filename dir)
212    obj))
213
214 (defsubst elmo-msgdb-overview-save (dir overview)
215   (elmo-object-save
216    (expand-file-name elmo-msgdb-overview-filename dir)
217    overview))
218
219 ;;;
220
221
222 (defvar modb-legacy-unread-marks-internal nil)
223 (defsubst modb-legacy-unread-marks ()
224   "Return an unread mark list"
225   (or modb-legacy-unread-marks-internal
226       (setq modb-legacy-unread-marks-internal
227             (list modb-legacy-new-mark
228                   modb-legacy-unread-uncached-mark
229                   modb-legacy-unread-cached-mark))))
230
231 (defvar modb-legacy-answered-marks-internal nil)
232 (defsubst modb-legacy-answered-marks ()
233   "Return an answered mark list"
234   (or modb-legacy-answered-marks-internal
235       (setq modb-legacy-answered-marks-internal
236             (list modb-legacy-answered-cached-mark
237                   modb-legacy-answered-uncached-mark))))
238
239 (defvar modb-legacy-uncached-marks-internal nil)
240 (defsubst modb-legacy-uncached-marks ()
241   (or modb-legacy-uncached-marks-internal
242       (setq modb-legacy-uncached-marks-internal
243             (list modb-legacy-new-mark
244                   modb-legacy-answered-uncached-mark
245                   modb-legacy-unread-uncached-mark
246                   modb-legacy-read-uncached-mark))))
247
248 (defsubst modb-legacy-mark-to-flags (mark)
249   (append
250    (and (string= mark modb-legacy-new-mark)
251         '(new))
252    (and (string= mark modb-legacy-important-mark)
253         '(important))
254    (and (member mark (modb-legacy-unread-marks))
255         '(unread))
256    (and (member mark (modb-legacy-answered-marks))
257         '(answered))
258    (and (not (member mark (modb-legacy-uncached-marks)))
259         '(cached))))
260
261 (defsubst modb-legacy-flags-to-mark (flags)
262   (cond ((memq 'new flags)
263          modb-legacy-new-mark)
264         ((memq 'important flags)
265          modb-legacy-important-mark)
266         ((memq 'answered flags)
267          (if (memq 'cached flags)
268              modb-legacy-answered-cached-mark
269            modb-legacy-answered-uncached-mark))
270         ((memq 'unread flags)
271          (if (memq 'cached flags)
272              modb-legacy-unread-cached-mark
273            modb-legacy-unread-uncached-mark))
274         (t
275          (if (memq 'cached flags)
276              nil
277            modb-legacy-read-uncached-mark))))
278
279 (defsubst elmo-msgdb-get-mark (msgdb number)
280   "Get mark string from MSGDB which corresponds to the message with NUMBER."
281   (cadr (elmo-get-hash-val (format "#%d" number)
282                            (elmo-msgdb-get-mark-hashtb msgdb))))
283
284 (defsubst elmo-msgdb-set-mark (msgdb number mark)
285   "Set MARK of the message with NUMBER in the MSGDB.
286 if MARK is nil, mark is removed."
287   (let ((elem (elmo-get-hash-val (format "#%d" number)
288                                  (elmo-msgdb-get-mark-hashtb msgdb))))
289     (if elem
290         (if mark
291             ;; Set mark of the elem
292             (setcar (cdr elem) mark)
293           ;; Delete elem from mark-alist
294           (elmo-msgdb-set-mark-alist
295            msgdb
296            (delq elem (elmo-msgdb-get-mark-alist msgdb)))
297           (elmo-clear-hash-val (format "#%d" number)
298                                (elmo-msgdb-get-mark-hashtb msgdb)))
299       (when mark
300         ;; Append new element.
301         (elmo-msgdb-set-mark-alist
302          msgdb
303          (nconc
304           (elmo-msgdb-get-mark-alist msgdb)
305           (list (setq elem (list number mark)))))
306         (elmo-set-hash-val (format "#%d" number) elem
307                            (elmo-msgdb-get-mark-hashtb msgdb))))
308     (modb-generic-set-flag-modified-internal msgdb t)
309     ;; return value.
310     t))
311
312 (defun elmo-msgdb-make-index (msgdb &optional overview mark-alist)
313   "Append OVERVIEW and MARK-ALIST to the index of MSGDB.
314 If OVERVIEW and MARK-ALIST are nil, make index for current MSGDB.
315 Return a list of message numbers which have duplicated message-ids."
316   (when msgdb
317     (let* ((overview (or overview (elmo-msgdb-get-overview msgdb)))
318            (mark-alist (or mark-alist (elmo-msgdb-get-mark-alist msgdb)))
319            (index (elmo-msgdb-get-index msgdb))
320            (ehash (or (car index) ;; append
321                       (elmo-make-hash (length overview))))
322            (mhash (or (cdr index) ;; append
323                       (elmo-make-hash (length overview))))
324            duplicates)
325       (while overview
326         ;; key is message-id
327         (if (elmo-get-hash-val (caar overview) ehash) ; duplicated.
328             (setq duplicates (cons
329                               (elmo-msgdb-overview-entity-get-number
330                                (car overview))
331                               duplicates)))
332         (if (caar overview)
333             (elmo-set-hash-val (caar overview) (car overview) ehash))
334         ;; key is number
335         (elmo-set-hash-val
336          (format "#%d"
337                  (elmo-msgdb-overview-entity-get-number (car overview)))
338          (car overview) ehash)
339         (setq overview (cdr overview)))
340       (while mark-alist
341         ;; key is number
342         (elmo-set-hash-val
343          (format "#%d" (car (car mark-alist)))
344          (car mark-alist) mhash)
345         (setq mark-alist (cdr mark-alist)))
346       (setq index (or index (cons ehash mhash)))
347       (elmo-msgdb-set-index msgdb index)
348       duplicates)))
349
350 (defun elmo-msgdb-clear-index (msgdb entity)
351   (let ((ehash (elmo-msgdb-get-entity-hashtb msgdb))
352         (mhash (elmo-msgdb-get-mark-hashtb msgdb))
353         number)
354     (when (and entity ehash)
355       (and (setq number (elmo-msgdb-overview-entity-get-number entity))
356            (elmo-clear-hash-val (format "#%d" number) ehash))
357       (and (car entity) ;; message-id
358            (elmo-clear-hash-val (car entity) ehash)))
359     (when (and entity mhash)
360       (and (setq number (elmo-msgdb-overview-entity-get-number entity))
361            (elmo-clear-hash-val (format "#%d" number) mhash)))))
362
363 ;;; Implement
364 ;;
365 (luna-define-method elmo-msgdb-load ((msgdb modb-legacy))
366   (let ((inhibit-quit t)
367         (path (elmo-msgdb-location msgdb)))
368     (when (file-exists-p (expand-file-name elmo-msgdb-mark-filename path))
369       (modb-legacy-set-overview-internal
370        msgdb
371        (elmo-msgdb-overview-load path))
372       (modb-legacy-set-number-alist-internal
373        msgdb
374        (elmo-msgdb-number-load path))
375       (modb-legacy-set-mark-alist-internal
376        msgdb
377        (elmo-msgdb-mark-load path))
378       (elmo-msgdb-make-index msgdb)
379       t)))
380
381 (luna-define-method elmo-msgdb-save ((msgdb modb-legacy))
382   (let ((path (elmo-msgdb-location msgdb)))
383     (when (elmo-msgdb-message-modified-p msgdb)
384       (elmo-msgdb-overview-save
385        path
386        (modb-legacy-overview-internal msgdb))
387       (elmo-msgdb-number-save
388        path
389        (modb-legacy-number-alist-internal msgdb))
390       (modb-generic-set-message-modified-internal msgdb nil))
391     (when (elmo-msgdb-flag-modified-p msgdb)
392       (elmo-msgdb-mark-save
393        path
394        (modb-legacy-mark-alist-internal msgdb))
395       (modb-generic-set-flag-modified-internal msgdb nil))))
396
397 (luna-define-method elmo-msgdb-append :around ((msgdb modb-legacy)
398                                                msgdb-append)
399   (if (eq (luna-class-name msgdb-append)
400           'modb-legacy)
401       (let (duplicates)
402         (elmo-msgdb-set-overview
403          msgdb
404          (nconc (elmo-msgdb-get-overview msgdb)
405                 (elmo-msgdb-get-overview msgdb-append)))
406         (elmo-msgdb-set-number-alist
407          msgdb
408          (nconc (elmo-msgdb-get-number-alist msgdb)
409                 (elmo-msgdb-get-number-alist msgdb-append)))
410         (elmo-msgdb-set-mark-alist
411          msgdb
412          (nconc (elmo-msgdb-get-mark-alist msgdb)
413                 (elmo-msgdb-get-mark-alist msgdb-append)))
414         (setq duplicates (elmo-msgdb-make-index
415                           msgdb
416                           (elmo-msgdb-get-overview msgdb-append)
417                           (elmo-msgdb-get-mark-alist msgdb-append)))
418         (elmo-msgdb-set-path
419          msgdb
420          (or (elmo-msgdb-get-path msgdb)
421              (elmo-msgdb-get-path msgdb-append)))
422         (modb-generic-set-message-modified-internal msgdb t)
423         (modb-generic-set-flag-modified-internal msgdb t)
424         duplicates)
425     (luna-call-next-method)))
426
427 (luna-define-method elmo-msgdb-clear :after ((msgdb modb-legacy))
428   (elmo-msgdb-set-overview msgdb nil)
429   (elmo-msgdb-set-number-alist msgdb nil)
430   (elmo-msgdb-set-mark-alist msgdb nil)
431   (elmo-msgdb-set-index msgdb nil))
432
433 (luna-define-method elmo-msgdb-length ((msgdb modb-legacy))
434   (length (modb-legacy-overview-internal msgdb)))
435
436 (luna-define-method elmo-msgdb-flags ((msgdb modb-legacy) number)
437   (modb-legacy-mark-to-flags (elmo-msgdb-get-mark msgdb number)))
438
439 (luna-define-method elmo-msgdb-set-flag ((msgdb modb-legacy)
440                                          number flag)
441   (case flag
442     (read
443      (elmo-msgdb-unset-flag msgdb number 'unread))
444     (uncached
445      (elmo-msgdb-unset-flag msgdb number 'cached))
446     (t
447      (let* ((cur-mark (elmo-msgdb-get-mark msgdb number))
448             (flags (modb-legacy-mark-to-flags cur-mark))
449             new-mark)
450        (and (memq 'new flags)
451             (setq flags (delq 'new flags)))
452        (or (memq flag flags)
453            (setq flags (cons flag flags)))
454        (when (and (eq flag 'unread)
455                   (memq 'answered flags))
456          (setq flags (delq 'answered flags)))
457        (setq new-mark (modb-legacy-flags-to-mark flags))
458        (unless (string= new-mark cur-mark)
459          (elmo-msgdb-set-mark msgdb number new-mark))))))
460
461 (luna-define-method elmo-msgdb-unset-flag ((msgdb modb-legacy)
462                                            number flag)
463   (case flag
464     (read
465      (elmo-msgdb-set-flag msgdb number 'unread))
466     (uncached
467      (elmo-msgdb-set-flag msgdb number 'cached))
468     (t
469      (let* ((cur-mark (elmo-msgdb-get-mark msgdb number))
470             (flags (modb-legacy-mark-to-flags cur-mark))
471             new-mark)
472        (and (memq 'new flags)
473             (setq flags (delq 'new flags)))
474        (and (memq flag flags)
475             (setq flags (delq flag flags)))
476        (when (and (eq flag 'unread)
477                   (memq 'answered flags))
478          (setq flags (delq 'answered flags)))
479        (setq new-mark (modb-legacy-flags-to-mark flags))
480        (unless (string= new-mark cur-mark)
481          (elmo-msgdb-set-mark msgdb number new-mark))))))
482
483 (luna-define-method elmo-msgdb-list-messages ((msgdb modb-legacy))
484   (mapcar 'elmo-msgdb-overview-entity-get-number
485           (elmo-msgdb-get-overview msgdb)))
486
487 (luna-define-method elmo-msgdb-list-flagged ((msgdb modb-legacy) flag)
488   (let ((case-fold-search nil)
489         mark-regexp matched)
490     (case flag
491       (new
492        (setq mark-regexp (regexp-quote modb-legacy-new-mark)))
493       (unread
494        (setq mark-regexp (elmo-regexp-opt (modb-legacy-unread-marks))))
495       (answered
496        (setq mark-regexp (elmo-regexp-opt (modb-legacy-answered-marks))))
497       (important
498        (setq mark-regexp (regexp-quote modb-legacy-important-mark)))
499       (read
500        (setq mark-regexp (elmo-regexp-opt (modb-legacy-unread-marks))))
501       (digest
502        (setq mark-regexp (elmo-regexp-opt
503                           (append (modb-legacy-unread-marks)
504                                   (list modb-legacy-important-mark)))))
505       (any
506        (setq mark-regexp (elmo-regexp-opt
507                           (append
508                            (modb-legacy-unread-marks)
509                            (modb-legacy-answered-marks)
510                            (list modb-legacy-important-mark))))))
511     (when mark-regexp
512       (if (eq flag 'read)
513           (dolist (number (elmo-msgdb-list-messages msgdb))
514             (let ((mark (elmo-msgdb-get-mark msgdb number)))
515               (unless (and mark (string-match mark-regexp mark))
516                 (setq matched (cons number matched)))))
517         (dolist (elem (elmo-msgdb-get-mark-alist msgdb))
518           (if (string-match mark-regexp (cadr elem))
519               (setq matched (cons (car elem) matched))))))
520     matched))
521
522 (luna-define-method elmo-msgdb-append-entity ((msgdb modb-legacy)
523                                               entity &optional flags)
524   (when entity
525     (let ((number (elmo-msgdb-overview-entity-get-number entity))
526           (message-id (elmo-msgdb-overview-entity-get-id entity))
527           mark)
528       (elmo-msgdb-set-overview
529        msgdb
530        (nconc (elmo-msgdb-get-overview msgdb)
531               (list entity)))
532       (elmo-msgdb-set-number-alist
533        msgdb
534        (nconc (elmo-msgdb-get-number-alist msgdb)
535               (list (cons number message-id))))
536       (modb-generic-set-message-modified-internal msgdb t)
537       (when (setq mark (modb-legacy-flags-to-mark flags))
538         (elmo-msgdb-set-mark-alist
539          msgdb
540          (nconc (elmo-msgdb-get-mark-alist msgdb)
541                 (list (list number mark))))
542         (modb-generic-set-flag-modified-internal msgdb t))
543       (elmo-msgdb-make-index
544        msgdb
545        (list entity)
546        (list (list number mark))))))
547
548 (luna-define-method elmo-msgdb-delete-messages ((msgdb modb-legacy)
549                                                 numbers)
550   (let* ((overview (elmo-msgdb-get-overview msgdb))
551          (number-alist (elmo-msgdb-get-number-alist msgdb))
552          (mark-alist (elmo-msgdb-get-mark-alist msgdb))
553          (index (elmo-msgdb-get-index msgdb))
554          ov-entity)
555     ;; remove from current database.
556     (dolist (number numbers)
557       (setq overview
558             (delq
559              (setq ov-entity
560                    (elmo-msgdb-message-entity msgdb number))
561              overview))
562       (setq number-alist (delq (assq number number-alist) number-alist))
563       (setq mark-alist (delq (assq number mark-alist) mark-alist))
564       ;;
565       (when index (elmo-msgdb-clear-index msgdb ov-entity)))
566     (elmo-msgdb-set-overview msgdb overview)
567     (elmo-msgdb-set-number-alist msgdb number-alist)
568     (elmo-msgdb-set-mark-alist msgdb mark-alist)
569     (elmo-msgdb-set-index msgdb index)
570     (modb-generic-set-message-modified-internal msgdb t)
571     (modb-generic-set-flag-modified-internal msgdb t)
572     t)) ;return value
573
574 (luna-define-method elmo-msgdb-sort-entities ((msgdb modb-legacy)
575                                               predicate &optional app-data)
576   (message "Sorting...")
577   (let ((overview (elmo-msgdb-get-overview msgdb)))
578     (elmo-msgdb-set-overview
579      msgdb
580      (sort overview (lambda (a b) (funcall predicate a b app-data))))
581     (message "Sorting...done")
582     msgdb))
583
584 (luna-define-method elmo-msgdb-message-entity ((msgdb modb-legacy) key)
585   (elmo-get-hash-val
586    (cond ((stringp key) key)
587          ((numberp key) (format "#%d" key)))
588    (elmo-msgdb-get-entity-hashtb msgdb)))
589
590 (require 'product)
591 (product-provide (provide 'modb-legacy) (require 'elmo-version))
592
593 ;;; modb-legacy.el ends here