summaryrefslogtreecommitdiffabout
path: root/libetpan/src/engine/mailengine.c
Unidiff
Diffstat (limited to 'libetpan/src/engine/mailengine.c') (more/less context) (ignore whitespace changes)
-rw-r--r--libetpan/src/engine/mailengine.c1636
1 files changed, 1636 insertions, 0 deletions
diff --git a/libetpan/src/engine/mailengine.c b/libetpan/src/engine/mailengine.c
new file mode 100644
index 0000000..be4df38
--- a/dev/null
+++ b/libetpan/src/engine/mailengine.c
@@ -0,0 +1,1636 @@
1/*
2 * libEtPan! -- a mail library
3 *
4 * Copyright (C) 2001, 2005 - DINH Viet Hoa
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the libEtPan! project nor the names of its
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*
33 * $Id$
34 */
35
36#include "mailengine.h"
37
38#ifndef CONFIG_H
39#define CONFIG_H
40#include "config.h"
41#endif
42
43#include "mailfolder.h"
44#include "maildriver.h"
45#include "imapdriver_cached.h"
46#include "mailstorage.h"
47#include "imapdriver_cached_message.h"
48#include <stdlib.h>
49#include "mailprivacy.h"
50#ifdef LIBETPAN_REENTRANT
51#include <pthread.h>
52#endif
53#include <string.h>
54
55/* ************************************************************* */
56/* Message finder */
57
58#if 0
59struct message_folder_finder {
60#ifdef LIBETPAN_REENTRANT
61 pthread_mutex_t lock;
62#endif
63
64 /* msg => folder */
65 chash * message_hash;
66};
67
68static int message_folder_finder_init(struct message_folder_finder * finder)
69{
70 int r;
71
72#ifdef LIBETPAN_REENTRANT
73 r = pthread_mutex_init(&finder->lock, NULL);
74 if (r != 0)
75 return MAIL_ERROR_MEMORY;
76#endif
77
78 finder->message_hash = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
79 if (finder->message_hash == NULL)
80 return MAIL_ERROR_MEMORY;
81
82 return MAIL_NO_ERROR;
83}
84
85static void message_folder_finder_done(struct message_folder_finder * finder)
86{
87 chash_free(finder->message_hash);
88#ifdef LIBETPAN_REENTRANT
89 pthread_mutex_destroy(&finder->lock);
90#endif
91}
92
93static struct mailfolder *
94message_folder_finder_lookup(struct message_folder_finder * finder,
95 mailmessage * msg)
96{
97 int r;
98 chashdatum key;
99 chashdatum data;
100 struct mailfolder * folder;
101
102 key.data = &msg;
103 key.len = sizeof(msg);
104#ifdef LIBETPAN_REENTRANT
105 pthread_mutex_lock(&finder->lock);
106#endif
107 r = chash_get(finder->message_hash, &key, &data);
108#ifdef LIBETPAN_REENTRANT
109 pthread_mutex_unlock(&finder->lock);
110#endif
111 if (r < 0)
112 return NULL;
113
114 folder = data.data;
115
116 return folder;
117}
118
119static inline int
120message_folder_finder_store_no_lock(struct message_folder_finder * finder,
121 mailmessage * msg, struct mailfolder * folder)
122{
123 int r;
124 chashdatum key;
125 chashdatum data;
126
127 key.data = &msg;
128 key.len = sizeof(msg);
129 data.data = folder;
130 data.len = 0;
131 r = chash_set(finder->message_hash, &key, &data, NULL);
132 if (r < 0)
133 return MAIL_ERROR_MEMORY;
134
135 return MAIL_NO_ERROR;
136}
137
138static int
139message_folder_finder_store(struct message_folder_finder * finder,
140 mailmessage * msg, struct mailfolder * folder)
141{
142 int r;
143
144#ifdef LIBETPAN_REENTRANT
145 pthread_mutex_lock(&finder->lock);
146#endif
147 r = message_folder_finder_store_no_lock(finder, msg, folder);
148#ifdef LIBETPAN_REENTRANT
149 pthread_mutex_unlock(&finder->lock);
150#endif
151
152 return r;
153}
154
155static inline void
156message_folder_finder_delete_no_lock(struct message_folder_finder * finder,
157 mailmessage * msg)
158{
159 chashdatum key;
160
161 key.data = &msg;
162 key.len = sizeof(msg);
163 chash_delete(finder->message_hash, &key, NULL);
164}
165
166static void
167message_folder_finder_delete(struct message_folder_finder * finder,
168 mailmessage * msg)
169{
170#ifdef LIBETPAN_REENTRANT
171 pthread_mutex_lock(&finder->lock);
172#endif
173 message_folder_finder_delete_no_lock(finder, msg);
174#ifdef LIBETPAN_REENTRANT
175 pthread_mutex_unlock(&finder->lock);
176#endif
177}
178#endif
179
180/* ************************************************************* */
181/* Message ref info */
182
183struct message_ref_elt {
184 mailmessage * msg;
185 int ref_count;
186 int mime_ref_count;
187 struct mailfolder * folder;
188 int lost;
189};
190
191static struct message_ref_elt *
192message_ref_elt_new(struct mailfolder * folder, mailmessage * msg)
193{
194 struct message_ref_elt * ref;
195
196 ref = malloc(sizeof(* ref));
197 if (ref == NULL)
198 return NULL;
199
200 ref->msg = msg;
201 ref->ref_count = 0;
202 ref->mime_ref_count = 0;
203 ref->folder = folder;
204 ref->lost = 0;
205
206 return ref;
207}
208
209static void message_ref_elt_free(struct message_ref_elt * ref_elt)
210{
211 free(ref_elt);
212}
213
214static inline int message_ref(struct message_ref_elt * ref_elt)
215{
216 ref_elt->ref_count ++;
217
218 return ref_elt->ref_count;
219}
220
221static inline int message_unref(struct message_ref_elt * ref_elt)
222{
223 ref_elt->ref_count --;
224
225 return ref_elt->ref_count;
226}
227
228
229static inline int message_mime_ref(struct mailprivacy * privacy,
230 struct message_ref_elt * ref_elt)
231{
232 int r;
233
234 if (ref_elt->mime_ref_count == 0) {
235 struct mailmime * mime;
236
237 r = mailprivacy_msg_get_bodystructure(privacy, ref_elt->msg, &mime);
238 if (r != MAIL_NO_ERROR)
239 return -r;
240 }
241
242 message_ref(ref_elt);
243
244 ref_elt->mime_ref_count ++;
245
246 return ref_elt->mime_ref_count;
247}
248
249static inline int message_mime_unref(struct mailprivacy * privacy,
250 struct message_ref_elt * ref_elt)
251{
252 message_unref(ref_elt);
253
254 ref_elt->mime_ref_count --;
255
256 if (ref_elt->mime_ref_count == 0)
257 mailprivacy_msg_flush(privacy, ref_elt->msg);
258
259 return ref_elt->mime_ref_count;
260}
261
262
263/* ************************************************************* */
264/* Folder ref info */
265
266struct folder_ref_info {
267 struct mailfolder * folder;
268#if 0
269 struct message_folder_finder * msg_folder_finder;
270#endif
271
272 /* msg => msg_ref_info */
273 chash * msg_hash;
274
275 /* uid => msg */
276 chash * uid_hash;
277
278 int lost_session;
279};
280
281static struct folder_ref_info *
282folder_ref_info_new(struct mailfolder * folder
283 /*, struct message_folder_finder * msg_folder_finder */)
284{
285 struct folder_ref_info * ref_info;
286
287 ref_info = malloc(sizeof(* ref_info));
288 if (ref_info == NULL)
289 goto err;
290
291 ref_info->folder = folder;
292#if 0
293 ref_info->msg_folder_finder = msg_folder_finder;
294#endif
295
296 ref_info->msg_hash = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
297 if (ref_info->msg_hash == NULL)
298 goto free;
299
300 ref_info->uid_hash = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYNONE);
301 if (ref_info->uid_hash == NULL)
302 goto free_msg_hash;
303
304 ref_info->lost_session = 1;
305
306 return ref_info;
307
308 free_msg_hash:
309 chash_free(ref_info->msg_hash);
310 free:
311 free(ref_info);
312 err:
313 return NULL;
314}
315
316static void folder_ref_info_free(struct folder_ref_info * ref_info)
317{
318 chash_free(ref_info->uid_hash);
319 chash_free(ref_info->msg_hash);
320 free(ref_info);
321}
322
323static struct message_ref_elt *
324folder_info_get_msg_ref(struct folder_ref_info * ref_info, mailmessage * msg)
325{
326 chashdatum key;
327 chashdatum data;
328 struct message_ref_elt * ref_elt;
329 int r;
330
331 key.data = &msg;
332 key.len = sizeof(msg);
333 r = chash_get(ref_info->msg_hash, &key, &data);
334 if (r < 0)
335 return NULL;
336
337 ref_elt = data.data;
338
339 return ref_elt;
340}
341
342static mailmessage *
343folder_info_get_msg_by_uid(struct folder_ref_info * ref_info,
344 char * uid)
345{
346 chashdatum key;
347 chashdatum data;
348 mailmessage * msg;
349 int r;
350
351 key.data = uid;
352 key.len = strlen(uid);
353 r = chash_get(ref_info->uid_hash, &key, &data);
354 if (r < 0)
355 return NULL;
356
357 msg = data.data;
358
359 return msg;
360}
361
362static int folder_message_ref(struct folder_ref_info * ref_info,
363 mailmessage * msg)
364{
365 struct message_ref_elt * msg_ref;
366
367 msg_ref = folder_info_get_msg_ref(ref_info, msg);
368 return message_ref(msg_ref);
369}
370
371static void folder_message_remove(struct folder_ref_info * ref_info,
372 mailmessage * msg);
373
374#ifdef DEBUG_ENGINE
375#include "etpan-app.h"
376
377void * engine_app = NULL;
378#endif
379
380static int folder_message_unref(struct folder_ref_info * ref_info,
381 mailmessage * msg)
382{
383 struct message_ref_elt * msg_ref;
384 int count;
385
386 msg_ref = folder_info_get_msg_ref(ref_info, msg);
387
388 if (msg_ref->ref_count == 0) {
389#ifdef ETPAN_APP_DEBUG
390 ETPAN_APP_DEBUG((engine_app, "** BUG detected negative ref count !"));
391#endif
392 }
393
394 count = message_unref(msg_ref);
395 if (count == 0) {
396 folder_message_remove(ref_info, msg);
397 mailmessage_free(msg);
398 }
399
400 return count;
401}
402
403static int folder_message_mime_ref(struct mailprivacy * privacy,
404 struct folder_ref_info * ref_info,
405 mailmessage * msg)
406{
407 struct message_ref_elt * msg_ref;
408
409 msg_ref = folder_info_get_msg_ref(ref_info, msg);
410
411 return message_mime_ref(privacy, msg_ref);
412}
413
414static int folder_message_mime_unref(struct mailprivacy * privacy,
415 struct folder_ref_info * ref_info,
416 mailmessage * msg)
417{
418 struct message_ref_elt * msg_ref;
419
420 msg_ref = folder_info_get_msg_ref(ref_info, msg);
421 return message_mime_unref(privacy, msg_ref);
422}
423
424static int folder_message_add(struct folder_ref_info * ref_info,
425 mailmessage * msg)
426{
427 chashdatum key;
428 chashdatum data;
429 struct message_ref_elt * msg_ref;
430 int r;
431
432 /*
433 r = message_folder_finder_store(ref_info->msg_folder_finder,
434 msg, ref_info->folder);
435 if (r != MAIL_NO_ERROR)
436 goto err;
437 */
438
439 msg_ref = message_ref_elt_new(ref_info->folder, msg);
440 if (msg_ref == NULL)
441 goto msg_folder_remove;
442
443 key.data = &msg;
444 key.len = sizeof(msg);
445 data.data = msg_ref;
446 data.len = 0;
447
448 r = chash_set(ref_info->msg_hash, &key, &data, NULL);
449 if (r < 0)
450 goto free_msg_ref;
451
452 if (msg->msg_uid != NULL) {
453 key.data = msg->msg_uid;
454 key.len = strlen(msg->msg_uid);
455 data.data = msg;
456 data.len = 0;
457
458 r = chash_set(ref_info->uid_hash, &key, &data, NULL);
459 if (r < 0)
460 goto remove_msg_ref;
461 }
462
463 return MAIL_NO_ERROR;
464
465 remove_msg_ref:
466 key.data = &msg;
467 key.len = sizeof(msg);
468 chash_delete(ref_info->msg_hash, &key, NULL);
469 free_msg_ref:
470 message_ref_elt_free(msg_ref);
471 msg_folder_remove:
472 /*
473 message_folder_finder_delete(ref_info->msg_folder_finder, msg);
474 */
475 err:
476 return MAIL_ERROR_MEMORY;
477}
478
479
480static void folder_message_remove(struct folder_ref_info * ref_info,
481 mailmessage * msg)
482{
483 chashdatum key;
484 struct message_ref_elt * msg_ref;
485
486 if (msg->msg_uid != NULL) {
487 key.data = msg->msg_uid;
488 key.len = strlen(msg->msg_uid);
489
490 chash_delete(ref_info->uid_hash, &key, NULL);
491 }
492
493 msg_ref = folder_info_get_msg_ref(ref_info, msg);
494 message_ref_elt_free(msg_ref);
495
496 key.data = &msg;
497 key.len = sizeof(msg);
498
499 chash_delete(ref_info->msg_hash, &key, NULL);
500
501 /*
502 message_folder_finder_delete(ref_info->msg_folder_finder, msg);
503 */
504}
505
506
507static int folder_update_msg_list(struct folder_ref_info * ref_info,
508 struct mailmessage_list ** p_new_msg_list,
509 struct mailmessage_list ** p_lost_msg_list)
510{
511 int r;
512 int res;
513 struct mailmessage_list * new_env_list;
514 unsigned int i;
515 carray * lost_msg_tab;
516 struct mailmessage_list * lost_msg_list;
517 unsigned int free_start_index;
518 chashiter * iter;
519 unsigned int lost_count;
520
521 r = mailfolder_get_messages_list(ref_info->folder, &new_env_list);
522 if (r != MAIL_NO_ERROR) {
523 res = r;
524 goto err;
525 }
526
527 for(iter = chash_begin(ref_info->msg_hash) ; iter != NULL ;
528 iter = chash_next(ref_info->msg_hash, iter)) {
529 struct message_ref_elt * msg_ref;
530 chashdatum data;
531
532 chash_value(iter, &data);
533 msg_ref = data.data;
534 msg_ref->lost = 1;
535 }
536
537 lost_count = chash_count(ref_info->msg_hash);
538
539 for(i = 0 ; i < carray_count(new_env_list->msg_tab) ; i ++) {
540 mailmessage * msg;
541 mailmessage * old_msg;
542
543 msg = carray_get(new_env_list->msg_tab, i);
544
545 if (msg->msg_uid == NULL)
546 continue;
547
548 old_msg = folder_info_get_msg_by_uid(ref_info, msg->msg_uid);
549 if (old_msg != NULL) {
550 struct message_ref_elt * msg_ref;
551
552 /* replace old message */
553 old_msg->msg_index = msg->msg_index;
554 carray_set(new_env_list->msg_tab, i, old_msg);
555 mailmessage_free(msg);
556
557 msg_ref = folder_info_get_msg_ref(ref_info, old_msg);
558 msg_ref->lost = 0;
559 lost_count --;
560 }
561 else {
562 /* set new message */
563 r = folder_message_add(ref_info, msg);
564 if (r != MAIL_NO_ERROR) {
565 free_start_index = i;
566 res = r;
567 goto free_remaining;
568 }
569 }
570 }
571
572 /* build the table of lost messages */
573 lost_msg_tab = carray_new(lost_count);
574 if (lost_msg_tab == NULL) {
575 res = MAIL_ERROR_MEMORY;
576 goto free_env_list;
577 }
578
579 carray_set_size(lost_msg_tab, lost_count);
580
581 i = 0;
582 for(iter = chash_begin(ref_info->msg_hash) ; iter != NULL ;
583 iter = chash_next(ref_info->msg_hash, iter)) {
584 struct message_ref_elt * msg_ref;
585 chashdatum key;
586 chashdatum value;
587 mailmessage * msg;
588
589 chash_key(iter, &key);
590 memcpy(&msg, key.data, sizeof(msg));
591
592 chash_value(iter, &value);
593 msg_ref = value.data;
594 if (msg_ref->lost) {
595 carray_set(lost_msg_tab, i, msg);
596 i ++;
597 }
598 }
599
600 lost_msg_list = mailmessage_list_new(lost_msg_tab);
601 if (lost_msg_list == NULL) {
602 res = MAIL_ERROR_MEMORY;
603 goto free_lost_msg_tab;
604 }
605
606 /* reference messages */
607 for(i = 0 ; i < carray_count(new_env_list->msg_tab) ; i ++) {
608 mailmessage * msg;
609
610 msg = carray_get(new_env_list->msg_tab, i);
611 folder_message_ref(ref_info, msg);
612 }
613
614 * p_new_msg_list = new_env_list;
615 * p_lost_msg_list = lost_msg_list;
616
617 return MAIL_NO_ERROR;
618
619 free_lost_msg_tab:
620 carray_free(lost_msg_tab);
621 free_env_list:
622 for(i = 0 ; i < carray_count(new_env_list->msg_tab) ; i ++) {
623 mailmessage * msg;
624 struct message_ref_elt * msg_ref;
625
626 msg = carray_get(new_env_list->msg_tab, i);
627 msg_ref = folder_info_get_msg_ref(ref_info, msg);
628 if (msg_ref != NULL) {
629 if (msg_ref->ref_count == 0)
630 folder_message_remove(ref_info, msg);
631 }
632 }
633 carray_set_size(new_env_list->msg_tab, 0);
634 mailmessage_list_free(new_env_list);
635 goto err;
636 free_remaining:
637 for(i = 0 ; i < carray_count(new_env_list->msg_tab) ; i ++) {
638 mailmessage * msg;
639 struct message_ref_elt * msg_ref;
640
641 msg = carray_get(new_env_list->msg_tab, i);
642 msg_ref = folder_info_get_msg_ref(ref_info, msg);
643 if (msg_ref != NULL) {
644 if (msg_ref->ref_count == 0)
645 folder_message_remove(ref_info, msg);
646 }
647 }
648 for(i = free_start_index ; i < carray_count(new_env_list->msg_tab) ; i ++) {
649 mailmessage * msg;
650
651 msg = carray_get(new_env_list->msg_tab, i);
652 mailmessage_free(msg);
653 }
654 carray_set_size(new_env_list->msg_tab, 0);
655 mailmessage_list_free(new_env_list);
656 err:
657 return res;
658}
659
660/*
661 folder_fetch_env_list()
662*/
663
664static int folder_fetch_env_list(struct folder_ref_info * ref_info,
665 struct mailmessage_list * msg_list)
666{
667 return mailfolder_get_envelopes_list(ref_info->folder, msg_list);
668}
669
670static void folder_free_msg_list(struct folder_ref_info * ref_info,
671 struct mailmessage_list * env_list)
672{
673 unsigned int i;
674
675 for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
676 mailmessage * msg;
677 int count;
678
679 msg = carray_get(env_list->msg_tab, i);
680
681 count = folder_message_unref(ref_info, msg);
682 }
683 carray_set_size(env_list->msg_tab, 0);
684 mailmessage_list_free(env_list);
685}
686
687
688/* ************************************************************* */
689/* Storage ref info */
690
691struct storage_ref_info {
692 struct mailstorage * storage;
693#if 0
694 struct message_folder_finder * msg_folder_finder;
695#endif
696
697#if 0
698 /* msg => folder */
699 chash * msg_ref;
700#endif
701
702 /* folder => folder_ref_info */
703 chash * folder_ref_info;
704};
705
706static struct storage_ref_info *
707storage_ref_info_new(struct mailstorage * storage
708 /*, struct message_folder_finder * msg_folder_finder */)
709{
710 struct storage_ref_info * ref_info;
711
712 ref_info = malloc(sizeof(* ref_info));
713 if (ref_info == NULL)
714 goto err;
715
716 ref_info->storage = storage;
717#if 0
718 ref_info->msg_folder_finder = msg_folder_finder;
719#endif
720
721 ref_info->folder_ref_info = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
722 if (ref_info->folder_ref_info == NULL)
723 goto free;
724
725 return ref_info;
726
727 free:
728 free(ref_info);
729 err:
730 return NULL;
731}
732
733static void storage_ref_info_free(struct storage_ref_info * ref_info)
734{
735#if 0
736 chash_free(ref_info->msg_ref);
737#endif
738 chash_free(ref_info->folder_ref_info);
739 free(ref_info);
740}
741
742
743static struct folder_ref_info *
744storage_get_folder_ref(struct storage_ref_info * ref_info,
745 struct mailfolder * folder)
746{
747 struct folder_ref_info * folder_ref;
748 chashdatum key;
749 chashdatum value;
750 int r;
751
752 key.data = &folder;
753 key.len = sizeof(folder);
754 r = chash_get(ref_info->folder_ref_info, &key, &value);
755 if (r < 0)
756 return NULL;
757
758 folder_ref = value.data;
759
760 return folder_ref;
761}
762
763static struct folder_ref_info *
764storage_folder_add_ref(struct storage_ref_info * ref_info,
765 struct mailfolder * folder)
766{
767 struct folder_ref_info * folder_ref;
768 chashdatum key;
769 chashdatum value;
770 int r;
771
772 folder_ref = folder_ref_info_new(folder /*, ref_info->msg_folder_finder */);
773 if (folder_ref == NULL)
774 goto err;
775
776 key.data = &folder;
777 key.len = sizeof(folder);
778 value.data = folder_ref;
779 value.len = 0;
780 r = chash_set(ref_info->folder_ref_info, &key, &value, NULL);
781 if (r < 0)
782 goto free;
783
784 return folder_ref;
785
786 free:
787 folder_ref_info_free(folder_ref);
788 err:
789 return NULL;
790}
791
792
793static void storage_folder_remove_ref(struct storage_ref_info * ref_info,
794 struct mailfolder * folder)
795{
796 struct folder_ref_info * folder_ref;
797 chashdatum key;
798 chashdatum value;
799 int r;
800
801 key.data = &folder;
802 key.len = sizeof(folder);
803 r = chash_get(ref_info->folder_ref_info, &key, &value);
804 if (r < 0)
805 return;
806
807 folder_ref = value.data;
808
809 if (folder_ref == NULL)
810 return;
811
812 folder_ref_info_free(folder_ref);
813
814 chash_delete(ref_info->folder_ref_info, &key, &value);
815}
816
817static int storage_folder_get_msg_list(struct storage_ref_info * ref_info,
818 struct mailfolder * folder,
819 struct mailmessage_list ** p_new_msg_list,
820 struct mailmessage_list ** p_lost_msg_list)
821{
822 struct folder_ref_info * folder_ref_info;
823
824 folder_ref_info = storage_get_folder_ref(ref_info, folder);
825 if (folder_ref_info == NULL)
826 return MAIL_ERROR_INVAL;
827
828 return folder_update_msg_list(folder_ref_info,
829 p_new_msg_list, p_lost_msg_list);
830}
831
832static int storage_folder_fetch_env_list(struct storage_ref_info * ref_info,
833 struct mailfolder * folder,
834 struct mailmessage_list * msg_list)
835{
836 struct folder_ref_info * folder_ref_info;
837
838 folder_ref_info = storage_get_folder_ref(ref_info, folder);
839 if (folder_ref_info == NULL)
840 return MAIL_ERROR_INVAL;
841
842 return folder_fetch_env_list(folder_ref_info, msg_list);
843}
844
845static void
846storage_folder_free_msg_list(struct storage_ref_info * ref_info,
847 struct mailfolder * folder,
848 struct mailmessage_list * env_list)
849{
850 struct folder_ref_info * folder_ref_info;
851
852 folder_ref_info = storage_get_folder_ref(ref_info, folder);
853
854 folder_free_msg_list(folder_ref_info, env_list);
855}
856
857
858/* connection and disconnection */
859
860static void
861folder_restore_session(struct folder_ref_info * ref_info)
862{
863 chashiter * iter;
864 mailsession * session;
865
866 session = ref_info->folder->fld_session;
867
868 for(iter = chash_begin(ref_info->msg_hash) ; iter != NULL ;
869 iter = chash_next(ref_info->msg_hash, iter)) {
870 chashdatum key;
871 mailmessage * msg;
872
873 chash_key(iter, &key);
874 memcpy(&msg, key.data, sizeof(msg));
875 msg->msg_session = session;
876
877 if (msg->msg_driver == imap_cached_message_driver) {
878 struct imap_cached_session_state_data * imap_cached_data;
879 mailmessage * ancestor_msg;
880
881 imap_cached_data = ref_info->folder->fld_session->sess_data;
882 ancestor_msg = msg->msg_data;
883 ancestor_msg->msg_session = imap_cached_data->imap_ancestor;
884 }
885 }
886}
887
888static void
889storage_restore_message_session(struct storage_ref_info * ref_info)
890{
891 chashiter * iter;
892
893 for(iter = chash_begin(ref_info->folder_ref_info) ; iter != NULL ;
894 iter = chash_next(ref_info->folder_ref_info, iter)) {
895 chashdatum data;
896 struct folder_ref_info * folder_ref_info;
897
898 chash_value(iter, &data);
899 folder_ref_info = data.data;
900 if (folder_ref_info->lost_session) {
901 if (folder_ref_info->folder->fld_session != NULL) {
902 /* restore folder session */
903 folder_restore_session(folder_ref_info);
904
905 folder_ref_info->lost_session = 0;
906 }
907 }
908 }
909}
910
911
912static int do_storage_connect(struct storage_ref_info * ref_info)
913{
914 int r;
915
916 r = mailstorage_connect(ref_info->storage);
917 if (r != MAIL_NO_ERROR)
918 return r;
919
920 return MAIL_NO_ERROR;
921}
922
923static void do_storage_disconnect(struct storage_ref_info * ref_info)
924{
925 clistiter * cur;
926
927 /* storage is disconnected, session is lost */
928 for(cur = clist_begin(ref_info->storage->sto_shared_folders) ; cur != NULL ;
929 cur = clist_next(cur)) {
930 struct folder_ref_info * folder_ref_info;
931 struct mailfolder * folder;
932
933 folder = clist_content(cur);
934 /* folder is disconnected (in storage), session is lost */
935
936 folder_ref_info = storage_get_folder_ref(ref_info, folder);
937 folder_ref_info->lost_session = 1;
938 }
939
940 /* storage is disconnected */
941 mailstorage_disconnect(ref_info->storage);
942}
943
944
945
946static int folder_connect(struct storage_ref_info * ref_info,
947 struct mailfolder * folder)
948{
949 int r;
950 struct folder_ref_info * folder_ref_info;
951
952 r = do_storage_connect(ref_info);
953 if (r != MAIL_NO_ERROR)
954 return r;
955
956 r = mailfolder_connect(folder);
957 if (r != MAIL_NO_ERROR)
958 return r;
959
960 folder_ref_info = storage_get_folder_ref(ref_info, folder);
961
962 return MAIL_NO_ERROR;
963}
964
965
966static void folder_disconnect(struct storage_ref_info * ref_info,
967 struct mailfolder * folder)
968{
969 struct folder_ref_info * folder_ref_info;
970
971 folder_ref_info = storage_get_folder_ref(ref_info, folder);
972
973 /* folder is disconnected, session is lost */
974 folder_ref_info->lost_session = 1;
975 mailfolder_disconnect(folder);
976
977 if (folder->fld_shared_session)
978 do_storage_disconnect(ref_info);
979}
980
981
982static int storage_folder_connect(struct storage_ref_info * ref_info,
983 struct mailfolder * folder)
984{
985 int r;
986 int res;
987 struct folder_ref_info * folder_ref_info;
988
989 folder_ref_info = storage_get_folder_ref(ref_info, folder);
990 if (folder_ref_info == NULL) {
991 folder_ref_info = storage_folder_add_ref(ref_info, folder);
992 if (folder_ref_info == NULL)
993 return MAIL_ERROR_MEMORY;
994 }
995
996 /* connect folder */
997
998 r = folder_connect(ref_info, folder);
999 if (r == MAIL_ERROR_STREAM) {
1000 /* properly handles disconnection */
1001
1002 /* reconnect */
1003 folder_disconnect(ref_info, folder);
1004 r = folder_connect(ref_info, folder);
1005 }
1006
1007 if (r != MAIL_NO_ERROR) {
1008 res = r;
1009 goto err;
1010 }
1011
1012 /* test folder connection */
1013 r = mailfolder_noop(folder);
1014 if (r == MAIL_ERROR_STREAM) {
1015 /* reconnect */
1016 folder_disconnect(ref_info, folder);
1017 r = folder_connect(ref_info, folder);
1018 }
1019
1020 if ((r != MAIL_ERROR_NOT_IMPLEMENTED) && (r != MAIL_NO_ERROR)) {
1021 res = r;
1022 goto disconnect;
1023 }
1024
1025 storage_restore_message_session(ref_info);
1026
1027 return MAIL_NO_ERROR;
1028
1029 disconnect:
1030 folder_disconnect(ref_info, folder);
1031 err:
1032 return res;
1033}
1034
1035static void storage_folder_disconnect(struct storage_ref_info * ref_info,
1036 struct mailfolder * folder)
1037{
1038 mailfolder_disconnect(folder);
1039 storage_folder_remove_ref(ref_info, folder);
1040}
1041
1042static int storage_connect(struct storage_ref_info * ref_info)
1043{
1044 int r;
1045 int res;
1046
1047 /* connect storage */
1048
1049 /* properly handles disconnection */
1050 r = do_storage_connect(ref_info);
1051 if (r == MAIL_ERROR_STREAM) {
1052 /* reconnect storage */
1053 do_storage_disconnect(ref_info);
1054 r = do_storage_connect(ref_info);
1055 }
1056
1057 if (r != MAIL_NO_ERROR) {
1058 res = r;
1059 goto disconnect;
1060 }
1061
1062 /* test storage connection */
1063
1064 r = mailsession_noop(ref_info->storage->sto_session);
1065 if ((r != MAIL_ERROR_NOT_IMPLEMENTED) && (r != MAIL_NO_ERROR)) {
1066 /* properly handles disconnection */
1067
1068 /* reconnect storage */
1069 do_storage_disconnect(ref_info);
1070 r = do_storage_connect(ref_info);
1071 }
1072
1073 if (r != MAIL_NO_ERROR) {
1074 res = r;
1075 goto disconnect;
1076 }
1077
1078 storage_restore_message_session(ref_info);
1079
1080 return MAIL_NO_ERROR;
1081
1082 disconnect:
1083 do_storage_disconnect(ref_info);
1084 return res;
1085}
1086
1087
1088static void storage_disconnect(struct storage_ref_info * ref_info)
1089{
1090 chashiter * iter;
1091
1092 /* disconnect folders */
1093 while ((iter = chash_begin(ref_info->folder_ref_info)) != NULL) {
1094 chashdatum key;
1095 struct mailfolder * folder;
1096
1097 chash_key(iter, &key);
1098 memcpy(&folder, key.data, sizeof(folder));
1099
1100 storage_folder_disconnect(ref_info, folder);
1101 }
1102
1103 /* disconnect storage */
1104 do_storage_disconnect(ref_info);
1105}
1106
1107
1108/* ************************************************************* */
1109/* interface for mailengine */
1110
1111struct mailengine {
1112 struct mailprivacy * privacy;
1113
1114#ifdef LIBETPAN_REENTRANT
1115 pthread_mutex_t storage_hash_lock;
1116#endif
1117 /* storage => storage_ref_info */
1118 chash * storage_hash;
1119
1120#if 0
1121 struct message_folder_finder msg_folder_finder;
1122#endif
1123};
1124
1125static struct storage_ref_info *
1126get_storage_ref_info(struct mailengine * engine,
1127 struct mailstorage * storage)
1128{
1129 chashdatum key;
1130 chashdatum data;
1131 int r;
1132 struct storage_ref_info * ref_info;
1133
1134 key.data = &storage;
1135 key.len = sizeof(storage);
1136#ifdef LIBETPAN_REENTRANT
1137 pthread_mutex_lock(&engine->storage_hash_lock);
1138#endif
1139 r = chash_get(engine->storage_hash, &key, &data);
1140#ifdef LIBETPAN_REENTRANT
1141 pthread_mutex_unlock(&engine->storage_hash_lock);
1142#endif
1143 if (r < 0)
1144 return NULL;
1145
1146 ref_info = data.data;
1147
1148 return ref_info;
1149}
1150
1151static struct storage_ref_info *
1152add_storage_ref_info(struct mailengine * engine,
1153 struct mailstorage * storage)
1154{
1155 chashdatum key;
1156 chashdatum data;
1157 int r;
1158 struct storage_ref_info * ref_info;
1159
1160 ref_info = storage_ref_info_new(storage
1161 /* , &engine->msg_folder_finder */);
1162 if (ref_info == NULL)
1163 goto err;
1164
1165 key.data = &storage;
1166 key.len = sizeof(storage);
1167 data.data = ref_info;
1168 data.len = 0;
1169
1170#ifdef LIBETPAN_REENTRANT
1171 pthread_mutex_lock(&engine->storage_hash_lock);
1172#endif
1173 r = chash_set(engine->storage_hash, &key, &data, NULL);
1174#ifdef LIBETPAN_REENTRANT
1175 pthread_mutex_unlock(&engine->storage_hash_lock);
1176#endif
1177 if (r < 0)
1178 goto free;
1179
1180 ref_info = data.data;
1181
1182 return ref_info;
1183
1184 free:
1185 storage_ref_info_free(ref_info);
1186 err:
1187 return NULL;
1188}
1189
1190static void
1191remove_storage_ref_info(struct mailengine * engine,
1192 struct mailstorage * storage)
1193{
1194 chashdatum key;
1195 chashdatum data;
1196 struct storage_ref_info * ref_info;
1197
1198 key.data = &storage;
1199 key.len = sizeof(storage);
1200
1201#ifdef LIBETPAN_REENTRANT
1202 pthread_mutex_lock(&engine->storage_hash_lock);
1203#endif
1204
1205 chash_get(engine->storage_hash, &key, &data);
1206 ref_info = data.data;
1207
1208 if (ref_info != NULL) {
1209 storage_ref_info_free(ref_info);
1210
1211 chash_delete(engine->storage_hash, &key, NULL);
1212 }
1213
1214#ifdef LIBETPAN_REENTRANT
1215 pthread_mutex_unlock(&engine->storage_hash_lock);
1216#endif
1217}
1218
1219struct mailengine *
1220libetpan_engine_new(struct mailprivacy * privacy)
1221{
1222 struct mailengine * engine;
1223 int r;
1224
1225 engine = malloc(sizeof(* engine));
1226 if (engine == NULL)
1227 goto err;
1228
1229 engine->privacy = privacy;
1230
1231#if 0
1232 r = message_folder_finder_init(&engine->msg_folder_finder);
1233 if (r != MAIL_NO_ERROR)
1234 goto free;
1235#endif
1236
1237#ifdef LIBETPAN_REENTRANT
1238 r = pthread_mutex_init(&engine->storage_hash_lock, NULL);
1239 if (r != 0)
1240 goto free;
1241#endif
1242
1243 engine->storage_hash = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
1244 if (engine->storage_hash == NULL)
1245 goto destroy_mutex;
1246
1247 return engine;
1248
1249 destroy_mutex:
1250#ifdef LIBETPAN_REENTRANT
1251 pthread_mutex_destroy(&engine->storage_hash_lock);
1252#endif
1253#if 0
1254 finder_done:
1255 message_folder_finder_done(&engine->msg_folder_finder);
1256#endif
1257 free:
1258 free(engine);
1259 err:
1260 return NULL;
1261}
1262
1263void libetpan_engine_free(struct mailengine * engine)
1264{
1265 chash_free(engine->storage_hash);
1266#ifdef LIBETPAN_REENTRANT
1267 pthread_mutex_destroy(&engine->storage_hash_lock);
1268#endif
1269#if 0
1270 message_folder_finder_done(&engine->msg_folder_finder);
1271#endif
1272 free(engine);
1273}
1274
1275#if 0
1276static struct folder_ref_info *
1277message_get_folder_ref(struct mailengine * engine,
1278 mailmessage * msg)
1279{
1280 struct mailfolder * folder;
1281 struct mailstorage * storage;
1282 struct storage_ref_info * storage_ref_info;
1283 struct folder_ref_info * folder_ref_info;
1284
1285 folder = message_folder_finder_lookup(&engine->msg_folder_finder, msg);
1286 if (folder == NULL)
1287 storage = NULL;
1288 else
1289 storage = folder->fld_storage;
1290
1291 storage_ref_info = get_storage_ref_info(engine, storage);
1292
1293 folder_ref_info = storage_get_folder_ref(storage_ref_info, folder);
1294
1295 return folder_ref_info;
1296}
1297#endif
1298
1299static struct folder_ref_info *
1300message_get_folder_ref(struct mailengine * engine,
1301 mailmessage * msg)
1302{
1303 struct mailfolder * folder;
1304 struct mailstorage * storage;
1305 struct storage_ref_info * storage_ref_info;
1306 struct folder_ref_info * folder_ref_info;
1307
1308 folder = msg->msg_folder;
1309 if (folder == NULL)
1310 storage = NULL;
1311 else
1312 storage = folder->fld_storage;
1313
1314 storage_ref_info = get_storage_ref_info(engine, storage);
1315
1316 folder_ref_info = storage_get_folder_ref(storage_ref_info, folder);
1317
1318 return folder_ref_info;
1319}
1320
1321int libetpan_message_ref(struct mailengine * engine,
1322 mailmessage * msg)
1323{
1324 struct folder_ref_info * ref_info;
1325
1326 ref_info = message_get_folder_ref(engine, msg);
1327
1328 return folder_message_ref(ref_info, msg);
1329}
1330
1331int libetpan_message_unref(struct mailengine * engine,
1332 mailmessage * msg)
1333{
1334 struct folder_ref_info * ref_info;
1335
1336 ref_info = message_get_folder_ref(engine, msg);
1337
1338 return folder_message_unref(ref_info, msg);
1339}
1340
1341
1342int libetpan_message_mime_ref(struct mailengine * engine,
1343 mailmessage * msg)
1344{
1345 struct folder_ref_info * ref_info;
1346
1347 ref_info = message_get_folder_ref(engine, msg);
1348
1349 return folder_message_mime_ref(engine->privacy, ref_info, msg);
1350}
1351
1352int libetpan_message_mime_unref(struct mailengine * engine,
1353 mailmessage * msg)
1354{
1355 struct folder_ref_info * ref_info;
1356
1357 ref_info = message_get_folder_ref(engine, msg);
1358
1359 return folder_message_mime_unref(engine->privacy, ref_info, msg);
1360}
1361
1362int libetpan_folder_get_msg_list(struct mailengine * engine,
1363 struct mailfolder * folder,
1364 struct mailmessage_list ** p_new_msg_list,
1365 struct mailmessage_list ** p_lost_msg_list)
1366{
1367 struct storage_ref_info * ref_info;
1368
1369 ref_info = get_storage_ref_info(engine, folder->fld_storage);
1370
1371 return storage_folder_get_msg_list(ref_info, folder,
1372 p_new_msg_list, p_lost_msg_list);
1373}
1374
1375int libetpan_folder_fetch_env_list(struct mailengine * engine,
1376 struct mailfolder * folder,
1377 struct mailmessage_list * msg_list)
1378{
1379 struct storage_ref_info * ref_info;
1380
1381 ref_info = get_storage_ref_info(engine, folder->fld_storage);
1382
1383 return storage_folder_fetch_env_list(ref_info, folder, msg_list);
1384}
1385
1386void libetpan_folder_free_msg_list(struct mailengine * engine,
1387 struct mailfolder * folder,
1388 struct mailmessage_list * env_list)
1389{
1390 struct storage_ref_info * ref_info;
1391
1392 ref_info = get_storage_ref_info(engine, folder->fld_storage);
1393
1394 storage_folder_free_msg_list(ref_info, folder, env_list);
1395}
1396
1397
1398int libetpan_storage_add(struct mailengine * engine,
1399 struct mailstorage * storage)
1400{
1401 struct storage_ref_info * storage_ref_info;
1402 struct folder_ref_info * folder_ref_info;
1403
1404 storage_ref_info = add_storage_ref_info(engine, storage);
1405 if (storage_ref_info == NULL)
1406 goto err;
1407
1408 if (storage == NULL) {
1409 folder_ref_info = storage_folder_add_ref(storage_ref_info, NULL);
1410 if (folder_ref_info == NULL)
1411 goto remove_storage_ref_info;
1412 }
1413
1414 return MAIL_NO_ERROR;
1415
1416 remove_storage_ref_info:
1417 remove_storage_ref_info(engine, storage);
1418 err:
1419 return MAIL_ERROR_MEMORY;
1420}
1421
1422void libetpan_storage_remove(struct mailengine * engine,
1423 struct mailstorage * storage)
1424{
1425 struct storage_ref_info * storage_ref_info;
1426
1427 storage_ref_info = get_storage_ref_info(engine, storage);
1428 if (storage == NULL) {
1429 storage_folder_remove_ref(storage_ref_info, NULL);
1430 }
1431
1432 remove_storage_ref_info(engine, storage);
1433}
1434
1435int libetpan_storage_connect(struct mailengine * engine,
1436 struct mailstorage * storage)
1437{
1438 struct storage_ref_info * ref_info;
1439
1440 ref_info = get_storage_ref_info(engine, storage);
1441
1442 return storage_connect(ref_info);
1443}
1444
1445
1446void libetpan_storage_disconnect(struct mailengine * engine,
1447 struct mailstorage * storage)
1448{
1449 struct storage_ref_info * ref_info;
1450
1451 ref_info = get_storage_ref_info(engine, storage);
1452
1453 storage_disconnect(ref_info);
1454}
1455
1456int libetpan_storage_used(struct mailengine * engine,
1457 struct mailstorage * storage)
1458{
1459 struct storage_ref_info * ref_info;
1460
1461 ref_info = get_storage_ref_info(engine, storage);
1462
1463 return (chash_count(ref_info->folder_ref_info) != 0);
1464}
1465
1466
1467int libetpan_folder_connect(struct mailengine * engine,
1468 struct mailfolder * folder)
1469{
1470 struct storage_ref_info * ref_info;
1471
1472 ref_info = get_storage_ref_info(engine, folder->fld_storage);
1473
1474 return storage_folder_connect(ref_info, folder);
1475}
1476
1477
1478void libetpan_folder_disconnect(struct mailengine * engine,
1479 struct mailfolder * folder)
1480{
1481 struct storage_ref_info * ref_info;
1482
1483 ref_info = get_storage_ref_info(engine, folder->fld_storage);
1484
1485 storage_folder_disconnect(ref_info, folder);
1486}
1487
1488
1489struct mailfolder *
1490libetpan_message_get_folder(struct mailengine * engine,
1491 mailmessage * msg)
1492{
1493#if 0
1494 return message_folder_finder_lookup(&engine->msg_folder_finder, msg);
1495#endif
1496 return msg->msg_folder;
1497}
1498
1499
1500struct mailstorage *
1501libetpan_message_get_storage(struct mailengine * engine,
1502 mailmessage * msg)
1503{
1504 struct mailfolder * folder;
1505
1506 folder = libetpan_message_get_folder(engine, msg);
1507
1508 if (folder == NULL)
1509 return NULL;
1510 else
1511 return folder->fld_storage;
1512}
1513
1514
1515int libetpan_message_register(struct mailengine * engine,
1516 struct mailfolder * folder,
1517 mailmessage * msg)
1518{
1519 struct storage_ref_info * storage_ref_info;
1520 int r;
1521 int res;
1522 struct folder_ref_info * folder_ref_info;
1523 struct mailstorage * storage;
1524
1525#if 0
1526 r = message_folder_finder_store(&engine->msg_folder_finder, msg, folder);
1527 if (r != MAIL_NO_ERROR) {
1528 res = r;
1529 goto err;
1530 }
1531#endif
1532
1533 if (folder != NULL)
1534 storage = folder->fld_storage;
1535 else
1536 storage = NULL;
1537
1538 storage_ref_info = get_storage_ref_info(engine, storage);
1539
1540 folder_ref_info = storage_get_folder_ref(storage_ref_info, folder);
1541
1542 r = folder_message_add(folder_ref_info, msg);
1543 if (r != MAIL_NO_ERROR) {
1544 res = r;
1545 goto delete;
1546 }
1547
1548 return MAIL_NO_ERROR;
1549
1550 delete:
1551#if 0
1552 message_folder_finder_delete(&engine->msg_folder_finder, msg);
1553#endif
1554 err:
1555 return res;
1556}
1557
1558struct mailprivacy *
1559libetpan_engine_get_privacy(struct mailengine * engine)
1560{
1561 return engine->privacy;
1562}
1563
1564
1565static void folder_debug(struct folder_ref_info * folder_ref_info, FILE * f)
1566{
1567 fprintf(f, "folder debug -- begin\n");
1568 if (folder_ref_info->folder == NULL) {
1569 fprintf(f, "NULL folder\n");
1570 }
1571 else {
1572 if (folder_ref_info->folder->fld_virtual_name != NULL)
1573 fprintf(f, "folder %s\n", folder_ref_info->folder->fld_virtual_name);
1574 else
1575 fprintf(f, "folder [no name]\n");
1576 }
1577
1578 fprintf(f, "message count: %i\n", chash_count(folder_ref_info->msg_hash));
1579 fprintf(f, "UID count: %i\n", chash_count(folder_ref_info->uid_hash));
1580 fprintf(f, "folder debug -- end\n");
1581}
1582
1583static void storage_debug(struct storage_ref_info * storage_ref_info, FILE * f)
1584{
1585 chashiter * iter;
1586
1587 fprintf(f, "storage debug -- begin\n");
1588 if (storage_ref_info->storage == NULL) {
1589 fprintf(f, "NULL storage\n");
1590 }
1591 else {
1592 if (storage_ref_info->storage->sto_id != NULL)
1593 fprintf(f, "storage %s\n", storage_ref_info->storage->sto_id);
1594 else
1595 fprintf(f, "storage [no name]\n");
1596 }
1597 fprintf(f, "folder count: %i\n",
1598 chash_count(storage_ref_info->folder_ref_info));
1599
1600 for(iter = chash_begin(storage_ref_info->folder_ref_info) ; iter != NULL ;
1601 iter = chash_next(storage_ref_info->folder_ref_info, iter)) {
1602 chashdatum data;
1603 struct folder_ref_info * folder_ref_info;
1604
1605 chash_value(iter, &data);
1606 folder_ref_info = data.data;
1607
1608 folder_debug(folder_ref_info, f);
1609 }
1610 fprintf(f, "storage debug -- end\n");
1611}
1612
1613void libetpan_engine_debug(struct mailengine * engine, FILE * f)
1614{
1615 chashiter * iter;
1616
1617 fprintf(f, "mail engine debug -- begin\n");
1618
1619 for(iter = chash_begin(engine->storage_hash) ; iter != NULL ;
1620 iter = chash_next(engine->storage_hash, iter)) {
1621 chashdatum data;
1622 struct storage_ref_info * storage_ref_info;
1623
1624 chash_value(iter, &data);
1625 storage_ref_info = data.data;
1626
1627 storage_debug(storage_ref_info, f);
1628 }
1629
1630#if 0
1631 fprintf(f, "global message references: %i\n",
1632 chash_count(engine->msg_folder_finder.message_hash));
1633#endif
1634 fprintf(f, "mail engine debug -- end\n");
1635}
1636