summaryrefslogtreecommitdiffabout
path: root/libetpan/src/driver/implementation/imap/imapdriver_cached_message.c
Unidiff
Diffstat (limited to 'libetpan/src/driver/implementation/imap/imapdriver_cached_message.c') (more/less context) (ignore whitespace changes)
-rw-r--r--libetpan/src/driver/implementation/imap/imapdriver_cached_message.c664
1 files changed, 664 insertions, 0 deletions
diff --git a/libetpan/src/driver/implementation/imap/imapdriver_cached_message.c b/libetpan/src/driver/implementation/imap/imapdriver_cached_message.c
new file mode 100644
index 0000000..34e1ca3
--- a/dev/null
+++ b/libetpan/src/driver/implementation/imap/imapdriver_cached_message.c
@@ -0,0 +1,664 @@
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 "imapdriver_cached_message.h"
37
38#include "imapdriver_tools.h"
39#include "imapdriver_message.h"
40#include "imapdriver_cached.h"
41#include "imapdriver_types.h"
42#include "imapdriver.h"
43#include "mailmessage.h"
44#include "generic_cache.h"
45#include "mail_cache_db.h"
46
47#include <string.h>
48#include <stdlib.h>
49
50static int imap_initialize(mailmessage * msg_info);
51
52static void imap_uninitialize(mailmessage * msg_info);
53
54static void imap_flush(mailmessage * msg_info);
55
56static void imap_check(mailmessage * msg_info);
57
58static void imap_fetch_result_free(mailmessage * msg_info,
59 char * msg);
60
61static int imap_fetch(mailmessage * msg_info,
62 char ** result,
63 size_t * result_len);
64
65static int imap_fetch_header(mailmessage * msg_info,
66 char ** result,
67 size_t * result_len);
68
69static int imap_fetch_body(mailmessage * msg_info,
70 char ** result, size_t * result_len);
71
72static int imap_fetch_size(mailmessage * msg_info,
73 size_t * result);
74
75static int imap_get_bodystructure(mailmessage * msg_info,
76 struct mailmime ** result);
77
78static int imap_fetch_section(mailmessage * msg_info,
79 struct mailmime * mime,
80 char ** result, size_t * result_len);
81
82static int imap_fetch_section_header(mailmessage * msg_info,
83 struct mailmime * mime,
84 char ** result,
85 size_t * result_len);
86
87static int imap_fetch_section_mime(mailmessage * msg_info,
88 struct mailmime * mime,
89 char ** result,
90 size_t * result_len);
91
92static int imap_fetch_section_body(mailmessage * msg_info,
93 struct mailmime * mime,
94 char ** result,
95 size_t * result_len);
96
97
98static int imap_fetch_envelope(mailmessage * msg_info,
99 struct mailimf_fields ** result);
100
101static int imap_get_flags(mailmessage * msg_info,
102 struct mail_flags ** result);
103
104static mailmessage_driver local_imap_cached_message_driver = {
105 .msg_name = "imap-cached",
106
107 .msg_initialize = imap_initialize,
108 .msg_uninitialize = imap_uninitialize,
109
110 .msg_flush = imap_flush,
111 .msg_check = imap_check,
112
113 .msg_fetch_result_free = imap_fetch_result_free,
114
115 .msg_fetch = imap_fetch,
116 .msg_fetch_header = imap_fetch_header,
117 .msg_fetch_body = imap_fetch_body,
118 .msg_fetch_size = imap_fetch_size,
119 .msg_get_bodystructure = imap_get_bodystructure,
120 .msg_fetch_section = imap_fetch_section,
121 .msg_fetch_section_header = imap_fetch_section_header,
122 .msg_fetch_section_mime = imap_fetch_section_mime,
123 .msg_fetch_section_body = imap_fetch_section_body,
124 .msg_fetch_envelope = imap_fetch_envelope,
125
126 .msg_get_flags = imap_get_flags,
127};
128
129mailmessage_driver * imap_cached_message_driver =
130&local_imap_cached_message_driver;
131
132static inline struct imap_cached_session_state_data *
133get_cached_session_data(mailmessage * msg)
134{
135 return msg->msg_session->sess_data;
136}
137
138static inline mailmessage * get_ancestor(mailmessage * msg_info)
139{
140 return msg_info->msg_data;
141}
142
143static inline struct imap_cached_session_state_data *
144cached_session_get_data(mailsession * s)
145{
146 return s->sess_data;
147}
148
149static inline mailsession * cached_session_get_ancestor(mailsession * s)
150{
151 return cached_session_get_data(s)->imap_ancestor;
152}
153
154static inline struct imap_session_state_data *
155cached_session_get_ancestor_data(mailsession * s)
156{
157 return cached_session_get_ancestor(s)->sess_data;
158}
159
160static inline mailimap *
161cached_session_get_imap_session(mailsession * session)
162{
163 return cached_session_get_ancestor_data(session)->imap_session;
164}
165
166static inline mailimap * get_imap_session(mailmessage * msg)
167{
168 return cached_session_get_imap_session(msg->msg_session);
169}
170
171static inline mailsession * get_ancestor_session(mailmessage * msg_info)
172{
173 return cached_session_get_ancestor(msg_info->msg_session);
174}
175
176
177static void generate_key_from_mime_section(char * key, size_t size,
178 struct mailmime * mime)
179{
180 clistiter * cur;
181 MMAPString * gstr;
182 struct mailmime_section * part;
183 int r;
184
185 snprintf(key, size, "unvalid");
186
187 r = mailmime_get_section_id(mime, &part);
188 if (r != MAILIMF_NO_ERROR)
189 goto err;
190
191 gstr = mmap_string_new("part");
192 if (gstr == NULL)
193 goto free_section;
194
195 for(cur = clist_begin(part->sec_list) ;
196 cur != NULL ; cur = clist_next(cur)) {
197 char s[20];
198
199 snprintf(s, 20, ".%u", * (uint32_t *) clist_content(cur));
200 if (mmap_string_append(gstr, s) == NULL)
201 goto free_str;
202 }
203
204 snprintf(key, size, "%s", gstr->str);
205
206 mmap_string_free(gstr);
207 mailmime_section_free(part);
208
209 return;
210
211 free_str:
212 mmap_string_free(gstr);
213 free_section:
214 mailmime_section_free(part);
215 err:;
216}
217
218static void generate_key_from_section(char * key, size_t size,
219 mailmessage * msg_info,
220 struct mailmime * mime, int type)
221{
222 char section_str[PATH_MAX];
223
224 generate_key_from_mime_section(section_str, PATH_MAX, mime);
225
226 switch (type) {
227 case IMAP_SECTION_MESSAGE:
228 snprintf(key, size, "%s-%s", msg_info->msg_uid, section_str);
229 break;
230 case IMAP_SECTION_HEADER:
231 snprintf(key, size, "%s-%s-header", msg_info->msg_uid, section_str);
232 break;
233 case IMAP_SECTION_MIME:
234 snprintf(key, size, "%s-%s-mime", msg_info->msg_uid, section_str);
235 break;
236 case IMAP_SECTION_BODY:
237 snprintf(key, size, "%s-%s-text", msg_info->msg_uid, section_str);
238 break;
239 }
240}
241
242static void generate_key_from_message(char * key, size_t size,
243 mailmessage * msg_info,
244 int type)
245{
246 switch (type) {
247 case MAILIMAP_MSG_ATT_RFC822:
248 snprintf(key, size, "%s-rfc822", msg_info->msg_uid);
249 break;
250 case MAILIMAP_MSG_ATT_RFC822_HEADER:
251 snprintf(key, size, "%s-rfc822-header", msg_info->msg_uid);
252 break;
253 case MAILIMAP_MSG_ATT_RFC822_TEXT:
254 snprintf(key, size, "%s-rfc822-text", msg_info->msg_uid);
255 break;
256 case MAILIMAP_MSG_ATT_ENVELOPE:
257 snprintf(key, size, "%s-envelope", msg_info->msg_uid);
258 break;
259 }
260}
261
262static void build_cache_name(char * filename, size_t size,
263 mailmessage * msg, char * key)
264{
265 char * quoted_mb;
266
267 quoted_mb = get_cached_session_data(msg)->imap_quoted_mb;
268
269 snprintf(filename, size, "%s/%s", quoted_mb, key);
270}
271
272static int imap_initialize(mailmessage * msg_info)
273{
274 mailmessage * ancestor;
275 int r;
276 char key[PATH_MAX];
277 char * uid;
278 mailimap * imap;
279
280 ancestor = mailmessage_new();
281 if (ancestor == NULL)
282 return MAIL_ERROR_MEMORY;
283
284 r = mailmessage_init(ancestor, get_ancestor_session(msg_info),
285 imap_message_driver,
286 msg_info->msg_index, 0);
287 if (r != MAIL_NO_ERROR) {
288 mailmessage_free(ancestor);
289 return r;
290 }
291
292 imap = get_imap_session(msg_info);
293
294 snprintf(key, PATH_MAX, "%u-%u",
295 imap->imap_selection_info->sel_uidvalidity, msg_info->msg_index);
296 uid = strdup(key);
297 if (uid == NULL) {
298 mailmessage_free(ancestor);
299 return MAIL_ERROR_MEMORY;
300 }
301
302 msg_info->msg_data = ancestor;
303 msg_info->msg_uid = uid;
304
305 return MAIL_NO_ERROR;
306}
307
308static void imap_uninitialize(mailmessage * msg_info)
309{
310 mailmessage_free(get_ancestor(msg_info));
311 msg_info->msg_data = NULL;
312}
313
314static void imap_flush(mailmessage * msg_info)
315{
316 if (msg_info->msg_mime != NULL) {
317 mailmime_free(msg_info->msg_mime);
318 msg_info->msg_mime = NULL;
319 }
320}
321
322static void imap_check(mailmessage * msg_info)
323{
324 get_ancestor(msg_info)->msg_flags = msg_info->msg_flags;
325 mailmessage_check(get_ancestor(msg_info));
326 get_ancestor(msg_info)->msg_flags = NULL;
327}
328
329static void imap_fetch_result_free(mailmessage * msg_info,
330 char * msg)
331{
332 mailmessage_fetch_result_free(get_ancestor(msg_info), msg);
333}
334
335static int imap_fetch(mailmessage * msg_info,
336 char ** result,
337 size_t * result_len)
338{
339 char key[PATH_MAX];
340 char filename[PATH_MAX];
341 int r;
342 char * str;
343 size_t len;
344
345 generate_key_from_message(key, PATH_MAX,
346 msg_info, MAILIMAP_MSG_ATT_RFC822);
347
348 build_cache_name(filename, PATH_MAX, msg_info, key);
349
350 r = generic_cache_read(filename, &str, &len);
351 if (r == MAIL_NO_ERROR) {
352 * result = str;
353 * result_len = len;
354
355 return MAIL_NO_ERROR;
356 }
357
358 r = mailmessage_fetch(get_ancestor(msg_info),
359 result, result_len);
360 if (r == MAIL_NO_ERROR)
361 generic_cache_store(filename, * result, strlen(* result));
362
363 return r;
364}
365
366static int imap_fetch_header(mailmessage * msg_info,
367 char ** result,
368 size_t * result_len)
369{
370 char key[PATH_MAX];
371 char filename[PATH_MAX];
372 int r;
373 char * str;
374 size_t len;
375
376 generate_key_from_message(key, PATH_MAX,
377 msg_info, MAILIMAP_MSG_ATT_RFC822_HEADER);
378
379 build_cache_name(filename, PATH_MAX, msg_info, key);
380
381 r = generic_cache_read(filename, &str, &len);
382 if (r == MAIL_NO_ERROR) {
383 * result = str;
384 * result_len = len;
385
386 return MAIL_NO_ERROR;
387 }
388
389 r = mailmessage_fetch_header(get_ancestor(msg_info), result,
390 result_len);
391 if (r == MAIL_NO_ERROR)
392 generic_cache_store(filename, * result, * result_len);
393
394 return r;
395}
396
397static int imap_fetch_body(mailmessage * msg_info,
398 char ** result, size_t * result_len)
399{
400 char key[PATH_MAX];
401 char filename[PATH_MAX];
402 int r;
403 char * str;
404 size_t len;
405
406 generate_key_from_message(key, PATH_MAX,
407 msg_info, MAILIMAP_MSG_ATT_RFC822_TEXT);
408
409 build_cache_name(filename, PATH_MAX, msg_info, key);
410
411 r = generic_cache_read(filename, &str, &len);
412 if (r == MAIL_NO_ERROR) {
413 * result = str;
414 * result_len = len;
415 return MAIL_NO_ERROR;
416 }
417
418 r = mailmessage_fetch_body(get_ancestor(msg_info), result,
419 result_len);
420 if (r == MAIL_NO_ERROR)
421 generic_cache_store(filename, * result, * result_len);
422
423 return r;
424}
425
426static int imap_fetch_size(mailmessage * msg_info,
427 size_t * result)
428{
429 return mailmessage_fetch_size(get_ancestor(msg_info), result);
430}
431
432static int imap_get_bodystructure(mailmessage * msg_info,
433 struct mailmime ** result)
434{
435 int r;
436
437 if (msg_info->msg_mime != NULL) {
438 * result = msg_info->msg_mime;
439
440 return MAIL_NO_ERROR;
441 }
442
443 r = mailmessage_get_bodystructure(get_ancestor(msg_info),
444 result);
445 if (r == MAIL_NO_ERROR) {
446 msg_info->msg_mime = get_ancestor(msg_info)->msg_mime;
447 get_ancestor(msg_info)->msg_mime = NULL;
448 }
449
450 return r;
451}
452
453static int imap_fetch_section(mailmessage * msg_info,
454 struct mailmime * mime,
455 char ** result, size_t * result_len)
456{
457 char key[PATH_MAX];
458 char filename[PATH_MAX];
459 int r;
460 char * str;
461 size_t len;
462
463 generate_key_from_section(key, PATH_MAX,
464 msg_info, mime, IMAP_SECTION_MESSAGE);
465
466 build_cache_name(filename, PATH_MAX, msg_info, key);
467
468 r = generic_cache_read(filename, &str, &len);
469 if (r == MAIL_NO_ERROR) {
470 * result = str;
471 * result_len = len;
472
473 return MAIL_NO_ERROR;
474 }
475
476 r = mailmessage_fetch_section(get_ancestor(msg_info),
477 mime, result, result_len);
478 if (r == MAIL_NO_ERROR)
479 generic_cache_store(filename, * result, * result_len);
480
481 return r;
482}
483
484static int imap_fetch_section_header(mailmessage * msg_info,
485 struct mailmime * mime,
486 char ** result,
487 size_t * result_len)
488{
489 char key[PATH_MAX];
490 char filename[PATH_MAX];
491 int r;
492 char * str;
493 size_t len;
494
495 generate_key_from_section(key, PATH_MAX,
496 msg_info, mime, IMAP_SECTION_HEADER);
497
498 build_cache_name(filename, PATH_MAX, msg_info, key);
499
500 r = generic_cache_read(filename, &str, &len);
501 if (r == MAIL_NO_ERROR) {
502 * result = str;
503 * result_len = len;
504
505 return MAIL_NO_ERROR;
506 }
507
508 r = mailmessage_fetch_section_header(get_ancestor(msg_info),
509 mime, result, result_len);
510 if (r == MAIL_NO_ERROR)
511 generic_cache_store(filename, * result, * result_len);
512
513 return r;
514}
515
516static int imap_fetch_section_mime(mailmessage * msg_info,
517 struct mailmime * mime,
518 char ** result,
519 size_t * result_len)
520{
521 char key[PATH_MAX];
522 char filename[PATH_MAX];
523 int r;
524 char * str;
525 size_t len;
526
527 generate_key_from_section(key, PATH_MAX,
528 msg_info, mime, IMAP_SECTION_MIME);
529
530 build_cache_name(filename, PATH_MAX, msg_info, key);
531
532 r = generic_cache_read(filename, &str, &len);
533 if (r == MAIL_NO_ERROR) {
534 * result = str;
535 * result_len = len;
536
537 return MAIL_NO_ERROR;
538 }
539
540 r = mailmessage_fetch_section_mime(get_ancestor(msg_info),
541 mime, result, result_len);
542 if (r == MAIL_NO_ERROR)
543 generic_cache_store(filename, * result, * result_len);
544
545 return r;
546}
547
548static int imap_fetch_section_body(mailmessage * msg_info,
549 struct mailmime * mime,
550 char ** result,
551 size_t * result_len)
552{
553 char key[PATH_MAX];
554 char filename[PATH_MAX];
555 int r;
556 char * str;
557 size_t len;
558
559 generate_key_from_section(key, PATH_MAX,
560 msg_info, mime, IMAP_SECTION_BODY);
561
562 build_cache_name(filename, PATH_MAX, msg_info, key);
563
564 r = generic_cache_read(filename, &str, &len);
565 if (r == MAIL_NO_ERROR) {
566
567 * result = str;
568 * result_len = len;
569
570 return MAIL_NO_ERROR;
571 }
572
573 r = mailmessage_fetch_section_body(get_ancestor(msg_info),
574 mime, result, result_len);
575 if (r == MAIL_NO_ERROR)
576 generic_cache_store(filename, * result, * result_len);
577
578 return r;
579}
580
581static int imap_get_flags(mailmessage * msg_info,
582 struct mail_flags ** result)
583{
584 int r;
585 struct mail_flags * flags;
586
587 if (msg_info->msg_flags != NULL) {
588 * result = msg_info->msg_flags;
589 return MAIL_NO_ERROR;
590 }
591
592 r = mailmessage_get_flags(get_ancestor(msg_info), &flags);
593 if (r != MAIL_NO_ERROR)
594 return r;
595
596 get_ancestor(msg_info)->msg_flags = NULL;
597 msg_info->msg_flags = flags;
598 * result = flags;
599
600 return MAIL_NO_ERROR;
601}
602
603#define ENV_NAME "env.db"
604
605static int imap_fetch_envelope(mailmessage * msg_info,
606 struct mailimf_fields ** result)
607{
608 struct mailimf_fields * fields;
609 int r;
610 struct mail_cache_db * cache_db;
611 MMAPString * mmapstr;
612 char filename[PATH_MAX];
613 struct imap_cached_session_state_data * data;
614 int res;
615
616 data = get_cached_session_data(msg_info);
617 if (data->imap_quoted_mb == NULL) {
618 res = MAIL_ERROR_BAD_STATE;
619 goto err;
620 }
621
622 snprintf(filename, PATH_MAX, "%s/%s", data->imap_quoted_mb, ENV_NAME);
623
624 r = mail_cache_db_open_lock(filename, &cache_db);
625 if (r < 0) {
626 res = MAIL_ERROR_MEMORY;
627 goto err;
628 }
629
630 mmapstr = mmap_string_new("");
631 if (mmapstr == NULL) {
632 res = MAIL_ERROR_MEMORY;
633 goto close_db;
634 }
635
636 r = imapdriver_get_cached_envelope(cache_db, mmapstr,
637 msg_info->msg_session, msg_info, &fields);
638
639 if ((r != MAIL_ERROR_CACHE_MISS) && (r != MAIL_NO_ERROR)) {
640 res = r;
641 goto close_db;
642 }
643
644 r = mailmessage_fetch_envelope(get_ancestor(msg_info), &fields);
645 if (r != MAIL_NO_ERROR) {
646 res = r;
647 goto close_db;
648 }
649
650 r = imapdriver_write_cached_envelope(cache_db, mmapstr,
651 msg_info->msg_session, msg_info, fields);
652
653 * result = fields;
654
655 mmap_string_free(mmapstr);
656 mail_cache_db_close_unlock(filename, cache_db);
657
658 return MAIL_NO_ERROR;
659
660 close_db:
661 mail_cache_db_close_unlock(filename, cache_db);
662 err:
663 return res;
664}