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