summaryrefslogtreecommitdiffabout
path: root/libetpan/src/driver/tools
Unidiff
Diffstat (limited to 'libetpan/src/driver/tools') (more/less context) (ignore whitespace changes)
-rw-r--r--libetpan/src/driver/tools/generic_cache.c729
-rw-r--r--libetpan/src/driver/tools/generic_cache.h109
-rw-r--r--libetpan/src/driver/tools/generic_cache_types.h56
-rw-r--r--libetpan/src/driver/tools/imfcache.c1429
-rw-r--r--libetpan/src/driver/tools/imfcache.h75
-rw-r--r--libetpan/src/driver/tools/mailthread.c1742
-rw-r--r--libetpan/src/driver/tools/mailthread.h108
-rw-r--r--libetpan/src/driver/tools/mailthread_types.c90
-rw-r--r--libetpan/src/driver/tools/mailthread_types.h64
9 files changed, 4402 insertions, 0 deletions
diff --git a/libetpan/src/driver/tools/generic_cache.c b/libetpan/src/driver/tools/generic_cache.c
new file mode 100644
index 0000000..3ff6e43
--- a/dev/null
+++ b/libetpan/src/driver/tools/generic_cache.c
@@ -0,0 +1,729 @@
1/*
2 * libEtPan! -- a mail stuff 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 "generic_cache.h"
37
38#include "libetpan-config.h"
39
40#include <unistd.h>
41#include <string.h>
42#include <sys/mman.h>
43#include <stdio.h>
44#include <sys/types.h>
45#include <sys/stat.h>
46#include <fcntl.h>
47#include <unistd.h>
48#include <stdlib.h>
49
50#include "maildriver_types.h"
51#include "imfcache.h"
52#include "chash.h"
53#include "mailmessage.h"
54#include "mail_cache_db.h"
55
56int generic_cache_create_dir(char * dirname)
57{
58 struct stat buf;
59 int r;
60
61 r = stat(dirname, &buf);
62 if (r != 0) {
63 r = mkdir(dirname, 0700);
64
65 if (r < 0)
66 return MAIL_ERROR_FILE;
67 }
68 else {
69 if (!S_ISDIR(buf.st_mode))
70 return MAIL_ERROR_FILE;
71 }
72
73 return MAIL_NO_ERROR;
74}
75
76int generic_cache_store(char * filename, char * content, size_t length)
77{
78 int fd;
79 char * str;
80
81 fd = open(filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
82 if (fd == -1)
83 return MAIL_ERROR_FILE;
84
85 if (ftruncate(fd, length) < 0)
86 return MAIL_ERROR_FILE;
87
88 str = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
89 if (str == MAP_FAILED)
90 return MAIL_ERROR_FILE;
91
92 memcpy(str, content, length);
93 msync(str, length, MS_SYNC);
94 munmap(str, length);
95
96 close(fd);
97
98 return MAIL_NO_ERROR;
99}
100
101int generic_cache_read(char * filename, char ** result, size_t * result_len)
102{
103 int fd;
104 char * str;
105 struct stat buf;
106 MMAPString * mmapstr;
107 char * content;
108 int res;
109
110 if (stat(filename, &buf) < 0) {
111 res = MAIL_ERROR_CACHE_MISS;
112 goto err;
113 }
114
115 fd = open(filename, O_RDONLY);
116 if (fd == -1) {
117 res = MAIL_ERROR_CACHE_MISS;
118 goto err;
119 }
120
121 str = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
122 if (str == MAP_FAILED) {
123 res = MAIL_ERROR_FILE;
124 goto close;
125 }
126
127 mmapstr = mmap_string_new_len(str, buf.st_size);
128 if (mmapstr == NULL) {
129 res = MAIL_ERROR_MEMORY;
130 goto unmap;
131 }
132
133 if (mmap_string_ref(mmapstr) < 0) {
134 res = MAIL_ERROR_MEMORY;
135 goto free;
136 }
137
138 content = mmapstr->str;
139
140 munmap(str, buf.st_size);
141 close(fd);
142
143 * result = content;
144 * result_len = buf.st_size;
145
146 return MAIL_NO_ERROR;
147
148 free:
149 mmap_string_free(mmapstr);
150 unmap:
151 munmap(str, buf.st_size);
152 close:
153 close(fd);
154 err:
155 return res;
156}
157
158static int flags_extension_read(MMAPString * mmapstr, size_t * index,
159 clist ** result)
160{
161 clist * list;
162 int r;
163 uint32_t count;
164 uint32_t i;
165 int res;
166
167 r = mailimf_cache_int_read(mmapstr, index, &count);
168 if (r != MAIL_NO_ERROR) {
169 res = r;
170 goto err;
171 }
172
173 list = clist_new();
174 if (list == NULL) {
175 res = MAIL_ERROR_MEMORY;
176 goto err;
177 }
178
179 for(i = 0 ; i < count ; i++) {
180 char * str;
181
182 r = mailimf_cache_string_read(mmapstr, index, &str);
183 if (r != MAIL_NO_ERROR) {
184 res = r;
185 goto free_list;
186 }
187
188 r = clist_append(list, str);
189 if (r < 0) {
190 free(str);
191 res = MAIL_ERROR_MEMORY;
192 goto free_list;
193 }
194 }
195
196 * result = list;
197
198 return MAIL_NO_ERROR;
199
200 free_list:
201 clist_foreach(list, (clist_func) free, NULL);
202 clist_free(list);
203 err:
204 return res;
205}
206
207static int generic_flags_read(MMAPString * mmapstr, size_t * index,
208 struct mail_flags ** result)
209{
210 clist * ext;
211 int r;
212 struct mail_flags * flags;
213 uint32_t value;
214 int res;
215
216 r = mailimf_cache_int_read(mmapstr, index, &value);
217 if (r != MAIL_NO_ERROR) {
218 res = r;
219 goto err;
220 }
221
222 r = flags_extension_read(mmapstr, index, &ext);
223 if (r != MAIL_NO_ERROR) {
224 res = r;
225 goto err;
226 }
227
228 flags = mail_flags_new(value, ext);
229 if (flags == NULL) {
230 res = r;
231 goto free;
232 }
233
234 * result = flags;
235
236 return MAIL_NO_ERROR;
237
238 free:
239 clist_foreach(ext, (clist_func) free, NULL);
240 clist_free(ext);
241 err:
242 return res;
243}
244
245static int flags_extension_write(MMAPString * mmapstr, size_t * index,
246 clist * ext)
247{
248 int r;
249 clistiter * cur;
250
251 r = mailimf_cache_int_write(mmapstr, index, clist_count(ext));
252 if (r != MAIL_NO_ERROR)
253 return r;
254
255 for(cur = clist_begin(ext) ; cur != NULL ; cur = clist_next(cur)) {
256 r = mailimf_cache_string_write(mmapstr, index,
257 clist_content(cur), strlen(clist_content(cur)));
258 if (r != MAIL_NO_ERROR)
259 return r;
260 }
261
262 return MAIL_NO_ERROR;
263}
264
265static int generic_flags_write(MMAPString * mmapstr, size_t * index,
266 struct mail_flags * flags)
267{
268 int r;
269
270 r = mailimf_cache_int_write(mmapstr, index,
271 flags->fl_flags & ~MAIL_FLAG_NEW);
272 if (r != MAIL_NO_ERROR)
273 return r;
274
275 r = flags_extension_write(mmapstr, index,
276 flags->fl_extension);
277 if (r != MAIL_NO_ERROR)
278 return r;
279
280 return MAIL_NO_ERROR;
281}
282
283
284
285
286static struct mail_flags * mail_flags_dup(struct mail_flags * flags)
287{
288 clist * list;
289 struct mail_flags * new_flags;
290 int r;
291 clistiter * cur;
292
293 list = clist_new();
294 if (list == NULL) {
295 goto err;
296 }
297
298 for(cur = clist_begin(flags->fl_extension) ; cur != NULL ;
299 cur = clist_next(cur)) {
300 char * ext;
301
302 ext = strdup(clist_content(cur));
303 if (ext == NULL) {
304 goto free;
305 }
306
307 r = clist_append(list, ext);
308 if (r < 0) {
309 free(ext);
310 goto free;
311 }
312 }
313
314 new_flags = mail_flags_new(flags->fl_flags, list);
315 if (new_flags == NULL) {
316 goto free;
317 }
318
319 return new_flags;
320
321 free:
322 clist_foreach(list, (clist_func) free, NULL);
323 clist_free(list);
324 err:
325 return NULL;
326}
327
328static mailmessage * mailmessage_build(mailmessage * msg)
329{
330 mailmessage * new_msg;
331
332 new_msg = malloc(sizeof(* new_msg));
333 if (new_msg == NULL)
334 goto err;
335
336 new_msg->msg_session = msg->msg_session;
337 new_msg->msg_driver = msg->msg_driver;
338 new_msg->msg_index = msg->msg_index;
339 if (msg->msg_uid == NULL)
340 new_msg->msg_uid = NULL;
341 else {
342 new_msg->msg_uid = strdup(msg->msg_uid);
343 if (new_msg->msg_uid == NULL)
344 goto free;
345 }
346
347 new_msg->msg_cached = msg->msg_cached;
348 new_msg->msg_size = msg->msg_size;
349 new_msg->msg_fields = NULL;
350 new_msg->msg_flags = mail_flags_dup(msg->msg_flags);
351 if (new_msg->msg_flags == NULL) {
352 free(new_msg->msg_uid);
353 goto free;
354 }
355
356 new_msg->msg_mime = NULL;
357 new_msg->msg_data = NULL;
358
359 return new_msg;
360
361 free:
362 free(new_msg);
363 err:
364 return NULL;
365}
366
367struct mail_flags_store * mail_flags_store_new(void)
368{
369 struct mail_flags_store * flags_store;
370
371 flags_store = malloc(sizeof(struct mail_flags_store));
372 if (flags_store == NULL)
373 goto err;
374
375 flags_store->fls_tab = carray_new(128);
376 if (flags_store->fls_tab == NULL)
377 goto free;
378
379 flags_store->fls_hash = chash_new(128, CHASH_COPYALL);
380 if (flags_store->fls_hash == NULL)
381 goto free_tab;
382
383 return flags_store;
384
385 free_tab:
386 carray_free(flags_store->fls_tab);
387 free:
388 free(flags_store);
389 err:
390 return NULL;
391}
392
393void mail_flags_store_clear(struct mail_flags_store * flags_store)
394{
395 unsigned int i;
396
397 for(i = 0 ; i < carray_count(flags_store->fls_tab) ; i ++) {
398 chashdatum key;
399 mailmessage * msg;
400
401 msg = carray_get(flags_store->fls_tab, i);
402
403 key.data = &msg->msg_index;
404 key.len = sizeof(msg->msg_index);
405 chash_delete(flags_store->fls_hash, &key, NULL);
406
407 mailmessage_free(msg);
408 }
409 carray_set_size(flags_store->fls_tab, 0);
410}
411
412void mail_flags_store_free(struct mail_flags_store * flags_store)
413{
414 mail_flags_store_clear(flags_store);
415 chash_free(flags_store->fls_hash);
416 carray_free(flags_store->fls_tab);
417 free(flags_store);
418}
419
420int mail_flags_store_set(struct mail_flags_store * flags_store,
421 mailmessage * msg)
422{
423 chashdatum key;
424 chashdatum value;
425 unsigned int index;
426 int res;
427 int r;
428 mailmessage * new_msg;
429
430 if (msg->msg_flags == NULL) {
431 res = MAIL_NO_ERROR;
432 goto err;
433 }
434
435 /* duplicate needed message info */
436 new_msg = mailmessage_build(msg);
437 if (new_msg == NULL) {
438 res = MAIL_ERROR_MEMORY;
439 goto err;
440 }
441
442 key.data = &new_msg->msg_index;
443 key.len = sizeof(new_msg->msg_index);
444
445 r = chash_get(flags_store->fls_hash, &key, &value);
446 if (r == 0) {
447 mailmessage * old_msg;
448
449 index = * (unsigned int *) value.data;
450 old_msg = carray_get(flags_store->fls_tab, index);
451 mailmessage_free(old_msg);
452 }
453 else {
454 r = carray_set_size(flags_store->fls_tab,
455 carray_count(flags_store->fls_tab) + 1);
456 if (r != 0) {
457 res = MAIL_ERROR_MEMORY;
458 goto err;
459 }
460 index = carray_count(flags_store->fls_tab) - 1;
461 }
462
463 carray_set(flags_store->fls_tab, index, new_msg);
464
465 value.data = &index;
466 value.len = sizeof(index);
467
468 r = chash_set(flags_store->fls_hash, &key, &value, NULL);
469 if (r < 0) {
470 carray_delete(flags_store->fls_tab, index);
471 res = MAIL_ERROR_MEMORY;
472 goto free;
473 }
474
475 return MAIL_NO_ERROR;
476
477 free:
478 mailmessage_free(new_msg);
479 err:
480 return res;
481}
482
483static int msg_index_compare(mailmessage ** msg1, mailmessage ** msg2)
484{
485 return (* msg1)->msg_index - (* msg2)->msg_index;
486}
487
488void mail_flags_store_sort(struct mail_flags_store * flags_store)
489{
490 qsort(carray_data(flags_store->fls_tab),
491 carray_count(flags_store->fls_tab), sizeof(mailmessage *),
492 (int (*)(const void *, const void *)) msg_index_compare);
493}
494
495struct mail_flags *
496mail_flags_store_get(struct mail_flags_store * flags_store, uint32_t index)
497{
498 struct mail_flags * flags;
499 chashdatum key;
500 chashdatum value;
501 int r;
502 unsigned int tab_index;
503 mailmessage * msg;
504
505 key.data = &index;
506 key.len = sizeof(index);
507
508 r = chash_get(flags_store->fls_hash, &key, &value);
509
510 if (r < 0)
511 return NULL;
512
513#if 0
514 flags = mail_flags_dup((struct mail_flags *) value.data);
515#endif
516 tab_index = * (unsigned int *) value.data;
517 msg = carray_get(flags_store->fls_tab, tab_index);
518 if (msg->msg_flags == NULL)
519 return NULL;
520
521 flags = mail_flags_dup(msg->msg_flags);
522
523 return flags;
524}
525
526int mail_flags_compare(struct mail_flags * flags1, struct mail_flags * flags2)
527{
528 clistiter * cur1;
529
530 if (clist_count(flags1->fl_extension) != clist_count(flags2->fl_extension))
531 return -1;
532
533 for(cur1 = clist_begin(flags1->fl_extension) ; cur1 != NULL ;
534 cur1 = clist_next(cur1)) {
535 char * flag1;
536 clistiter * cur2;
537 int found;
538
539 flag1 = clist_content(cur1);
540
541 found = 0;
542 for(cur2 = clist_begin(flags2->fl_extension) ; cur2 != NULL ;
543 cur2 = clist_next(cur2)) {
544 char * flag2;
545
546 flag2 = clist_content(cur2);
547
548 if (strcasecmp(flag1, flag2) == 0) {
549 found = 1;
550 break;
551 }
552 }
553
554 if (!found)
555 return -1;
556 }
557
558 return flags1->fl_flags - flags2->fl_flags;
559}
560
561
562int generic_cache_fields_read(struct mail_cache_db * cache_db,
563 MMAPString * mmapstr,
564 char * keyname, struct mailimf_fields ** result)
565{
566 int r;
567 int res;
568 size_t cur_token;
569 struct mailimf_fields * fields;
570 void * data;
571 size_t data_len;
572
573 r = mail_cache_db_get(cache_db, keyname, strlen(keyname), &data, &data_len);
574 if (r != 0) {
575 res = MAIL_ERROR_CACHE_MISS;
576 goto err;
577 }
578
579 r = mail_serialize_clear(mmapstr, &cur_token);
580 if (r != MAIL_NO_ERROR) {
581 res = r;
582 goto err;
583 }
584
585 if (mmap_string_append_len(mmapstr, data, data_len) == NULL) {
586 res = MAIL_ERROR_MEMORY;
587 goto err;
588 }
589
590 r = mailimf_cache_fields_read(mmapstr, &cur_token, &fields);
591 if (r != MAIL_NO_ERROR) {
592 res = r;
593 goto err;
594 }
595
596 * result = fields;
597
598 return MAIL_NO_ERROR;
599
600 err:
601 return res;
602}
603
604int generic_cache_fields_write(struct mail_cache_db * cache_db,
605 MMAPString * mmapstr,
606 char * keyname, struct mailimf_fields * fields)
607{
608 int r;
609 int res;
610 size_t cur_token;
611
612 r = mail_serialize_clear(mmapstr, &cur_token);
613 if (r != MAIL_NO_ERROR) {
614 res = r;
615 goto err;
616 }
617
618 r = mailimf_cache_fields_write(mmapstr, &cur_token, fields);
619 if (r != MAIL_NO_ERROR) {
620 res = r;
621 goto err;
622 }
623
624 r = mail_cache_db_put(cache_db, keyname, strlen(keyname),
625 mmapstr->str, mmapstr->len);
626 if (r != 0) {
627 res = MAIL_ERROR_FILE;
628 goto err;
629 }
630
631 return MAIL_NO_ERROR;
632
633 err:
634 return res;
635}
636
637int generic_cache_flags_read(struct mail_cache_db * cache_db,
638 MMAPString * mmapstr,
639 char * keyname, struct mail_flags ** result)
640{
641 int r;
642 int res;
643 size_t cur_token;
644 struct mail_flags * flags;
645 void * data;
646 size_t data_len;
647
648 r = mail_cache_db_get(cache_db, keyname, strlen(keyname), &data, &data_len);
649 if (r != 0) {
650 res = MAIL_ERROR_CACHE_MISS;
651 goto err;
652 }
653
654 r = mail_serialize_clear(mmapstr, &cur_token);
655 if (r != MAIL_NO_ERROR) {
656 res = r;
657 goto err;
658 }
659
660 if (mmap_string_append_len(mmapstr, data, data_len) == NULL) {
661 res = MAIL_ERROR_MEMORY;
662 goto err;
663 }
664
665 r = generic_flags_read(mmapstr, &cur_token, &flags);
666 if (r != MAIL_NO_ERROR) {
667 res = r;
668 goto err;
669 }
670
671 * result = flags;
672
673 return MAIL_NO_ERROR;
674
675 err:
676 return res;
677}
678
679int generic_cache_flags_write(struct mail_cache_db * cache_db,
680 MMAPString * mmapstr,
681 char * keyname, struct mail_flags * flags)
682{
683 int r;
684 int res;
685 size_t cur_token;
686
687 r = mail_serialize_clear(mmapstr, &cur_token);
688 if (r != MAIL_NO_ERROR) {
689 res = r;
690 goto err;
691 }
692
693 r = generic_flags_write(mmapstr, &cur_token, flags);
694 if (r != MAIL_NO_ERROR) {
695 res = r;
696 goto err;
697 }
698
699 r = mail_cache_db_put(cache_db, keyname, strlen(keyname),
700 mmapstr->str, mmapstr->len);
701 if (r != 0) {
702 res = MAIL_ERROR_FILE;
703 goto err;
704 }
705
706 return MAIL_NO_ERROR;
707
708 err:
709 return res;
710}
711
712
713int generic_cache_delete(struct mail_cache_db * cache_db,
714 char * keyname)
715{
716 int r;
717 int res;
718
719 r = mail_cache_db_del(cache_db, keyname, strlen(keyname));
720 if (r != 0) {
721 res = MAIL_ERROR_FILE;
722 goto err;
723 }
724
725 return MAIL_NO_ERROR;
726
727 err:
728 return res;
729}
diff --git a/libetpan/src/driver/tools/generic_cache.h b/libetpan/src/driver/tools/generic_cache.h
new file mode 100644
index 0000000..934a53d
--- a/dev/null
+++ b/libetpan/src/driver/tools/generic_cache.h
@@ -0,0 +1,109 @@
1/*
2 * libEtPan! -- a mail stuff 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#ifndef GENERIC_CACHE_H
37
38#define GENERIC_CACHE_H
39
40#ifdef __cplusplus
41extern "C" {
42#endif
43
44#include "generic_cache_types.h"
45#include "mailmessage_types.h"
46#include "chash.h"
47#include "carray.h"
48#include "mail_cache_db_types.h"
49
50int generic_cache_create_dir(char * dirname);
51
52int generic_cache_store(char * filename, char * content, size_t length);
53int generic_cache_read(char * filename, char ** result, size_t * result_len);
54
55int generic_cache_fields_read(struct mail_cache_db * cache_db,
56 MMAPString * mmapstr,
57 char * keyname, struct mailimf_fields ** result);
58
59int generic_cache_fields_write(struct mail_cache_db * cache_db,
60 MMAPString * mmapstr,
61 char * keyname, struct mailimf_fields * fields);
62
63int generic_cache_flags_read(struct mail_cache_db * cache_db,
64 MMAPString * mmapstr,
65 char * keyname, struct mail_flags ** result);
66
67int generic_cache_flags_write(struct mail_cache_db * cache_db,
68 MMAPString * mmapstr,
69 char * keyname, struct mail_flags * flags);
70
71int generic_cache_delete(struct mail_cache_db * cache_db, char * keyname);
72
73#if 0
74int generic_cache_fields_read(DB * dbp, MMAPString * mmapstr,
75 char * keyname, struct mailimf_fields ** result);
76
77int generic_cache_fields_write(DB * dbp, MMAPString * mmapstr,
78 char * keyname, struct mailimf_fields * fields);
79
80int generic_cache_flags_read(DB * dbp, MMAPString * mmapstr,
81 char * keyname, struct mail_flags ** result);
82
83int generic_cache_flags_write(DB * dbp, MMAPString * mmapstr,
84 char * keyname, struct mail_flags * flags);
85
86int generic_cache_delete(DB * dbp, char * keyname);
87#endif
88
89struct mail_flags_store * mail_flags_store_new(void);
90
91void mail_flags_store_clear(struct mail_flags_store * flags_store);
92
93void mail_flags_store_free(struct mail_flags_store * flags_store);
94
95int mail_flags_store_set(struct mail_flags_store * flags_store,
96 mailmessage * msg);
97
98void mail_flags_store_sort(struct mail_flags_store * flags_store);
99
100struct mail_flags *
101mail_flags_store_get(struct mail_flags_store * flags_store, uint32_t index);
102
103int mail_flags_compare(struct mail_flags * flags1, struct mail_flags * flags2);
104
105#ifdef __cplusplus
106}
107#endif
108
109#endif
diff --git a/libetpan/src/driver/tools/generic_cache_types.h b/libetpan/src/driver/tools/generic_cache_types.h
new file mode 100644
index 0000000..bc69b3c
--- a/dev/null
+++ b/libetpan/src/driver/tools/generic_cache_types.h
@@ -0,0 +1,56 @@
1/*
2 * libEtPan! -- a mail stuff 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#ifndef GENERIC_CACHE_TYPE_H
37
38#define GENERIC_CACHE_TYPE_H
39
40#include <libetpan/carray.h>
41#include <libetpan/chash.h>
42
43#ifdef __cplusplus
44extern "C" {
45#endif
46
47struct mail_flags_store {
48 carray * fls_tab;
49 chash * fls_hash;
50};
51
52#ifdef __cplusplus
53}
54#endif
55
56#endif
diff --git a/libetpan/src/driver/tools/imfcache.c b/libetpan/src/driver/tools/imfcache.c
new file mode 100644
index 0000000..7c6a5be
--- a/dev/null
+++ b/libetpan/src/driver/tools/imfcache.c
@@ -0,0 +1,1429 @@
1/*
2 * libEtPan! -- a mail stuff 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 "imfcache.h"
37
38#include <stdlib.h>
39#include <string.h>
40
41static int mailimf_cache_field_write(MMAPString * mmapstr, size_t * index,
42 struct mailimf_field * field);
43static int mailimf_cache_orig_date_write(MMAPString * mmapstr, size_t * index,
44 struct mailimf_orig_date * date);
45static int mailimf_cache_date_time_write(MMAPString * mmapstr, size_t * index,
46 struct mailimf_date_time * date_time);
47static int mailimf_cache_from_write(MMAPString * mmapstr, size_t * index,
48 struct mailimf_from * from);
49static int mailimf_cache_sender_write(MMAPString * mmapstr, size_t * index,
50 struct mailimf_sender * sender);
51static int mailimf_cache_reply_to_write(MMAPString * mmapstr, size_t * index,
52 struct mailimf_reply_to * reply_to);
53static int mailimf_cache_to_write(MMAPString * mmapstr, size_t * index,
54 struct mailimf_to * to);
55static int mailimf_cache_cc_write(MMAPString * mmapstr, size_t * index,
56 struct mailimf_cc * to);
57static int mailimf_cache_bcc_write(MMAPString * mmapstr, size_t * index,
58 struct mailimf_bcc * to);
59static int mailimf_cache_message_id_write(MMAPString * mmapstr, size_t * index,
60 struct mailimf_message_id * message_id);
61static int mailimf_cache_msg_id_list_write(MMAPString * mmapstr, size_t * index,
62 clist * list);
63static int mailimf_cache_in_reply_to_write(MMAPString * mmapstr, size_t * index,
64 struct mailimf_in_reply_to *
65 in_reply_to);
66static int mailimf_cache_references_write(MMAPString * mmapstr, size_t * index,
67 struct mailimf_references * references);
68static int mailimf_cache_subject_write(MMAPString * mmapstr, size_t * index,
69 struct mailimf_subject * subject);
70static int mailimf_cache_address_list_write(MMAPString * mmapstr,
71 size_t * index,
72 struct mailimf_address_list *
73 addr_list);
74static int mailimf_cache_address_write(MMAPString * mmapstr, size_t * index,
75 struct mailimf_address * addr);
76static int mailimf_cache_group_write(MMAPString * mmapstr, size_t * index,
77 struct mailimf_group * group);
78static int mailimf_cache_mailbox_list_write(MMAPString * mmapstr,
79 size_t * index,
80 struct mailimf_mailbox_list * mb_list);
81static int mailimf_cache_mailbox_write(MMAPString * mmapstr, size_t * index,
82 struct mailimf_mailbox * mb);
83
84
85static int mailimf_cache_field_read(MMAPString * mmapstr, size_t * index,
86 struct mailimf_field ** result);
87static int mailimf_cache_orig_date_read(MMAPString * mmapstr, size_t * index,
88 struct mailimf_orig_date ** result);
89static int mailimf_cache_date_time_read(MMAPString * mmapstr, size_t * index,
90 struct mailimf_date_time ** result);
91static int mailimf_cache_from_read(MMAPString * mmapstr, size_t * index,
92 struct mailimf_from ** result);
93static int mailimf_cache_sender_read(MMAPString * mmapstr, size_t * index,
94 struct mailimf_sender ** result);
95static int mailimf_cache_reply_to_read(MMAPString * mmapstr, size_t * index,
96 struct mailimf_reply_to ** result);
97static int mailimf_cache_to_read(MMAPString * mmapstr, size_t * index,
98 struct mailimf_to ** result);
99static int mailimf_cache_cc_read(MMAPString * mmapstr, size_t * index,
100 struct mailimf_cc ** result);
101static int mailimf_cache_bcc_read(MMAPString * mmapstr, size_t * index,
102 struct mailimf_bcc ** result);
103static int mailimf_cache_message_id_read(MMAPString * mmapstr, size_t * index,
104 struct mailimf_message_id ** result);
105static int mailimf_cache_msg_id_list_read(MMAPString * mmapstr, size_t * index,
106 clist ** result);
107static int
108mailimf_cache_in_reply_to_read(MMAPString * mmapstr, size_t * index,
109 struct mailimf_in_reply_to ** result);
110
111static int mailimf_cache_references_read(MMAPString * mmapstr, size_t * index,
112 struct mailimf_references ** result);
113static int mailimf_cache_subject_read(MMAPString * mmapstr, size_t * index,
114 struct mailimf_subject ** result);
115static int mailimf_cache_address_list_read(MMAPString * mmapstr, size_t * index,
116 struct mailimf_address_list ** result);
117static int mailimf_cache_address_read(MMAPString * mmapstr, size_t * index,
118 struct mailimf_address ** result);
119static int mailimf_cache_group_read(MMAPString * mmapstr, size_t * index,
120 struct mailimf_group ** result);
121static int
122mailimf_cache_mailbox_list_read(MMAPString * mmapstr, size_t * index,
123 struct mailimf_mailbox_list ** result);
124static int mailimf_cache_mailbox_read(MMAPString * mmapstr, size_t * index,
125 struct mailimf_mailbox ** result);
126
127enum {
128 CACHE_NULL_POINTER = 0,
129 CACHE_NOT_NULL = 1,
130};
131
132int mail_serialize_clear(MMAPString * mmapstr, size_t * index)
133{
134 if (mmap_string_set_size(mmapstr, 0) == NULL)
135 return MAIL_ERROR_MEMORY;
136
137 * index = 0;
138
139 return MAIL_NO_ERROR;
140}
141
142int mail_serialize_write(MMAPString * mmapstr, size_t * index,
143 char * buf, size_t size)
144{
145 if (mmap_string_append_len(mmapstr, buf, size) == NULL)
146 return MAIL_ERROR_MEMORY;
147
148 * index = * index + size;
149
150 return MAIL_NO_ERROR;
151}
152
153int mail_serialize_read(MMAPString * mmapstr, size_t * index,
154 char * buf, size_t size)
155{
156 size_t cur_token;
157
158 cur_token = * index;
159
160 if (cur_token + size > mmapstr->len)
161 return MAIL_ERROR_STREAM;
162
163 memcpy(buf, mmapstr->str + cur_token, size);
164 * index = cur_token + size;
165
166 return MAIL_NO_ERROR;
167}
168
169int mailimf_cache_int_write(MMAPString * mmapstr, size_t * index,
170 uint32_t value)
171{
172 unsigned char ch;
173 int r;
174 int i;
175
176 for(i = 0 ; i < 4 ; i ++) {
177 ch = value % 256;
178
179 r = mail_serialize_write(mmapstr, index, &ch, 1);
180 if (r != MAIL_NO_ERROR)
181 return r;
182 value /= 256;
183 }
184
185 return MAIL_NO_ERROR;
186}
187
188int mailimf_cache_int_read(MMAPString * mmapstr, size_t * index,
189 uint32_t * result)
190{
191 unsigned char ch;
192 uint32_t value;
193 int i;
194 int r;
195
196 value = 0;
197 for(i = 0 ; i < 4 ; i ++) {
198 r = mail_serialize_read(mmapstr, index, &ch, 1);
199 if (r != MAIL_NO_ERROR)
200 return r;
201 value = value | ch << (i << 3);
202 }
203
204 * result = value;
205
206 return MAIL_NO_ERROR;
207}
208
209
210int mailimf_cache_string_write(MMAPString * mmapstr, size_t * index,
211 char * str, size_t length)
212{
213 int r;
214
215 if (str == NULL) {
216 r = mailimf_cache_int_write(mmapstr, index, CACHE_NULL_POINTER);
217 if (r != MAIL_NO_ERROR)
218 return r;
219 }
220 else {
221 r = mailimf_cache_int_write(mmapstr, index, CACHE_NOT_NULL);
222 if (r != MAIL_NO_ERROR)
223 return r;
224
225 r = mailimf_cache_int_write(mmapstr, index, length);
226 if (r != MAIL_NO_ERROR)
227 return r;
228
229 if (length != 0) {
230 r = mail_serialize_write(mmapstr, index, str, length);
231 if (r != MAIL_NO_ERROR)
232 return MAIL_ERROR_FILE;
233 }
234 }
235
236 return MAIL_NO_ERROR;
237}
238
239int mailimf_cache_string_read(MMAPString * mmapstr, size_t * index,
240 char ** result)
241{
242 int r;
243 uint32_t length;
244 char * str;
245 uint32_t type;
246
247 r = mailimf_cache_int_read(mmapstr, index, &type);
248 if (r != MAIL_NO_ERROR)
249 return r;
250
251 if (type == CACHE_NULL_POINTER) {
252 str = NULL;
253 }
254 else {
255 r = mailimf_cache_int_read(mmapstr, index, &length);
256 if (r != MAIL_NO_ERROR)
257 return r;
258
259 str = malloc(length + 1);
260 if (str == NULL)
261 return MAIL_ERROR_MEMORY;
262
263 r = mail_serialize_read(mmapstr, index, str, length);
264 if (r != MAIL_NO_ERROR)
265 return MAIL_ERROR_FILE;
266
267 str[length] = 0;
268 }
269
270 * result = str;
271
272 return MAIL_NO_ERROR;
273}
274
275int mailimf_cache_fields_write(MMAPString * mmapstr, size_t * index,
276 struct mailimf_fields * fields)
277{
278 clistiter * cur;
279 int r;
280
281 r = mailimf_cache_int_write(mmapstr, index,
282 clist_count(fields->fld_list));
283 if (r != MAIL_NO_ERROR)
284 return r;
285
286 for(cur = clist_begin(fields->fld_list) ; cur != NULL ;
287 cur = clist_next(cur)) {
288 r = mailimf_cache_field_write(mmapstr, index, clist_content(cur));
289 if (r != MAIL_NO_ERROR)
290 return r;
291 }
292
293 return MAIL_NO_ERROR;
294}
295
296int mailimf_cache_fields_read(MMAPString * mmapstr, size_t * index,
297 struct mailimf_fields ** result)
298{
299 clist * list;
300 int r;
301 uint32_t count;
302 uint32_t i;
303 struct mailimf_fields * fields;
304 int res;
305
306 r = mailimf_cache_int_read(mmapstr, index, &count);
307 if (r != MAIL_NO_ERROR) {
308 res = r;
309 goto err;
310 }
311
312 list = clist_new();
313 if (list == NULL) {
314 res = MAIL_ERROR_MEMORY;
315 goto err;
316 }
317
318 for(i = 0 ; i < count ; i++) {
319 struct mailimf_field * field;
320
321 r = mailimf_cache_field_read(mmapstr, index, &field);
322 if (r != MAIL_NO_ERROR) {
323 res = r;
324 goto free_list;
325 }
326
327 r = clist_append(list, field);
328 if (r < 0) {
329 mailimf_field_free(field);
330 res = MAIL_ERROR_MEMORY;
331 goto free_list;
332 }
333 }
334
335 fields = mailimf_fields_new(list);
336 if (fields == NULL) {
337 res = MAIL_ERROR_MEMORY;
338 goto free_list;
339 }
340
341 * result = fields;
342
343 return MAIL_NO_ERROR;
344
345 free_list:
346 clist_foreach(list, (clist_func) mailimf_field_free, NULL);
347 clist_free(list);
348 err:
349 return res;
350}
351
352
353static int mailimf_cache_field_write(MMAPString * mmapstr, size_t * index,
354 struct mailimf_field * field)
355{
356 int r;
357
358 r = mailimf_cache_int_write(mmapstr, index, field->fld_type);
359 if (r != MAIL_NO_ERROR)
360 return r;
361
362 switch (field->fld_type) {
363 case MAILIMF_FIELD_ORIG_DATE:
364 r = mailimf_cache_orig_date_write(mmapstr, index,
365 field->fld_data.fld_orig_date);
366 break;
367 case MAILIMF_FIELD_FROM:
368 r = mailimf_cache_from_write(mmapstr, index,
369 field->fld_data.fld_from);
370 break;
371 case MAILIMF_FIELD_SENDER:
372 r = mailimf_cache_sender_write(mmapstr, index,
373 field->fld_data.fld_sender);
374 break;
375 case MAILIMF_FIELD_REPLY_TO:
376 r = mailimf_cache_reply_to_write(mmapstr, index,
377 field->fld_data.fld_reply_to);
378 break;
379 case MAILIMF_FIELD_TO:
380 r = mailimf_cache_to_write(mmapstr, index,
381 field->fld_data.fld_to);
382 break;
383 case MAILIMF_FIELD_CC:
384 r = mailimf_cache_cc_write(mmapstr, index,
385 field->fld_data.fld_cc);
386 break;
387 case MAILIMF_FIELD_BCC:
388 r = mailimf_cache_bcc_write(mmapstr, index,
389 field->fld_data.fld_bcc);
390 break;
391 case MAILIMF_FIELD_MESSAGE_ID:
392 r = mailimf_cache_message_id_write(mmapstr, index,
393 field->fld_data.fld_message_id);
394 break;
395 case MAILIMF_FIELD_IN_REPLY_TO:
396 r = mailimf_cache_in_reply_to_write(mmapstr, index,
397 field->fld_data.fld_in_reply_to);
398 break;
399 case MAILIMF_FIELD_REFERENCES:
400 r = mailimf_cache_references_write(mmapstr, index,
401 field->fld_data.fld_references);
402 break;
403 case MAILIMF_FIELD_SUBJECT:
404 r = mailimf_cache_subject_write(mmapstr, index,
405 field->fld_data.fld_subject);
406 break;
407 default:
408 r = 0;
409 break;
410 }
411
412 if (r != MAIL_NO_ERROR)
413 return r;
414
415 return MAIL_NO_ERROR;
416}
417
418
419static int mailimf_cache_field_read(MMAPString * mmapstr, size_t * index,
420 struct mailimf_field ** result)
421{
422 int r;
423 uint32_t type;
424 struct mailimf_orig_date * orig_date;
425 struct mailimf_from * from;
426 struct mailimf_sender * sender;
427 struct mailimf_to * to;
428 struct mailimf_reply_to * reply_to;
429 struct mailimf_cc * cc;
430 struct mailimf_bcc * bcc;
431 struct mailimf_message_id * message_id;
432 struct mailimf_in_reply_to * in_reply_to;
433 struct mailimf_references * references;
434 struct mailimf_subject * subject;
435 struct mailimf_field * field;
436 int res;
437
438 orig_date = NULL;
439 from = NULL;
440 sender = NULL;
441 to = NULL;
442 reply_to = NULL;
443 cc = NULL;
444 bcc = NULL;
445 message_id = NULL;
446 in_reply_to = NULL;
447 references = NULL;
448 subject = NULL;
449 field = NULL;
450
451 r = mailimf_cache_int_read(mmapstr, index, &type);
452 if (r != MAIL_NO_ERROR) {
453 res = r;
454 goto err;
455 }
456
457 switch (type) {
458 case MAILIMF_FIELD_ORIG_DATE:
459 r = mailimf_cache_orig_date_read(mmapstr, index, &orig_date);
460 break;
461 case MAILIMF_FIELD_FROM:
462 r = mailimf_cache_from_read(mmapstr, index, &from);
463 break;
464 case MAILIMF_FIELD_SENDER:
465 r = mailimf_cache_sender_read(mmapstr, index, &sender);
466 break;
467 case MAILIMF_FIELD_REPLY_TO:
468 r = mailimf_cache_reply_to_read(mmapstr, index, &reply_to);
469 break;
470 case MAILIMF_FIELD_TO:
471 r = mailimf_cache_to_read(mmapstr, index, &to);
472 break;
473 case MAILIMF_FIELD_CC:
474 r = mailimf_cache_cc_read(mmapstr, index, &cc);
475 break;
476 case MAILIMF_FIELD_BCC:
477 r = mailimf_cache_bcc_read(mmapstr, index, &bcc);
478 break;
479 case MAILIMF_FIELD_MESSAGE_ID:
480 r = mailimf_cache_message_id_read(mmapstr, index, &message_id);
481 break;
482 case MAILIMF_FIELD_IN_REPLY_TO:
483 r = mailimf_cache_in_reply_to_read(mmapstr, index, &in_reply_to);
484 break;
485 case MAILIMF_FIELD_REFERENCES:
486 r = mailimf_cache_references_read(mmapstr, index, &references);
487 break;
488 case MAILIMF_FIELD_SUBJECT:
489 r = mailimf_cache_subject_read(mmapstr, index, &subject);
490 break;
491 default:
492 r = MAIL_ERROR_INVAL;
493 break;
494 }
495
496 if (r != MAIL_NO_ERROR) {
497 res = r;
498 goto free;
499 }
500
501 field = mailimf_field_new(type, NULL, NULL, NULL, NULL, NULL,
502 NULL, NULL, NULL, orig_date, from, sender, reply_to,
503 to, cc, bcc, message_id,
504 in_reply_to, references,
505 subject, NULL, NULL, NULL);
506 if (field == NULL) {
507 res = MAIL_ERROR_MEMORY;
508 goto free;
509 }
510
511 * result = field;
512
513 return MAIL_NO_ERROR;
514
515 free:
516 if (orig_date != NULL)
517 mailimf_orig_date_free(orig_date);
518 if (from != NULL)
519 mailimf_from_free(from);
520 if (sender != NULL)
521 mailimf_sender_free(sender);
522 if (reply_to != NULL)
523 mailimf_reply_to_free(reply_to);
524 if (to != NULL)
525 mailimf_to_free(to);
526 if (cc != NULL)
527 mailimf_cc_free(cc);
528 if (bcc != NULL)
529 mailimf_bcc_free(bcc);
530 if (message_id != NULL)
531 mailimf_message_id_free(message_id);
532 if (in_reply_to != NULL)
533 mailimf_in_reply_to_free(in_reply_to);
534 if (references != NULL)
535 mailimf_references_free(references);
536 if (subject != NULL)
537 mailimf_subject_free(subject);
538 err:
539 return res;
540}
541
542static int mailimf_cache_orig_date_write(MMAPString * mmapstr, size_t * index,
543 struct mailimf_orig_date * date)
544{
545 return mailimf_cache_date_time_write(mmapstr, index, date->dt_date_time);
546}
547
548static int mailimf_cache_orig_date_read(MMAPString * mmapstr, size_t * index,
549 struct mailimf_orig_date ** result)
550{
551 int r;
552 struct mailimf_date_time * date_time;
553 struct mailimf_orig_date * orig_date;
554
555 r = mailimf_cache_date_time_read(mmapstr, index, &date_time);
556 if (r != MAIL_NO_ERROR)
557 return r;
558
559 orig_date = mailimf_orig_date_new(date_time);
560 if (orig_date == NULL) {
561 mailimf_date_time_free(date_time);
562 return MAIL_ERROR_MEMORY;
563 }
564
565 * result = orig_date;
566
567 return MAIL_NO_ERROR;
568}
569
570static int mailimf_cache_date_time_write(MMAPString * mmapstr, size_t * index,
571 struct mailimf_date_time * date_time)
572{
573 int r;
574
575 r = mailimf_cache_int_write(mmapstr, index, date_time->dt_day);
576 if (r != MAIL_NO_ERROR)
577 return r;
578
579 r = mailimf_cache_int_write(mmapstr, index, date_time->dt_month);
580 if (r != MAIL_NO_ERROR)
581 return r;
582
583 r = mailimf_cache_int_write(mmapstr, index, date_time->dt_year);
584 if (r != MAIL_NO_ERROR)
585 return r;
586
587 r = mailimf_cache_int_write(mmapstr, index, date_time->dt_hour);
588 if (r != MAIL_NO_ERROR)
589 return r;
590
591 r = mailimf_cache_int_write(mmapstr, index, date_time->dt_min);
592 if (r != MAIL_NO_ERROR)
593 return r;
594
595 r = mailimf_cache_int_write(mmapstr, index, date_time->dt_sec);
596 if (r != MAIL_NO_ERROR)
597 return r;
598
599 r = mailimf_cache_int_write(mmapstr, index, date_time->dt_zone);
600 if (r != MAIL_NO_ERROR)
601 return r;
602
603 return MAIL_NO_ERROR;
604}
605
606static int mailimf_cache_date_time_read(MMAPString * mmapstr, size_t * index,
607 struct mailimf_date_time ** result)
608{
609 int r;
610 uint32_t day;
611 uint32_t month;
612 uint32_t year;
613 uint32_t hour;
614 uint32_t min;
615 uint32_t sec;
616 uint32_t zone;
617 struct mailimf_date_time * date_time;
618
619 r = mailimf_cache_int_read(mmapstr, index, &day);
620 if (r != MAIL_NO_ERROR)
621 return r;
622
623 r = mailimf_cache_int_read(mmapstr, index, &month);
624 if (r != MAIL_NO_ERROR)
625 return r;
626
627 r = mailimf_cache_int_read(mmapstr, index, &year);
628 if (r != MAIL_NO_ERROR)
629 return r;
630
631 r = mailimf_cache_int_read(mmapstr, index, &hour);
632 if (r != MAIL_NO_ERROR)
633 return r;
634
635 r = mailimf_cache_int_read(mmapstr, index, &min);
636 if (r != MAIL_NO_ERROR)
637 return r;
638
639 r = mailimf_cache_int_read(mmapstr, index, &sec);
640 if (r != MAIL_NO_ERROR)
641 return r;
642
643 r = mailimf_cache_int_read(mmapstr, index, &zone);
644 if (r != MAIL_NO_ERROR)
645 return r;
646
647 date_time = mailimf_date_time_new(day, month, year, hour, min, sec, zone);
648 if (date_time == NULL)
649 return MAIL_ERROR_MEMORY;
650
651 * result = date_time;
652
653 return MAIL_NO_ERROR;
654
655}
656
657
658static int mailimf_cache_from_write(MMAPString * mmapstr, size_t * index,
659 struct mailimf_from * from)
660{
661 return mailimf_cache_mailbox_list_write(mmapstr, index, from->frm_mb_list);
662}
663
664static int mailimf_cache_from_read(MMAPString * mmapstr, size_t * index,
665 struct mailimf_from ** result)
666{
667 struct mailimf_mailbox_list * mb_list;
668 struct mailimf_from * from;
669 int r;
670
671 r = mailimf_cache_mailbox_list_read(mmapstr, index, &mb_list);
672 if (r != MAIL_NO_ERROR)
673 return r;
674
675 from = mailimf_from_new(mb_list);
676 if (from == NULL) {
677 mailimf_mailbox_list_free(mb_list);
678 return MAIL_ERROR_MEMORY;
679 }
680
681 * result = from;
682
683 return MAIL_NO_ERROR;
684}
685
686static int mailimf_cache_sender_write(MMAPString * mmapstr, size_t * index,
687 struct mailimf_sender * sender)
688{
689 return mailimf_cache_mailbox_write(mmapstr, index, sender->snd_mb);
690}
691
692static int mailimf_cache_sender_read(MMAPString * mmapstr, size_t * index,
693 struct mailimf_sender ** result)
694{
695 int r;
696 struct mailimf_mailbox * mb;
697 struct mailimf_sender * sender;
698
699 r = mailimf_cache_mailbox_read(mmapstr, index, &mb);
700 if (r != MAIL_NO_ERROR)
701 return r;
702
703 sender = mailimf_sender_new(mb);
704 if (sender == NULL) {
705 mailimf_mailbox_free(mb);
706 return MAIL_ERROR_MEMORY;
707 }
708
709 * result = sender;
710
711 return MAIL_NO_ERROR;
712}
713
714static int mailimf_cache_reply_to_write(MMAPString * mmapstr, size_t * index,
715 struct mailimf_reply_to * reply_to)
716{
717 return mailimf_cache_address_list_write(mmapstr, index,
718 reply_to->rt_addr_list);
719}
720
721static int mailimf_cache_reply_to_read(MMAPString * mmapstr, size_t * index,
722 struct mailimf_reply_to ** result)
723{
724 int r;
725 struct mailimf_address_list * addr_list;
726 struct mailimf_reply_to * reply_to;
727
728 r = mailimf_cache_address_list_read(mmapstr, index, &addr_list);
729 if (r != MAIL_NO_ERROR)
730 return r;
731
732 reply_to = mailimf_reply_to_new(addr_list);
733 if (reply_to == NULL) {
734 mailimf_address_list_free(addr_list);
735 return MAIL_ERROR_MEMORY;
736 }
737
738 * result = reply_to;
739
740 return MAIL_NO_ERROR;
741}
742
743static int mailimf_cache_to_write(MMAPString * mmapstr, size_t * index,
744 struct mailimf_to * to)
745{
746 return mailimf_cache_address_list_write(mmapstr, index, to->to_addr_list);
747}
748
749static int mailimf_cache_to_read(MMAPString * mmapstr, size_t * index,
750 struct mailimf_to ** result)
751{
752 int r;
753 struct mailimf_address_list * addr_list;
754 struct mailimf_to * to;
755
756 r = mailimf_cache_address_list_read(mmapstr, index, &addr_list);
757 if (r != MAIL_NO_ERROR)
758 return r;
759
760 to = mailimf_to_new(addr_list);
761 if (to == NULL) {
762 mailimf_address_list_free(addr_list);
763 return MAIL_ERROR_MEMORY;
764 }
765
766 * result = to;
767
768 return MAIL_NO_ERROR;
769}
770
771static int mailimf_cache_cc_write(MMAPString * mmapstr, size_t * index,
772 struct mailimf_cc * cc)
773{
774 return mailimf_cache_address_list_write(mmapstr, index, cc->cc_addr_list);
775}
776
777static int mailimf_cache_cc_read(MMAPString * mmapstr, size_t * index,
778 struct mailimf_cc ** result)
779{
780 int r;
781 struct mailimf_address_list * addr_list;
782 struct mailimf_cc * cc;
783
784 r = mailimf_cache_address_list_read(mmapstr, index, &addr_list);
785 if (r != MAIL_NO_ERROR)
786 return r;
787
788 cc = mailimf_cc_new(addr_list);
789 if (cc == NULL) {
790 mailimf_address_list_free(addr_list);
791 return MAIL_ERROR_MEMORY;
792 }
793
794 * result = cc;
795
796 return MAIL_NO_ERROR;
797}
798
799static int mailimf_cache_bcc_write(MMAPString * mmapstr, size_t * index,
800 struct mailimf_bcc * bcc)
801{
802 return mailimf_cache_address_list_write(mmapstr, index, bcc->bcc_addr_list);
803}
804
805static int mailimf_cache_bcc_read(MMAPString * mmapstr, size_t * index,
806 struct mailimf_bcc ** result)
807{
808 int r;
809 struct mailimf_address_list * addr_list;
810 struct mailimf_bcc * bcc;
811
812 r = mailimf_cache_address_list_read(mmapstr, index, &addr_list);
813 if (r != MAIL_NO_ERROR)
814 return r;
815
816 bcc = mailimf_bcc_new(addr_list);
817 if (bcc == NULL) {
818 mailimf_address_list_free(addr_list);
819 return MAIL_ERROR_MEMORY;
820 }
821
822 * result = bcc;
823
824 return MAIL_NO_ERROR;
825}
826
827static int
828mailimf_cache_message_id_write(MMAPString * mmapstr, size_t * index,
829 struct mailimf_message_id * message_id)
830{
831 return mailimf_cache_string_write(mmapstr, index,
832 message_id->mid_value, strlen(message_id->mid_value));
833}
834
835static int mailimf_cache_message_id_read(MMAPString * mmapstr, size_t * index,
836 struct mailimf_message_id ** result)
837{
838 struct mailimf_message_id * message_id;
839 char * str;
840 int r;
841
842 r = mailimf_cache_string_read(mmapstr, index, &str);
843 if (r != MAIL_NO_ERROR)
844 return r;
845
846 message_id = mailimf_message_id_new(str);
847 if (message_id == NULL) {
848 free(str);
849 return MAIL_ERROR_MEMORY;
850 }
851
852 * result = message_id;
853
854 return MAIL_NO_ERROR;
855}
856
857static int
858mailimf_cache_msg_id_list_write(MMAPString * mmapstr, size_t * index,
859 clist * list)
860{
861 clistiter * cur;
862 int r;
863
864 r = mailimf_cache_int_write(mmapstr, index, clist_count(list));
865 if (r != MAIL_NO_ERROR)
866 return r;
867
868 for(cur = clist_begin(list) ; cur != NULL ; cur = clist_next(cur)) {
869 char * msgid;
870
871 msgid = clist_content(cur);
872
873 r = mailimf_cache_string_write(mmapstr, index, msgid, strlen(msgid));
874 if (r != MAIL_NO_ERROR)
875 return r;
876 }
877
878 return MAIL_NO_ERROR;
879}
880
881static int mailimf_cache_msg_id_list_read(MMAPString * mmapstr, size_t * index,
882 clist ** result)
883{
884 clist * list;
885 int r;
886 uint32_t count;
887 uint32_t i;
888 int res;
889
890 r = mailimf_cache_int_read(mmapstr, index, &count);
891 if (r != MAIL_NO_ERROR) {
892 res = r;
893 goto err;
894 }
895
896 list = clist_new();
897 if (list == NULL) {
898 res = MAIL_ERROR_MEMORY;
899 goto err;
900 }
901
902 for(i = 0 ; i < count ; i++) {
903 char * msgid;
904
905 r = mailimf_cache_string_read(mmapstr, index, &msgid);
906 if (r != MAIL_NO_ERROR) {
907 res = r;
908 goto err;
909 }
910
911 r = clist_append(list, msgid);
912 if (r < 0) {
913 free(msgid);
914 res = MAIL_ERROR_MEMORY;
915 goto free_list;
916 }
917 }
918
919 * result = list;
920
921 return MAIL_NO_ERROR;
922
923 free_list:
924 clist_foreach(list, (clist_func) free, NULL);
925 clist_free(list);
926 err:
927 return res;
928}
929
930static int
931mailimf_cache_in_reply_to_write(MMAPString * mmapstr, size_t * index,
932 struct mailimf_in_reply_to * in_reply_to)
933{
934 return mailimf_cache_msg_id_list_write(mmapstr, index,
935 in_reply_to->mid_list);
936}
937
938static int mailimf_cache_in_reply_to_read(MMAPString * mmapstr, size_t * index,
939 struct mailimf_in_reply_to ** result)
940{
941 int r;
942 clist * msg_id_list;
943 struct mailimf_in_reply_to * in_reply_to;
944
945 r = mailimf_cache_msg_id_list_read(mmapstr, index, &msg_id_list);
946 if (r != MAIL_NO_ERROR)
947 return r;
948
949 in_reply_to = mailimf_in_reply_to_new(msg_id_list);
950 if (in_reply_to == NULL) {
951 clist_foreach(msg_id_list, (clist_func) free, NULL);
952 clist_free(msg_id_list);
953 return MAIL_ERROR_MEMORY;
954 }
955
956 * result = in_reply_to;
957
958 return MAIL_NO_ERROR;
959}
960
961static int mailimf_cache_references_write(MMAPString * mmapstr, size_t * index,
962 struct mailimf_references * references)
963{
964 return mailimf_cache_msg_id_list_write(mmapstr, index,
965 references->mid_list);
966}
967
968static int mailimf_cache_references_read(MMAPString * mmapstr, size_t * index,
969 struct mailimf_references ** result)
970{
971 int r;
972 clist * msg_id_list;
973 struct mailimf_references * references;
974
975 r = mailimf_cache_msg_id_list_read(mmapstr, index, &msg_id_list);
976 if (r != MAIL_NO_ERROR)
977 return r;
978
979 references = mailimf_references_new(msg_id_list);
980 if (references == NULL) {
981 clist_foreach(msg_id_list, (clist_func) free, NULL);
982 clist_free(msg_id_list);
983 return MAIL_ERROR_MEMORY;
984 }
985
986 * result = references;
987
988 return MAIL_NO_ERROR;
989}
990
991
992static int mailimf_cache_subject_write(MMAPString * mmapstr, size_t * index,
993 struct mailimf_subject * subject)
994{
995 return mailimf_cache_string_write(mmapstr, index,
996 subject->sbj_value, strlen(subject->sbj_value));
997}
998
999static int mailimf_cache_subject_read(MMAPString * mmapstr, size_t * index,
1000 struct mailimf_subject ** result)
1001{
1002 char * str;
1003 struct mailimf_subject * subject;
1004 int r;
1005
1006 r = mailimf_cache_string_read(mmapstr, index, &str);
1007 if (r != MAIL_NO_ERROR)
1008 return r;
1009
1010 if (str == NULL) {
1011 str = strdup("");
1012 if (str == NULL)
1013 return MAIL_ERROR_MEMORY;
1014 }
1015
1016 subject = mailimf_subject_new(str);
1017 if (subject == NULL) {
1018 free(str);
1019 return MAIL_ERROR_MEMORY;
1020 }
1021
1022 * result = subject;
1023
1024 return MAIL_NO_ERROR;
1025}
1026
1027
1028static int
1029mailimf_cache_address_list_write(MMAPString * mmapstr, size_t * index,
1030 struct mailimf_address_list * addr_list)
1031{
1032 clistiter * cur;
1033 int r;
1034
1035 if (addr_list == NULL) {
1036 r = mailimf_cache_int_write(mmapstr, index, CACHE_NULL_POINTER);
1037 if (r != MAIL_NO_ERROR)
1038 return r;
1039 }
1040 else {
1041 r = mailimf_cache_int_write(mmapstr, index, CACHE_NOT_NULL);
1042 if (r != MAIL_NO_ERROR)
1043 return r;
1044
1045 r = mailimf_cache_int_write(mmapstr, index,
1046 clist_count(addr_list->ad_list));
1047 if (r != MAIL_NO_ERROR)
1048 return r;
1049
1050 for(cur = clist_begin(addr_list->ad_list) ; cur != NULL ;
1051 cur = clist_next(cur)) {
1052 struct mailimf_address * addr;
1053
1054 addr = clist_content(cur);
1055
1056 r = mailimf_cache_address_write(mmapstr, index, addr);
1057 if (r != MAIL_NO_ERROR)
1058 return r;
1059 }
1060 }
1061
1062 return MAIL_NO_ERROR;
1063}
1064
1065static int
1066mailimf_cache_address_list_read(MMAPString * mmapstr, size_t * index,
1067 struct mailimf_address_list ** result)
1068{
1069 struct mailimf_address_list * addr_list;
1070 uint32_t count;
1071 uint32_t i;
1072 int r;
1073 clist * list;
1074 int res;
1075 uint32_t type;
1076
1077 r = mailimf_cache_int_read(mmapstr, index, &type);
1078 if (r != MAIL_NO_ERROR) {
1079 res = r;
1080 goto err;
1081 }
1082
1083 if (type == CACHE_NULL_POINTER) {
1084 * result = NULL;
1085 return MAIL_NO_ERROR;
1086 }
1087
1088 r = mailimf_cache_int_read(mmapstr, index, &count);
1089 if (r != MAIL_NO_ERROR) {
1090 res = r;
1091 goto err;
1092 }
1093
1094 list = clist_new();
1095 if (list == NULL) {
1096 res = MAIL_ERROR_MEMORY;
1097 goto err;
1098 }
1099
1100 for(i = 0 ; i < count ; i++) {
1101 struct mailimf_address * addr;
1102
1103 r = mailimf_cache_address_read(mmapstr, index, &addr);
1104 if (r != MAIL_NO_ERROR) {
1105 res = r;
1106 goto free_list;
1107 }
1108
1109 r = clist_append(list, addr);
1110 if (r < 0) {
1111 mailimf_address_free(addr);
1112 res = MAIL_ERROR_MEMORY;
1113 goto free_list;
1114 }
1115 }
1116
1117 addr_list = mailimf_address_list_new(list);
1118 if (addr_list == NULL) {
1119 res = MAIL_ERROR_MEMORY;
1120 goto free_list;
1121 }
1122
1123 * result = addr_list;
1124
1125 return MAIL_NO_ERROR;
1126
1127 free_list:
1128 clist_foreach(list, (clist_func) mailimf_address_free, NULL);
1129 clist_free(list);
1130 err:
1131 return res;
1132}
1133
1134static int mailimf_cache_address_write(MMAPString * mmapstr, size_t * index,
1135 struct mailimf_address * addr)
1136{
1137 int r;
1138
1139 r = mailimf_cache_int_write(mmapstr, index, addr->ad_type);
1140 if (r != MAIL_NO_ERROR)
1141 return r;
1142
1143 switch(addr->ad_type) {
1144 case MAILIMF_ADDRESS_MAILBOX:
1145 r = mailimf_cache_mailbox_write(mmapstr, index, addr->ad_data.ad_mailbox);
1146 if (r != MAIL_NO_ERROR)
1147 return r;
1148
1149 break;
1150
1151 case MAILIMF_ADDRESS_GROUP:
1152 r = mailimf_cache_group_write(mmapstr, index, addr->ad_data.ad_group);
1153 if (r != MAIL_NO_ERROR)
1154 return r;
1155
1156 break;
1157 }
1158
1159 return MAIL_NO_ERROR;
1160}
1161
1162static int mailimf_cache_address_read(MMAPString * mmapstr, size_t * index,
1163 struct mailimf_address ** result)
1164{
1165 uint32_t type;
1166 int r;
1167 struct mailimf_mailbox * mailbox;
1168 struct mailimf_group * group;
1169 struct mailimf_address * addr;
1170
1171 r = mailimf_cache_int_read(mmapstr, index, &type);
1172 if (r != MAIL_NO_ERROR)
1173 return r;
1174
1175 mailbox = NULL;
1176 group = NULL;
1177
1178 switch (type) {
1179 case MAILIMF_ADDRESS_MAILBOX:
1180 r = mailimf_cache_mailbox_read(mmapstr, index, &mailbox);
1181 if (r != MAIL_NO_ERROR)
1182 return r;
1183
1184 break;
1185
1186 case MAILIMF_ADDRESS_GROUP:
1187 r = mailimf_cache_group_read(mmapstr, index, &group);
1188 if (r != MAIL_NO_ERROR)
1189 return r;
1190
1191 break;
1192 }
1193
1194 addr = mailimf_address_new(type, mailbox, group);
1195 if (addr == NULL)
1196 goto free;
1197
1198 * result = addr;
1199
1200 return MAIL_NO_ERROR;
1201
1202 free:
1203 if (mailbox != NULL)
1204 mailimf_mailbox_free(mailbox);
1205 if (group != NULL)
1206 mailimf_group_free(group);
1207 return MAIL_ERROR_MEMORY;
1208}
1209
1210static int mailimf_cache_group_write(MMAPString * mmapstr, size_t * index,
1211 struct mailimf_group * group)
1212{
1213 int r;
1214
1215 r = mailimf_cache_string_write(mmapstr, index, group->grp_display_name,
1216 strlen(group->grp_display_name));
1217 if (r != MAIL_NO_ERROR)
1218 return r;
1219
1220 r = mailimf_cache_mailbox_list_write(mmapstr, index, group->grp_mb_list);
1221 if (r != MAIL_NO_ERROR)
1222 return r;
1223
1224 return MAIL_NO_ERROR;
1225}
1226
1227static int mailimf_cache_group_read(MMAPString * mmapstr, size_t * index,
1228 struct mailimf_group ** result)
1229{
1230 int r;
1231 char * display_name;
1232 struct mailimf_mailbox_list * mb_list;
1233 struct mailimf_group * group;
1234 int res;
1235
1236 r = mailimf_cache_string_read(mmapstr, index, &display_name);
1237 if (r != MAIL_NO_ERROR) {
1238 res = r;
1239 goto err;
1240 }
1241
1242 r = mailimf_cache_mailbox_list_read(mmapstr, index, &mb_list);
1243 if (r != MAIL_NO_ERROR) {
1244 res = r;
1245 goto free_dsp_name;
1246 }
1247
1248 group = mailimf_group_new(display_name, mb_list);
1249 if (group == NULL) {
1250 res = MAIL_ERROR_MEMORY;
1251 goto free_mb_list;
1252 }
1253
1254 * result = group;
1255
1256 return MAIL_NO_ERROR;
1257
1258 free_mb_list:
1259 mailimf_mailbox_list_free(mb_list);
1260 free_dsp_name:
1261 free(display_name);
1262 err:
1263 return res;
1264}
1265
1266static int
1267mailimf_cache_mailbox_list_write(MMAPString * mmapstr, size_t * index,
1268 struct mailimf_mailbox_list * mb_list)
1269{
1270 clistiter * cur;
1271 int r;
1272
1273 if (mb_list == NULL) {
1274 r = mailimf_cache_int_write(mmapstr, index, CACHE_NULL_POINTER);
1275 if (r != MAIL_NO_ERROR)
1276 return r;
1277 }
1278 else {
1279 r = mailimf_cache_int_write(mmapstr, index, CACHE_NOT_NULL);
1280 if (r != MAIL_NO_ERROR)
1281 return r;
1282
1283 r = mailimf_cache_int_write(mmapstr, index,
1284 clist_count(mb_list->mb_list));
1285 if (r != MAIL_NO_ERROR)
1286 return r;
1287
1288 for(cur = clist_begin(mb_list->mb_list) ; cur != NULL ;
1289 cur = clist_next(cur)) {
1290 struct mailimf_mailbox * mb;
1291
1292 mb = clist_content(cur);
1293
1294 r = mailimf_cache_mailbox_write(mmapstr, index, mb);
1295 if (r != MAIL_NO_ERROR)
1296 return r;
1297 }
1298 }
1299
1300 return MAIL_NO_ERROR;
1301}
1302
1303static int
1304mailimf_cache_mailbox_list_read(MMAPString * mmapstr, size_t * index,
1305 struct mailimf_mailbox_list ** result)
1306{
1307 clist * list;
1308 int r;
1309 uint32_t count;
1310 uint32_t i;
1311 struct mailimf_mailbox_list * mb_list;
1312 int res;
1313 uint32_t type;
1314
1315 r = mailimf_cache_int_read(mmapstr, index, &type);
1316 if (r != MAIL_NO_ERROR) {
1317 res = r;
1318 goto err;
1319 }
1320
1321 if (type == CACHE_NULL_POINTER) {
1322 * result = NULL;
1323 return MAIL_NO_ERROR;
1324 }
1325
1326 r = mailimf_cache_int_read(mmapstr, index, &count);
1327 if (r != MAIL_NO_ERROR) {
1328 res = r;
1329 goto err;
1330 }
1331
1332 list = clist_new();
1333 if (list == NULL) {
1334 res = MAIL_ERROR_MEMORY;
1335 goto err;
1336 }
1337
1338 for(i = 0 ; i < count ; i++) {
1339 struct mailimf_mailbox * mb;
1340
1341 r = mailimf_cache_mailbox_read(mmapstr, index, &mb);
1342 if (r != MAIL_NO_ERROR) {
1343 res = r;
1344 goto free_list;
1345 }
1346
1347 r = clist_append(list, mb);
1348 if (r < 0) {
1349 mailimf_mailbox_free(mb);
1350 res = MAIL_ERROR_MEMORY;
1351 goto free_list;
1352 }
1353 }
1354
1355 mb_list = mailimf_mailbox_list_new(list);
1356 if (mb_list == NULL) {
1357 res = MAIL_ERROR_MEMORY;
1358 goto free_list;
1359 }
1360
1361 * result = mb_list;
1362
1363 return MAIL_NO_ERROR;
1364
1365 free_list:
1366 clist_foreach(list, (clist_func) mailimf_mailbox_free, NULL);
1367 clist_free(list);
1368 err:
1369 return res;
1370}
1371
1372static int mailimf_cache_mailbox_write(MMAPString * mmapstr, size_t * index,
1373 struct mailimf_mailbox * mb)
1374{
1375 int r;
1376
1377 if (mb->mb_display_name) {
1378 r = mailimf_cache_string_write(mmapstr, index,
1379 mb->mb_display_name, strlen(mb->mb_display_name));
1380 if (r != MAIL_NO_ERROR)
1381 return r;
1382 }
1383 else {
1384 r = mailimf_cache_string_write(mmapstr, index, NULL, 0);
1385 if (r != MAIL_NO_ERROR)
1386 return r;
1387 }
1388
1389 r = mailimf_cache_string_write(mmapstr, index,
1390 mb->mb_addr_spec, strlen(mb->mb_addr_spec));
1391 if (r != MAIL_NO_ERROR)
1392 return r;
1393
1394 return MAIL_NO_ERROR;
1395}
1396
1397static int mailimf_cache_mailbox_read(MMAPString * mmapstr, size_t * index,
1398 struct mailimf_mailbox ** result)
1399{
1400 int r;
1401 char * dsp_name;
1402 char * addr_spec;
1403 struct mailimf_mailbox * mb;
1404
1405 dsp_name = NULL;
1406
1407 r = mailimf_cache_string_read(mmapstr, index, &dsp_name);
1408 if (r != MAIL_NO_ERROR)
1409 return r;
1410
1411 r = mailimf_cache_string_read(mmapstr, index, &addr_spec);
1412 if (r != MAIL_NO_ERROR)
1413 goto free_dsp_name;
1414
1415 mb = mailimf_mailbox_new(dsp_name, addr_spec);
1416 if (mb == NULL)
1417 goto free_addr;
1418
1419 * result = mb;
1420
1421 return MAIL_NO_ERROR;
1422
1423 free_addr:
1424 free(addr_spec);
1425 free_dsp_name:
1426 if (dsp_name != NULL)
1427 free(dsp_name);
1428 return MAIL_ERROR_MEMORY;
1429}
diff --git a/libetpan/src/driver/tools/imfcache.h b/libetpan/src/driver/tools/imfcache.h
new file mode 100644
index 0000000..f054a12
--- a/dev/null
+++ b/libetpan/src/driver/tools/imfcache.h
@@ -0,0 +1,75 @@
1/*
2 * libEtPan! -- a mail stuff 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#ifndef IMFCACHE_H
37
38#define IMFCACHE_H
39
40#include <stdio.h>
41#include "mailimf.h"
42#include "maildriver_types.h"
43#include "mmapstring.h"
44
45#ifdef __cplusplus
46extern "C" {
47#endif
48
49int mail_serialize_clear(MMAPString * mmapstr, size_t * index);
50
51int mail_serialize_write(MMAPString * mmapstr, size_t * index,
52 char * buf, size_t size);
53
54int mail_serialize_read(MMAPString * mmapstr, size_t * index,
55 char * buf, size_t size);
56
57int mailimf_cache_int_write(MMAPString * mmapstr, size_t * index,
58 uint32_t value);
59int mailimf_cache_string_write(MMAPString * mmapstr, size_t * index,
60 char * str, size_t length);
61int mailimf_cache_int_read(MMAPString * mmapstr, size_t * index,
62 uint32_t * result);
63int mailimf_cache_string_read(MMAPString * mmapstr, size_t * index,
64 char ** result);
65
66int mailimf_cache_fields_write(MMAPString * mmapstr, size_t * index,
67 struct mailimf_fields * fields);
68int mailimf_cache_fields_read(MMAPString * mmapstr, size_t * index,
69 struct mailimf_fields ** result);
70
71#ifdef __cplusplus
72}
73#endif
74
75#endif
diff --git a/libetpan/src/driver/tools/mailthread.c b/libetpan/src/driver/tools/mailthread.c
new file mode 100644
index 0000000..32f73cd
--- a/dev/null
+++ b/libetpan/src/driver/tools/mailthread.c
@@ -0,0 +1,1742 @@
1/*
2 * libEtPan! -- a mail stuff 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 "mailthread.h"
37#include "mailthread_types.h"
38
39#include <string.h>
40#include <time.h>
41#include <stdlib.h>
42#include <ctype.h>
43
44#include "mail.h"
45#include "chash.h"
46#include "carray.h"
47#include "clist.h"
48#include "mailmessage.h"
49
50static inline char * get_msg_id(mailmessage * msg)
51{
52 if (msg->msg_single_fields.fld_message_id != NULL)
53 return msg->msg_single_fields.fld_message_id->mid_value;
54 else
55 return NULL;
56}
57
58static inline clist * get_ref(mailmessage * msg)
59{
60 if (msg->msg_single_fields.fld_references != NULL)
61 return msg->msg_single_fields.fld_references->mid_list;
62 else
63 return NULL;
64}
65
66static inline clist * get_in_reply_to(mailmessage * msg)
67{
68 if (msg->msg_single_fields.fld_in_reply_to != NULL)
69 return msg->msg_single_fields.fld_in_reply_to->mid_list;
70 else
71 return NULL;
72}
73
74static inline int skip_subj_blob(char * subj, size_t * begin,
75 size_t length)
76{
77 /* subj-blob = "[" *BLOBCHAR "]" *WSP */
78 size_t cur_token;
79
80 cur_token = * begin;
81
82 if (subj[cur_token] != '[')
83 return FALSE;
84
85 cur_token ++;
86
87 while (1) {
88 if (cur_token >= length)
89 return FALSE;
90
91 if (subj[cur_token] == '[')
92 return FALSE;
93
94 if (subj[cur_token] == ']')
95 break;
96
97 cur_token ++;
98 }
99
100 cur_token ++;
101
102 while (1) {
103 if (cur_token >= length)
104 break;
105
106 if (subj[cur_token] != ' ')
107 break;
108
109 cur_token ++;
110 }
111
112 * begin = cur_token;
113
114 return TRUE;
115}
116
117static inline int skip_subj_refwd(char * subj, size_t * begin,
118 size_t length)
119{
120 /* subj-refwd = ("re" / ("fw" ["d"])) *WSP [subj-blob] ":" */
121 size_t cur_token;
122 int prefix;
123
124 cur_token = * begin;
125
126 prefix = FALSE;
127 if (length >= 3) {
128 if (strncasecmp(subj + cur_token, "fwd", 3) == 0) {
129 cur_token += 3;
130 prefix = TRUE;
131 }
132 }
133 if (!prefix) {
134 if (length >= 2) {
135 if (strncasecmp(subj + cur_token, "fw", 2) == 0) {
136 cur_token += 2;
137 prefix = TRUE;
138 }
139 else if (strncasecmp(subj + cur_token, "re", 2) == 0) {
140 cur_token += 2;
141 prefix = TRUE;
142 }
143 }
144 }
145
146 if (!prefix)
147 return FALSE;
148
149 while (1) {
150 if (cur_token >= length)
151 break;
152
153 if (subj[cur_token] != ' ')
154 break;
155
156 cur_token ++;
157 }
158
159 skip_subj_blob(subj, &cur_token, length);
160
161 if (subj[cur_token] != ':')
162 return FALSE;
163
164 cur_token ++;
165
166 * begin = cur_token;
167
168 return TRUE;
169}
170
171static inline int skip_subj_leader(struct mailmessage_tree * tree,
172 char * subj, size_t * begin,
173 size_t length)
174{
175 size_t cur_token;
176
177 cur_token = * begin;
178
179 /* subj-leader = (*subj-blob subj-refwd) / WSP */
180
181 if (subj[cur_token] == ' ') {
182 cur_token ++;
183 }
184 else {
185 while (cur_token < length) {
186 if (!skip_subj_blob(subj, &cur_token, length))
187 break;
188 }
189 if (!skip_subj_refwd(subj, &cur_token, length))
190 return FALSE;
191 tree->node_is_reply = TRUE;
192 }
193
194 * begin = cur_token;
195
196 return TRUE;
197}
198
199
200static char * extract_subject(char * default_from,
201 struct mailmessage_tree * tree,
202 char * str)
203{
204 char * subj;
205 char * cur;
206 char * write_pos;
207 size_t len;
208 size_t begin;
209
210 char * decoded;
211 size_t cur_token;
212
213 int do_repeat_5;
214 int do_repeat_6;
215 int r;
216
217 /*
218 (1) Convert any RFC 2047 encoded-words in the subject to
219 UTF-8.
220 */
221
222 decoded = NULL;
223
224 cur_token = 0;
225 r = mailmime_encoded_phrase_parse(default_from, str, strlen(str),
226 &cur_token, "utf-8",
227 &decoded);
228
229 if (r == MAILIMF_NO_ERROR) {
230 subj = decoded;
231 }
232 else
233 subj = strdup(str);
234
235 len = strlen(subj);
236
237 /*
238 Convert all tabs and continuations to space.
239 Convert all multiple spaces to a single space.
240 */
241
242 cur = subj;
243 write_pos = subj;
244 while (* cur != '\0') {
245 int cont;
246
247 switch (* cur) {
248 case '\t':
249 case '\r':
250 case '\n':
251 cont = TRUE;
252
253 cur ++;
254 while (* cur && cont) {
255 switch (* cur) {
256 case '\t':
257 case '\r':
258 case '\n':
259 cont = TRUE;
260 break;
261 default:
262 cont = FALSE;
263 break;
264 }
265 cur ++;
266 }
267
268 * write_pos = ' ';
269 write_pos ++;
270
271 break;
272
273 default:
274 * write_pos = * cur;
275 write_pos ++;
276
277 cur ++;
278
279 break;
280 }
281 }
282 * write_pos = '\0';
283
284 begin = 0;
285
286 do {
287 do_repeat_6 = FALSE;
288
289 /*
290 (2) Remove all trailing text of the subject that matches
291 the subj-trailer ABNF, repeat until no more matches are
292 possible.
293 */
294
295 while (len > 0) {
296 int chg;
297
298 chg = FALSE;
299
300 /* subj-trailer = "(fwd)" / WSP */
301 if (subj[len - 1] == ' ') {
302 subj[len - 1] = '\0';
303 len --;
304 }
305 else {
306 if (len < 5)
307 break;
308
309 if (strncasecmp(subj + len - 5, "(fwd)", 5) != 0)
310 break;
311
312 subj[len - 5] = '\0';
313 len -= 5;
314 tree->node_is_reply = TRUE;
315 }
316 }
317
318 do {
319 size_t saved_begin;
320
321 do_repeat_5 = FALSE;
322
323 /*
324 (3) Remove all prefix text of the subject that matches the
325 subj-leader ABNF.
326 */
327
328 if (skip_subj_leader(tree, subj, &begin, len))
329 do_repeat_5 = TRUE;
330
331 /*
332 (4) If there is prefix text of the subject that matches the
333 subj-blob ABNF, and removing that prefix leaves a non-empty
334 subj-base, then remove the prefix text.
335 */
336
337 saved_begin = begin;
338 if (skip_subj_blob(subj, &begin, len)) {
339 if (begin == len) {
340 /* this will leave a empty subject base */
341 begin = saved_begin;
342 }
343 else
344 do_repeat_5 = TRUE;
345 }
346
347 /*
348 (5) Repeat (3) and (4) until no matches remain.
349 Note: it is possible to defer step (2) until step (6),
350 but this requires checking for subj-trailer in step (4).
351 */
352
353 }
354 while (do_repeat_5);
355
356 /*
357 (6) If the resulting text begins with the subj-fwd-hdr ABNF
358 and ends with the subj-fwd-trl ABNF, remove the
359 subj-fwd-hdr and subj-fwd-trl and repeat from step (2).
360 */
361
362 if (len >= 5) {
363 size_t saved_begin;
364
365 saved_begin = begin;
366 if (strncasecmp(subj + begin, "[fwd:", 5) == 0) {
367 begin += 5;
368
369 if (subj[len - 1] != ']')
370 saved_begin = begin;
371 else {
372 tree->node_is_reply = TRUE;
373
374 subj[len - 1] = '\0';
375 len --;
376 do_repeat_6 = TRUE;
377 }
378 }
379 }
380
381 }
382 while (do_repeat_6);
383
384 /*
385 (7) The resulting text is the "base subject" used in
386 threading.
387 */
388
389 /* convert to upper case */
390
391 cur = subj + begin;
392 write_pos = subj;
393
394 while (* cur != '\0') {
395 * write_pos = (char) toupper((unsigned char) * cur);
396 cur ++;
397 write_pos ++;
398 }
399 * write_pos = '\0';
400
401 return subj;
402}
403
404static int get_extracted_subject(char * default_from,
405 struct mailmessage_tree * tree,
406 char ** result)
407{
408 if (tree->node_msg->msg_single_fields.fld_subject != NULL) {
409 char * subj;
410
411 subj = extract_subject(default_from,
412 tree, tree->node_msg->msg_single_fields.fld_subject->sbj_value);
413 if (subj == NULL)
414 return MAIL_ERROR_MEMORY;
415
416 * result = subj;
417
418 return MAIL_NO_ERROR;
419 }
420
421 return MAIL_ERROR_SUBJECT_NOT_FOUND;
422}
423
424static int get_thread_subject(char * default_from,
425 struct mailmessage_tree * tree,
426 char ** result)
427{
428 char * thread_subject;
429 int r;
430 unsigned int i;
431
432 if (tree->node_msg != NULL) {
433 if (tree->node_msg->msg_fields != NULL) {
434 r = get_extracted_subject(default_from, tree, &thread_subject);
435
436 if (r != MAIL_NO_ERROR)
437 return r;
438
439 * result = thread_subject;
440 return MAIL_NO_ERROR;
441 }
442 }
443
444 for(i = 0 ; i < carray_count(tree->node_children) ; i ++) {
445 struct mailmessage_tree * child;
446
447 child = carray_get(tree->node_children, i);
448
449 r = get_thread_subject(default_from, child, &thread_subject);
450
451 switch (r) {
452 case MAIL_NO_ERROR:
453 * result = thread_subject;
454 return MAIL_NO_ERROR;
455
456 case MAIL_ERROR_SUBJECT_NOT_FOUND:
457 /* do nothing */
458 break;
459
460 default:
461 return r;
462 }
463 }
464
465 return MAIL_ERROR_SUBJECT_NOT_FOUND;
466}
467
468
469
470#ifndef WRONG
471 #define WRONG(-1)
472#endif /* !defined WRONG */
473
474static int tmcomp(struct tm * atmp, struct tm * btmp)
475{
476 register intresult;
477
478 if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
479 (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
480 (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
481 (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
482 (result = (atmp->tm_min - btmp->tm_min)) == 0)
483 result = atmp->tm_sec - btmp->tm_sec;
484 return result;
485}
486
487static time_t mkgmtime(struct tm * tmp)
488{
489 register int dir;
490 register int bits;
491 register int saved_seconds;
492 time_t t;
493 struct tm yourtm, *mytm;
494
495 yourtm = *tmp;
496 saved_seconds = yourtm.tm_sec;
497 yourtm.tm_sec = 0;
498 /*
499 ** Calculate the number of magnitude bits in a time_t
500 ** (this works regardless of whether time_t is
501 ** signed or unsigned, though lint complains if unsigned).
502 */
503 for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
504 ;
505 /*
506 ** If time_t is signed, then 0 is the median value,
507 ** if time_t is unsigned, then 1 << bits is median.
508 */
509 t = (t < 0) ? 0 : ((time_t) 1 << bits);
510 for ( ; ; ) {
511 mytm = gmtime(&t);
512 dir = tmcomp(mytm, &yourtm);
513 if (dir != 0) {
514 if (bits-- < 0)
515 return WRONG;
516 if (bits < 0)
517 --t;
518 else if (dir > 0)
519 t -= (time_t) 1 << bits;
520 elset += (time_t) 1 << bits;
521 continue;
522 }
523 break;
524 }
525 t += saved_seconds;
526 return t;
527}
528
529static inline time_t get_date(mailmessage * msg)
530{
531 struct tm tmval;
532 time_t timeval;
533 struct mailimf_date_time * date_time;
534
535 if (msg->msg_single_fields.fld_orig_date == NULL)
536 return (time_t) -1;
537
538 date_time = msg->msg_single_fields.fld_orig_date->dt_date_time;
539
540 tmval.tm_sec = date_time->dt_sec;
541 tmval.tm_min = date_time->dt_min;
542 tmval.tm_hour = date_time->dt_hour;
543 tmval.tm_sec = date_time->dt_sec;
544 tmval.tm_mday = date_time->dt_day;
545 tmval.tm_mon = date_time->dt_month - 1;
546 tmval.tm_year = date_time->dt_year - 1900;
547
548 timeval = mkgmtime(&tmval);
549
550 timeval -= date_time->dt_zone * 36;
551
552 return timeval;
553}
554
555static inline int is_descendant(struct mailmessage_tree * node,
556 struct mailmessage_tree * maybe_child)
557{
558 unsigned int i;
559
560 for(i = 0 ; i < carray_count(node->node_children) ; i++) {
561 struct mailmessage_tree * tree;
562
563 tree = carray_get(node->node_children, i);
564 if (tree == maybe_child)
565 return TRUE;
566 if (carray_count(tree->node_children) != 0)
567 if (is_descendant(tree, maybe_child))
568 return TRUE;
569 }
570
571 return FALSE;
572}
573
574static int delete_dummy(carray * rootlist, carray * sibling_list,
575 unsigned int cur, unsigned int * pnext)
576{
577 struct mailmessage_tree * env_tree;
578 int res;
579 int r;
580 unsigned int cur_child;
581 unsigned int next;
582
583 env_tree = carray_get(sibling_list, cur);
584
585 cur_child = 0;
586 while (cur_child < carray_count(env_tree->node_children)) {
587 delete_dummy(rootlist, env_tree->node_children, cur_child, &cur_child);
588 }
589
590 if (env_tree->node_msg == NULL) {
591 if (carray_count(env_tree->node_children) == 0) {
592
593 /* If it is a dummy message with NO children, delete it. */
594 mailmessage_tree_free(env_tree);
595 carray_delete(sibling_list, cur);
596 next = cur;
597 }
598 else {
599 /* If it is a dummy message with children, delete it, but
600 promote its children to the current level. */
601
602 /*
603 Do not promote the children if doing so would make them
604 children of the root, unless there is only one child.
605 */
606
607 cur_child = 0;
608 if ((sibling_list != rootlist) ||
609 (carray_count(env_tree->node_children) == 1)) {
610 while (cur_child < carray_count(env_tree->node_children)) {
611 struct mailmessage_tree * child;
612
613 child = carray_get(env_tree->node_children, cur_child);
614 r = carray_add(sibling_list, child, NULL);
615 if (r < 0) {
616 res = MAIL_ERROR_MEMORY;
617 goto err;
618 }
619 /* set new parent of the children */
620 child->node_parent = env_tree->node_parent;
621
622 carray_delete(env_tree->node_children, cur_child);
623 }
624 mailmessage_tree_free(env_tree);
625 carray_delete(sibling_list, cur);
626 next = cur;
627 }
628 else
629 next = cur + 1;
630 }
631 }
632 else
633 next = cur + 1;
634
635 * pnext = next;
636
637 return MAIL_NO_ERROR;
638
639 err:
640 return res;
641}
642
643static inline time_t tree_get_date(struct mailmessage_tree * tree)
644{
645 if (tree->node_msg != NULL) {
646 return tree->node_date;
647 }
648 else {
649 struct mailmessage_tree * subtree;
650
651 if (carray_count(tree->node_children) == 0)
652 return (time_t) -1;
653
654 subtree = carray_get(tree->node_children, 0);
655
656 return subtree->node_date;
657 }
658}
659
660static inline uint32_t tree_get_index(struct mailmessage_tree * tree)
661{
662 if (tree->node_msg == NULL)
663 return 0;
664
665 return tree->node_msg->msg_index;
666}
667
668int mailthread_tree_timecomp(struct mailmessage_tree ** ptree1,
669 struct mailmessage_tree ** ptree2)
670{
671 time_t date1;
672 time_t date2;
673
674 date1 = tree_get_date(* ptree1);
675 date2 = tree_get_date(* ptree2);
676
677 if ((date1 == (time_t) -1) || (date2 == (time_t) -1)) {
678 uint32_t index1;
679 uint32_t index2;
680
681 index1 = tree_get_index(* ptree1);
682 index2 = tree_get_index(* ptree2);
683 return (int) ((long) index1 - (long) index2);
684 }
685
686 return (int) ((long) date1 - (long) date2);
687}
688
689static int tree_subj_time_comp(struct mailmessage_tree ** ptree1,
690 struct mailmessage_tree ** ptree2)
691{
692 char * subj1;
693 char * subj2;
694 time_t date1;
695 time_t date2;
696 int r;
697
698 subj1 = (* ptree1)->node_base_subject;
699 subj2 = (* ptree2)->node_base_subject;
700
701 if ((subj1 != NULL) && (subj2 != NULL))
702 r = strcmp(subj1, subj2);
703 else {
704 if ((subj1 == NULL) && (subj2 == NULL))
705 r = 0;
706 else if (subj1 == NULL)
707 r = -1;
708 else /* subj2 == NULL */
709 r = 1;
710 }
711
712 if (r != 0)
713 return r;
714
715 date1 = (* ptree1)->node_date;
716 date2 = (* ptree2)->node_date;
717
718 if ((date1 == (time_t) -1) || (date2 == (time_t) -1))
719 return ((int32_t) (* ptree1)->node_msg->msg_index) -
720 ((int32_t) (* ptree2)->node_msg->msg_index);
721
722 return (int) ((long) date1 - (long) date2);
723}
724
725
726
727int mail_thread_sort(struct mailmessage_tree * tree,
728 int (* comp_func)(struct mailmessage_tree **,
729 struct mailmessage_tree **),
730 int sort_sub)
731{
732 unsigned int cur;
733 int r;
734 int res;
735
736 for(cur = 0 ; cur < carray_count(tree->node_children) ; cur ++) {
737 struct mailmessage_tree * subtree;
738
739 subtree = carray_get(tree->node_children, cur);
740
741 if (sort_sub) {
742 r = mail_thread_sort(subtree, comp_func, sort_sub);
743 if (r != MAIL_NO_ERROR) {
744 res = r;
745 goto err;
746 }
747 }
748 }
749
750 qsort(carray_data(tree->node_children), carray_count(tree->node_children),
751 sizeof(struct mailmessage_tree *),
752 (int (*)(const void *, const void *)) comp_func);
753
754 return MAIL_NO_ERROR;
755
756 err:
757 return res;
758}
759
760
761static int
762mail_build_thread_references(char * default_from,
763 struct mailmessage_list * env_list,
764 struct mailmessage_tree ** result,
765 int use_subject,
766 int (* comp_func)(struct mailmessage_tree **,
767 struct mailmessage_tree **))
768{
769 int r;
770 int res;
771 chash * msg_id_hash;
772 unsigned int cur;
773 struct mailmessage_tree * root;
774 carray * rootlist;
775 carray * msg_list;
776 unsigned int i;
777 chash * subject_hash;
778
779 msg_id_hash = chash_new(128, CHASH_COPYNONE);
780 if (msg_id_hash == NULL) {
781 res = MAIL_ERROR_MEMORY;
782 goto err;
783 }
784
785 root = mailmessage_tree_new(NULL, (time_t) -1, NULL);
786 if (root == NULL) {
787 res = MAIL_ERROR_MEMORY;
788 goto free_hash;
789 }
790 rootlist = root->node_children;
791
792 msg_list = carray_new(128);
793 if (msg_list == NULL) {
794 res = MAIL_ERROR_MEMORY;
795 goto free_root;
796 }
797
798 /* collect message-ID */
799 for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
800 mailmessage * msg;
801 char * msgid;
802 struct mailmessage_tree * env_tree;
803 chashdatum hashkey;
804 chashdatum hashdata;
805 chashdatum hashold;
806 time_t date;
807
808 msg = carray_get(env_list->msg_tab, i);
809
810 if (msg == NULL)
811 continue;
812
813 if (msg->msg_fields != NULL) {
814 msgid = get_msg_id(msg);
815
816 if (msgid == NULL) {
817 msgid = mailimf_get_message_id();
818 }
819 else {
820 hashkey.data = msgid;
821 hashkey.len = strlen(msgid);
822
823 if (chash_get(msg_id_hash, &hashkey, &hashdata) == 0)
824 msgid = mailimf_get_message_id();
825 else
826 msgid = strdup(msgid);
827 }
828
829 if (msgid == NULL) {
830 res = MAIL_ERROR_MEMORY;
831 goto free_list;
832 }
833
834 date = get_date(msg);
835
836 env_tree = mailmessage_tree_new(msgid, date, msg);
837 if (env_tree == NULL) {
838 res = MAIL_ERROR_MEMORY;
839 goto free_list;
840 }
841
842 r = carray_add(msg_list, env_tree, NULL);
843 if (r < 0) {
844 mailmessage_tree_free(env_tree);
845 res = MAIL_ERROR_MEMORY;
846 goto free_list;
847 }
848
849 hashkey.data = msgid;
850 hashkey.len = strlen(msgid);
851
852 hashdata.data = env_tree;
853 hashdata.len = 0;
854
855 r = chash_set(msg_id_hash, &hashkey, &hashdata, &hashold);
856 if (r < 0) {
857 res = MAIL_ERROR_MEMORY;
858 goto free_list;
859 }
860 }
861 }
862
863 /* (1) for all messages */
864
865 for(cur = 0 ; cur < carray_count(msg_list) ; cur ++) {
866 struct mailmessage_tree * env_tree;
867 mailmessage * msg;
868 clist * ref;
869
870 env_tree = carray_get(msg_list, cur);
871
872 msg = env_tree->node_msg;
873
874 ref = NULL;
875 if (msg != NULL) {
876 ref = get_ref(msg);
877 if (ref == NULL)
878 ref = get_in_reply_to(msg);
879 }
880
881 /* (A) Using the Message IDs in the message's references, link
882 the corresponding messages (those whose Message-ID header
883 line contains the given reference Message ID) together as
884 parent/child.
885 */
886
887 if (ref != NULL) {
888 /* try to start a tree */
889
890 clistiter * cur_ref;
891 chashdatum hashkey;
892 chashdatum hashdata;
893 chashdatum hashold;
894 struct mailmessage_tree * env_cur_tree;
895 struct mailmessage_tree * last_env_cur_tree;
896
897 env_cur_tree = NULL;
898 for(cur_ref = clist_begin(ref) ; cur_ref != NULL ;
899 cur_ref = clist_next(cur_ref)) {
900 char * msgid;
901
902 last_env_cur_tree = env_cur_tree;
903
904 msgid = clist_content(cur_ref);
905
906 hashkey.data = msgid;
907 hashkey.len = strlen(msgid);
908
909 r = chash_get(msg_id_hash, &hashkey, &hashdata);
910 if (r < 0) {
911 /* not found, create a dummy message */
912 msgid = strdup(msgid);
913 if (msgid == NULL) {
914 res = MAIL_ERROR_MEMORY;
915 goto free_list;
916 }
917
918 env_cur_tree = mailmessage_tree_new(msgid, (time_t) -1, NULL);
919 if (env_cur_tree == NULL) {
920 free(msgid);
921 res = MAIL_ERROR_MEMORY;
922 goto free_list;
923 }
924
925 r = carray_add(msg_list, env_cur_tree, NULL);
926 if (r < 0) {
927 mailmessage_tree_free(env_cur_tree);
928 res = MAIL_ERROR_MEMORY;
929 goto free_list;
930 }
931
932 hashkey.data = msgid;
933 hashkey.len = strlen(msgid);
934
935 hashdata.data = env_cur_tree;
936 hashdata.len = 0;
937
938 r = chash_set(msg_id_hash, &hashkey, &hashdata, &hashold);
939 if (r < 0) {
940 res = MAIL_ERROR_MEMORY;
941 goto free_list;
942 }
943 }
944 else {
945 env_cur_tree = hashdata.data;
946 }
947
948 if (last_env_cur_tree != NULL) {
949 if (env_cur_tree->node_parent == NULL) {
950 /* make it one child */
951 if (env_cur_tree != last_env_cur_tree) {
952 if (!is_descendant(env_cur_tree, last_env_cur_tree)) {
953 /* set parent */
954 env_cur_tree->node_parent = last_env_cur_tree;
955 r = carray_add(last_env_cur_tree->node_children,
956 env_cur_tree, NULL);
957 if (r < 0) {
958 res = MAIL_ERROR_MEMORY;
959 goto free_list;
960 }
961 }
962 }
963 }
964 }
965 }
966
967 /* (B) Create a parent/child link between the last reference
968 (or NIL if there are no references) and the current message.
969 If the current message already has a parent, it is probably
970 the result of a truncated References header line, so break
971 the current parent/child link before creating the new
972 correct one.
973 */
974
975 last_env_cur_tree = env_cur_tree;
976
977 if (last_env_cur_tree != NULL) {
978 if (env_tree->node_parent == NULL) {
979 if (last_env_cur_tree != env_tree) {
980 if (!is_descendant(env_tree, last_env_cur_tree)) {
981 /* set parent */
982 env_tree->node_parent = last_env_cur_tree;
983 r = carray_add(last_env_cur_tree->node_children, env_tree, NULL);
984 if (r < 0) {
985 res = MAIL_ERROR_MEMORY;
986 goto free_list;
987 }
988 }
989 }
990 }
991 }
992 }
993 }
994
995 chash_free(msg_id_hash);
996 msg_id_hash = NULL;
997
998 /* (2) Gather together all of the messages that have no parents
999 and make them all children (siblings of one another) of a dummy
1000 parent (the "root").
1001 */
1002
1003 for(cur = 0 ; cur < carray_count(msg_list) ; cur ++) {
1004 struct mailmessage_tree * env_tree;
1005
1006 env_tree = carray_get(msg_list, cur);
1007 if (env_tree->node_parent == NULL) {
1008 r = carray_add(rootlist, env_tree, NULL);
1009 if (r < 0) {
1010 res = MAIL_ERROR_MEMORY;
1011 goto free_list;
1012 }
1013 /* set parent */
1014 env_tree->node_parent = root;
1015 }
1016 }
1017
1018 carray_free(msg_list);
1019 msg_list = NULL;
1020
1021 /* (3) Prune dummy messages from the thread tree.
1022 */
1023
1024 cur = 0;
1025 while (cur < carray_count(rootlist)) {
1026 r = delete_dummy(rootlist, rootlist, cur, &cur);
1027 if (r != MAIL_NO_ERROR) {
1028 res = r;
1029 goto free_list;
1030 }
1031 }
1032
1033 /* (4) Sort the messages under the root (top-level siblings only)
1034 by sent date.
1035 */
1036
1037 r = mail_thread_sort(root, mailthread_tree_timecomp, FALSE);
1038 if (r != MAIL_NO_ERROR) {
1039 res = r;
1040 goto free_list;
1041 }
1042
1043 if (use_subject) {
1044
1045 /* (5) Gather together messages under the root that have the same
1046 extracted subject text.
1047
1048 (A) Create a table for associating extracted subjects with
1049 messages.
1050 */
1051
1052 subject_hash = chash_new(128, CHASH_COPYVALUE);
1053 if (subject_hash == NULL) {
1054 res = MAIL_ERROR_MEMORY;
1055 goto free_list;
1056 }
1057
1058 /*
1059 (B) Populate the subject table with one message per
1060 extracted subject. For each child of the root:
1061 */
1062
1063 for(cur = 0 ; cur < carray_count(rootlist) ; cur ++) {
1064 struct mailmessage_tree * env_tree;
1065 chashdatum key;
1066 chashdatum data;
1067 char * base_subject;
1068 int r;
1069
1070 env_tree = carray_get(rootlist, cur);
1071
1072 /*
1073 (i) Find the subject of this thread by extracting the
1074 base subject from the current message, or its first child
1075 if the current message is a dummy.
1076 */
1077
1078 r = get_thread_subject(default_from, env_tree, &base_subject);
1079
1080 /*
1081 (ii) If the extracted subject is empty, skip this
1082 message.
1083 */
1084
1085 if (r == MAIL_ERROR_SUBJECT_NOT_FOUND) {
1086 /* no subject found */
1087 continue;
1088 }
1089 else if (r == MAIL_NO_ERROR) {
1090 if (* base_subject == '\0') {
1091 /* subject empty */
1092 free(base_subject);
1093 continue;
1094 }
1095 else {
1096 /* do nothing */
1097 }
1098 }
1099 else {
1100 res = r;
1101 goto free_subject_hash;
1102 }
1103
1104 env_tree->node_base_subject = base_subject;
1105
1106 /*
1107 (iii) Lookup the message associated with this extracted
1108 subject in the table.
1109 */
1110
1111 key.data = base_subject;
1112 key.len = strlen(base_subject);
1113
1114 r = chash_get(subject_hash, &key, &data);
1115
1116 if (r < 0) {
1117 /*
1118 (iv) If there is no message in the table with this
1119 subject, add the current message and the extracted
1120 subject to the subject table.
1121 */
1122
1123 data.data = &cur;
1124 data.len = sizeof(cur);
1125
1126 r = chash_set(subject_hash, &key, &data, NULL);
1127 if (r < 0) {
1128 res = MAIL_ERROR_MEMORY;
1129 goto free_subject_hash;
1130 }
1131 }
1132 else {
1133 /*
1134 Otherwise, replace the message in the table with the
1135 current message if the message in the table is not a
1136 dummy AND either of the following criteria are true:
1137 The current message is a dummy, OR
1138 The message in the table is a reply or forward (its
1139 original subject contains a subj-refwd part and/or a
1140 "(fwd)" subj-trailer) and the current message is not.
1141 */
1142 struct mailmessage_tree * msg_in_table;
1143 unsigned int * iter_in_table;
1144 int replace;
1145
1146 iter_in_table = data.data;
1147 msg_in_table = carray_get(rootlist, cur);
1148
1149 replace = FALSE;
1150 /* message is dummy if info is NULL */
1151 if (msg_in_table->node_msg != NULL) {
1152
1153 if (env_tree->node_msg == NULL)
1154 replace = TRUE;
1155 else {
1156 if (env_tree->node_is_reply && !env_tree->node_is_reply)
1157 replace = TRUE;
1158 }
1159 }
1160
1161 if (replace) {
1162 data.data = &cur;
1163 data.len = sizeof(cur);
1164
1165 r = chash_set(subject_hash, &key, &data, NULL);
1166 if (r < 0) {
1167 res = MAIL_ERROR_MEMORY;
1168 goto free_subject_hash;
1169 }
1170 }
1171 }
1172 }
1173
1174 /*
1175 (C) Merge threads with the same subject. For each child of
1176 the root:
1177 */
1178
1179 cur = 0;
1180 while (cur < carray_count(rootlist)) {
1181 struct mailmessage_tree * env_tree;
1182 chashdatum key;
1183 chashdatum data;
1184 int r;
1185 struct mailmessage_tree * main_tree;
1186 unsigned int * main_cur;
1187
1188 env_tree = carray_get(rootlist, cur);
1189
1190 if (env_tree == NULL)
1191 goto next_msg;
1192
1193 /*
1194 (i) Find the subject of this thread as in step 4.B.i
1195 above.
1196 */
1197
1198 /* already done in tree->node_base_subject */
1199
1200 /*
1201 (ii) If the extracted subject is empty, skip this
1202 message.
1203 */
1204
1205 if (env_tree->node_base_subject == NULL)
1206 goto next_msg;
1207
1208 if (* env_tree->node_base_subject == '\0')
1209 goto next_msg;
1210
1211 /*
1212 (iii) Lookup the message associated with this extracted
1213 subject in the table.
1214 */
1215
1216 key.data = env_tree->node_base_subject;
1217 key.len = strlen(env_tree->node_base_subject);
1218
1219 r = chash_get(subject_hash, &key, &data);
1220 if (r < 0)
1221 goto next_msg;
1222
1223 /*
1224 (iv) If the message in the table is the current message,
1225 skip this message.
1226 */
1227
1228 main_cur = data.data;
1229 if (* main_cur == cur)
1230 goto next_msg;
1231
1232 /*
1233 Otherwise, merge the current message with the one in the
1234 table using the following rules:
1235 */
1236
1237 main_tree = carray_get(rootlist, * main_cur);
1238
1239 /*
1240 If both messages are dummies, append the current
1241 message's children to the children of the message in
1242 the table (the children of both messages become
1243 siblings), and then delete the current message.
1244 */
1245
1246 if ((env_tree->node_msg == NULL) && (main_tree->node_msg == NULL)) {
1247 unsigned int old_size;
1248
1249 old_size = carray_count(main_tree->node_children);
1250
1251 r = carray_set_size(main_tree->node_children, old_size +
1252 carray_count(env_tree->node_children));
1253 if (r < 0) {
1254 res = MAIL_ERROR_MEMORY;
1255 goto free_subject_hash;
1256 }
1257
1258 for(i = 0 ; i < carray_count(env_tree->node_children) ; i ++) {
1259 struct mailmessage_tree * child;
1260
1261 child = carray_get(env_tree->node_children, i);
1262 carray_set(main_tree->node_children, old_size + i, child);
1263 /* set parent */
1264 child->node_parent = main_tree;
1265 }
1266 carray_set_size(env_tree->node_children, 0);
1267 /* this is the only case where children can be NULL,
1268 this is before freeing it */
1269 mailmessage_tree_free(env_tree);
1270 carray_delete_fast(rootlist, cur);
1271 }
1272
1273 /*
1274 If the message in the table is a dummy and the current
1275 message is not, make the current message a child of
1276 the message in the table (a sibling of it's children).
1277 */
1278
1279 else if (main_tree->node_msg == NULL) {
1280 r = carray_add(main_tree->node_children, env_tree, NULL);
1281 if (r < 0) {
1282 res = MAIL_ERROR_MEMORY;
1283 goto free_subject_hash;
1284 }
1285 /* set parent */
1286 env_tree->node_parent = main_tree;
1287
1288 carray_delete_fast(rootlist, cur);
1289 }
1290
1291 /*
1292 If the current message is a reply or forward and the
1293 message in the table is not, make the current message
1294 a child of the message in the table (a sibling of it's
1295 children).
1296 */
1297
1298 else if (env_tree->node_is_reply && !main_tree->node_is_reply) {
1299 r = carray_add(main_tree->node_children, env_tree, NULL);
1300 if (r < 0) {
1301 res = MAIL_ERROR_MEMORY;
1302 goto free_subject_hash;
1303 }
1304 /* set parent */
1305 env_tree->node_parent = main_tree;
1306
1307 carray_delete_fast(rootlist, cur);
1308 }
1309
1310 /*
1311 Otherwise, create a new dummy message and make both
1312 the current message and the message in the table
1313 children of the dummy. Then replace the message in
1314 the table with the dummy message.
1315 Note: Subject comparisons are case-insensitive, as
1316 described under "Internationalization
1317 Considerations."
1318 */
1319
1320 else {
1321 struct mailmessage_tree * new_main_tree;
1322 char * base_subject;
1323 unsigned int last;
1324
1325 new_main_tree = mailmessage_tree_new(NULL, (time_t) -1, NULL);
1326 if (new_main_tree == NULL) {
1327 res = MAIL_ERROR_MEMORY;
1328 goto free_subject_hash;
1329 }
1330
1331 /* main_tree->node_base_subject is never NULL */
1332
1333 base_subject = strdup(main_tree->node_base_subject);
1334 if (base_subject == NULL) {
1335 mailmessage_tree_free(new_main_tree);
1336 res = MAIL_ERROR_MEMORY;
1337 goto free_subject_hash;
1338 }
1339
1340 new_main_tree->node_base_subject = base_subject;
1341
1342 r = carray_add(rootlist, new_main_tree, &last);
1343 if (r < 0) {
1344 mailmessage_tree_free(new_main_tree);
1345 res = MAIL_ERROR_MEMORY;
1346 goto free_subject_hash;
1347 }
1348
1349 r = carray_add(new_main_tree->node_children, main_tree, NULL);
1350 if (r < 0) {
1351 res = MAIL_ERROR_MEMORY;
1352 goto free_subject_hash;
1353 }
1354 /* set parent */
1355 main_tree->node_parent = new_main_tree;
1356
1357 carray_delete_fast(rootlist, * main_cur);
1358
1359 r = carray_add(new_main_tree->node_children, env_tree, NULL);
1360 if (r < 0) {
1361 res = MAIL_ERROR_MEMORY;
1362 goto free_subject_hash;
1363 }
1364 /* set parent */
1365 env_tree->node_parent = new_main_tree;
1366
1367 carray_delete_fast(rootlist, cur);
1368
1369 data.data = &last;
1370 data.len = sizeof(last);
1371
1372 r = chash_set(subject_hash, &key, &data, NULL);
1373
1374 if (r < 0) {
1375 res = MAIL_ERROR_MEMORY;
1376 goto free_subject_hash;
1377 }
1378 }
1379
1380 continue;
1381
1382 next_msg:
1383 cur ++;
1384 continue;
1385 }
1386
1387 i = 0;
1388 for(cur = 0 ; cur < carray_count(rootlist) ; cur ++) {
1389 struct mailmessage_tree * env_tree;
1390
1391 env_tree = carray_get(rootlist, cur);
1392 if (env_tree == NULL)
1393 continue;
1394
1395 carray_set(rootlist, i, env_tree);
1396 i ++;
1397 }
1398 carray_set_size(rootlist, i);
1399
1400 chash_free(subject_hash);
1401 }
1402
1403 /*
1404 (6) Traverse the messages under the root and sort each set of
1405 siblings by sent date. Traverse the messages in such a way
1406 that the "youngest" set of siblings are sorted first, and the
1407 "oldest" set of siblings are sorted last (grandchildren are
1408 sorted before children, etc).
1409
1410 In the case of an exact match on
1411 sent date or if either of the Date: headers used in a
1412 comparison can not be parsed, use the order in which the
1413 messages appear in the mailbox (that is, by sequence number) to
1414 determine the order. In the case of a dummy message (which can
1415 only occur with top-level siblings), use its first child for
1416 sorting.
1417 */
1418
1419#if 0
1420 if (comp_func != NULL) {
1421 r = mail_thread_sort(root, comp_func, TRUE);
1422 if (r != MAIL_NO_ERROR) {
1423 res = r;
1424 goto free_list;
1425 }
1426 }
1427#endif
1428 if (comp_func == NULL)
1429 comp_func = mailthread_tree_timecomp;
1430
1431 r = mail_thread_sort(root, comp_func, TRUE);
1432 if (r != MAIL_NO_ERROR) {
1433 res = r;
1434 goto free_list;
1435 }
1436
1437 * result = root;
1438
1439 return MAIL_NO_ERROR;
1440
1441 free_subject_hash:
1442 chash_free(subject_hash);
1443 free_list:
1444 if (msg_list != NULL) {
1445 for(i = 0 ; i < carray_count(msg_list) ; i ++)
1446 mailmessage_tree_free(carray_get(msg_list, i));
1447 carray_free(msg_list);
1448 }
1449 free_root:
1450 mailmessage_tree_free_recursive(root);
1451 free_hash:
1452 if (msg_id_hash != NULL)
1453 chash_free(msg_id_hash);
1454 err:
1455 return res;
1456}
1457
1458
1459
1460static int
1461mail_build_thread_orderedsubject(char * default_from,
1462 struct mailmessage_list * env_list,
1463 struct mailmessage_tree ** result,
1464 int (* comp_func)(struct mailmessage_tree **,
1465 struct mailmessage_tree **))
1466{
1467 unsigned int i;
1468 carray * rootlist;
1469 unsigned int cur;
1470 struct mailmessage_tree * root;
1471 int res;
1472 int r;
1473 struct mailmessage_tree * current_thread;
1474
1475 root = mailmessage_tree_new(NULL, (time_t) -1, NULL);
1476 if (root == NULL) {
1477 res = MAIL_ERROR_MEMORY;
1478 goto err;
1479 }
1480 rootlist = root->node_children;
1481
1482 /*
1483 The ORDEREDSUBJECT threading algorithm is also referred to as
1484 "poor man's threading."
1485 */
1486
1487 for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
1488 mailmessage * msg;
1489 struct mailmessage_tree * env_tree;
1490 char * base_subject;
1491 time_t date;
1492
1493 msg = carray_get(env_list->msg_tab, i);
1494
1495 if (msg == NULL)
1496 continue;
1497
1498 if (msg->msg_fields != NULL) {
1499
1500 date = get_date(msg);
1501
1502 env_tree = mailmessage_tree_new(NULL, date, msg);
1503 if (env_tree == NULL) {
1504 res = MAIL_ERROR_MEMORY;
1505 goto free;
1506 }
1507
1508 /* set parent */
1509 env_tree->node_parent = root;
1510 r = carray_add(rootlist, env_tree, NULL);
1511 if (r < 0) {
1512 mailmessage_tree_free(env_tree);
1513 res = MAIL_ERROR_MEMORY;
1514 goto free;
1515 }
1516
1517 r = get_extracted_subject(default_from, env_tree, &base_subject);
1518 switch (r) {
1519 case MAIL_NO_ERROR:
1520 env_tree->node_base_subject = base_subject;
1521 break;
1522
1523 case MAIL_ERROR_SUBJECT_NOT_FOUND:
1524 break;
1525
1526 default:
1527 res = r;
1528 goto free;
1529 }
1530 }
1531 }
1532
1533 /*
1534 The searched messages are sorted by
1535 subject and then by the sent date.
1536 */
1537
1538 r = mail_thread_sort(root, tree_subj_time_comp, FALSE);
1539 if (r != MAIL_NO_ERROR) {
1540 res = r;
1541 goto free;
1542 }
1543
1544 /*
1545 The messages are then split
1546 into separate threads, with each thread containing messages
1547 with the same extracted subject text.
1548 */
1549
1550 current_thread = NULL;
1551
1552 cur = 0;
1553 while (cur < carray_count(rootlist)) {
1554 struct mailmessage_tree * cur_env_tree;
1555
1556 cur_env_tree = carray_get(rootlist, cur);
1557 if (current_thread == NULL) {
1558 current_thread = cur_env_tree;
1559 cur ++;
1560 continue;
1561 }
1562
1563 if ((cur_env_tree->node_base_subject == NULL) ||
1564 (current_thread->node_base_subject == NULL)) {
1565 current_thread = cur_env_tree;
1566 cur ++;
1567 continue;
1568 }
1569
1570 if (strcmp(cur_env_tree->node_base_subject,
1571 current_thread->node_base_subject) == 0) {
1572
1573 /* set parent */
1574 cur_env_tree->node_parent = current_thread;
1575 r = carray_add(current_thread->node_children, cur_env_tree, NULL);
1576 if (r < 0) {
1577 res = MAIL_ERROR_MEMORY;
1578 goto free;
1579 }
1580
1581 carray_delete(rootlist, cur);
1582 }
1583 else
1584 cur ++;
1585 current_thread = cur_env_tree;
1586 }
1587
1588 /*
1589 Finally, the threads are
1590 sorted by the sent date of the first message in the thread.
1591 Note that each message in a thread is a child (as opposed to a
1592 sibling) of the previous message.
1593 */
1594
1595#if 0
1596 if (comp_func != NULL) {
1597 r = mail_thread_sort(root, comp_func, FALSE);
1598 if (r != MAIL_NO_ERROR) {
1599 res = r;
1600 goto free;
1601 }
1602 }
1603#endif
1604
1605 if (comp_func == NULL)
1606 comp_func = mailthread_tree_timecomp;
1607
1608 r = mail_thread_sort(root, comp_func, FALSE);
1609 if (r != MAIL_NO_ERROR) {
1610 res = r;
1611 goto free;
1612 }
1613
1614 * result = root;
1615
1616 return MAIL_NO_ERROR;
1617
1618 free:
1619 mailmessage_tree_free_recursive(root);
1620 err:
1621 return res;
1622}
1623
1624
1625static int
1626mail_build_thread_none(char * default_from,
1627 struct mailmessage_list * env_list,
1628 struct mailmessage_tree ** result,
1629 int (* comp_func)(struct mailmessage_tree **,
1630 struct mailmessage_tree **))
1631{
1632 unsigned int i;
1633 carray * rootlist;
1634 struct mailmessage_tree * root;
1635 int res;
1636 int r;
1637
1638 root = mailmessage_tree_new(NULL, (time_t) -1, NULL);
1639 if (root == NULL) {
1640 res = MAIL_ERROR_MEMORY;
1641 goto err;
1642 }
1643 rootlist = root->node_children;
1644
1645 for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
1646 mailmessage * msg;
1647 struct mailmessage_tree * env_tree;
1648 char * base_subject;
1649 time_t date;
1650
1651 msg = carray_get(env_list->msg_tab, i);
1652
1653 if (msg == NULL)
1654 continue;
1655
1656 if (msg->msg_fields != NULL) {
1657
1658 date = get_date(msg);
1659
1660 env_tree = mailmessage_tree_new(NULL, date, msg);
1661 if (env_tree == NULL) {
1662 res = MAIL_ERROR_MEMORY;
1663 goto free;
1664 }
1665
1666 /* set parent */
1667 env_tree->node_parent = root;
1668 r = carray_add(rootlist, env_tree, NULL);
1669 if (r < 0) {
1670 mailmessage_tree_free(env_tree);
1671 res = MAIL_ERROR_MEMORY;
1672 goto free;
1673 }
1674
1675 r = get_extracted_subject(default_from, env_tree, &base_subject);
1676 switch (r) {
1677 case MAIL_NO_ERROR:
1678 env_tree->node_base_subject = base_subject;
1679 break;
1680
1681 case MAIL_ERROR_SUBJECT_NOT_FOUND:
1682 break;
1683
1684 default:
1685 res = r;
1686 goto free;
1687 }
1688 }
1689 }
1690
1691 if (comp_func == NULL)
1692 comp_func = mailthread_tree_timecomp;
1693
1694 r = mail_thread_sort(root, comp_func, FALSE);
1695 if (r != MAIL_NO_ERROR) {
1696 res = r;
1697 goto free;
1698 }
1699
1700 * result = root;
1701
1702 return MAIL_NO_ERROR;
1703
1704 free:
1705 mailmessage_tree_free_recursive(root);
1706 err:
1707 return res;
1708}
1709
1710
1711int mail_build_thread(int type, char * default_from,
1712 struct mailmessage_list * env_list,
1713 struct mailmessage_tree ** result,
1714 int (* comp_func)(struct mailmessage_tree **,
1715 struct mailmessage_tree **))
1716{
1717 unsigned int i;
1718
1719 for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++)
1720 mailmessage_resolve_single_fields(carray_get(env_list->msg_tab, i));
1721
1722 switch (type) {
1723 case MAIL_THREAD_REFERENCES:
1724 return mail_build_thread_references(default_from,
1725 env_list, result, TRUE, comp_func);
1726
1727 case MAIL_THREAD_REFERENCES_NO_SUBJECT:
1728 return mail_build_thread_references(default_from,
1729 env_list, result, FALSE, comp_func);
1730
1731 case MAIL_THREAD_ORDEREDSUBJECT:
1732 return mail_build_thread_orderedsubject(default_from,
1733 env_list, result, comp_func);
1734
1735 case MAIL_THREAD_NONE:
1736 return mail_build_thread_none(default_from,
1737 env_list, result, comp_func);
1738
1739 default:
1740 return MAIL_ERROR_NOT_IMPLEMENTED;
1741 }
1742}
diff --git a/libetpan/src/driver/tools/mailthread.h b/libetpan/src/driver/tools/mailthread.h
new file mode 100644
index 0000000..fa2f4bc
--- a/dev/null
+++ b/libetpan/src/driver/tools/mailthread.h
@@ -0,0 +1,108 @@
1/*
2 * libEtPan! -- a mail stuff 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#ifndef MAILTHREAD_H
37
38#define MAILTHREAD_H
39
40#include <libetpan/mailthread_types.h>
41
42#ifdef __cplusplus
43extern "C" {
44#endif
45
46/*
47 mail_build_thread constructs a tree with the message using the
48 given style.
49
50 @param type is the type of threading to apply, the value can be
51 MAIL_THREAD_REFERENCES, MAIL_THREAD_REFERENCES_NO_SUBJECT,
52 MAIL_THREAD_ORDEREDSUBJECT or MAIL_THREAD_NONE,
53
54 @param default_from is the default charset to use whenever the
55 subject is not tagged with a charset. "US-ASCII" can be used
56 if you don't know what to use.
57
58 @param env_list is the message list (with header fields fetched)
59 to use to build the message tree.
60
61 @param result * result) will contain the resulting message tree.
62
63 @param if comp_func is NULL, no sorting algorithm is used.
64
65 @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
66 on error
67*/
68
69int mail_build_thread(int type, char * default_from,
70 struct mailmessage_list * env_list,
71 struct mailmessage_tree ** result,
72 int (* comp_func)(struct mailmessage_tree **,
73 struct mailmessage_tree **));
74
75/*
76 mail_thread_sort sort the messages in the message tree, using the
77 given sort function.
78
79 @param tree is the message tree to sort.
80
81 @param comp_func is the sort function to use (this is the same kind of
82 functions than those used for qsort()). mailthread_tree_timecomp can be
83 used for default sort.
84
85 @param sort_sub if this value is 0, only the children of the root message
86 are sorted.
87*/
88
89int mail_thread_sort(struct mailmessage_tree * tree,
90 int (* comp_func)(struct mailmessage_tree **,
91 struct mailmessage_tree **),
92 int sort_sub);
93
94/*
95 mailthread_tree_timecomp is the default sort function.
96
97 The message are compared by date, then by message numbers.
98 The tree are given in (* ptree1) and (* ptree2).
99*/
100
101int mailthread_tree_timecomp(struct mailmessage_tree ** ptree1,
102 struct mailmessage_tree ** ptree2);
103
104#ifdef __cplusplus
105}
106#endif
107
108#endif
diff --git a/libetpan/src/driver/tools/mailthread_types.c b/libetpan/src/driver/tools/mailthread_types.c
new file mode 100644
index 0000000..dc2a4ca
--- a/dev/null
+++ b/libetpan/src/driver/tools/mailthread_types.c
@@ -0,0 +1,90 @@
1/*
2 * libEtPan! -- a mail stuff 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 "mailthread_types.h"
37
38#include "mail.h"
39#include <stdlib.h>
40
41struct mailmessage_tree *
42mailmessage_tree_new(char * node_msgid, time_t node_date,
43 mailmessage * node_msg)
44{
45 struct mailmessage_tree * tree;
46 carray * array;
47
48 array = carray_new(16);
49 if (array == NULL)
50 return NULL;
51
52 tree = malloc(sizeof(* tree));
53 tree->node_parent = NULL;
54 tree->node_date = node_date;
55 tree->node_msgid = node_msgid;
56 tree->node_msg = node_msg;
57 tree->node_children = array;
58 tree->node_base_subject = NULL;
59 tree->node_is_reply = FALSE;
60
61 return tree;
62}
63
64void mailmessage_tree_free(struct mailmessage_tree * tree)
65{
66 if (tree->node_base_subject != NULL)
67 free(tree->node_base_subject);
68
69 if (tree->node_children != NULL)
70 carray_free(tree->node_children);
71 if (tree->node_msgid != NULL)
72 free(tree->node_msgid);
73
74 free(tree);
75}
76
77void mailmessage_tree_free_recursive(struct mailmessage_tree * tree)
78{
79 unsigned int i;
80
81 for(i = 0 ; i < carray_count(tree->node_children) ; i++) {
82 struct mailmessage_tree * child;
83
84 child = carray_get(tree->node_children, i);
85
86 mailmessage_tree_free_recursive(child);
87 }
88
89 mailmessage_tree_free(tree);
90}
diff --git a/libetpan/src/driver/tools/mailthread_types.h b/libetpan/src/driver/tools/mailthread_types.h
new file mode 100644
index 0000000..3325904
--- a/dev/null
+++ b/libetpan/src/driver/tools/mailthread_types.h
@@ -0,0 +1,64 @@
1/*
2 * libEtPan! -- a mail stuff 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#ifndef MAILTHREAD_TYPES_H
37
38#define MAILTHREAD_TYPES_H
39
40#ifdef __cplusplus
41extern "C" {
42#endif
43
44#include <libetpan/maildriver_types.h>
45#include <libetpan/mailmessage_types.h>
46
47/*
48 This is the type of tree construction to apply.
49*/
50
51enum {
52 MAIL_THREAD_REFERENCES, /* this is threading using
53 References fields only) */
54 MAIL_THREAD_REFERENCES_NO_SUBJECT, /* this is threading using References
55 fields, then subject */
56 MAIL_THREAD_ORDEREDSUBJECT, /* this is threading using only subject */
57 MAIL_THREAD_NONE, /* no thread */
58};
59
60#ifdef __cplusplus
61}
62#endif
63
64#endif