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