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: imapdriver_cached.c,v 1.61 2008/02/20 22:35:47 hoa Exp $
34  */
35 
36 #ifdef HAVE_CONFIG_H
37 #	include <config.h>
38 #endif
39 
40 #include "imapdriver_cached.h"
41 
42 #include "libetpan-config.h"
43 
44 #include <stdio.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <fcntl.h>
48 #include <string.h>
49 #ifdef HAVE_UNISTD_H
50 #	include <unistd.h>
51 #endif
52 #include <stdlib.h>
53 
54 #include "mail.h"
55 #include "imapdriver_tools.h"
56 #include "imapdriver_tools_private.h"
57 #include "mail_cache_db.h"
58 #include "mailmessage.h"
59 #include "imapdriver_cached_message.h"
60 #include "maildriver.h"
61 #include "imapdriver_types.h"
62 #include "generic_cache.h"
63 #include "imfcache.h"
64 #include "maildriver_tools.h"
65 #include "imapdriver.h"
66 
67 static int imapdriver_cached_initialize(mailsession * session);
68 static void imapdriver_cached_uninitialize(mailsession * session);
69 
70 static int imapdriver_cached_parameters(mailsession * session,
71 					int id, void * value);
72 
73 static int imapdriver_cached_connect_stream(mailsession * session,
74 					    mailstream * s);
75 
76 static int imapdriver_cached_starttls(mailsession * session);
77 
78 static int imapdriver_cached_login(mailsession * session,
79 				   const char * userid, const char * password);
80 static int imapdriver_cached_logout(mailsession * session);
81 static int imapdriver_cached_noop(mailsession * session);
82 static int imapdriver_cached_build_folder_name(mailsession * session,
83 					       const char * mb,
84 					       const char * name, char ** result);
85 static int imapdriver_cached_create_folder(mailsession * session, const char * mb);
86 static int imapdriver_cached_delete_folder(mailsession * session, const char * mb);
87 static int imapdriver_cached_rename_folder(mailsession * session, const char * mb,
88 					   const char * new_name);
89 static int imapdriver_cached_check_folder(mailsession * session);
90 static int imapdriver_cached_examine_folder(mailsession * session,
91 					    const char * mb);
92 static int imapdriver_cached_select_folder(mailsession * session, const char * mb);
93 static int imapdriver_cached_expunge_folder(mailsession * session);
94 static int imapdriver_cached_status_folder(mailsession * session, const char * mb,
95 					   uint32_t * result_messages,
96 					   uint32_t * result_recent,
97 					   uint32_t * result_unseen);
98 static int imapdriver_cached_messages_number(mailsession * session,
99 					     const char * mb,
100 					     uint32_t * result);
101 static int imapdriver_cached_recent_number(mailsession * session, const char * mb,
102 					   uint32_t * result);
103 static int imapdriver_cached_unseen_number(mailsession * session, const char * mb,
104 					   uint32_t * result);
105 static int imapdriver_cached_list_folders(mailsession * session, const char * mb,
106 					  struct mail_list ** result);
107 static int imapdriver_cached_lsub_folders(mailsession * session, const char * mb,
108 					  struct mail_list ** result);
109 static int imapdriver_cached_subscribe_folder(mailsession * session,
110 					      const char * mb);
111 static int imapdriver_cached_unsubscribe_folder(mailsession * session,
112 						const char * mb);
113 static int imapdriver_cached_append_message(mailsession * session,
114 					    const char * message, size_t size);
115 static int imapdriver_cached_append_message_flags(mailsession * session,
116     const char * message, size_t size, struct mail_flags * flags);
117 static int imapdriver_cached_copy_message(mailsession * session,
118 					  uint32_t num, const char * mb);
119 
120 static int imapdriver_cached_get_messages_list(mailsession * session,
121 						struct mailmessage_list **
122 						result);
123 static int
124 imapdriver_cached_get_envelopes_list(mailsession * session,
125 				     struct mailmessage_list * env_list);
126 static int imapdriver_cached_remove_message(mailsession * session,
127 					    uint32_t num);
128 
129 #if 0
130 static int imapdriver_cached_search_messages(mailsession * session,
131 					      const char * charset,
132 					      struct mail_search_key * key,
133 					      struct mail_search_result **
134 					      result);
135 #endif
136 
137 static int imapdriver_cached_get_message(mailsession * session,
138 					 uint32_t num, mailmessage ** result);
139 
140 static int imapdriver_cached_get_message_by_uid(mailsession * session,
141     const char * uid,
142     mailmessage ** result);
143 
144 static int imapdriver_cached_login_sasl(mailsession * session,
145     const char * auth_type,
146     const char * server_fqdn,
147     const char * local_ip_port,
148     const char * remote_ip_port,
149     const char * login, const char * auth_name,
150     const char * password, const char * realm);
151 
152 static mailsession_driver local_imap_cached_session_driver = {
153   /* sess_name */ "imap-cached",
154 
155   /* sess_initialize */ imapdriver_cached_initialize,
156   /* sess_uninitialize */ imapdriver_cached_uninitialize,
157 
158   /* sess_parameters */ imapdriver_cached_parameters,
159 
160   /* sess_connect_stream */ imapdriver_cached_connect_stream,
161   /* sess_connect_path */ NULL,
162   /* sess_starttls */ imapdriver_cached_starttls,
163   /* sess_login */ imapdriver_cached_login,
164   /* sess_logout */ imapdriver_cached_logout,
165   /* sess_noop */ imapdriver_cached_noop,
166 
167   /* sess_build_folder_name */ imapdriver_cached_build_folder_name,
168   /* sess_create_folder */ imapdriver_cached_create_folder,
169   /* sess_delete_folder */ imapdriver_cached_delete_folder,
170   /* sess_rename_folder */ imapdriver_cached_rename_folder,
171   /* sess_check_folder */ imapdriver_cached_check_folder,
172   /* sess_examine_folder */ imapdriver_cached_examine_folder,
173   /* sess_select_folder */ imapdriver_cached_select_folder,
174   /* sess_expunge_folder */ imapdriver_cached_expunge_folder,
175   /* sess_status_folder */ imapdriver_cached_status_folder,
176   /* sess_messages_number */ imapdriver_cached_messages_number,
177   /* sess_recent_number */ imapdriver_cached_recent_number,
178   /* sess_unseen_number */ imapdriver_cached_unseen_number,
179   /* sess_list_folders */ imapdriver_cached_list_folders,
180   /* sess_lsub_folders */ imapdriver_cached_lsub_folders,
181   /* sess_subscribe_folder */ imapdriver_cached_subscribe_folder,
182   /* sess_unsubscribe_folder */ imapdriver_cached_unsubscribe_folder,
183 
184   /* sess_append_message */ imapdriver_cached_append_message,
185   /* sess_append_message_flags */ imapdriver_cached_append_message_flags,
186   /* sess_copy_message */ imapdriver_cached_copy_message,
187   /* sess_move_message */ NULL,
188 
189   /* sess_get_message */ imapdriver_cached_get_message,
190   /* sess_get_message_by_uid */ imapdriver_cached_get_message_by_uid,
191 
192   /* sess_get_messages_list */ imapdriver_cached_get_messages_list,
193   /* sess_get_envelopes_list */ imapdriver_cached_get_envelopes_list,
194   /* sess_remove_message */ imapdriver_cached_remove_message,
195 #if 0
196   /* sess_search_messages */ imapdriver_cached_search_messages,
197 #endif
198   /* sess_cached_login_sasl */ imapdriver_cached_login_sasl
199 };
200 
201 mailsession_driver * imap_cached_session_driver =
202 &local_imap_cached_session_driver;
203 
204 #define CACHE_MESSAGE_LIST
205 
206 static inline struct imap_cached_session_state_data *
get_cached_data(mailsession * session)207 get_cached_data(mailsession * session)
208 {
209   return session->sess_data;
210 }
211 
get_ancestor(mailsession * s)212 static inline mailsession * get_ancestor(mailsession * s)
213 {
214   return get_cached_data(s)->imap_ancestor;
215 }
216 
217 static inline
get_ancestor_data(mailsession * s)218 struct imap_session_state_data * get_ancestor_data(mailsession * s)
219 {
220   return get_ancestor(s)->sess_data;
221 }
222 
get_imap_session(mailsession * session)223 static inline mailimap * get_imap_session(mailsession * session)
224 {
225   return get_ancestor_data(session)->imap_session;
226 }
227 
imapdriver_cached_initialize(mailsession * session)228 static int imapdriver_cached_initialize(mailsession * session)
229 {
230   struct imap_cached_session_state_data * data;
231 
232   data = malloc(sizeof(* data));
233   if (data == NULL)
234     goto err;
235 
236   data->imap_ancestor = mailsession_new(imap_session_driver);
237   if (data->imap_ancestor == NULL)
238     goto free_data;
239   data->imap_quoted_mb = NULL;
240   data->imap_cache_directory[0] = '\0';
241   data->imap_uid_list = carray_new(128);
242   if (data->imap_uid_list == NULL)
243     goto free_session;
244   data->imap_uidvalidity = 0;
245 
246   session->sess_data = data;
247 
248   return MAIL_NO_ERROR;
249 
250  free_session:
251   mailsession_free(data->imap_ancestor);
252  free_data:
253   free(data);
254  err:
255   return MAIL_ERROR_MEMORY;
256 }
257 
258 static void
free_quoted_mb(struct imap_cached_session_state_data * imap_cached_data)259 free_quoted_mb(struct imap_cached_session_state_data * imap_cached_data)
260 {
261   if (imap_cached_data->imap_quoted_mb != NULL) {
262     free(imap_cached_data->imap_quoted_mb);
263     imap_cached_data->imap_quoted_mb = NULL;
264   }
265 }
266 
267 struct uid_cache_item {
268   uint32_t uid;
269   uint32_t size;
270 };
271 
update_uid_cache(mailsession * session,struct mailmessage_list * env_list)272 static int update_uid_cache(mailsession * session,
273     struct mailmessage_list * env_list)
274 {
275   unsigned int i;
276   int r;
277   struct imap_cached_session_state_data * data;
278   int res;
279   mailimap * imap;
280 
281   data = get_cached_data(session);
282   imap = get_imap_session(session);
283 
284   /* free all UID cache */
285   for(i = 0 ; i < carray_count(data->imap_uid_list) ; i ++) {
286     struct uid_cache_item * cache_item;
287 
288     cache_item = carray_get(data->imap_uid_list, i);
289     free(cache_item);
290   }
291 
292   if (env_list == NULL) {
293     r = carray_set_size(data->imap_uid_list, 0);
294     if (r < 0) {
295       res = MAIL_ERROR_MEMORY;
296       goto err;
297     }
298   }
299   else {
300     /* build UID cache */
301     r = carray_set_size(data->imap_uid_list,
302         carray_count(env_list->msg_tab));
303     if (r < 0) {
304       res = MAIL_ERROR_MEMORY;
305       goto err;
306     }
307 
308     for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
309       struct uid_cache_item * cache_item;
310       mailmessage * msg;
311 
312       cache_item = malloc(sizeof(* cache_item));
313       if (cache_item == NULL) {
314         res = MAIL_ERROR_MEMORY;
315         goto err;
316       }
317       msg = carray_get(env_list->msg_tab, i);
318       cache_item->uid = msg->msg_index;
319       cache_item->size = (uint32_t) msg->msg_size;
320 
321       carray_set(data->imap_uid_list, i, cache_item);
322     }
323   }
324   data->imap_uidvalidity = imap->imap_selection_info->sel_uidvalidity;
325 
326   return MAIL_NO_ERROR;
327 
328  err:
329   return res;
330 }
331 
check_for_uid_cache(mailsession * session)332 static void check_for_uid_cache(mailsession * session)
333 {
334 #if 0
335   mailsession * imap;
336 #endif
337   mailimap * imap;
338 #if 0
339   struct imap_session_state_data * imap_data;
340 #endif
341   clist * list;
342   clistiter * cur;
343   struct imap_cached_session_state_data * data;
344   unsigned int i;
345   unsigned dest;
346 
347   data = get_cached_data(session);
348 #if 0
349   imap = get_ancestor(session);
350 
351   imap_data = imap->data;
352 #endif
353 
354   imap = get_imap_session(session);
355 
356   if (imap->imap_response_info == NULL)
357     return;
358 
359   list = imap->imap_response_info->rsp_expunged;
360   if (list == NULL)
361     return;
362 
363   dest = 0;
364   i = 0;
365   /* remove expunged */
366   for(cur = clist_begin(list) ; cur != NULL ; cur = clist_next(cur)) {
367     uint32_t expunged;
368 
369     expunged = * (uint32_t *) clist_content(cur);
370 
371     while (i < carray_count(data->imap_uid_list)) {
372       struct uid_cache_item * cache_item;
373 
374       if (dest + 1 == expunged) {
375         cache_item = carray_get(data->imap_uid_list, i);
376         free(cache_item);
377         i ++;
378         break;
379       }
380       else {
381         cache_item = carray_get(data->imap_uid_list, i);
382         carray_set(data->imap_uid_list, dest, cache_item);
383         i ++;
384         dest ++;
385       }
386     }
387   }
388   /* complete list */
389   while (i < carray_count(data->imap_uid_list)) {
390     struct uid_cache_item * cache_item;
391 
392     cache_item = carray_get(data->imap_uid_list, i);
393     carray_set(data->imap_uid_list, dest, cache_item);
394     i ++;
395     dest ++;
396   }
397   carray_set_size(data->imap_uid_list, dest);
398 }
399 
imapdriver_cached_uninitialize(mailsession * session)400 static void imapdriver_cached_uninitialize(mailsession * session)
401 {
402   struct imap_cached_session_state_data * data;
403   unsigned int i;
404 
405   data = get_cached_data(session);
406 
407   for(i = 0 ; i < carray_count(data->imap_uid_list) ; i ++) {
408     struct uid_cache_item * cache_item;
409 
410     cache_item = carray_get(data->imap_uid_list, i);
411     free(cache_item);
412   }
413   carray_free(data->imap_uid_list);
414   free_quoted_mb(data);
415   mailsession_free(data->imap_ancestor);
416   free(data);
417 
418   session->sess_data = NULL;
419 }
420 
421 
imapdriver_cached_parameters(mailsession * session,int id,void * value)422 static int imapdriver_cached_parameters(mailsession * session,
423 					int id, void * value)
424 {
425   struct imap_cached_session_state_data * data;
426   int r;
427 
428   data = get_cached_data(session);
429 
430   switch (id) {
431   case IMAPDRIVER_CACHED_SET_CACHE_DIRECTORY:
432     strncpy(data->imap_cache_directory, value, PATH_MAX);
433     data->imap_cache_directory[PATH_MAX - 1] = '\0';
434 
435     r = generic_cache_create_dir(data->imap_cache_directory);
436     if (r != MAIL_NO_ERROR)
437       return r;
438 
439     return MAIL_NO_ERROR;
440 
441   default:
442     return mailsession_parameters(data->imap_ancestor, id, value);
443   }
444 }
445 
446 
imapdriver_cached_connect_stream(mailsession * session,mailstream * s)447 static int imapdriver_cached_connect_stream(mailsession * session,
448 					    mailstream * s)
449 {
450   int r;
451 
452   check_for_uid_cache(session);
453 
454   r = mailsession_connect_stream(get_ancestor(session), s);
455 
456   check_for_uid_cache(session);
457 
458   return r;
459 }
460 
imapdriver_cached_starttls(mailsession * session)461 static int imapdriver_cached_starttls(mailsession * session)
462 {
463   int r;
464 
465   r =  mailsession_starttls(get_ancestor(session));
466 
467   check_for_uid_cache(session);
468 
469   return r;
470 }
471 
imapdriver_cached_login(mailsession * session,const char * userid,const char * password)472 static int imapdriver_cached_login(mailsession * session,
473 				   const char * userid, const char * password)
474 {
475   int r;
476 
477   r = mailsession_login(get_ancestor(session), userid, password);
478 
479   check_for_uid_cache(session);
480 
481   return r;
482 }
483 
imapdriver_cached_logout(mailsession * session)484 static int imapdriver_cached_logout(mailsession * session)
485 {
486   int r;
487 
488   r = mailsession_logout(get_ancestor(session));
489 
490   check_for_uid_cache(session);
491 
492   if (r == MAIL_NO_ERROR) {
493     struct imap_cached_session_state_data * imap_cached_data;
494 
495     imap_cached_data = get_cached_data(session);
496 
497     free_quoted_mb(imap_cached_data);
498   }
499 
500   return r;
501 }
502 
imapdriver_cached_noop(mailsession * session)503 static int imapdriver_cached_noop(mailsession * session)
504 {
505   int r;
506 
507   r = mailsession_noop(get_ancestor(session));
508 
509   check_for_uid_cache(session);
510 
511   return r;
512 }
513 
imapdriver_cached_build_folder_name(mailsession * session,const char * mb,const char * name,char ** result)514 static int imapdriver_cached_build_folder_name(mailsession * session,
515 					       const char * mb,
516 					       const char * name, char ** result)
517 {
518   int r;
519 
520   r = mailsession_build_folder_name(get_ancestor(session), mb,
521       name, result);
522 
523   check_for_uid_cache(session);
524 
525   return r;
526 }
527 
imapdriver_cached_create_folder(mailsession * session,const char * mb)528 static int imapdriver_cached_create_folder(mailsession * session, const char * mb)
529 {
530   int r;
531 
532   r = mailsession_create_folder(get_ancestor(session), mb);
533 
534   check_for_uid_cache(session);
535 
536   return r;
537 }
538 
imapdriver_cached_delete_folder(mailsession * session,const char * mb)539 static int imapdriver_cached_delete_folder(mailsession * session, const char * mb)
540 {
541   int r;
542 
543   r = mailsession_delete_folder(get_ancestor(session), mb);
544 
545   check_for_uid_cache(session);
546 
547   return r;
548 }
549 
imapdriver_cached_rename_folder(mailsession * session,const char * mb,const char * new_name)550 static int imapdriver_cached_rename_folder(mailsession * session, const char * mb,
551 					   const char * new_name)
552 {
553   int r;
554 
555   r = mailsession_rename_folder(get_ancestor(session), mb, new_name);
556 
557   check_for_uid_cache(session);
558 
559   return r;
560 }
561 
imapdriver_cached_check_folder(mailsession * session)562 static int imapdriver_cached_check_folder(mailsession * session)
563 {
564   int r;
565 
566   r = mailsession_check_folder(get_ancestor(session));
567 
568   check_for_uid_cache(session);
569 
570   return r;
571 }
572 
imapdriver_cached_examine_folder(mailsession * session,const char * mb)573 static int imapdriver_cached_examine_folder(mailsession * session,
574 					    const char * mb)
575 {
576   int r;
577 
578   r = mailsession_examine_folder(get_ancestor(session), mb);
579 
580   check_for_uid_cache(session);
581 
582   return r;
583 }
584 
get_cache_folder(mailsession * session,char ** result)585 static int get_cache_folder(mailsession * session, char ** result)
586 {
587 #if 0
588   mailsession * imap_session;
589 #endif
590   mailimap * imap;
591   char * mb;
592   char * cache_dir;
593   char * dirname;
594   char * quoted_mb;
595   int res;
596   int r;
597   char key[PATH_MAX];
598 #if 0
599   struct imap_session_state_data * imap_data;
600   struct imap_cached_session_state_data * cached_data;
601 #endif
602 
603 #if 0
604   imap_session = get_ancestor(session);
605   imap_data = imap_session->data;
606   imap = imap_data->session;
607 #endif
608   imap = get_imap_session(session);
609 
610   mb = get_ancestor_data(session)->imap_mailbox;
611 
612   cache_dir = get_cached_data(session)->imap_cache_directory;
613 
614   if (imap->imap_state != MAILIMAP_STATE_SELECTED)
615     return MAIL_ERROR_BAD_STATE;
616 
617   if (imap->imap_selection_info == NULL)
618     return MAIL_ERROR_BAD_STATE;
619 
620   quoted_mb = maildriver_quote_mailbox(mb);
621   if (quoted_mb == NULL) {
622     res = MAIL_ERROR_MEMORY;
623     goto err;
624   }
625 
626   snprintf(key, PATH_MAX, "%s/%s", cache_dir, quoted_mb);
627 
628   dirname = strdup(key);
629   if (dirname == NULL) {
630     res = MAIL_ERROR_MEMORY;
631     goto free_mb;
632   }
633 
634   r = generic_cache_create_dir(dirname);
635   if (r != MAIL_NO_ERROR) {
636     res = r;
637     goto free_dirname;
638   }
639 
640   free(quoted_mb);
641 
642   * result = dirname;
643 
644   return MAIL_NO_ERROR;
645 
646  free_dirname:
647   free(dirname);
648  free_mb:
649   free(quoted_mb);
650  err:
651   return res;
652 }
653 
imapdriver_cached_select_folder(mailsession * session,const char * mb)654 static int imapdriver_cached_select_folder(mailsession * session, const char * mb)
655 {
656   int r;
657   char * quoted_mb;
658   struct imap_cached_session_state_data * data;
659   char * old_mb;
660 
661   old_mb = get_ancestor_data(session)->imap_mailbox;
662   if (old_mb != NULL)
663     if (strcmp(mb, old_mb) == 0)
664       return MAIL_NO_ERROR;
665 
666   r = mailsession_select_folder(get_ancestor(session), mb);
667   if (r != MAIL_NO_ERROR)
668     return r;
669 
670   check_for_uid_cache(session);
671 
672   quoted_mb = NULL;
673   r = get_cache_folder(session, &quoted_mb);
674   if (r != MAIL_NO_ERROR)
675     return r;
676 
677   data = get_cached_data(session);
678   if (data->imap_quoted_mb != NULL)
679     free(data->imap_quoted_mb);
680   data->imap_quoted_mb = quoted_mb;
681 
682   /* clear UID cache */
683   carray_set_size(data->imap_uid_list, 0);
684 
685   return MAIL_NO_ERROR;
686 }
687 
imapdriver_cached_expunge_folder(mailsession * session)688 static int imapdriver_cached_expunge_folder(mailsession * session)
689 {
690   int r;
691 
692   r = mailsession_expunge_folder(get_ancestor(session));
693 
694   check_for_uid_cache(session);
695 
696   return r;
697 }
698 
imapdriver_cached_status_folder(mailsession * session,const char * mb,uint32_t * result_messages,uint32_t * result_recent,uint32_t * result_unseen)699 static int imapdriver_cached_status_folder(mailsession * session, const char * mb,
700     uint32_t * result_messages, uint32_t * result_recent,
701     uint32_t * result_unseen)
702 {
703   int r;
704 
705   r = mailsession_status_folder(get_ancestor(session), mb, result_messages,
706       result_recent, result_unseen);
707 
708   check_for_uid_cache(session);
709 
710   return r;
711 }
712 
imapdriver_cached_messages_number(mailsession * session,const char * mb,uint32_t * result)713 static int imapdriver_cached_messages_number(mailsession * session,
714 					     const char * mb,
715 					     uint32_t * result)
716 {
717   int r;
718 
719   r = mailsession_messages_number(get_ancestor(session), mb, result);
720 
721   check_for_uid_cache(session);
722 
723   return r;
724 }
725 
imapdriver_cached_recent_number(mailsession * session,const char * mb,uint32_t * result)726 static int imapdriver_cached_recent_number(mailsession * session, const char * mb,
727 					   uint32_t * result)
728 {
729   int r;
730 
731   r = mailsession_recent_number(get_ancestor(session), mb, result);
732 
733   check_for_uid_cache(session);
734 
735   return r;
736 }
737 
imapdriver_cached_unseen_number(mailsession * session,const char * mb,uint32_t * result)738 static int imapdriver_cached_unseen_number(mailsession * session, const char * mb,
739 					   uint32_t * result)
740 {
741   int r;
742 
743   r = mailsession_unseen_number(get_ancestor(session), mb, result);
744 
745   check_for_uid_cache(session);
746 
747   return r;
748 }
749 
imapdriver_cached_list_folders(mailsession * session,const char * mb,struct mail_list ** result)750 static int imapdriver_cached_list_folders(mailsession * session, const char * mb,
751 					  struct mail_list ** result)
752 {
753   int r;
754 
755   r = mailsession_list_folders(get_ancestor(session), mb, result);
756 
757   check_for_uid_cache(session);
758 
759   return r;
760 }
761 
imapdriver_cached_lsub_folders(mailsession * session,const char * mb,struct mail_list ** result)762 static int imapdriver_cached_lsub_folders(mailsession * session, const char * mb,
763 					  struct mail_list ** result)
764 {
765   int r;
766 
767   r = mailsession_lsub_folders(get_ancestor(session), mb, result);
768 
769   check_for_uid_cache(session);
770 
771   return r;
772 }
773 
imapdriver_cached_subscribe_folder(mailsession * session,const char * mb)774 static int imapdriver_cached_subscribe_folder(mailsession * session,
775 					      const char * mb)
776 {
777   int r;
778 
779   r = mailsession_subscribe_folder(get_ancestor(session), mb);
780 
781   check_for_uid_cache(session);
782 
783   return r;
784 }
785 
imapdriver_cached_unsubscribe_folder(mailsession * session,const char * mb)786 static int imapdriver_cached_unsubscribe_folder(mailsession * session,
787 						const char * mb)
788 {
789   int r;
790 
791   r = mailsession_unsubscribe_folder(get_ancestor(session), mb);
792 
793   check_for_uid_cache(session);
794 
795   return r;
796 }
797 
imapdriver_cached_append_message(mailsession * session,const char * message,size_t size)798 static int imapdriver_cached_append_message(mailsession * session,
799 					    const char * message, size_t size)
800 {
801   int r;
802 
803   r = mailsession_append_message(get_ancestor(session), message, size);
804 
805   check_for_uid_cache(session);
806 
807   return r;
808 }
809 
imapdriver_cached_append_message_flags(mailsession * session,const char * message,size_t size,struct mail_flags * flags)810 static int imapdriver_cached_append_message_flags(mailsession * session,
811     const char * message, size_t size, struct mail_flags * flags)
812 {
813   int r;
814 
815   r = mailsession_append_message_flags(get_ancestor(session),
816       message, size, flags);
817 
818   check_for_uid_cache(session);
819 
820   return r;
821 }
822 
imapdriver_cached_copy_message(mailsession * session,uint32_t num,const char * mb)823 static int imapdriver_cached_copy_message(mailsession * session,
824 					  uint32_t num, const char * mb)
825 {
826   int r;
827 
828   r = mailsession_copy_message(get_ancestor(session), num, mb);
829 
830   check_for_uid_cache(session);
831 
832   return r;
833 }
834 
cmp_uid(uint32_t ** pa,uint32_t ** pb)835 static int cmp_uid(uint32_t ** pa, uint32_t ** pb)
836 {
837   uint32_t * a;
838   uint32_t * b;
839 
840   a = * pa;
841   b = * pb;
842 
843   return * a - * b;
844 }
845 
846 
get_uid_from_filename(char * filename)847 static void get_uid_from_filename(char * filename)
848 {
849   char * p;
850 
851   p = strstr(filename, "-part");
852   if (p != NULL)
853     * p = 0;
854   p = strstr(filename, "-envelope");
855   if (p != NULL)
856     * p = 0;
857   p = strstr(filename, "-rfc822");
858   if (p != NULL)
859     * p = 0;
860 }
861 
862 #define ENV_NAME "env.db"
863 
boostrap_cache(mailsession * session)864 static int boostrap_cache(mailsession * session)
865 {
866   struct mail_cache_db * cache_db;
867   char filename[PATH_MAX];
868   struct imap_cached_session_state_data * data;
869   MMAPString * mmapstr;
870   int r;
871   int res;
872   chashiter * iter;
873   chash * keys;
874   chash * keys_uid;
875 
876   data = get_cached_data(session);
877 
878   if (data->imap_quoted_mb == NULL) {
879     res = MAIL_ERROR_BAD_STATE;
880     goto err;
881   }
882 
883   mmapstr = mmap_string_new("");
884   if (mmapstr == NULL) {
885     res = MAIL_ERROR_MEMORY;
886     goto err;
887   }
888 
889   snprintf(filename, PATH_MAX, "%s/%s", data->imap_quoted_mb, ENV_NAME);
890 
891   r = mail_cache_db_open_lock(filename, &cache_db);
892   if (r < 0) {
893     res = MAIL_ERROR_FILE;
894     goto free_mmapstr;
895   }
896 
897   keys = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
898   if (keys == NULL) {
899     res = MAIL_ERROR_MEMORY;
900     goto close_db;
901   }
902 
903   r = mail_cache_db_get_keys(cache_db, keys);
904   if (r < 0) {
905     res = MAIL_ERROR_MEMORY;
906     goto free_keys;
907   }
908 
909   keys_uid = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
910   if (keys_uid == NULL) {
911     res = MAIL_ERROR_MEMORY;
912     goto free_keys;
913   }
914 
915   for(iter = chash_begin(keys) ; iter != NULL ; iter = chash_next(keys, iter)) {
916     chashdatum key;
917     chashdatum value;
918     char msg_uid[PATH_MAX];
919 
920     chash_key(iter, &key);
921     if (key.len >= sizeof(msg_uid)) {
922       strncpy(msg_uid, key.data, sizeof(msg_uid));
923       msg_uid[sizeof(msg_uid) - 1] = 0;
924     }
925     else {
926       strncpy(msg_uid, key.data, key.len);
927       msg_uid[key.len] = 0;
928     }
929 
930     get_uid_from_filename(msg_uid);
931     key.data = msg_uid;
932     key.len = (unsigned int) strlen(msg_uid) + 1;
933     value.data = NULL;
934     value.len = 0;
935     chash_set(keys_uid, &key, &value, NULL);
936   }
937 
938   for(iter = chash_begin(keys_uid) ; iter != NULL ; iter = chash_next(keys_uid, iter)) {
939     chashdatum key;
940     uint32_t uidvalidity;
941     uint32_t indx;
942     char * uid;
943     char * p1, * p2;
944     struct uid_cache_item * cache_item;
945 
946     chash_key(iter, &key);
947     uid = key.data;
948 
949     uidvalidity = (uint32_t) strtoul(uid, &p1, 10);
950     if (p1 == uid || * p1 != '-')
951       continue;
952 
953     data->imap_uidvalidity = uidvalidity;
954 
955     p1++;
956     indx = (uint32_t) strtoul(p1, &p2, 10);
957     if (p2 == p1 || * p2 != '\0')
958       continue;
959 
960     cache_item = malloc(sizeof(* cache_item));
961     if (cache_item == NULL) {
962       res = MAIL_ERROR_MEMORY;
963       goto free_keys_uid;
964     }
965 
966     cache_item->uid = indx;
967     cache_item->size = 0;
968 
969     carray_add(data->imap_uid_list, cache_item, NULL);
970   }
971 
972   chash_free(keys_uid);
973   chash_free(keys);
974 
975   mail_cache_db_close_unlock(filename, cache_db);
976   mmap_string_free(mmapstr);
977 
978   return MAIL_NO_ERROR;
979 
980  free_keys_uid:
981   chash_free(keys_uid);
982  free_keys:
983   chash_free(keys);
984  close_db:
985   mail_cache_db_close_unlock(filename, cache_db);
986  free_mmapstr:
987   mmap_string_free(mmapstr);
988  err:
989   return res;
990 }
991 
992 
imapdriver_cached_get_messages_list(mailsession * session,struct mailmessage_list ** result)993 static int imapdriver_cached_get_messages_list(mailsession * session,
994 					       struct mailmessage_list **
995 					       result)
996 {
997   mailimap * imap;
998   uint32_t uid_max;
999   struct imap_cached_session_state_data * data;
1000   struct mailmessage_list * env_list;
1001   unsigned i;
1002   int r;
1003   int res;
1004   carray * tab;
1005 
1006   data = get_cached_data(session);
1007   imap = get_imap_session(session);
1008 
1009   uid_max = 0;
1010 
1011 #ifdef CACHE_MESSAGE_LIST
1012   if (data->imap_uidvalidity == 0) {
1013     boostrap_cache(session);
1014   }
1015 
1016   if (imap->imap_selection_info->sel_uidvalidity != data->imap_uidvalidity) {
1017     update_uid_cache(session, NULL);
1018   }
1019 
1020   /* get UID max */
1021   uid_max = 0;
1022   for(i = 0 ; i < carray_count(data->imap_uid_list) ; i ++) {
1023     struct uid_cache_item * cache_item;
1024 
1025     cache_item = carray_get(data->imap_uid_list, i);
1026     if (cache_item->uid > uid_max)
1027       uid_max = cache_item->uid;
1028   }
1029 #endif
1030 
1031   r = imap_get_messages_list(imap,  session, imap_cached_message_driver,
1032       uid_max + 1, &env_list);
1033 
1034   check_for_uid_cache(session);
1035 
1036   if (r != MAIL_NO_ERROR) {
1037     res = r;
1038     goto err;
1039   }
1040 
1041 #ifdef CACHE_MESSAGE_LIST
1042   /* remove unsollicited message */
1043   i = 0;
1044   while (i < carray_count(env_list->msg_tab)) {
1045     mailmessage * msg;
1046 
1047     msg = carray_get(env_list->msg_tab, i);
1048     if (msg->msg_index < uid_max + 1) {
1049       mailmessage_free(msg);
1050       carray_delete(env_list->msg_tab, i);
1051     }
1052     else {
1053       i ++;
1054     }
1055   }
1056 
1057   tab = carray_new(carray_count(env_list->msg_tab) +
1058       carray_count(data->imap_uid_list));
1059   if (tab == NULL) {
1060     res = MAIL_ERROR_MEMORY;
1061     goto free;
1062   }
1063   carray_set_size(tab,
1064       carray_count(env_list->msg_tab) + carray_count(data->imap_uid_list));
1065 
1066   /* sort cached data before adding them to the list */
1067   qsort(carray_data(data->imap_uid_list), carray_count(data->imap_uid_list),
1068       sizeof(* carray_data(data->imap_uid_list)),
1069       (int (*)(const void *, const void *)) cmp_uid);
1070 
1071   /* adds cached UID */
1072   for(i = 0 ; i < carray_count(data->imap_uid_list) ; i ++) {
1073     struct uid_cache_item * cache_item;
1074     mailmessage * msg;
1075 
1076     cache_item = carray_get(data->imap_uid_list, i);
1077 
1078     msg = mailmessage_new();
1079     if (msg == NULL) {
1080       res = MAIL_ERROR_MEMORY;
1081       goto free;
1082     }
1083 
1084     r = mailmessage_init(msg, session, imap_cached_message_driver,
1085         cache_item->uid, cache_item->size);
1086     if (r != MAIL_NO_ERROR) {
1087       mailmessage_free(msg);
1088       res = r;
1089       goto free;
1090     }
1091 
1092     carray_set(tab, i, msg);
1093   }
1094 
1095   /* adds new elements */
1096   for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
1097     mailmessage * msg;
1098 
1099     msg = carray_get(env_list->msg_tab, i);
1100     carray_set(tab, carray_count(data->imap_uid_list) + i, msg);
1101   }
1102 
1103   /* replace list of messages in env_list */
1104   carray_free(env_list->msg_tab);
1105   env_list->msg_tab = tab;
1106 
1107   r = update_uid_cache(session, env_list);
1108   if (r != MAIL_NO_ERROR) {
1109     res = r;
1110     goto free;
1111   }
1112 #endif
1113 
1114   * result = env_list;
1115 
1116   return MAIL_NO_ERROR;
1117 
1118  free:
1119   mailmessage_list_free(env_list);
1120  err:
1121   return res;
1122 }
1123 
1124 #define IMAP_SET_MAX_COUNT 100
1125 
get_flags_list(mailsession * session,struct mailmessage_list * env_list)1126 static int get_flags_list(mailsession * session,
1127 			  struct mailmessage_list * env_list)
1128 {
1129   struct mailimap_set * set;
1130   struct mailimap_fetch_att * fetch_att;
1131   struct mailimap_fetch_type * fetch_type;
1132   int res;
1133   clist * fetch_result;
1134   int r;
1135   clist * msg_list;
1136 #if 0
1137   struct imap_session_state_data * data;
1138 #endif
1139   unsigned i;
1140   unsigned dest;
1141   clistiter * set_iter;
1142 
1143 #if 0
1144   data = session->data;
1145 #endif
1146 
1147   fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
1148   if (fetch_type == NULL) {
1149     res = MAIL_ERROR_MEMORY;
1150     goto err;
1151   }
1152 
1153   fetch_att = mailimap_fetch_att_new_uid();
1154   if (fetch_att == NULL) {
1155     res = MAIL_ERROR_MEMORY;
1156     goto free_fetch_type;
1157   }
1158 
1159   r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1160   if (r != MAILIMAP_NO_ERROR) {
1161     mailimap_fetch_att_free(fetch_att);
1162     res = MAIL_ERROR_MEMORY;
1163     goto free_fetch_type;
1164   }
1165 
1166   fetch_att = mailimap_fetch_att_new_flags();
1167   if (fetch_att == NULL) {
1168     res = MAIL_ERROR_MEMORY;
1169     goto free_fetch_type;
1170   }
1171 
1172   r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
1173   if (r != MAILIMAP_NO_ERROR) {
1174     mailimap_fetch_att_free(fetch_att);
1175     res = MAIL_ERROR_MEMORY;
1176     goto free_fetch_type;
1177   }
1178 
1179   r = maildriver_env_list_to_msg_list_no_flags(env_list, &msg_list);
1180   if (r != MAIL_NO_ERROR) {
1181     res = MAIL_ERROR_MEMORY;
1182     goto free_fetch_type;
1183   }
1184 
1185   if (clist_begin(msg_list) == NULL) {
1186     /* no need to fetch envelopes */
1187 
1188     clist_free(msg_list);
1189     mailimap_fetch_type_free(fetch_type);
1190     return MAIL_NO_ERROR;
1191   }
1192 
1193   r = imap_msg_list_to_imap_set(msg_list, &set);
1194   if (r != MAIL_NO_ERROR) {
1195     clist_foreach(msg_list, (clist_func) free, NULL);
1196     clist_free(msg_list);
1197     res = MAIL_ERROR_MEMORY;
1198     goto free_fetch_type;
1199   }
1200   clist_foreach(msg_list, (clist_func) free, NULL);
1201   clist_free(msg_list);
1202 
1203   set_iter = clist_begin(set->set_list);
1204   while (set_iter != NULL) {
1205     struct mailimap_set * subset;
1206     unsigned int count;
1207 
1208     subset = mailimap_set_new_empty();
1209     if (subset == NULL) {
1210       res = MAIL_ERROR_MEMORY;
1211       mailimap_fetch_type_free(fetch_type);
1212       mailimap_set_free(set);
1213       res = MAIL_ERROR_MEMORY;
1214       goto err;
1215     }
1216 
1217     count = 0;
1218     while (count < IMAP_SET_MAX_COUNT) {
1219       struct mailimap_set_item * item;
1220 
1221       item = clist_content(set_iter);
1222       set_iter = clist_delete(set->set_list, set_iter);
1223 
1224       r = mailimap_set_add(subset, item);
1225       if (r != MAILIMAP_NO_ERROR) {
1226         mailimap_set_item_free(item);
1227         mailimap_set_free(subset);
1228         mailimap_fetch_type_free(fetch_type);
1229         mailimap_set_free(set);
1230         res = MAIL_ERROR_MEMORY;
1231         goto err;
1232       }
1233 
1234       count ++;
1235 
1236       if (set_iter == NULL)
1237         break;
1238     }
1239 
1240     r = mailimap_uid_fetch(get_imap_session(session), subset,
1241         fetch_type, &fetch_result);
1242 
1243     mailimap_set_free(subset);
1244 
1245     switch (r) {
1246     case MAILIMAP_NO_ERROR:
1247       break;
1248     default:
1249       mailimap_fetch_type_free(fetch_type);
1250       mailimap_set_free(set);
1251       return imap_error_to_mail_error(r);
1252     }
1253 
1254 #if 0
1255     if (clist_begin(fetch_result) == NULL) {
1256       res = MAIL_ERROR_FETCH;
1257       goto err;
1258     }
1259 #endif
1260 
1261     r = imap_fetch_result_to_envelop_list(fetch_result, env_list);
1262     mailimap_fetch_list_free(fetch_result);
1263 
1264     if (r != MAIL_NO_ERROR) {
1265       mailimap_fetch_type_free(fetch_type);
1266       mailimap_set_free(set);
1267       res = MAIL_ERROR_MEMORY;
1268       goto err;
1269     }
1270   }
1271 
1272 #if 0
1273   r = mailimap_uid_fetch(get_imap_session(session), set,
1274 			 fetch_type, &fetch_result);
1275 #endif
1276 
1277   mailimap_fetch_type_free(fetch_type);
1278   mailimap_set_free(set);
1279 
1280 #if 0
1281   switch (r) {
1282   case MAILIMAP_NO_ERROR:
1283     break;
1284   default:
1285     return imap_error_to_mail_error(r);
1286   }
1287 
1288   r = imap_fetch_result_to_envelop_list(fetch_result, env_list);
1289   mailimap_fetch_list_free(fetch_result);
1290 
1291   if (r != MAIL_NO_ERROR) {
1292     res = MAIL_ERROR_MEMORY;
1293     goto err;
1294   }
1295 #endif
1296 
1297   /* remove messages that don't have flags */
1298   i = 0;
1299   dest = 0;
1300   while (i < carray_count(env_list->msg_tab)) {
1301     mailmessage * msg;
1302 
1303     msg = carray_get(env_list->msg_tab, i);
1304     if (msg->msg_flags != NULL) {
1305       carray_set(env_list->msg_tab, dest, msg);
1306       dest ++;
1307     }
1308     else {
1309       mailmessage_free(msg);
1310     }
1311     i ++;
1312   }
1313   carray_set_size(env_list->msg_tab, dest);
1314 
1315   return MAIL_NO_ERROR;
1316 
1317  free_fetch_type:
1318   mailimap_fetch_type_free(fetch_type);
1319  err:
1320   return res;
1321 }
1322 
1323 
1324 static int
imapdriver_cached_get_envelopes_list(mailsession * session,struct mailmessage_list * env_list)1325 imapdriver_cached_get_envelopes_list(mailsession * session,
1326 				     struct mailmessage_list * env_list)
1327 {
1328   int r;
1329   int res;
1330   uint32_t i;
1331   struct imap_cached_session_state_data * data;
1332   MMAPString * mmapstr;
1333   struct mail_cache_db * cache_db;
1334   char filename[PATH_MAX];
1335 
1336   data = get_cached_data(session);
1337   if (data->imap_quoted_mb == NULL) {
1338     res = MAIL_ERROR_BAD_STATE;
1339     goto err;
1340   }
1341 
1342   mmapstr = mmap_string_new("");
1343   if (mmapstr == NULL) {
1344     res = MAIL_ERROR_MEMORY;
1345     goto err;
1346   }
1347 
1348   snprintf(filename, PATH_MAX, "%s/%s", data->imap_quoted_mb, ENV_NAME);
1349 
1350   r = mail_cache_db_open_lock(filename, &cache_db);
1351   if (r < 0) {
1352     res = MAIL_ERROR_FILE;
1353     goto free_mmapstr;
1354   }
1355 
1356   /* fill with cached */
1357 
1358   for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
1359     mailmessage * msg;
1360     struct mailimf_fields * fields;
1361 
1362     msg = carray_get(env_list->msg_tab, i);
1363 
1364     if (msg->msg_fields == NULL) {
1365       r = imapdriver_get_cached_envelope(cache_db, mmapstr,
1366           session, msg, &fields);
1367       if (r == MAIL_NO_ERROR) {
1368 	msg->msg_cached = TRUE;
1369 	msg->msg_fields = fields;
1370       }
1371     }
1372   }
1373 
1374   mail_cache_db_close_unlock(filename, cache_db);
1375 
1376   r = mailsession_get_envelopes_list(get_ancestor(session), env_list);
1377 
1378   check_for_uid_cache(session);
1379 
1380   if (r != MAIL_NO_ERROR) {
1381     res = r;
1382     goto free_mmapstr;
1383   }
1384 
1385   r = get_flags_list(session, env_list);
1386 
1387   if (r != MAIL_NO_ERROR) {
1388     res = r;
1389     goto free_mmapstr;
1390   }
1391 
1392 #ifdef CACHE_MESSAGE_LIST
1393   r = update_uid_cache(session, env_list);
1394   if (r != MAIL_NO_ERROR) {
1395     res = r;
1396     goto free_mmapstr;
1397   }
1398 #endif
1399 
1400   /* must write cache */
1401 
1402   r = mail_cache_db_open_lock(filename, &cache_db);
1403   if (r < 0) {
1404     res = MAIL_ERROR_FILE;
1405     goto free_mmapstr;
1406   }
1407 
1408   for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
1409     mailmessage * msg;
1410 
1411     msg = carray_get(env_list->msg_tab, i);
1412 
1413     if (msg->msg_fields != NULL) {
1414       if (!msg->msg_cached) {
1415 	r = imapdriver_write_cached_envelope(cache_db, mmapstr,
1416             session, msg, msg->msg_fields);
1417       }
1418     }
1419   }
1420 
1421   /* flush cache */
1422 
1423   maildriver_cache_clean_up(cache_db, NULL, env_list);
1424 
1425   mail_cache_db_close_unlock(filename, cache_db);
1426   mmap_string_free(mmapstr);
1427 
1428   /* remove cache files */
1429 
1430   maildriver_message_cache_clean_up(data->imap_quoted_mb, env_list,
1431       get_uid_from_filename);
1432 
1433   return MAIL_NO_ERROR;
1434 
1435  free_mmapstr:
1436   mmap_string_free(mmapstr);
1437  err:
1438   return res;
1439 }
1440 
imapdriver_cached_remove_message(mailsession * session,uint32_t num)1441 static int imapdriver_cached_remove_message(mailsession * session,
1442 					    uint32_t num)
1443 {
1444   int r;
1445 
1446   r = mailsession_remove_message(get_ancestor(session), num);
1447 
1448   check_for_uid_cache(session);
1449 
1450   return r;
1451 }
1452 
1453 #if 0
1454 static int imapdriver_cached_search_messages(mailsession * session,
1455 					     char * charset,
1456 					     struct mail_search_key * key,
1457 					     struct mail_search_result **
1458 					     result)
1459 {
1460   int r;
1461 
1462   r = mailsession_search_messages(get_ancestor(session), charset, key, result);
1463 
1464   check_for_uid_cache(session);
1465 
1466   return r;
1467 }
1468 #endif
1469 
imapdriver_cached_get_message(mailsession * session,uint32_t num,mailmessage ** result)1470 static int imapdriver_cached_get_message(mailsession * session,
1471 					 uint32_t num, mailmessage ** result)
1472 {
1473   mailmessage * msg_info;
1474   int r;
1475 
1476   msg_info = mailmessage_new();
1477   if (msg_info == NULL)
1478     return MAIL_ERROR_MEMORY;
1479 
1480   r = mailmessage_init(msg_info, session, imap_cached_message_driver, num, 0);
1481   if (r != MAIL_NO_ERROR) {
1482     mailmessage_free(msg_info);
1483     return r;
1484   }
1485 
1486   * result = msg_info;
1487 
1488   return MAIL_NO_ERROR;
1489 }
1490 
1491 /* Retrieve a message by UID
1492  * libEtPan! uid format for IMAP is "UIDVALIDITY-UID"
1493  * where UIDVALIDITY and UID are decimal representation of
1494  * respectively uidvalidity and uid numbers.
1495  * Return value:
1496  * MAIL_ERROR_INVAL if uid is NULL or has an incorrect format.
1497  * MAIL_ERROR_MSG_NOT_FOUND if uidvalidity has changed or uid was not found
1498  * MAIL_NO_ERROR if message was found. Result is in result
1499  */
imapdriver_cached_get_message_by_uid(mailsession * session,const char * uid,mailmessage ** result)1500 static int imapdriver_cached_get_message_by_uid(mailsession * session,
1501     const char * uid,
1502     mailmessage ** result)
1503 {
1504   uint32_t uidvalidity;
1505   uint32_t num;
1506   char * p1, * p2;
1507   mailimap *imap;
1508 
1509   if (uid == NULL)
1510     return MAIL_ERROR_INVAL;
1511 
1512   uidvalidity = (uint32_t) strtoul(uid, &p1, 10);
1513   if (p1 == uid || * p1 != '-')
1514     return MAIL_ERROR_INVAL;
1515 
1516   p1++;
1517   num = (uint32_t) strtoul(p1, &p2, 10);
1518   if (p2 == p1 || * p2 != '\0')
1519     return MAIL_ERROR_INVAL;
1520 
1521   imap = get_imap_session(session);
1522   if (imap->imap_selection_info->sel_uidvalidity != uidvalidity)
1523     return MAIL_ERROR_MSG_NOT_FOUND;
1524 
1525   return imapdriver_cached_get_message(session, num, result);
1526 }
1527 
imapdriver_cached_login_sasl(mailsession * session,const char * auth_type,const char * server_fqdn,const char * local_ip_port,const char * remote_ip_port,const char * login,const char * auth_name,const char * password,const char * realm)1528 static int imapdriver_cached_login_sasl(mailsession * session,
1529     const char * auth_type,
1530     const char * server_fqdn,
1531     const char * local_ip_port,
1532     const char * remote_ip_port,
1533     const char * login, const char * auth_name,
1534     const char * password, const char * realm)
1535 {
1536   return mailsession_login_sasl(get_ancestor(session), auth_type,
1537       server_fqdn,
1538       local_ip_port,
1539       remote_ip_port,
1540       login, auth_name,
1541       password, realm);
1542 }
1543