summaryrefslogtreecommitdiffabout
path: root/libetpan/src/driver/implementation/mbox/mboxdriver.c
Unidiff
Diffstat (limited to 'libetpan/src/driver/implementation/mbox/mboxdriver.c') (more/less context) (ignore whitespace changes)
-rw-r--r--libetpan/src/driver/implementation/mbox/mboxdriver.c515
1 files changed, 515 insertions, 0 deletions
diff --git a/libetpan/src/driver/implementation/mbox/mboxdriver.c b/libetpan/src/driver/implementation/mbox/mboxdriver.c
new file mode 100644
index 0000000..72afa6d
--- a/dev/null
+++ b/libetpan/src/driver/implementation/mbox/mboxdriver.c
@@ -0,0 +1,515 @@
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$
34 */
35
36#include "mboxdriver.h"
37
38#include <stdio.h>
39#include <string.h>
40#include <sys/types.h>
41#include <dirent.h>
42#include <unistd.h>
43#include <sys/stat.h>
44#include <ctype.h>
45#include <stdlib.h>
46#include <sys/times.h>
47
48#include "mail.h"
49#include "maildriver_tools.h"
50#include "mailmbox.h"
51#include "mboxdriver_tools.h"
52#include "maildriver.h"
53#include "carray.h"
54#include "mboxdriver_message.h"
55#include "mailmessage.h"
56
57static int mboxdriver_initialize(mailsession * session);
58
59static void mboxdriver_uninitialize(mailsession * session);
60
61static int mboxdriver_parameters(mailsession * session,
62 int id, void * value);
63
64static int mboxdriver_connect_path(mailsession * session, char * path);
65
66static int mboxdriver_logout(mailsession * session);
67
68static int mboxdriver_expunge_folder(mailsession * session);
69
70static int mboxdriver_status_folder(mailsession * session, char * mb,
71 uint32_t * result_messages, uint32_t * result_recent,
72 uint32_t * result_unseen);
73
74static int mboxdriver_messages_number(mailsession * session, char * mb,
75 uint32_t * result);
76
77static int mboxdriver_append_message(mailsession * session,
78 char * message, size_t size);
79
80static int mboxdriver_append_message_flags(mailsession * session,
81 char * message, size_t size, struct mail_flags * flags);
82
83static int mboxdriver_get_messages_list(mailsession * session,
84 struct mailmessage_list ** result);
85
86static int
87mboxdriver_get_envelopes_list(mailsession * session,
88 struct mailmessage_list * env_list);
89
90static int mboxdriver_remove_message(mailsession * session, uint32_t num);
91
92static int mboxdriver_get_message(mailsession * session,
93 uint32_t num, mailmessage ** result);
94
95static int mboxdriver_get_message_by_uid(mailsession * session,
96 const char * uid,
97 mailmessage ** result);
98
99static mailsession_driver local_mbox_session_driver = {
100 .sess_name = "mbox",
101
102 .sess_initialize = mboxdriver_initialize,
103 .sess_uninitialize = mboxdriver_uninitialize,
104
105 .sess_parameters = mboxdriver_parameters,
106
107 .sess_connect_path = mboxdriver_connect_path,
108 .sess_connect_stream = NULL,
109 .sess_starttls = NULL,
110 .sess_login = NULL,
111 .sess_logout = mboxdriver_logout,
112 .sess_noop = NULL,
113
114 .sess_build_folder_name = NULL,
115 .sess_create_folder = NULL,
116 .sess_delete_folder = NULL,
117 .sess_rename_folder = NULL,
118 .sess_check_folder = NULL,
119 .sess_examine_folder = NULL,
120 .sess_select_folder = NULL,
121 .sess_expunge_folder = mboxdriver_expunge_folder,
122 .sess_status_folder = mboxdriver_status_folder,
123 .sess_messages_number = mboxdriver_messages_number,
124 .sess_recent_number = mboxdriver_messages_number,
125 .sess_unseen_number = mboxdriver_messages_number,
126 .sess_list_folders = NULL,
127 .sess_lsub_folders = NULL,
128 .sess_subscribe_folder = NULL,
129 .sess_unsubscribe_folder = NULL,
130
131 .sess_append_message = mboxdriver_append_message,
132 .sess_append_message_flags = mboxdriver_append_message_flags,
133 .sess_copy_message = NULL,
134 .sess_move_message = NULL,
135
136 .sess_get_messages_list = mboxdriver_get_messages_list,
137 .sess_get_envelopes_list = mboxdriver_get_envelopes_list,
138 .sess_remove_message = mboxdriver_remove_message,
139#if 0
140 .sess_search_messages = maildriver_generic_search_messages,
141#endif
142
143 .sess_get_message = mboxdriver_get_message,
144 .sess_get_message_by_uid = mboxdriver_get_message_by_uid,
145};
146
147mailsession_driver * mbox_session_driver = &local_mbox_session_driver;
148
149static inline struct mbox_session_state_data * get_data(mailsession * session)
150{
151 return session->sess_data;
152}
153
154static inline struct mailmbox_folder * get_mbox_session(mailsession * session)
155{
156 return get_data(session)->mbox_folder;
157}
158
159static int mboxdriver_initialize(mailsession * session)
160{
161 struct mbox_session_state_data * data;
162
163 data = malloc(sizeof(* data));
164 if (data == NULL)
165 goto err;
166
167 data->mbox_folder = NULL;
168
169 data->mbox_force_read_only = FALSE;
170 data->mbox_force_no_uid = TRUE;
171
172 session->sess_data = data;
173
174 return MAIL_NO_ERROR;
175
176 err:
177 return MAIL_ERROR_MEMORY;
178}
179
180static void free_state(struct mbox_session_state_data * mbox_data)
181{
182 if (mbox_data->mbox_folder != NULL) {
183 mailmbox_done(mbox_data->mbox_folder);
184 mbox_data->mbox_folder = NULL;
185 }
186}
187
188static void mboxdriver_uninitialize(mailsession * session)
189{
190 struct mbox_session_state_data * data;
191
192 data = get_data(session);
193
194 free_state(data);
195
196 free(data);
197}
198
199static int mboxdriver_parameters(mailsession * session,
200 int id, void * value)
201{
202 struct mbox_session_state_data * data;
203
204 data = get_data(session);
205
206 switch (id) {
207 case MBOXDRIVER_SET_READ_ONLY:
208 {
209 int * param;
210
211 param = value;
212
213 data->mbox_force_read_only = * param;
214 return MAIL_NO_ERROR;
215 }
216
217 case MBOXDRIVER_SET_NO_UID:
218 {
219 int * param;
220
221 param = value;
222
223 data->mbox_force_no_uid = * param;
224 return MAIL_NO_ERROR;
225 }
226 }
227
228 return MAIL_ERROR_INVAL;
229}
230
231
232static int mboxdriver_connect_path(mailsession * session, char * path)
233{
234 struct mbox_session_state_data * mbox_data;
235 struct mailmbox_folder * folder;
236 int r;
237
238 mbox_data = get_data(session);
239
240 if (mbox_data->mbox_folder != NULL)
241 return MAIL_ERROR_BAD_STATE;
242
243 r = mailmbox_init(path,
244 mbox_data->mbox_force_read_only,
245 mbox_data->mbox_force_no_uid,
246 0,
247 &folder);
248
249 if (r != MAILMBOX_NO_ERROR)
250 return mboxdriver_mbox_error_to_mail_error(r);
251
252 mbox_data->mbox_folder = folder;
253
254 return MAIL_NO_ERROR;
255}
256
257static int mboxdriver_logout(mailsession * session)
258{
259 struct mbox_session_state_data * mbox_data;
260
261 mbox_data = get_data(session);
262
263 if (mbox_data->mbox_folder == NULL)
264 return MAIL_ERROR_BAD_STATE;
265
266 free_state(mbox_data);
267
268 mbox_data->mbox_folder = NULL;
269
270 return MAIL_NO_ERROR;
271}
272
273static int mboxdriver_expunge_folder(mailsession * session)
274{
275 int r;
276 struct mbox_session_state_data * mbox_data;
277
278 mbox_data = get_data(session);
279
280 if (mbox_data->mbox_folder == NULL)
281 return MAIL_ERROR_BAD_STATE;
282
283 r = mailmbox_expunge(mbox_data->mbox_folder);
284 if (r != MAILMBOX_NO_ERROR)
285 return mboxdriver_mbox_error_to_mail_error(r);
286
287 return MAIL_NO_ERROR;
288}
289
290static int mboxdriver_status_folder(mailsession * session, char * mb,
291 uint32_t * result_messages, uint32_t * result_recent,
292 uint32_t * result_unseen)
293{
294 uint32_t count;
295 int r;
296
297 r = mboxdriver_messages_number(session, mb, &count);
298 if (r != MAIL_NO_ERROR)
299 return r;
300
301 * result_messages = count;
302 * result_recent = count;
303 * result_unseen = count;
304
305 return MAIL_NO_ERROR;
306}
307
308static int mboxdriver_messages_number(mailsession * session, char * mb,
309 uint32_t * result)
310{
311 struct mailmbox_folder * folder;
312 int r;
313
314 folder = get_mbox_session(session);
315 if (folder == NULL)
316 return MAIL_ERROR_STATUS;
317
318 r = mailmbox_validate_read_lock(folder);
319 if (r != MAIL_NO_ERROR)
320 return r;
321
322 mailmbox_read_unlock(folder);
323
324 * result = carray_count(folder->mb_tab) - folder->mb_deleted_count;
325
326 return MAILMBOX_NO_ERROR;
327}
328
329/* messages operations */
330
331static int mboxdriver_append_message(mailsession * session,
332 char * message, size_t size)
333{
334 int r;
335 struct mailmbox_folder * folder;
336
337 folder = get_mbox_session(session);
338 if (folder == NULL)
339 return MAIL_ERROR_APPEND;
340
341 r = mailmbox_append_message(folder, message, size);
342
343 switch (r) {
344 case MAILMBOX_ERROR_FILE:
345 return MAIL_ERROR_DISKSPACE;
346 default:
347 return mboxdriver_mbox_error_to_mail_error(r);
348 }
349}
350
351static int mboxdriver_append_message_flags(mailsession * session,
352 char * message, size_t size, struct mail_flags * flags)
353{
354 return mboxdriver_append_message(session, message, size);
355}
356
357static int mboxdriver_get_messages_list(mailsession * session,
358 struct mailmessage_list ** result)
359{
360 struct mailmbox_folder * folder;
361 int res;
362
363 folder = get_mbox_session(session);
364 if (folder == NULL) {
365 res = MAIL_ERROR_BAD_STATE;
366 goto err;
367 }
368
369 return mbox_get_messages_list(folder, session, mbox_message_driver, result);
370
371 err:
372 return res;
373}
374
375static int
376mboxdriver_get_envelopes_list(mailsession * session,
377 struct mailmessage_list * env_list)
378{
379 struct mailmbox_folder * folder;
380 unsigned int i;
381 int r;
382 int res;
383
384 folder = get_mbox_session(session);
385 if (folder == NULL) {
386 res = MAIL_ERROR_BAD_STATE;
387 goto err;
388 }
389
390 r = mailmbox_validate_read_lock(folder);
391 if (r != MAILMBOX_NO_ERROR) {
392 res = mboxdriver_mbox_error_to_mail_error(r);
393 goto err;
394 }
395
396 for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
397 mailmessage * msg;
398 struct mailimf_fields * fields;
399 char * headers;
400 size_t headers_len;
401 size_t cur_token;
402
403 msg = carray_get(env_list->msg_tab, i);
404 if (msg == NULL)
405 continue;
406
407 if (msg->msg_fields != NULL)
408 continue;
409
410 r = mailmbox_fetch_msg_headers_no_lock(folder,
411 msg->msg_index, &headers, &headers_len);
412 if (r != MAILMBOX_NO_ERROR) {
413 res = mboxdriver_mbox_error_to_mail_error(r);
414 goto unlock;
415 }
416
417 cur_token = 0;
418 r = mailimf_envelope_fields_parse(headers, headers_len,
419 &cur_token, &fields);
420
421 if (r != MAILIMF_NO_ERROR)
422 continue;
423
424 msg->msg_fields = fields;
425 }
426
427 mailmbox_read_unlock(folder);
428
429 return MAIL_NO_ERROR;
430
431 unlock:
432 mailmbox_read_unlock(folder);
433 err:
434 return res;
435}
436
437
438static int mboxdriver_remove_message(mailsession * session, uint32_t num)
439{
440 int r;
441 struct mailmbox_folder * folder;
442
443 folder = get_mbox_session(session);
444 if (folder == NULL)
445 return MAIL_ERROR_DELETE;
446
447 r = mailmbox_delete_msg(folder, num);
448
449 return mboxdriver_mbox_error_to_mail_error(r);
450}
451
452static int mboxdriver_get_message(mailsession * session,
453 uint32_t num, mailmessage ** result)
454{
455 mailmessage * msg_info;
456 int r;
457
458 msg_info = mailmessage_new();
459 if (msg_info == NULL)
460 return MAIL_ERROR_MEMORY;
461
462 r = mailmessage_init(msg_info, session, mbox_message_driver, num, 0);
463 if (r != MAIL_NO_ERROR) {
464 mailmessage_free(msg_info);
465 return r;
466 }
467
468 * result = msg_info;
469
470 return MAIL_NO_ERROR;
471}
472
473static int mboxdriver_get_message_by_uid(mailsession * session,
474 const char * uid,
475 mailmessage ** result)
476{
477 uint32_t num;
478 char * p;
479 chashdatum key;
480 chashdatum data;
481 struct mailmbox_msg_info * info;
482 struct mailmbox_folder * folder;
483 int r;
484
485 if (uid == NULL)
486 return MAIL_ERROR_INVAL;
487
488 num = strtoul(uid, &p, 10);
489 if (p == uid || * p != '-')
490 return MAIL_ERROR_INVAL;
491
492 folder = get_mbox_session(session);
493 if (folder == NULL)
494 return MAIL_ERROR_BAD_STATE;
495
496 key.data = &num;
497 key.len = sizeof(num);
498
499 r = chash_get(folder->mb_hash, &key, &data);
500 if (r == 0) {
501 char * body_len_p = p + 1;
502 size_t body_len;
503
504 info = data.data;
505 /* Check if the cached message has the same UID */
506 body_len = strtoul(body_len_p, &p, 10);
507 if (p == body_len_p || * p != '\0')
508 return MAIL_ERROR_INVAL;
509
510 if (body_len == info->msg_body_len)
511 return mboxdriver_get_message(session, num, result);
512 }
513
514 return MAIL_ERROR_MSG_NOT_FOUND;
515}