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: mboxdriver_tools.c,v 1.17 2008/02/20 22:15:50 hoa Exp $
34  */
35 
36 #ifdef HAVE_CONFIG_H
37 #	include <config.h>
38 #endif
39 
40 #include "mboxdriver_tools.h"
41 
42 #include <sys/types.h>
43 #include <sys/stat.h>
44 #include <fcntl.h>
45 #ifdef HAVE_UNISTD_H
46 #	include <unistd.h>
47 #endif
48 
49 #include "maildriver_types.h"
50 #include "mailmbox.h"
51 #include "mboxdriver_cached.h"
52 #include "mboxdriver.h"
53 #include "generic_cache.h"
54 #include "mailmessage.h"
55 #include "imfcache.h"
56 #include "mail_cache_db.h"
57 
58 static inline struct mbox_session_state_data *
session_get_data(mailsession * session)59 session_get_data(mailsession * session)
60 {
61   return session->sess_data;
62 }
63 
64 static inline struct mailmbox_folder *
session_get_mbox_session(mailsession * session)65 session_get_mbox_session(mailsession * session)
66 {
67   return session_get_data(session)->mbox_folder;
68 }
69 
70 static inline struct mbox_cached_session_state_data *
cached_session_get_data(mailsession * session)71 cached_session_get_data(mailsession * session)
72 {
73   return session->sess_data;
74 }
75 
76 static inline mailsession *
cached_session_get_ancestor(mailsession * session)77 cached_session_get_ancestor(mailsession * session)
78 {
79   return cached_session_get_data(session)->mbox_ancestor;
80 }
81 
82 static inline struct mbox_session_state_data *
cached_session_get_ancestor_data(mailsession * session)83 cached_session_get_ancestor_data(mailsession * session)
84 {
85   return cached_session_get_ancestor(session)->sess_data;
86 }
87 
88 static inline struct mailmbox_folder *
cached_session_get_mbox_session(mailsession * session)89 cached_session_get_mbox_session(mailsession * session)
90 {
91   return session_get_mbox_session(cached_session_get_ancestor(session));
92 }
93 
94 
mboxdriver_mbox_error_to_mail_error(int error)95 int mboxdriver_mbox_error_to_mail_error(int error)
96 {
97   switch (error) {
98   case MAILMBOX_NO_ERROR:
99     return MAIL_NO_ERROR;
100 
101   case MAILMBOX_ERROR_PARSE:
102     return MAIL_ERROR_PARSE;
103 
104   case MAILMBOX_ERROR_INVAL:
105     return MAIL_ERROR_INVAL;
106 
107   case MAILMBOX_ERROR_FILE_NOT_FOUND:
108     return MAIL_ERROR_PARSE;
109 
110   case MAILMBOX_ERROR_MEMORY:
111     return MAIL_ERROR_MEMORY;
112 
113   case MAILMBOX_ERROR_TEMPORARY_FILE:
114     return MAIL_ERROR_PARSE;
115 
116   case MAILMBOX_ERROR_FILE:
117     return MAIL_ERROR_FILE;
118 
119   case MAILMBOX_ERROR_MSG_NOT_FOUND:
120     return MAIL_ERROR_MSG_NOT_FOUND;
121 
122   case MAILMBOX_ERROR_READONLY:
123     return MAIL_ERROR_READONLY;
124 
125   default:
126     return MAIL_ERROR_INVAL;
127   }
128 }
129 
mboxdriver_fetch_msg(mailsession * session,uint32_t indx,char ** result,size_t * result_len)130 int mboxdriver_fetch_msg(mailsession * session, uint32_t indx,
131 			 char ** result, size_t * result_len)
132 {
133   int r;
134   char * msg_content;
135   size_t msg_length;
136   struct mailmbox_folder * folder;
137 
138   folder = session_get_mbox_session(session);
139   if (folder == NULL)
140     return MAIL_ERROR_BAD_STATE;
141 
142   r = mailmbox_fetch_msg(folder, indx, &msg_content, &msg_length);
143   if (r != MAILMBOX_NO_ERROR)
144     return mboxdriver_mbox_error_to_mail_error(r);
145 
146   * result = msg_content;
147   * result_len = msg_length;
148 
149   return MAIL_NO_ERROR;
150 }
151 
152 
mboxdriver_fetch_size(mailsession * session,uint32_t indx,size_t * result)153 int mboxdriver_fetch_size(mailsession * session, uint32_t indx,
154 			  size_t * result)
155 {
156   struct mailmbox_folder * folder;
157   int r;
158   char * data;
159   size_t len;
160   int res;
161 
162   folder = session_get_mbox_session(session);
163   if (folder == NULL) {
164     res = MAIL_ERROR_FETCH;
165     goto err;
166   }
167 
168   r = mailmbox_validate_read_lock(folder);
169   if (r != MAILMBOX_NO_ERROR) {
170     res = mboxdriver_mbox_error_to_mail_error(r);
171     goto err;
172   }
173 
174   r = mailmbox_fetch_msg_no_lock(folder, indx, &data, &len);
175   if (r != MAILMBOX_NO_ERROR) {
176     res = mboxdriver_mbox_error_to_mail_error(r);
177     goto unlock;
178   }
179 
180   mailmbox_read_unlock(folder);
181 
182   * result = len;
183 
184   return MAIL_NO_ERROR;
185 
186  unlock:
187   mailmbox_read_unlock(folder);
188  err:
189   return res;
190 }
191 
192 int
mboxdriver_get_cached_flags(struct mail_cache_db * cache_db,MMAPString * mmapstr,mailsession * session,uint32_t num,struct mail_flags ** result)193 mboxdriver_get_cached_flags(struct mail_cache_db * cache_db,
194     MMAPString * mmapstr,
195     mailsession * session,
196     uint32_t num,
197     struct mail_flags ** result)
198 {
199   int r;
200   char keyname[PATH_MAX];
201   struct mail_flags * flags;
202   int res;
203   struct mailmbox_msg_info * info;
204   struct mailmbox_folder * folder;
205   chashdatum key;
206   chashdatum data;
207 
208   folder = cached_session_get_mbox_session(session);
209   if (folder == NULL) {
210     res = MAIL_ERROR_BAD_STATE;
211     goto err;
212   }
213 
214   key.data = &num;
215   key.len = sizeof(num);
216 
217   r = chash_get(folder->mb_hash, &key, &data);
218   if (r < 0) {
219     res = MAIL_ERROR_MSG_NOT_FOUND;
220     goto err;
221   }
222 
223   info = data.data;
224 
225   snprintf(keyname, PATH_MAX, "%u-%lu-flags", num,
226       (unsigned long) info->msg_body_len);
227 
228   r = generic_cache_flags_read(cache_db, mmapstr, keyname, &flags);
229   if (r != MAIL_NO_ERROR) {
230     res = r;
231     goto err;
232   }
233 
234   * result = flags;
235 
236   return MAIL_NO_ERROR;
237 
238  err:
239   return res;
240 }
241 
242 int
mboxdriver_write_cached_flags(struct mail_cache_db * cache_db,MMAPString * mmapstr,char * uid,struct mail_flags * flags)243 mboxdriver_write_cached_flags(struct mail_cache_db * cache_db,
244     MMAPString * mmapstr,
245     char * uid,
246     struct mail_flags * flags)
247 {
248   int r;
249   char keyname[PATH_MAX];
250   int res;
251 
252   snprintf(keyname, PATH_MAX, "%s-flags", uid);
253 
254   r = generic_cache_flags_write(cache_db, mmapstr, keyname, flags);
255   if (r != MAIL_NO_ERROR) {
256     res = r;
257     goto err;
258   }
259 
260   return MAIL_NO_ERROR;
261 
262  err:
263   return res;
264 }
265 
mboxdriver_fetch_header(mailsession * session,uint32_t indx,char ** result,size_t * result_len)266 int mboxdriver_fetch_header(mailsession * session, uint32_t indx,
267 			    char ** result, size_t * result_len)
268 {
269   int r;
270   char * msg_content;
271   size_t msg_length;
272   struct mailmbox_folder * folder;
273 
274   folder = session_get_mbox_session(session);
275   if (folder == NULL)
276     return MAIL_ERROR_BAD_STATE;
277 
278   r = mailmbox_fetch_msg_headers(folder, indx, &msg_content, &msg_length);
279   if (r != MAILMBOX_NO_ERROR)
280     return mboxdriver_mbox_error_to_mail_error(r);
281 
282   * result = msg_content;
283   * result_len = msg_length;
284 
285   return MAIL_NO_ERROR;
286 }
287 
mbox_get_locked_messages_list(struct mailmbox_folder * folder,mailsession * session,mailmessage_driver * driver,int (* lock)(struct mailmbox_folder *),int (* unlock)(struct mailmbox_folder *),struct mailmessage_list ** result)288 int mbox_get_locked_messages_list(struct mailmbox_folder * folder,
289     mailsession * session,
290     mailmessage_driver * driver,
291     int (* lock)(struct mailmbox_folder *),
292     int (* unlock)(struct mailmbox_folder *),
293     struct mailmessage_list ** result)
294 {
295   struct mailmessage_list * env_list;
296   unsigned int i;
297   int r;
298   int res;
299   carray * tab;
300 
301   tab = carray_new(128);
302   if (tab == NULL) {
303     res = MAIL_ERROR_MEMORY;
304     goto err;
305   }
306 
307   r = lock(folder);
308   if (r != MAIL_NO_ERROR) {
309     res = r;
310     goto free;
311   }
312 
313   for(i = 0 ; i < carray_count(folder->mb_tab) ; i ++) {
314     struct mailmbox_msg_info * msg_info;
315     mailmessage * msg;
316 
317     msg_info = carray_get(folder->mb_tab, i);
318     if (msg_info == NULL)
319       continue;
320 
321     if (msg_info->msg_deleted)
322       continue;
323 
324     msg = mailmessage_new();
325     if (msg == NULL) {
326       res = MAIL_ERROR_MEMORY;
327       goto unlock;
328     }
329 
330     r = mailmessage_init(msg, session, driver, msg_info->msg_uid,
331         msg_info->msg_size - msg_info->msg_start_len);
332     if (r != MAIL_NO_ERROR) {
333       res = r;
334       goto unlock;
335     }
336 
337     r = carray_add(tab, msg, NULL);
338     if (r < 0) {
339       mailmessage_free(msg);
340       res = MAIL_ERROR_MEMORY;
341       goto unlock;
342     }
343   }
344 
345   env_list = mailmessage_list_new(tab);
346   if (env_list == NULL) {
347     res = MAIL_ERROR_MEMORY;
348     goto unlock;
349   }
350 
351   unlock(folder);
352 
353   * result = env_list;
354 
355   return MAIL_NO_ERROR;
356 
357  unlock:
358   unlock(folder);
359  free:
360   for(i = 0 ; i < carray_count(tab) ; i ++)
361     mailmessage_free(carray_get(tab, i));
362   carray_free(tab);
363  err:
364   return res;
365 }
366 
release_read_mbox(struct mailmbox_folder * folder)367 static int release_read_mbox(struct mailmbox_folder * folder)
368 {
369   int r;
370 
371   r = mailmbox_read_unlock(folder);
372   return mboxdriver_mbox_error_to_mail_error(r);
373 }
374 
acquire_read_mbox(struct mailmbox_folder * folder)375 static int acquire_read_mbox(struct mailmbox_folder * folder)
376 {
377   int r;
378 
379   r = mailmbox_validate_read_lock(folder);
380   return mboxdriver_mbox_error_to_mail_error(r);
381 }
382 
release_write_mbox(struct mailmbox_folder * folder)383 static int release_write_mbox(struct mailmbox_folder * folder)
384 {
385   int r;
386 
387   r = mailmbox_write_unlock(folder);
388   return mboxdriver_mbox_error_to_mail_error(r);
389 }
390 
acquire_write_mbox(struct mailmbox_folder * folder)391 static int acquire_write_mbox(struct mailmbox_folder * folder)
392 {
393   int r;
394   int res;
395 
396   r = mailmbox_validate_write_lock(folder);
397   if (r != MAILMBOX_NO_ERROR) {
398     res = mboxdriver_mbox_error_to_mail_error(r);
399     goto err;
400   }
401 
402   if (folder->mb_written_uid < folder->mb_max_uid) {
403     r = mailmbox_expunge_no_lock(folder);
404     if (r != MAILMBOX_NO_ERROR) {
405       res = mboxdriver_mbox_error_to_mail_error(r);
406       goto unlock;
407     }
408   }
409 
410   return MAIL_NO_ERROR;
411 
412  unlock:
413   mailmbox_write_unlock(folder);
414  err:
415   return res;
416 }
417 
418 /* get message list with all valid written UID */
419 
mbox_get_uid_messages_list(struct mailmbox_folder * folder,mailsession * session,mailmessage_driver * driver,struct mailmessage_list ** result)420 int mbox_get_uid_messages_list(struct mailmbox_folder * folder,
421     mailsession * session,
422     mailmessage_driver * driver,
423     struct mailmessage_list ** result)
424 {
425   return mbox_get_locked_messages_list(folder, session, driver,
426       acquire_write_mbox, release_write_mbox, result);
427 }
428 
429 
430 /* get message list */
431 
mbox_get_messages_list(struct mailmbox_folder * folder,mailsession * session,mailmessage_driver * driver,struct mailmessage_list ** result)432 int mbox_get_messages_list(struct mailmbox_folder * folder,
433     mailsession * session,
434     mailmessage_driver * driver,
435     struct mailmessage_list ** result)
436 {
437   return mbox_get_locked_messages_list(folder, session, driver,
438       acquire_read_mbox, release_read_mbox, result);
439 }
440