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 = #
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