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: generic_cache.c,v 1.34 2008/02/20 22:15:51 hoa Exp $
34 */
35
36 #ifdef HAVE_CONFIG_H
37 # include <config.h>
38 #endif
39
40 #include "generic_cache.h"
41
42 #include "libetpan-config.h"
43
44 #ifdef HAVE_UNISTD_H
45 # include <unistd.h>
46 #endif
47 #ifdef HAVE_SYS_MMAN_H
48 # include <sys/mman.h>
49 #endif
50 #ifdef WIN32
51 # include "win_etpan.h"
52 #endif
53 #include <string.h>
54 #include <stdio.h>
55 #include <sys/types.h>
56 #include <sys/stat.h>
57 #include <fcntl.h>
58 #include <stdlib.h>
59
60 #include "maildriver_types.h"
61 #include "imfcache.h"
62 #include "chash.h"
63 #include "mailmessage.h"
64 #include "mail_cache_db.h"
65
generic_cache_create_dir(char * dirname)66 int generic_cache_create_dir(char * dirname)
67 {
68 struct stat buf;
69 int r;
70
71 r = stat(dirname, &buf);
72 if (r != 0) {
73
74 #ifdef WIN32
75 r = mkdir(dirname);
76 #else
77 r = mkdir(dirname, 0700);
78 #endif
79
80 if (r < 0)
81 return MAIL_ERROR_FILE;
82 }
83 else {
84 if (!S_ISDIR(buf.st_mode))
85 return MAIL_ERROR_FILE;
86 }
87
88 return MAIL_NO_ERROR;
89 }
90
generic_cache_store(char * filename,char * content,size_t length)91 int generic_cache_store(char * filename, char * content, size_t length)
92 {
93 int fd;
94 char * str;
95
96 fd = open(filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
97 if (fd == -1)
98 return MAIL_ERROR_FILE;
99
100 if (ftruncate(fd, length) < 0) {
101 close(fd);
102 return MAIL_ERROR_FILE;
103 }
104
105 str = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
106 if (str == (char *)MAP_FAILED) {
107 close(fd);
108 return MAIL_ERROR_FILE;
109 }
110
111 memcpy(str, content, length);
112 msync(str, length, MS_SYNC);
113 munmap(str, length);
114
115 close(fd);
116
117 return MAIL_NO_ERROR;
118 }
119
generic_cache_read(char * filename,char ** result,size_t * result_len)120 int generic_cache_read(char * filename, char ** result, size_t * result_len)
121 {
122 int fd;
123 char * str;
124 struct stat buf;
125 MMAPString * mmapstr;
126 char * content;
127 int res;
128
129 if (stat(filename, &buf) < 0) {
130 res = MAIL_ERROR_CACHE_MISS;
131 goto err;
132 }
133
134 fd = open(filename, O_RDONLY);
135 if (fd == -1) {
136 res = MAIL_ERROR_CACHE_MISS;
137 goto err;
138 }
139
140 str = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
141 if (str == (char *)MAP_FAILED) {
142 res = MAIL_ERROR_FILE;
143 goto close;
144 }
145
146 mmapstr = mmap_string_new_len(str, buf.st_size);
147 if (mmapstr == NULL) {
148 res = MAIL_ERROR_MEMORY;
149 goto unmap;
150 }
151
152 if (mmap_string_ref(mmapstr) < 0) {
153 res = MAIL_ERROR_MEMORY;
154 goto free;
155 }
156
157 content = mmapstr->str;
158
159 munmap(str, buf.st_size);
160 close(fd);
161
162 * result = content;
163 * result_len = buf.st_size;
164
165 return MAIL_NO_ERROR;
166
167 free:
168 mmap_string_free(mmapstr);
169 unmap:
170 munmap(str, buf.st_size);
171 close:
172 close(fd);
173 err:
174 return res;
175 }
176
flags_extension_read(MMAPString * mmapstr,size_t * indx,clist ** result)177 static int flags_extension_read(MMAPString * mmapstr, size_t * indx,
178 clist ** result)
179 {
180 clist * list;
181 int r;
182 uint32_t count;
183 uint32_t i;
184 int res;
185
186 r = mailimf_cache_int_read(mmapstr, indx, &count);
187 if (r != MAIL_NO_ERROR) {
188 res = r;
189 goto err;
190 }
191
192 list = clist_new();
193 if (list == NULL) {
194 res = MAIL_ERROR_MEMORY;
195 goto err;
196 }
197
198 for(i = 0 ; i < count ; i++) {
199 char * str;
200
201 r = mailimf_cache_string_read(mmapstr, indx, &str);
202 if (r != MAIL_NO_ERROR) {
203 res = r;
204 goto free_list;
205 }
206
207 r = clist_append(list, str);
208 if (r < 0) {
209 free(str);
210 res = MAIL_ERROR_MEMORY;
211 goto free_list;
212 }
213 }
214
215 * result = list;
216
217 return MAIL_NO_ERROR;
218
219 free_list:
220 clist_foreach(list, (clist_func) free, NULL);
221 clist_free(list);
222 err:
223 return res;
224 }
225
generic_flags_read(MMAPString * mmapstr,size_t * indx,struct mail_flags ** result)226 static int generic_flags_read(MMAPString * mmapstr, size_t * indx,
227 struct mail_flags ** result)
228 {
229 clist * ext;
230 int r;
231 struct mail_flags * flags;
232 uint32_t value;
233 int res;
234
235 r = mailimf_cache_int_read(mmapstr, indx, &value);
236 if (r != MAIL_NO_ERROR) {
237 res = r;
238 goto err;
239 }
240
241 ext = NULL;
242 r = flags_extension_read(mmapstr, indx, &ext);
243 if (r != MAIL_NO_ERROR) {
244 res = r;
245 goto err;
246 }
247
248 flags = mail_flags_new(value, ext);
249 if (flags == NULL) {
250 res = r;
251 goto free;
252 }
253
254 * result = flags;
255
256 return MAIL_NO_ERROR;
257
258 free:
259 clist_foreach(ext, (clist_func) free, NULL);
260 clist_free(ext);
261 err:
262 return res;
263 }
264
flags_extension_write(MMAPString * mmapstr,size_t * indx,clist * ext)265 static int flags_extension_write(MMAPString * mmapstr, size_t * indx,
266 clist * ext)
267 {
268 int r;
269 clistiter * cur;
270
271 r = mailimf_cache_int_write(mmapstr, indx, clist_count(ext));
272 if (r != MAIL_NO_ERROR)
273 return r;
274
275 for(cur = clist_begin(ext) ; cur != NULL ; cur = clist_next(cur)) {
276 char * ext_flag;
277
278 ext_flag = clist_content(cur);
279 r = mailimf_cache_string_write(mmapstr, indx,
280 ext_flag, strlen(ext_flag));
281 if (r != MAIL_NO_ERROR)
282 return r;
283 }
284
285 return MAIL_NO_ERROR;
286 }
287
generic_flags_write(MMAPString * mmapstr,size_t * indx,struct mail_flags * flags)288 static int generic_flags_write(MMAPString * mmapstr, size_t * indx,
289 struct mail_flags * flags)
290 {
291 int r;
292
293 r = mailimf_cache_int_write(mmapstr, indx,
294 flags->fl_flags & ~MAIL_FLAG_NEW);
295 if (r != MAIL_NO_ERROR)
296 return r;
297
298 r = flags_extension_write(mmapstr, indx,
299 flags->fl_extension);
300 if (r != MAIL_NO_ERROR)
301 return r;
302
303 return MAIL_NO_ERROR;
304 }
305
306
307
308
mail_flags_dup(struct mail_flags * flags)309 static struct mail_flags * mail_flags_dup(struct mail_flags * flags)
310 {
311 clist * list;
312 struct mail_flags * new_flags;
313 int r;
314 clistiter * cur;
315
316 list = clist_new();
317 if (list == NULL) {
318 goto err;
319 }
320
321 for(cur = clist_begin(flags->fl_extension) ; cur != NULL ;
322 cur = clist_next(cur)) {
323 char * ext;
324 char * original_ext;
325
326 original_ext = clist_content(cur);
327 ext = strdup(original_ext);
328 if (ext == NULL) {
329 goto free;
330 }
331
332 r = clist_append(list, ext);
333 if (r < 0) {
334 free(ext);
335 goto free;
336 }
337 }
338
339 new_flags = mail_flags_new(flags->fl_flags, list);
340 if (new_flags == NULL) {
341 goto free;
342 }
343
344 return new_flags;
345
346 free:
347 clist_foreach(list, (clist_func) free, NULL);
348 clist_free(list);
349 err:
350 return NULL;
351 }
352
mailmessage_build(mailmessage * msg)353 static mailmessage * mailmessage_build(mailmessage * msg)
354 {
355 mailmessage * new_msg;
356
357 new_msg = malloc(sizeof(* new_msg));
358 if (new_msg == NULL)
359 goto err;
360
361 new_msg->msg_session = msg->msg_session;
362 new_msg->msg_driver = msg->msg_driver;
363 new_msg->msg_index = msg->msg_index;
364 if (msg->msg_uid == NULL)
365 new_msg->msg_uid = NULL;
366 else {
367 new_msg->msg_uid = strdup(msg->msg_uid);
368 if (new_msg->msg_uid == NULL)
369 goto free;
370 }
371
372 new_msg->msg_cached = msg->msg_cached;
373 new_msg->msg_size = msg->msg_size;
374 new_msg->msg_fields = NULL;
375 new_msg->msg_flags = mail_flags_dup(msg->msg_flags);
376 if (new_msg->msg_flags == NULL) {
377 free(new_msg->msg_uid);
378 goto free;
379 }
380
381 new_msg->msg_mime = NULL;
382 new_msg->msg_data = NULL;
383
384 return new_msg;
385
386 free:
387 free(new_msg);
388 err:
389 return NULL;
390 }
391
mail_flags_store_new(void)392 struct mail_flags_store * mail_flags_store_new(void)
393 {
394 struct mail_flags_store * flags_store;
395
396 flags_store = malloc(sizeof(struct mail_flags_store));
397 if (flags_store == NULL)
398 goto err;
399
400 flags_store->fls_tab = carray_new(128);
401 if (flags_store->fls_tab == NULL)
402 goto free;
403
404 flags_store->fls_hash = chash_new(128, CHASH_COPYALL);
405 if (flags_store->fls_hash == NULL)
406 goto free_tab;
407
408 return flags_store;
409
410 free_tab:
411 carray_free(flags_store->fls_tab);
412 free:
413 free(flags_store);
414 err:
415 return NULL;
416 }
417
mail_flags_store_clear(struct mail_flags_store * flags_store)418 void mail_flags_store_clear(struct mail_flags_store * flags_store)
419 {
420 unsigned int i;
421
422 for(i = 0 ; i < carray_count(flags_store->fls_tab) ; i ++) {
423 chashdatum key;
424 mailmessage * msg;
425
426 msg = carray_get(flags_store->fls_tab, i);
427
428 key.data = &msg->msg_index;
429 key.len = sizeof(msg->msg_index);
430 chash_delete(flags_store->fls_hash, &key, NULL);
431
432 mailmessage_free(msg);
433 }
434 carray_set_size(flags_store->fls_tab, 0);
435 }
436
mail_flags_store_free(struct mail_flags_store * flags_store)437 void mail_flags_store_free(struct mail_flags_store * flags_store)
438 {
439 mail_flags_store_clear(flags_store);
440 chash_free(flags_store->fls_hash);
441 carray_free(flags_store->fls_tab);
442 free(flags_store);
443 }
444
mail_flags_store_set(struct mail_flags_store * flags_store,mailmessage * msg)445 int mail_flags_store_set(struct mail_flags_store * flags_store,
446 mailmessage * msg)
447 {
448 chashdatum key;
449 chashdatum value;
450 unsigned int indx;
451 int res;
452 int r;
453 mailmessage * new_msg;
454
455 if (msg->msg_flags == NULL) {
456 res = MAIL_NO_ERROR;
457 goto err;
458 }
459
460 /* duplicate needed message info */
461 new_msg = mailmessage_build(msg);
462 if (new_msg == NULL) {
463 res = MAIL_ERROR_MEMORY;
464 goto err;
465 }
466
467 key.data = &new_msg->msg_index;
468 key.len = sizeof(new_msg->msg_index);
469
470 r = chash_get(flags_store->fls_hash, &key, &value);
471 if (r == 0) {
472 mailmessage * old_msg;
473
474 indx = * (unsigned int *) value.data;
475 old_msg = carray_get(flags_store->fls_tab, indx);
476 mailmessage_free(old_msg);
477 }
478 else {
479 r = carray_set_size(flags_store->fls_tab,
480 carray_count(flags_store->fls_tab) + 1);
481 if (r != 0) {
482 res = MAIL_ERROR_MEMORY;
483 goto err;
484 }
485 indx = carray_count(flags_store->fls_tab) - 1;
486 }
487
488 carray_set(flags_store->fls_tab, indx, new_msg);
489
490 value.data = &indx;
491 value.len = sizeof(indx);
492
493 r = chash_set(flags_store->fls_hash, &key, &value, NULL);
494 if (r < 0) {
495 carray_delete(flags_store->fls_tab, indx);
496 res = MAIL_ERROR_MEMORY;
497 goto free;
498 }
499
500 return MAIL_NO_ERROR;
501
502 free:
503 mailmessage_free(new_msg);
504 err:
505 return res;
506 }
507
msg_index_compare(mailmessage ** msg1,mailmessage ** msg2)508 static int msg_index_compare(mailmessage ** msg1, mailmessage ** msg2)
509 {
510 return (* msg1)->msg_index - (* msg2)->msg_index;
511 }
512
mail_flags_store_sort(struct mail_flags_store * flags_store)513 void mail_flags_store_sort(struct mail_flags_store * flags_store)
514 {
515 qsort(carray_data(flags_store->fls_tab),
516 carray_count(flags_store->fls_tab), sizeof(mailmessage *),
517 (int (*)(const void *, const void *)) msg_index_compare);
518 }
519
520 struct mail_flags *
mail_flags_store_get(struct mail_flags_store * flags_store,uint32_t indx)521 mail_flags_store_get(struct mail_flags_store * flags_store, uint32_t indx)
522 {
523 struct mail_flags * flags;
524 chashdatum key;
525 chashdatum value;
526 int r;
527 unsigned int tab_index;
528 mailmessage * msg;
529
530 key.data = &indx;
531 key.len = sizeof(indx);
532
533 r = chash_get(flags_store->fls_hash, &key, &value);
534
535 if (r < 0)
536 return NULL;
537
538 #if 0
539 flags = mail_flags_dup((struct mail_flags *) value.data);
540 #endif
541 tab_index = * (unsigned int *) value.data;
542 msg = carray_get(flags_store->fls_tab, tab_index);
543 if (msg->msg_flags == NULL)
544 return NULL;
545
546 flags = mail_flags_dup(msg->msg_flags);
547
548 return flags;
549 }
550
mail_flags_compare(struct mail_flags * flags1,struct mail_flags * flags2)551 int mail_flags_compare(struct mail_flags * flags1, struct mail_flags * flags2)
552 {
553 clistiter * cur1;
554
555 if (clist_count(flags1->fl_extension) != clist_count(flags2->fl_extension))
556 return -1;
557
558 for(cur1 = clist_begin(flags1->fl_extension) ; cur1 != NULL ;
559 cur1 = clist_next(cur1)) {
560 char * flag1;
561 clistiter * cur2;
562 int found;
563
564 flag1 = clist_content(cur1);
565
566 found = 0;
567 for(cur2 = clist_begin(flags2->fl_extension) ; cur2 != NULL ;
568 cur2 = clist_next(cur2)) {
569 char * flag2;
570
571 flag2 = clist_content(cur2);
572
573 if (strcasecmp(flag1, flag2) == 0) {
574 found = 1;
575 break;
576 }
577 }
578
579 if (!found)
580 return -1;
581 }
582
583 return flags1->fl_flags - flags2->fl_flags;
584 }
585
generic_cache_fields_read(struct mail_cache_db * cache_db,MMAPString * mmapstr,char * keyname,struct mailimf_fields ** result)586 int generic_cache_fields_read(struct mail_cache_db * cache_db,
587 MMAPString * mmapstr,
588 char * keyname, struct mailimf_fields ** result)
589 {
590 int r;
591 int res;
592 size_t cur_token;
593 struct mailimf_fields * fields;
594 void * data;
595 size_t data_len;
596
597 r = mail_cache_db_get(cache_db, keyname, strlen(keyname), &data, &data_len);
598 if (r != 0) {
599 res = MAIL_ERROR_CACHE_MISS;
600 goto err;
601 }
602
603 r = mail_serialize_clear(mmapstr, &cur_token);
604 if (r != MAIL_NO_ERROR) {
605 res = r;
606 goto err;
607 }
608
609 if (mmap_string_append_len(mmapstr, data, data_len) == NULL) {
610 res = MAIL_ERROR_MEMORY;
611 goto err;
612 }
613
614 r = mailimf_cache_fields_read(mmapstr, &cur_token, &fields);
615 if (r != MAIL_NO_ERROR) {
616 res = r;
617 goto err;
618 }
619
620 * result = fields;
621
622 return MAIL_NO_ERROR;
623
624 err:
625 return res;
626 }
627
generic_cache_fields_write(struct mail_cache_db * cache_db,MMAPString * mmapstr,char * keyname,struct mailimf_fields * fields)628 int generic_cache_fields_write(struct mail_cache_db * cache_db,
629 MMAPString * mmapstr,
630 char * keyname, struct mailimf_fields * fields)
631 {
632 int r;
633 int res;
634 size_t cur_token;
635
636 r = mail_serialize_clear(mmapstr, &cur_token);
637 if (r != MAIL_NO_ERROR) {
638 res = r;
639 goto err;
640 }
641
642 r = mailimf_cache_fields_write(mmapstr, &cur_token, fields);
643 if (r != MAIL_NO_ERROR) {
644 res = r;
645 goto err;
646 }
647
648 r = mail_cache_db_put(cache_db, keyname, strlen(keyname),
649 mmapstr->str, mmapstr->len);
650 if (r != 0) {
651 res = MAIL_ERROR_FILE;
652 goto err;
653 }
654
655 return MAIL_NO_ERROR;
656
657 err:
658 return res;
659 }
660
generic_cache_flags_read(struct mail_cache_db * cache_db,MMAPString * mmapstr,char * keyname,struct mail_flags ** result)661 int generic_cache_flags_read(struct mail_cache_db * cache_db,
662 MMAPString * mmapstr,
663 char * keyname, struct mail_flags ** result)
664 {
665 int r;
666 int res;
667 size_t cur_token;
668 struct mail_flags * flags;
669 void * data;
670 size_t data_len;
671
672 data = NULL;
673 data_len = 0;
674 r = mail_cache_db_get(cache_db, keyname, strlen(keyname), &data, &data_len);
675 if (r != 0) {
676 res = MAIL_ERROR_CACHE_MISS;
677 goto err;
678 }
679
680 r = mail_serialize_clear(mmapstr, &cur_token);
681 if (r != MAIL_NO_ERROR) {
682 res = r;
683 goto err;
684 }
685
686 if (mmap_string_append_len(mmapstr, data, data_len) == NULL) {
687 res = MAIL_ERROR_MEMORY;
688 goto err;
689 }
690
691 flags = NULL;
692 r = generic_flags_read(mmapstr, &cur_token, &flags);
693 if (r != MAIL_NO_ERROR) {
694 res = r;
695 goto err;
696 }
697
698 * result = flags;
699
700 return MAIL_NO_ERROR;
701
702 err:
703 return res;
704 }
705
generic_cache_flags_write(struct mail_cache_db * cache_db,MMAPString * mmapstr,char * keyname,struct mail_flags * flags)706 int generic_cache_flags_write(struct mail_cache_db * cache_db,
707 MMAPString * mmapstr,
708 char * keyname, struct mail_flags * flags)
709 {
710 int r;
711 int res;
712 size_t cur_token;
713
714 r = mail_serialize_clear(mmapstr, &cur_token);
715 if (r != MAIL_NO_ERROR) {
716 res = r;
717 goto err;
718 }
719
720 r = generic_flags_write(mmapstr, &cur_token, flags);
721 if (r != MAIL_NO_ERROR) {
722 res = r;
723 goto err;
724 }
725
726 r = mail_cache_db_put(cache_db, keyname, strlen(keyname),
727 mmapstr->str, mmapstr->len);
728 if (r != 0) {
729 res = MAIL_ERROR_FILE;
730 goto err;
731 }
732
733 return MAIL_NO_ERROR;
734
735 err:
736 return res;
737 }
738
739
generic_cache_delete(struct mail_cache_db * cache_db,char * keyname)740 int generic_cache_delete(struct mail_cache_db * cache_db,
741 char * keyname)
742 {
743 int r;
744 int res;
745
746 r = mail_cache_db_del(cache_db, keyname, strlen(keyname));
747 if (r != 0) {
748 res = MAIL_ERROR_FILE;
749 goto err;
750 }
751
752 return MAIL_NO_ERROR;
753
754 err:
755 return res;
756 }
757
758
759