author | zautrix <zautrix> | 2005-03-18 20:17:03 (UTC) |
---|---|---|
committer | zautrix <zautrix> | 2005-03-18 20:17:03 (UTC) |
commit | 9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf (patch) (unidiff) | |
tree | 2528e6cc740225ca0f47d5ac8ff70f7d3bb10621 /libetpan/src/driver/tools | |
parent | 9319998f20f03dcc217fbb39656755dc65226276 (diff) | |
download | kdepimpi-9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf.zip kdepimpi-9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf.tar.gz kdepimpi-9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf.tar.bz2 |
Initial revision
-rw-r--r-- | libetpan/src/driver/tools/generic_cache.c | 729 | ||||
-rw-r--r-- | libetpan/src/driver/tools/generic_cache.h | 109 | ||||
-rw-r--r-- | libetpan/src/driver/tools/generic_cache_types.h | 56 | ||||
-rw-r--r-- | libetpan/src/driver/tools/imfcache.c | 1429 | ||||
-rw-r--r-- | libetpan/src/driver/tools/imfcache.h | 75 | ||||
-rw-r--r-- | libetpan/src/driver/tools/mailthread.c | 1742 | ||||
-rw-r--r-- | libetpan/src/driver/tools/mailthread.h | 108 | ||||
-rw-r--r-- | libetpan/src/driver/tools/mailthread_types.c | 90 | ||||
-rw-r--r-- | libetpan/src/driver/tools/mailthread_types.h | 64 |
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 | |||
56 | int 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 | |||
76 | int 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 | |||
101 | int 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 | |||
158 | static 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 | |||
207 | static 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 | |||
245 | static 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 | |||
265 | static 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 | |||
286 | static 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 | |||
328 | static 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 | |||
367 | struct 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 | |||
393 | void 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 | |||
412 | void 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 | |||
420 | int 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 | |||
483 | static int msg_index_compare(mailmessage ** msg1, mailmessage ** msg2) | ||
484 | { | ||
485 | return (* msg1)->msg_index - (* msg2)->msg_index; | ||
486 | } | ||
487 | |||
488 | void 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 | |||
495 | struct mail_flags * | ||
496 | mail_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 | |||
526 | int 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 | |||
562 | int 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 | |||
604 | int 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 | |||
637 | int 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 | |||
679 | int 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 | |||
713 | int 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 | ||
41 | extern "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 | |||
50 | int generic_cache_create_dir(char * dirname); | ||
51 | |||
52 | int generic_cache_store(char * filename, char * content, size_t length); | ||
53 | int generic_cache_read(char * filename, char ** result, size_t * result_len); | ||
54 | |||
55 | int generic_cache_fields_read(struct mail_cache_db * cache_db, | ||
56 | MMAPString * mmapstr, | ||
57 | char * keyname, struct mailimf_fields ** result); | ||
58 | |||
59 | int generic_cache_fields_write(struct mail_cache_db * cache_db, | ||
60 | MMAPString * mmapstr, | ||
61 | char * keyname, struct mailimf_fields * fields); | ||
62 | |||
63 | int generic_cache_flags_read(struct mail_cache_db * cache_db, | ||
64 | MMAPString * mmapstr, | ||
65 | char * keyname, struct mail_flags ** result); | ||
66 | |||
67 | int generic_cache_flags_write(struct mail_cache_db * cache_db, | ||
68 | MMAPString * mmapstr, | ||
69 | char * keyname, struct mail_flags * flags); | ||
70 | |||
71 | int generic_cache_delete(struct mail_cache_db * cache_db, char * keyname); | ||
72 | |||
73 | #if 0 | ||
74 | int generic_cache_fields_read(DB * dbp, MMAPString * mmapstr, | ||
75 | char * keyname, struct mailimf_fields ** result); | ||
76 | |||
77 | int generic_cache_fields_write(DB * dbp, MMAPString * mmapstr, | ||
78 | char * keyname, struct mailimf_fields * fields); | ||
79 | |||
80 | int generic_cache_flags_read(DB * dbp, MMAPString * mmapstr, | ||
81 | char * keyname, struct mail_flags ** result); | ||
82 | |||
83 | int generic_cache_flags_write(DB * dbp, MMAPString * mmapstr, | ||
84 | char * keyname, struct mail_flags * flags); | ||
85 | |||
86 | int generic_cache_delete(DB * dbp, char * keyname); | ||
87 | #endif | ||
88 | |||
89 | struct mail_flags_store * mail_flags_store_new(void); | ||
90 | |||
91 | void mail_flags_store_clear(struct mail_flags_store * flags_store); | ||
92 | |||
93 | void mail_flags_store_free(struct mail_flags_store * flags_store); | ||
94 | |||
95 | int mail_flags_store_set(struct mail_flags_store * flags_store, | ||
96 | mailmessage * msg); | ||
97 | |||
98 | void mail_flags_store_sort(struct mail_flags_store * flags_store); | ||
99 | |||
100 | struct mail_flags * | ||
101 | mail_flags_store_get(struct mail_flags_store * flags_store, uint32_t index); | ||
102 | |||
103 | int 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 | ||
44 | extern "C" { | ||
45 | #endif | ||
46 | |||
47 | struct 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 | |||
41 | static int mailimf_cache_field_write(MMAPString * mmapstr, size_t * index, | ||
42 | struct mailimf_field * field); | ||
43 | static int mailimf_cache_orig_date_write(MMAPString * mmapstr, size_t * index, | ||
44 | struct mailimf_orig_date * date); | ||
45 | static int mailimf_cache_date_time_write(MMAPString * mmapstr, size_t * index, | ||
46 | struct mailimf_date_time * date_time); | ||
47 | static int mailimf_cache_from_write(MMAPString * mmapstr, size_t * index, | ||
48 | struct mailimf_from * from); | ||
49 | static int mailimf_cache_sender_write(MMAPString * mmapstr, size_t * index, | ||
50 | struct mailimf_sender * sender); | ||
51 | static int mailimf_cache_reply_to_write(MMAPString * mmapstr, size_t * index, | ||
52 | struct mailimf_reply_to * reply_to); | ||
53 | static int mailimf_cache_to_write(MMAPString * mmapstr, size_t * index, | ||
54 | struct mailimf_to * to); | ||
55 | static int mailimf_cache_cc_write(MMAPString * mmapstr, size_t * index, | ||
56 | struct mailimf_cc * to); | ||
57 | static int mailimf_cache_bcc_write(MMAPString * mmapstr, size_t * index, | ||
58 | struct mailimf_bcc * to); | ||
59 | static int mailimf_cache_message_id_write(MMAPString * mmapstr, size_t * index, | ||
60 | struct mailimf_message_id * message_id); | ||
61 | static int mailimf_cache_msg_id_list_write(MMAPString * mmapstr, size_t * index, | ||
62 | clist * list); | ||
63 | static int mailimf_cache_in_reply_to_write(MMAPString * mmapstr, size_t * index, | ||
64 | struct mailimf_in_reply_to * | ||
65 | in_reply_to); | ||
66 | static int mailimf_cache_references_write(MMAPString * mmapstr, size_t * index, | ||
67 | struct mailimf_references * references); | ||
68 | static int mailimf_cache_subject_write(MMAPString * mmapstr, size_t * index, | ||
69 | struct mailimf_subject * subject); | ||
70 | static int mailimf_cache_address_list_write(MMAPString * mmapstr, | ||
71 | size_t * index, | ||
72 | struct mailimf_address_list * | ||
73 | addr_list); | ||
74 | static int mailimf_cache_address_write(MMAPString * mmapstr, size_t * index, | ||
75 | struct mailimf_address * addr); | ||
76 | static int mailimf_cache_group_write(MMAPString * mmapstr, size_t * index, | ||
77 | struct mailimf_group * group); | ||
78 | static int mailimf_cache_mailbox_list_write(MMAPString * mmapstr, | ||
79 | size_t * index, | ||
80 | struct mailimf_mailbox_list * mb_list); | ||
81 | static int mailimf_cache_mailbox_write(MMAPString * mmapstr, size_t * index, | ||
82 | struct mailimf_mailbox * mb); | ||
83 | |||
84 | |||
85 | static int mailimf_cache_field_read(MMAPString * mmapstr, size_t * index, | ||
86 | struct mailimf_field ** result); | ||
87 | static int mailimf_cache_orig_date_read(MMAPString * mmapstr, size_t * index, | ||
88 | struct mailimf_orig_date ** result); | ||
89 | static int mailimf_cache_date_time_read(MMAPString * mmapstr, size_t * index, | ||
90 | struct mailimf_date_time ** result); | ||
91 | static int mailimf_cache_from_read(MMAPString * mmapstr, size_t * index, | ||
92 | struct mailimf_from ** result); | ||
93 | static int mailimf_cache_sender_read(MMAPString * mmapstr, size_t * index, | ||
94 | struct mailimf_sender ** result); | ||
95 | static int mailimf_cache_reply_to_read(MMAPString * mmapstr, size_t * index, | ||
96 | struct mailimf_reply_to ** result); | ||
97 | static int mailimf_cache_to_read(MMAPString * mmapstr, size_t * index, | ||
98 | struct mailimf_to ** result); | ||
99 | static int mailimf_cache_cc_read(MMAPString * mmapstr, size_t * index, | ||
100 | struct mailimf_cc ** result); | ||
101 | static int mailimf_cache_bcc_read(MMAPString * mmapstr, size_t * index, | ||
102 | struct mailimf_bcc ** result); | ||
103 | static int mailimf_cache_message_id_read(MMAPString * mmapstr, size_t * index, | ||
104 | struct mailimf_message_id ** result); | ||
105 | static int mailimf_cache_msg_id_list_read(MMAPString * mmapstr, size_t * index, | ||
106 | clist ** result); | ||
107 | static int | ||
108 | mailimf_cache_in_reply_to_read(MMAPString * mmapstr, size_t * index, | ||
109 | struct mailimf_in_reply_to ** result); | ||
110 | |||
111 | static int mailimf_cache_references_read(MMAPString * mmapstr, size_t * index, | ||
112 | struct mailimf_references ** result); | ||
113 | static int mailimf_cache_subject_read(MMAPString * mmapstr, size_t * index, | ||
114 | struct mailimf_subject ** result); | ||
115 | static int mailimf_cache_address_list_read(MMAPString * mmapstr, size_t * index, | ||
116 | struct mailimf_address_list ** result); | ||
117 | static int mailimf_cache_address_read(MMAPString * mmapstr, size_t * index, | ||
118 | struct mailimf_address ** result); | ||
119 | static int mailimf_cache_group_read(MMAPString * mmapstr, size_t * index, | ||
120 | struct mailimf_group ** result); | ||
121 | static int | ||
122 | mailimf_cache_mailbox_list_read(MMAPString * mmapstr, size_t * index, | ||
123 | struct mailimf_mailbox_list ** result); | ||
124 | static int mailimf_cache_mailbox_read(MMAPString * mmapstr, size_t * index, | ||
125 | struct mailimf_mailbox ** result); | ||
126 | |||
127 | enum { | ||
128 | CACHE_NULL_POINTER = 0, | ||
129 | CACHE_NOT_NULL = 1, | ||
130 | }; | ||
131 | |||
132 | int 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 | |||
142 | int 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 | |||
153 | int 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 | |||
169 | int 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 | |||
188 | int 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 | |||
210 | int 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 | |||
239 | int 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 | |||
275 | int 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 | |||
296 | int 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 | |||
353 | static 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 | |||
419 | static 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 | |||
542 | static 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 | |||
548 | static 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 | |||
570 | static 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 | |||
606 | static 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 | |||
658 | static 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 | |||
664 | static 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 | |||
686 | static 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 | |||
692 | static 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 | |||
714 | static 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 | |||
721 | static 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 | |||
743 | static 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 | |||
749 | static 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 | |||
771 | static 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 | |||
777 | static 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 | |||
799 | static 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 | |||
805 | static 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 | |||
827 | static int | ||
828 | mailimf_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 | |||
835 | static 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 | |||
857 | static int | ||
858 | mailimf_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 | |||
881 | static 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 | |||
930 | static int | ||
931 | mailimf_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 | |||
938 | static 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 | |||
961 | static 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 | |||
968 | static 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 | |||
992 | static 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 | |||
999 | static 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 | |||
1028 | static int | ||
1029 | mailimf_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 | |||
1065 | static int | ||
1066 | mailimf_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 | |||
1134 | static 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 | |||
1162 | static 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 | |||
1210 | static 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 | |||
1227 | static 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 | |||
1266 | static int | ||
1267 | mailimf_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 | |||
1303 | static int | ||
1304 | mailimf_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 | |||
1372 | static 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 | |||
1397 | static 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 | ||
46 | extern "C" { | ||
47 | #endif | ||
48 | |||
49 | int mail_serialize_clear(MMAPString * mmapstr, size_t * index); | ||
50 | |||
51 | int mail_serialize_write(MMAPString * mmapstr, size_t * index, | ||
52 | char * buf, size_t size); | ||
53 | |||
54 | int mail_serialize_read(MMAPString * mmapstr, size_t * index, | ||
55 | char * buf, size_t size); | ||
56 | |||
57 | int mailimf_cache_int_write(MMAPString * mmapstr, size_t * index, | ||
58 | uint32_t value); | ||
59 | int mailimf_cache_string_write(MMAPString * mmapstr, size_t * index, | ||
60 | char * str, size_t length); | ||
61 | int mailimf_cache_int_read(MMAPString * mmapstr, size_t * index, | ||
62 | uint32_t * result); | ||
63 | int mailimf_cache_string_read(MMAPString * mmapstr, size_t * index, | ||
64 | char ** result); | ||
65 | |||
66 | int mailimf_cache_fields_write(MMAPString * mmapstr, size_t * index, | ||
67 | struct mailimf_fields * fields); | ||
68 | int 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 | |||
50 | static 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 | |||
58 | static 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 | |||
66 | static 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 | |||
74 | static 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 | |||
117 | static 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 | |||
171 | static 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 | |||
200 | static 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 | |||
404 | static 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 | |||
424 | static 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 | |||
474 | static 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 | |||
487 | static 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 | |||
529 | static 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 | |||
555 | static 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 | |||
574 | static 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 | |||
643 | static 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 | |||
660 | static 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 | |||
668 | int 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 | |||
689 | static 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 | |||
727 | int 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 | |||
761 | static int | ||
762 | mail_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 | |||
1460 | static int | ||
1461 | mail_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 | |||
1625 | static int | ||
1626 | mail_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 | |||
1711 | int 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 | ||
43 | extern "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 | |||
69 | int 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 | |||
89 | int 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 | |||
101 | int 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 | |||
41 | struct mailmessage_tree * | ||
42 | mailmessage_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 | |||
64 | void 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 | |||
77 | void 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 | ||
41 | extern "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 | |||
51 | enum { | ||
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 | ||