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: dbdriver.c,v 1.14 2010/04/05 14:21:35 hoa Exp $
34  */
35 
36 #ifdef HAVE_CONFIG_H
37 #	include <config.h>
38 #endif
39 
40 #include "dbdriver.h"
41 #include "imfcache.h"
42 #include "generic_cache.h"
43 #include "libetpan-config.h"
44 #include "dbdriver_message.h"
45 #include "mail_cache_db.h"
46 #include <string.h>
47 #include <stdlib.h>
48 #include "mailmessage.h"
49 
50 static int initialize(mailsession * session);
51 
52 static void uninitialize(mailsession * session);
53 
54 static int connect_path(mailsession * session, const char * path);
55 
56 static int logout(mailsession * session);
57 
58 static int expunge_folder(mailsession * session);
59 
60 static int status_folder(mailsession * session, const char * mb,
61     uint32_t * result_messages, uint32_t * result_recent,
62     uint32_t * result_unseen);
63 
64 static int recent_number(mailsession * session, const char * mb,
65     uint32_t * result);
66 
67 static int unseen_number(mailsession * session, const char * mb,
68     uint32_t * result);
69 
70 static int messages_number(mailsession * session, const char * mb,
71     uint32_t * result);
72 
73 static int append_message(mailsession * session,
74     const char * message, size_t size);
75 
76 static int append_message_flags(mailsession * session,
77     const char * message, size_t size, struct mail_flags * flags);
78 
79 static int get_messages_list(mailsession * session,
80     struct mailmessage_list ** result);
81 
82 static int get_envelopes_list(mailsession * session,
83     struct mailmessage_list * env_list);
84 
85 static int check_folder(mailsession * session);
86 
87 static int get_message(mailsession * session,
88     uint32_t num, mailmessage ** result);
89 
90 static int get_message_by_uid(mailsession * session,
91     const char * uid, mailmessage ** result);
92 
93 static mailsession_driver local_db_session_driver = {
94   /* sess_name */ "db",
95 
96   /* sess_initialize */ initialize,
97   /* sess_uninitialize */ uninitialize,
98 
99   /* sess_parameters */ NULL,
100 
101   /* sess_connect_stream */ NULL,
102   /* sess_connect_path */ connect_path,
103   /* sess_starttls */ NULL,
104   /* sess_login */ NULL,
105   /* sess_logout */ logout,
106   /* sess_noop */ NULL,
107 
108   /* sess_build_folder_name */ NULL,
109   /* sess_create_folder */ NULL,
110   /* sess_delete_folder */ NULL,
111   /* sess_rename_folder */ NULL,
112   /* sess_check_folder */ check_folder,
113   /* sess_examine_folder */ NULL,
114   /* sess_select_folder */ NULL,
115   /* sess_expunge_folder */ expunge_folder,
116   /* sess_status_folder */ status_folder,
117   /* sess_messages_number */ messages_number,
118   /* sess_recent_number */ recent_number,
119   /* sess_unseen_number */ unseen_number,
120   /* sess_list_folders */ NULL,
121   /* sess_lsub_folders */ NULL,
122   /* sess_subscribe_folder */ NULL,
123   /* sess_unsubscribe_folder */ NULL,
124 
125   /* sess_append_message */ append_message,
126   /* sess_append_message_flags */ append_message_flags,
127   /* sess_copy_message */ NULL,
128   /* sess_move_message */ NULL,
129 
130   /* sess_get_message */ get_message,
131   /* sess_get_message_by_uid */ get_message_by_uid,
132 
133   /* sess_get_messages_list */ get_messages_list,
134   /* sess_get_envelopes_list */ get_envelopes_list,
135   /* sess_remove_message */ NULL,
136   /* sess_login_sasl */ NULL
137 };
138 
139 mailsession_driver * db_session_driver = &local_db_session_driver;
140 
get_data(mailsession * session)141 static inline struct db_session_state_data * get_data(mailsession * session)
142 {
143   return session->sess_data;
144 }
145 
flags_store_process(mailsession * session)146 static int flags_store_process(mailsession * session)
147 {
148   unsigned int i;
149   MMAPString * mmapstr;
150   int r;
151   int res;
152   struct mail_cache_db * maildb;
153   struct db_session_state_data * data;
154   struct mail_flags_store * flags_store;
155 
156   data = get_data(session);
157 
158   flags_store = data->db_flags_store;
159 
160   if (carray_count(flags_store->fls_tab) == 0)
161     return MAIL_NO_ERROR;
162 
163   mmapstr = mmap_string_new("");
164   if (mmapstr == NULL) {
165     res = MAIL_ERROR_MEMORY;
166     goto err;
167   }
168 
169   r = mail_cache_db_open_lock(data->db_filename, &maildb);
170   if (r < 0) {
171     res = MAIL_ERROR_FILE;
172     goto free_mmapstr;
173   }
174 
175   for(i = 0 ; i < carray_count(flags_store->fls_tab) ; i ++) {
176     mailmessage * msg;
177     char key[PATH_MAX];
178 
179     msg = carray_get(flags_store->fls_tab, i);
180 
181     snprintf(key, sizeof(key), "%lu-flags", (unsigned long) msg->msg_index);
182 
183     r = generic_cache_flags_write(maildb, mmapstr,
184         key, msg->msg_flags);
185   }
186 
187   mail_flags_store_clear(flags_store);
188 
189   mail_cache_db_close_unlock(data->db_filename, maildb);
190   mmap_string_free(mmapstr);
191 
192   return MAIL_NO_ERROR;
193 
194  free_mmapstr:
195   mmap_string_free(mmapstr);
196  err:
197   return res;
198 }
199 
db_get_next_msg_number(struct mail_cache_db * maildb,uint32_t * p_num)200 static int db_get_next_msg_number(struct mail_cache_db * maildb,
201     uint32_t * p_num)
202 {
203   int r;
204   char key_value[PATH_MAX];
205   uint32_t num;
206   void * serialized;
207   size_t serialized_len;
208   int res;
209   MMAPString * mmapstr;
210   size_t cur_token;
211 
212   mmapstr = mmap_string_new("");
213   if (mmapstr == NULL) {
214     res = MAIL_ERROR_MEMORY;
215     goto err;
216   }
217 
218   snprintf(key_value, sizeof(key_value), "next-msg");
219 
220   r = mail_cache_db_get(maildb, key_value, strlen(key_value),
221       &serialized, &serialized_len);
222 
223   if (r >= 0) {
224     if (mmap_string_append_len(mmapstr, serialized, serialized_len) == NULL) {
225       res = MAIL_ERROR_MEMORY;
226       goto err;
227     }
228 
229     cur_token = 0;
230     r = mailimf_cache_int_read(mmapstr, &cur_token, &num);
231     if (r < 0)
232       num = 1;
233   }
234   else {
235     num = 1;
236   }
237 
238   mmap_string_set_size(mmapstr, 0);
239   cur_token = 0;
240   r = mailimf_cache_int_write(mmapstr, &cur_token, num + 1);
241   if (r < 0) {
242     res = MAIL_ERROR_MEMORY;
243     goto free_mmapstr;
244   }
245 
246   r = mail_cache_db_put(maildb, key_value, strlen(key_value),
247       mmapstr->str, mmapstr->len);
248   if (r < 0) {
249     res = MAIL_ERROR_FILE;
250     goto free_mmapstr;
251   }
252 
253   mmap_string_free(mmapstr);
254 
255   * p_num = num;
256 
257   return MAIL_NO_ERROR;
258 
259  free_mmapstr:
260   mmap_string_free(mmapstr);
261  err:
262   return res;
263 }
264 
db_set_message_list(struct mail_cache_db * maildb,carray * msglist)265 static int db_set_message_list(struct mail_cache_db * maildb,
266     carray * msglist)
267 {
268   MMAPString * mmapstr;
269   char key_value[PATH_MAX];
270   int r;
271   unsigned int i;
272   size_t cur_token;
273   int res;
274 
275   mmapstr = mmap_string_new("");
276   if (mmapstr == NULL) {
277     res = MAIL_ERROR_MEMORY;
278     goto err;
279   }
280 
281   cur_token = 0;
282   for(i = 0 ; i < carray_count(msglist) ; i ++) {
283     uint32_t * msg;
284 
285     msg = carray_get(msglist, i);
286     r = mailimf_cache_int_write(mmapstr, &cur_token, * msg);
287     if (r != MAIL_NO_ERROR) {
288       res = r;
289       goto free_mmapstr;
290     }
291   }
292 
293   snprintf(key_value, sizeof(key_value), "message-list");
294   r = mail_cache_db_put(maildb, key_value, strlen(key_value),
295       mmapstr->str, mmapstr->len);
296   if (r < 0) {
297     res = MAIL_ERROR_FILE;
298     goto err;
299   }
300 
301   mmap_string_free(mmapstr);
302 
303   return MAIL_NO_ERROR;
304 
305  free_mmapstr:
306   mmap_string_free(mmapstr);
307  err:
308   return res;
309 }
310 
db_get_message_list(struct mail_cache_db * maildb,carray ** p_msglist)311 static int db_get_message_list(struct mail_cache_db * maildb,
312     carray ** p_msglist)
313 {
314   carray * msglist;
315   void * serialized;
316   size_t serialized_len;
317   int r;
318   char key_value[PATH_MAX];
319   int res;
320   unsigned int i;
321 
322   msglist = carray_new(16);
323   if (msglist == NULL) {
324     res = MAIL_ERROR_MEMORY;
325     goto err;
326   }
327 
328   snprintf(key_value, sizeof(key_value), "message-list");
329   r = mail_cache_db_get(maildb, key_value, strlen(key_value),
330       &serialized, &serialized_len);
331   if (r >= 0) {
332     MMAPString * mmapstr;
333     size_t cur_token;
334 
335     /* collect message list */
336 
337     mmapstr = mmap_string_new_len(serialized, serialized_len);
338     if (mmapstr == NULL) {
339       res = MAIL_ERROR_MEMORY;
340       goto free_msglist;
341     }
342 
343     cur_token = 0;
344     do {
345       uint32_t num;
346       uint32_t * msg;
347 
348       r = mailimf_cache_int_read(mmapstr, &cur_token, &num);
349       if (r != MAIL_NO_ERROR)
350         break;
351 
352       msg = malloc(sizeof(* msg));
353       if (msg == NULL) {
354         res = MAIL_ERROR_MEMORY;
355         mmap_string_free(mmapstr);
356         goto free_msglist;
357       }
358       * msg = num;
359 
360       r = carray_add(msglist, msg, NULL);
361       if (r < 0) {
362         res = MAIL_ERROR_MEMORY;
363         free(msg);
364         mmap_string_free(mmapstr);
365         goto free_msglist;
366       }
367     } while (1);
368 
369     mmap_string_free(mmapstr);
370   }
371 
372   * p_msglist = msglist;
373 
374   return MAIL_NO_ERROR;
375 
376  free_msglist:
377   for(i = 0 ; i < carray_count(msglist) ; i ++) {
378     uint32_t * msg;
379 
380     msg = carray_get(msglist, i);
381     free(msg);
382   }
383   carray_free(msglist);
384  err:
385   return res;
386 }
387 
initialize(mailsession * session)388 static int initialize(mailsession * session)
389 {
390   struct db_session_state_data * data;
391 
392   data = malloc(sizeof(* data));
393   if (data == NULL)
394     goto err;
395 
396   data->db_filename[0] = '\0';
397 
398   data->db_flags_store = mail_flags_store_new();
399   if (data->db_flags_store == NULL)
400     goto free;
401 
402   session->sess_data = data;
403 
404   return MAIL_NO_ERROR;
405 
406  free:
407   free(data);
408  err:
409   return MAIL_ERROR_MEMORY;
410 }
411 
uninitialize(mailsession * session)412 static void uninitialize(mailsession * session)
413 {
414   struct db_session_state_data * data;
415 
416   data = get_data(session);
417 
418   flags_store_process(session);
419 
420   mail_flags_store_free(data->db_flags_store);
421 
422   free(data);
423 
424   session->sess_data = NULL;
425 }
426 
connect_path(mailsession * session,const char * path)427 static int connect_path(mailsession * session, const char * path)
428 {
429   struct db_session_state_data * data;
430 
431   data = get_data(session);
432 
433   strncpy(data->db_filename, path, sizeof(data->db_filename));
434 
435   return MAIL_NO_ERROR;
436 }
437 
logout(mailsession * session)438 static int logout(mailsession * session)
439 {
440   return MAIL_NO_ERROR;
441 }
442 
expunge_folder(mailsession * session)443 static int expunge_folder(mailsession * session)
444 {
445   int r;
446   char key_value[PATH_MAX];
447   struct mail_cache_db * maildb;
448   carray * msglist;
449   unsigned int i;
450   struct db_session_state_data * data;
451   int res;
452   chash * msg_table;
453   MMAPString * mmapstr;
454 
455   data = get_data(session);
456 
457   flags_store_process(session);
458 
459   r = mail_cache_db_open_lock(data->db_filename, &maildb);
460   if (r < 0) {
461     res = MAIL_ERROR_FILE;
462     goto err;
463   }
464 
465   r = db_get_message_list(maildb, &msglist);
466   if (r != MAIL_NO_ERROR) {
467     res = r;
468     goto close_db;
469   }
470 
471   msg_table = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
472   if (msg_table == NULL) {
473     res = MAIL_ERROR_MEMORY;
474     goto free_msglist;
475   }
476 
477   mmapstr = mmap_string_new("");
478   if (mmapstr == NULL) {
479     res = MAIL_ERROR_MEMORY;
480     goto free_msgtable;
481   }
482 
483   i = 0;
484   while (i < carray_count(msglist)) {
485     uint32_t num;
486     uint32_t * msg;
487     chashdatum key;
488     chashdatum value;
489     struct mail_flags * flags;
490     int deleted;
491 
492     msg = carray_get(msglist, i);
493     num = * msg;
494 
495     deleted = 0;
496     snprintf(key_value, sizeof(key_value), "%lu-flags",
497         (unsigned long) num);
498     r = generic_cache_flags_read(maildb, mmapstr, key_value, &flags);
499     if (r == MAIL_NO_ERROR) {
500       if ((flags->fl_flags & MAIL_FLAG_DELETED) != 0)
501         deleted = 1;
502     }
503 
504     if (!deleted) {
505       snprintf(key_value, sizeof(key_value), "%lu", (unsigned long) num);
506       key.data = key_value;
507       key.len = (unsigned int) strlen(key_value);
508       chash_set(msg_table, &key, &value, NULL);
509 
510       snprintf(key_value, sizeof(key_value), "%lu-envelope",
511           (unsigned long) num);
512       key.data = key_value;
513       key.len = (unsigned int) strlen(key_value);
514       chash_set(msg_table, &key, &value, NULL);
515 
516       snprintf(key_value, sizeof(key_value), "%lu-flags",
517           (unsigned long) num);
518       key.data = key_value;
519       key.len = (unsigned int) strlen(key_value);
520       chash_set(msg_table, &key, &value, NULL);
521 
522       i ++;
523     }
524     else {
525       free(msg);
526       carray_delete(msglist, i);
527     }
528   }
529 
530   mmap_string_free(mmapstr);
531 
532   r = mail_cache_db_clean_up(maildb, msg_table);
533 
534   chash_free(msg_table);
535 
536   r = db_set_message_list(maildb, msglist);
537 
538   for(i = 0 ; i < carray_count(msglist) ; i ++) {
539     uint32_t * msg;
540 
541     msg = carray_get(msglist, i);
542     free(msg);
543   }
544   carray_free(msglist);
545 
546   mail_cache_db_close_unlock(data->db_filename, maildb);
547 
548   return MAIL_NO_ERROR;
549 
550  free_msgtable:
551   chash_free(msg_table);
552  free_msglist:
553   for(i = 0 ; i < carray_count(msglist) ; i ++) {
554     uint32_t * msg;
555 
556     msg = carray_get(msglist, i);
557     free(msg);
558   }
559  close_db:
560   mail_cache_db_close_unlock(data->db_filename, maildb);
561  err:
562   return res;
563 }
564 
status_folder(mailsession * session,const char * mb,uint32_t * result_messages,uint32_t * result_recent,uint32_t * result_unseen)565 static int status_folder(mailsession * session, const char * mb,
566     uint32_t * result_messages, uint32_t * result_recent,
567     uint32_t * result_unseen)
568 {
569   struct mail_cache_db * maildb;
570   char key_value[PATH_MAX];
571   MMAPString * mmapstr;
572   uint32_t messages;
573   uint32_t recent;
574   uint32_t unseen;
575   struct db_session_state_data * data;
576   int r;
577   int res;
578   carray * msglist;
579   unsigned int i;
580 
581   data = get_data(session);
582 
583   flags_store_process(session);
584 
585   r = mail_cache_db_open_lock(data->db_filename, &maildb);
586   if (r < 0) {
587     res = MAIL_ERROR_FILE;
588     goto err;
589   }
590 
591   r = db_get_message_list(maildb, &msglist);
592   if (r != MAIL_NO_ERROR) {
593     res = r;
594     goto close_db;
595   }
596 
597   mmapstr = mmap_string_new("");
598   if (mmapstr == NULL) {
599     res = MAIL_ERROR_MEMORY;
600     goto free_list;
601   }
602 
603   messages = 0;
604   recent = 0;
605   unseen = 0;
606   for(i = 0 ; i < carray_count(msglist) ; i ++) {
607     uint32_t num;
608     uint32_t * msg;
609     struct mail_flags * flags;
610 
611     msg = carray_get(msglist, i);
612     num = * msg;
613     free(msg);
614     carray_set(msglist, i, NULL);
615 
616     messages ++;
617 
618     snprintf(key_value, sizeof(key_value), "%lu-flags", (unsigned long) num);
619 
620     r = generic_cache_flags_read(maildb, mmapstr, key_value, &flags);
621     if (r == MAIL_NO_ERROR) {
622       if ((flags->fl_flags & MAIL_FLAG_NEW) != 0) {
623         recent ++;
624       }
625       if ((flags->fl_flags & MAIL_FLAG_SEEN) == 0) {
626         unseen ++;
627       }
628       mail_flags_free(flags);
629     }
630   }
631 
632   mmap_string_free(mmapstr);
633 
634   carray_free(msglist);
635 
636   mail_cache_db_close_unlock(data->db_filename, maildb);
637 
638   * result_messages = messages;
639   * result_unseen = unseen;
640   * result_recent = recent;
641 
642   return MAIL_NO_ERROR;
643 
644  free_list:
645   for(i = 0 ; i < carray_count(msglist) ; i ++) {
646     uint32_t * msg;
647 
648     msg = carray_get(msglist, i);
649     if (msg != NULL)
650       free(msg);
651   }
652   carray_free(msglist);
653  close_db:
654   mail_cache_db_close_unlock(data->db_filename, maildb);
655  err:
656   return res;
657 }
658 
recent_number(mailsession * session,const char * mb,uint32_t * result)659 static int recent_number(mailsession * session, const char * mb,
660     uint32_t * result)
661 {
662   uint32_t dummy_messages;
663   uint32_t dummy_unseen;
664 
665   return status_folder(session, mb,
666       &dummy_messages, result, &dummy_unseen);
667 }
668 
unseen_number(mailsession * session,const char * mb,uint32_t * result)669 static int unseen_number(mailsession * session, const char * mb,
670     uint32_t * result)
671 {
672   uint32_t dummy_messages;
673   uint32_t dummy_recent;
674 
675   return status_folder(session, mb,
676       &dummy_messages, &dummy_recent, result);
677 }
678 
messages_number(mailsession * session,const char * mb,uint32_t * result)679 static int messages_number(mailsession * session, const char * mb,
680     uint32_t * result)
681 {
682   uint32_t dummy_unseen;
683   uint32_t dummy_recent;
684 
685   return status_folder(session, mb,
686       result, &dummy_recent, &dummy_unseen);
687 }
688 
append_message(mailsession * session,const char * message,size_t size)689 static int append_message(mailsession * session,
690     const char * message, size_t size)
691 {
692   return append_message_flags(session, message, size, NULL);
693 }
694 
append_message_flags(mailsession * session,const char * message,size_t size,struct mail_flags * flags)695 static int append_message_flags(mailsession * session,
696     const char * message, size_t size, struct mail_flags * flags)
697 {
698   carray * msglist;
699   unsigned int i;
700   uint32_t * msg;
701   uint32_t num;
702   char key_value[PATH_MAX];
703   MMAPString * mmapstr;
704   struct mail_cache_db * maildb;
705   struct db_session_state_data * data;
706   size_t cur_token;
707   struct mailimf_fields * fields;
708   int r;
709   int res;
710 
711   data = get_data(session);
712 
713   r = mail_cache_db_open_lock(data->db_filename, &maildb);
714   if (r < 0) {
715     res = MAIL_ERROR_FILE;
716     goto err;
717   }
718 
719   num = 0;
720   r = db_get_next_msg_number(maildb, &num);
721   if (r != MAIL_NO_ERROR) {
722     res = r;
723     goto err;
724   }
725 
726   r = db_get_message_list(maildb, &msglist);
727   if (r != MAIL_NO_ERROR) {
728     res = r;
729     goto close_db;
730   }
731 
732   msg = malloc(sizeof(* msg));
733   if (msg == NULL) {
734     res = MAIL_ERROR_MEMORY;
735     goto free_msglist;
736   }
737 
738   * msg = num;
739 
740   r = carray_add(msglist, msg, NULL);
741   if (r < 0) {
742     res = MAIL_ERROR_MEMORY;
743     free(msg);
744     goto free_msglist;
745   }
746 
747   r = db_set_message_list(maildb, msglist);
748   if (r != MAIL_NO_ERROR) {
749     res = r;
750     goto free_msglist;
751   }
752 
753   /* free msglist */
754 
755   for(i = 0 ; i < carray_count(msglist) ; i ++) {
756     msg = carray_get(msglist, i);
757     free(msg);
758   }
759   carray_free(msglist);
760 
761   snprintf(key_value, sizeof(key_value), "%lu", (unsigned long) num);
762 
763   r = mail_cache_db_put(maildb, key_value, strlen(key_value),
764       message, size);
765   if (r < 0) {
766     res = MAIL_ERROR_FILE;
767     goto close_db;
768   }
769 
770   /* write envelope */
771 
772   cur_token = 0;
773   r = mailimf_envelope_fields_parse(message, size, &cur_token, &fields);
774   if (r != MAILIMF_NO_ERROR) {
775     res = MAIL_ERROR_PARSE;
776     goto close_db;
777   }
778 
779   mmapstr = mmap_string_new("");
780   if (mmapstr == NULL) {
781     res = MAIL_ERROR_MEMORY;
782     goto close_db;
783   }
784 
785   cur_token = 0;
786   r = mailimf_cache_fields_write(mmapstr, &cur_token, fields);
787   if (r != MAIL_NO_ERROR) {
788     res = r;
789     mmap_string_free(mmapstr);
790     goto close_db;
791   }
792 
793   snprintf(key_value, sizeof(key_value), "%lu-envelope", (unsigned long) num);
794 
795   r = mail_cache_db_put(maildb, key_value, strlen(key_value),
796       mmapstr->str, mmapstr->len);
797 
798   mmap_string_free(mmapstr);
799 
800   mailimf_fields_free(fields);
801 
802   /* write flags */
803 
804   if (flags != NULL) {
805     snprintf(key_value, sizeof(key_value), "%lu-flags", (unsigned long) num);
806 
807     mmapstr = mmap_string_new("");
808     if (mmapstr == NULL) {
809       res = MAIL_ERROR_MEMORY;
810       goto close_db;
811     }
812 
813     r = generic_cache_flags_write(maildb, mmapstr,
814         key_value, flags);
815 
816     mmap_string_free(mmapstr);
817 
818     if (r != MAIL_NO_ERROR) {
819       res = MAIL_ERROR_FILE;
820       goto close_db;
821     }
822   }
823 
824   mail_cache_db_close_unlock(data->db_filename, maildb);
825 
826   return MAIL_NO_ERROR;
827 
828  free_msglist:
829   for(i = 0 ; i < carray_count(msglist) ; i ++) {
830     msg = carray_get(msglist, i);
831     free(msg);
832   }
833   carray_free(msglist);
834  close_db:
835   mail_cache_db_close_unlock(data->db_filename, maildb);
836  err:
837   return res;
838 }
839 
get_messages_list(mailsession * session,struct mailmessage_list ** result)840 static int get_messages_list(mailsession * session,
841     struct mailmessage_list ** result)
842 {
843   int r;
844   char key[PATH_MAX];
845   struct mail_cache_db * maildb;
846   struct db_session_state_data * data;
847   int res;
848   carray * msglist;
849   unsigned int i;
850   carray * msgtab;
851   struct mailmessage_list * driver_msglist;
852 
853   data = get_data(session);
854 
855   r = mail_cache_db_open_lock(data->db_filename, &maildb);
856   if (r < 0) {
857     res = MAIL_ERROR_FILE;
858     goto err;
859   }
860 
861   r = db_get_message_list(maildb, &msglist);
862   if (r != MAIL_NO_ERROR) {
863     res = r;
864     goto close_db;
865   }
866 
867   msgtab = carray_new(16);
868   if (msgtab == NULL) {
869     res = MAIL_ERROR_MEMORY;
870     goto close_db;
871   }
872 
873   for(i = 0 ; i < carray_count(msglist) ; i ++) {
874     uint32_t msg_num;
875     uint32_t * pmsg_num;
876     mailmessage * msg;
877     size_t size;
878 
879     pmsg_num = carray_get(msglist, i);
880     msg_num = * pmsg_num;
881     free(pmsg_num);
882     carray_set(msglist, i, NULL);
883 
884     snprintf(key, sizeof(key), "%lu", (unsigned long) msg_num);
885     r = mail_cache_db_get_size(maildb, key, strlen(key), &size);
886     if (r < 0) {
887       continue;
888     }
889 
890     msg = mailmessage_new();
891     if (msg == NULL) {
892       res = MAIL_ERROR_MEMORY;
893       goto free_list;
894     }
895 
896     r = mailmessage_init(msg, session, db_message_driver,
897         msg_num, size);
898     if (r != MAIL_NO_ERROR) {
899       mailmessage_free(msg);
900       res = r;
901       goto free_list;
902     }
903 
904     r = carray_add(msgtab, msg, NULL);
905     if (r < 0) {
906       mailmessage_free(msg);
907       res = MAIL_ERROR_MEMORY;
908       goto free_list;
909     }
910   }
911   carray_free(msglist);
912 
913   driver_msglist = mailmessage_list_new(msgtab);
914   if (driver_msglist == NULL) {
915     res = MAIL_ERROR_MEMORY;
916     goto free_list;
917   }
918 
919   mail_cache_db_close_unlock(data->db_filename, maildb);
920 
921   * result = driver_msglist;
922 
923   return MAIL_NO_ERROR;
924 
925  free_list:
926   for(i = 0 ; i < carray_count(msgtab) ; i ++) {
927     mailmessage * msg;
928 
929     msg = carray_get(msgtab, i);
930     mailmessage_free(msg);
931   }
932   carray_free(msgtab);
933 
934   for(i = 0 ; i < carray_count(msglist) ; i ++) {
935     uint32_t * msg;
936 
937     msg = carray_get(msglist, i);
938     if (msg != NULL)
939       free(msg);
940   }
941   carray_free(msglist);
942  close_db:
943   mail_cache_db_close_unlock(data->db_filename, maildb);
944  err:
945   return res;
946 }
947 
get_envelopes_list(mailsession * session,struct mailmessage_list * env_list)948 static int get_envelopes_list(mailsession * session,
949     struct mailmessage_list * env_list)
950 {
951   unsigned int i;
952   char key[PATH_MAX];
953   int r;
954   struct mail_cache_db * maildb;
955   int res;
956   struct db_session_state_data * data;
957   MMAPString * mmapstr;
958 
959   data = get_data(session);
960 
961   flags_store_process(session);
962 
963   r = mail_cache_db_open_lock(data->db_filename, &maildb);
964   if (r < 0) {
965     res = MAIL_ERROR_FILE;
966     goto err;
967   }
968 
969   mmapstr = mmap_string_new("");
970   if (mmapstr == NULL) {
971     res = MAIL_ERROR_MEMORY;
972     goto close_db;
973   }
974 
975   for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
976     mailmessage * msg;
977 
978     msg = carray_get(env_list->msg_tab, i);
979     if (msg->msg_fields == NULL) {
980       snprintf(key, sizeof(key), "%lu-envelope",
981           (unsigned long) msg->msg_index);
982 
983       r = generic_cache_fields_read(maildb, mmapstr,
984         key, &msg->msg_fields);
985     }
986 
987     if (msg->msg_flags == NULL) {
988       snprintf(key, sizeof(key), "%lu-flags",
989           (unsigned long) msg->msg_index);
990 
991       r = generic_cache_flags_read(maildb, mmapstr,
992           key, &msg->msg_flags);
993     }
994   }
995 
996   mmap_string_free(mmapstr);
997 
998   mail_cache_db_close_unlock(data->db_filename, maildb);
999 
1000   return MAIL_NO_ERROR;
1001 
1002  close_db:
1003   mail_cache_db_close_unlock(data->db_filename, maildb);
1004  err:
1005   return res;
1006 }
1007 
check_folder(mailsession * session)1008 static int check_folder(mailsession * session)
1009 {
1010   flags_store_process(session);
1011 
1012   return MAIL_NO_ERROR;
1013 }
1014 
get_message(mailsession * session,uint32_t num,mailmessage ** result)1015 static int get_message(mailsession * session,
1016     uint32_t num, mailmessage ** result)
1017 {
1018   mailmessage * msg;
1019   int r;
1020   size_t size;
1021   char key[PATH_MAX];
1022   struct db_session_state_data * data;
1023   struct mail_cache_db * maildb;
1024   int res;
1025 
1026   data = get_data(session);
1027 
1028   r = mail_cache_db_open_lock(data->db_filename, &maildb);
1029   if (r < 0) {
1030     res = MAIL_ERROR_FILE;
1031     goto err;
1032   }
1033 
1034   msg = mailmessage_new();
1035   if (msg == NULL) {
1036     res = MAIL_ERROR_MEMORY;
1037     goto close_db;
1038   }
1039 
1040   size = 0;
1041   snprintf(key, sizeof(key), "%lu", (unsigned long) num);
1042   r = mail_cache_db_get_size(maildb, key, (size_t) strlen(key), &size);
1043   /* ignore error */
1044 
1045   r = mailmessage_init(msg, session, db_message_driver,
1046       num, size);
1047   if (r != MAIL_NO_ERROR) {
1048     mailmessage_free(msg);
1049     res = r;
1050     goto close_db;
1051   }
1052 
1053   mail_cache_db_close_unlock(data->db_filename, maildb);
1054 
1055   return MAIL_NO_ERROR;
1056 
1057  close_db:
1058   mail_cache_db_close_unlock(data->db_filename, maildb);
1059  err:
1060   return res;
1061 }
1062 
get_message_by_uid(mailsession * session,const char * uid,mailmessage ** result)1063 static int get_message_by_uid(mailsession * session,
1064     const char * uid, mailmessage ** result)
1065 {
1066   uint32_t msg_num;
1067 
1068   msg_num = (uint32_t) strtoul(uid, NULL, 10);
1069 
1070   return get_message(session, msg_num, result);
1071 }
1072