Improve some sieve-related translations
[claws.git] / src / plugins / mailmbox / mailmbox.c
blob66b025ef208f489bd38ce56a48747a1575618309
1 /*
2 * libEtPan! -- a mail stuff library
4 * Copyright (C) 2001, 2002 - DINH Viet Hoa
5 * All rights reserved.
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.
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.
33 * $Id$
36 #ifdef HAVE_CONFIG_H
37 # include "config.h"
38 #include "claws-features.h"
39 #endif
41 #include "mailmbox.h"
43 #include <sys/file.h>
44 #include <sys/stat.h>
45 #include <unistd.h>
46 #include <sys/mman.h>
47 #include <fcntl.h>
48 #include <time.h>
49 #include <sys/types.h>
51 #include <string.h>
52 #include <ctype.h>
53 #include <stdlib.h>
54 #include <stdio.h>
55 #include <limits.h>
57 #include "mmapstring.h"
58 #include "mailmbox_parse.h"
59 #include "maillock.h"
60 #include "file-utils.h"
61 #include "utils.h"
64 http://www.qmail.org/qmail-manual-html/man5/mbox.html
65 RFC 2076
68 /* mbox is a file with a corresponding filename */
70 #define UID_HEADER "X-LibEtPan-UID:"
72 #ifndef TRUE
73 #define TRUE 1
74 #endif
76 #ifndef FALSE
77 #define FALSE 0
78 #endif
80 int claws_mailmbox_write_lock(struct claws_mailmbox_folder * folder)
82 int r;
84 if (folder->mb_read_only)
85 return MAILMBOX_ERROR_READONLY;
87 r = maillock_write_lock(folder->mb_filename, folder->mb_fd);
88 if (r == 0)
89 return MAILMBOX_NO_ERROR;
90 else
91 return MAILMBOX_ERROR_FILE;
94 int claws_mailmbox_write_unlock(struct claws_mailmbox_folder * folder)
96 int r;
98 r = maillock_write_unlock(folder->mb_filename, folder->mb_fd);
99 if (r == 0)
100 return MAILMBOX_NO_ERROR;
101 else
102 return MAILMBOX_ERROR_FILE;
105 int claws_mailmbox_read_lock(struct claws_mailmbox_folder * folder)
107 int r;
109 r = maillock_read_lock(folder->mb_filename, folder->mb_fd);
110 if (r == 0)
111 return MAILMBOX_NO_ERROR;
112 else
113 return MAILMBOX_ERROR_FILE;
116 int claws_mailmbox_read_unlock(struct claws_mailmbox_folder * folder)
118 int r;
120 r = maillock_read_unlock(folder->mb_filename, folder->mb_fd);
121 if (r == 0)
122 return MAILMBOX_NO_ERROR;
123 else
124 return MAILMBOX_ERROR_FILE;
129 map the file into memory.
130 the file must be locked.
133 int claws_mailmbox_map(struct claws_mailmbox_folder * folder)
135 char * str;
136 GStatBuf buf;
137 int res;
138 int r;
140 r = g_stat(folder->mb_filename, &buf);
141 if (r < 0) {
142 debug_print("stat failed %d\n", r);
143 res = MAILMBOX_ERROR_FILE;
144 goto err;
147 if (buf.st_size == 0) {
148 folder->mb_mapping = NULL;
149 folder->mb_mapping_size = 0;
150 return MAILMBOX_NO_ERROR;
152 if (folder->mb_read_only)
153 str = (char *) mmap(NULL, buf.st_size, PROT_READ,
154 MAP_PRIVATE, folder->mb_fd, 0);
155 else
156 str = (char *) mmap(NULL, buf.st_size, PROT_READ | PROT_WRITE,
157 MAP_SHARED, folder->mb_fd, 0);
158 if (str == MAP_FAILED) {
159 perror("mmap");
160 debug_print("map of %lld bytes failed\n", (long long)buf.st_size);
161 res = MAILMBOX_ERROR_FILE;
162 goto err;
165 folder->mb_mapping = str;
166 folder->mb_mapping_size = buf.st_size;
168 return MAILMBOX_NO_ERROR;
170 err:
171 return res;
175 unmap the file
178 void claws_mailmbox_unmap(struct claws_mailmbox_folder * folder)
180 munmap(folder->mb_mapping, folder->mb_mapping_size);
181 folder->mb_mapping = NULL;
182 folder->mb_mapping_size = 0;
185 void claws_mailmbox_sync(struct claws_mailmbox_folder * folder)
187 msync(folder->mb_mapping, folder->mb_mapping_size, MS_SYNC);
190 void claws_mailmbox_timestamp(struct claws_mailmbox_folder * folder)
192 int r;
193 GStatBuf buf;
195 r = g_stat(folder->mb_filename, &buf);
196 if (r < 0)
197 folder->mb_mtime = (time_t) -1;
198 else
199 folder->mb_mtime = buf.st_mtime;
203 open the file
206 int claws_mailmbox_open(struct claws_mailmbox_folder * folder)
208 int fd = -1;
209 int read_only;
211 if (!folder->mb_read_only) {
212 read_only = FALSE;
213 fd = open(folder->mb_filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
216 if (folder->mb_read_only || (fd < 0)) {
217 read_only = TRUE;
218 fd = open(folder->mb_filename, O_RDONLY);
219 if (fd < 0)
220 return MAILMBOX_ERROR_FILE_NOT_FOUND;
223 folder->mb_fd = fd;
224 folder->mb_read_only = read_only;
226 return MAILMBOX_NO_ERROR;
230 close the file
233 void claws_mailmbox_close(struct claws_mailmbox_folder * folder)
235 close(folder->mb_fd);
236 folder->mb_fd = -1;
240 static int claws_mailmbox_validate_lock(struct claws_mailmbox_folder * folder,
241 int (* custom_lock)(struct claws_mailmbox_folder *),
242 int (* custom_unlock)(struct claws_mailmbox_folder *))
244 GStatBuf buf;
245 int res;
246 int r;
248 r = g_stat(folder->mb_filename, &buf);
249 if (r < 0) {
250 buf.st_mtime = (time_t) -1;
253 if ((buf.st_mtime != folder->mb_mtime) ||
254 ((size_t) buf.st_size != folder->mb_mapping_size)) {
255 int r;
257 claws_mailmbox_unmap(folder);
258 claws_mailmbox_close(folder);
260 r = claws_mailmbox_open(folder);
261 if (r != MAILMBOX_NO_ERROR) {
262 res = r;
263 goto err;
266 r = custom_lock(folder);
267 if (r != MAILMBOX_NO_ERROR) {
268 res = r;
269 goto err;
272 r = claws_mailmbox_map(folder);
273 if (r != MAILMBOX_NO_ERROR) {
274 res = r;
275 goto err_unlock;
278 r = claws_mailmbox_parse(folder);
279 if (r != MAILMBOX_NO_ERROR) {
280 res = r;
281 goto err_unlock;
284 folder->mb_mtime = buf.st_mtime;
286 return MAILMBOX_NO_ERROR;
288 else {
289 r = custom_lock(folder);
290 if (r != MAILMBOX_NO_ERROR) {
291 res = r;
292 goto err;
296 return MAILMBOX_NO_ERROR;
298 err_unlock:
299 custom_unlock(folder);
300 err:
301 return res;
305 int claws_mailmbox_validate_write_lock(struct claws_mailmbox_folder * folder)
307 return claws_mailmbox_validate_lock(folder,
308 claws_mailmbox_write_lock,
309 claws_mailmbox_write_unlock);
313 int claws_mailmbox_validate_read_lock(struct claws_mailmbox_folder * folder)
315 return claws_mailmbox_validate_lock(folder,
316 claws_mailmbox_read_lock,
317 claws_mailmbox_read_unlock);
321 /* ********************************************************************** */
322 /* append messages */
324 #define MAX_FROM_LINE_SIZE 256
326 static inline size_t get_line(const char * line, size_t length,
327 const char ** pnext_line, size_t * pcount)
329 size_t count;
331 count = 0;
333 while (1) {
334 if (length == 0)
335 break;
337 if (* line == '\r') {
338 line ++;
340 count ++;
341 length --;
343 if (length > 0) {
344 if (* line == '\n') {
345 line ++;
347 count ++;
348 length --;
350 break;
354 else if (* line == '\n') {
355 line ++;
357 count ++;
358 length --;
360 break;
362 else {
363 line ++;
364 length --;
365 count ++;
369 * pnext_line = line;
370 * pcount = count;
372 return count;
376 TODO : should strip \r\n if any
377 see also in write_fixed_line
380 static inline size_t get_fixed_line_size(const char * line, size_t length,
381 const char ** pnext_line, size_t * pcount,
382 size_t * pfixed_count)
384 size_t count;
385 const char * next_line;
386 size_t fixed_count;
388 if (!get_line(line, length, &next_line, &count))
389 return 0;
391 fixed_count = count;
392 if (count >= 5) {
393 if (line[0] == 'F') {
394 if (strncmp(line, "From ", 5) == 0)
395 fixed_count ++;
399 * pnext_line = next_line;
400 * pcount = count;
401 * pfixed_count = fixed_count;
403 return count;
406 static size_t get_fixed_message_size(const char * message, size_t size,
407 uint32_t uid, int force_no_uid)
409 size_t fixed_size;
410 size_t cur_token;
411 size_t left;
412 const char * next;
413 const char * cur;
414 int end;
415 int r;
416 uint32_t tmp_uid;
418 cur_token = 0;
420 fixed_size = 0;
422 /* headers */
424 end = FALSE;
425 while (!end) {
426 size_t begin;
427 int ignore;
429 ignore = FALSE;
430 begin = cur_token;
431 if (cur_token + strlen(UID_HEADER) <= size) {
432 if (message[cur_token] == 'X') {
433 if (strncasecmp(message + cur_token, UID_HEADER,
434 strlen(UID_HEADER)) == 0) {
435 ignore = TRUE;
440 r = mailimf_ignore_field_parse(message, size, &cur_token);
441 switch (r) {
442 case MAILIMF_NO_ERROR:
443 if (!ignore)
444 fixed_size += cur_token - begin;
445 break;
446 case MAILIMF_ERROR_PARSE:
447 default:
448 end = TRUE;
449 break;
453 if (!force_no_uid) {
454 /* UID header */
456 #if CRLF_BADNESS
457 fixed_size += strlen(UID_HEADER " \r\n");
458 #else
459 fixed_size += strlen(UID_HEADER " \n");
460 #endif
462 tmp_uid = uid;
463 while (tmp_uid >= 10) {
464 tmp_uid /= 10;
465 fixed_size ++;
467 fixed_size ++;
470 /* body */
472 left = size - cur_token;
473 next = message + cur_token;
474 while (left > 0) {
475 size_t count;
476 size_t fixed_count;
478 cur = next;
480 if (!get_fixed_line_size(cur, left, &next, &count, &fixed_count))
481 break;
483 fixed_size += fixed_count;
484 left -= count;
487 return fixed_size;
490 static inline char * write_fixed_line(char * str,
491 const char * line, size_t length,
492 const char ** pnext_line, size_t * pcount)
494 size_t count;
495 const char * next_line;
497 if (!get_line(line, length, &next_line, &count))
498 return str;
500 if (count >= 5) {
501 if (line[0] == 'F') {
502 if (strncmp(line, "From ", 5) == 0) {
503 * str = '>';
504 str ++;
509 memcpy(str, line, count);
511 * pnext_line = next_line;
512 * pcount = count;
513 str += count;
515 return str;
518 static char * write_fixed_message(char * str,
519 const char * message, size_t size,
520 uint32_t uid, int force_no_uid)
522 size_t cur_token;
523 size_t left;
524 int end;
525 int r;
526 const char * cur_src;
527 size_t numlen;
529 cur_token = 0;
531 /* headers */
533 end = FALSE;
534 while (!end) {
535 size_t begin;
536 int ignore;
538 ignore = FALSE;
539 begin = cur_token;
540 if (cur_token + strlen(UID_HEADER) <= size) {
541 if (message[cur_token] == 'X') {
542 if (strncasecmp(message + cur_token, UID_HEADER,
543 strlen(UID_HEADER)) == 0) {
544 ignore = TRUE;
549 r = mailimf_ignore_field_parse(message, size, &cur_token);
550 switch (r) {
551 case MAILIMF_NO_ERROR:
552 if (!ignore) {
553 memcpy(str, message + begin, cur_token - begin);
554 str += cur_token - begin;
556 break;
557 case MAILIMF_ERROR_PARSE:
558 default:
559 end = TRUE;
560 break;
564 if (!force_no_uid) {
565 /* UID header */
567 memcpy(str, UID_HEADER " ", strlen(UID_HEADER " "));
568 str += strlen(UID_HEADER " ");
569 #if CRLF_BADNESS
570 numlen = snprintf(str, 20, "%i\r\n", uid);
571 #else
572 numlen = snprintf(str, 20, "%i\n", uid);
573 #endif
574 str += numlen;
577 /* body */
579 cur_src = message + cur_token;
580 left = size - cur_token;
581 while (left > 0) {
582 size_t count = 0;
583 const char * next = NULL;
585 str = write_fixed_line(str, cur_src, left, &next, &count);
587 cur_src = next;
588 left -= count;
591 return str;
594 #define DEFAULT_FROM_LINE "From - Wed Jun 30 21:49:08 1993\n"
597 claws_mailmbox_append_message_list_no_lock(struct claws_mailmbox_folder * folder,
598 carray * append_tab)
600 size_t extra_size;
601 int r;
602 char from_line[MAX_FROM_LINE_SIZE] = DEFAULT_FROM_LINE;
603 struct tm time_info;
604 time_t date;
605 int res;
606 size_t old_size;
607 char * str;
608 unsigned int i;
609 size_t from_size;
610 size_t left;
611 size_t crlf_count;
613 if (folder->mb_read_only) {
614 res = MAILMBOX_ERROR_READONLY;
615 goto err;
618 date = time(NULL);
619 from_size = strlen(DEFAULT_FROM_LINE);
620 if (localtime_r(&date, &time_info) != NULL)
621 from_size = strftime(from_line, MAX_FROM_LINE_SIZE, "From - %a %b %_2d %T %Y\n", &time_info);
623 extra_size = 0;
624 for(i = 0 ; i < carray_count(append_tab) ; i ++) {
625 struct claws_mailmbox_append_info * info;
627 info = carray_get(append_tab, i);
628 extra_size += from_size;
629 extra_size += get_fixed_message_size(info->ai_message, info->ai_size,
630 folder->mb_max_uid + i + 1,
631 folder->mb_no_uid);
632 #if CRLF_BADNESS
633 extra_size += 2; /* CR LF */
634 #else
635 extra_size += 1; /* CR LF */
636 #endif
639 left = folder->mb_mapping_size;
640 crlf_count = 0;
641 while (left >= 1) {
642 if (folder->mb_mapping[left - 1] == '\n') {
643 crlf_count ++;
644 left --;
646 #if CRLF_BADNESS
647 else if (folder->mb_mapping[left - 1] == '\r') {
648 left --;
650 #endif
651 else
652 break;
654 if (crlf_count == 2)
655 break;
658 old_size = folder->mb_mapping_size;
659 claws_mailmbox_unmap(folder);
661 if (old_size != 0) {
662 if (crlf_count != 2)
663 #if CRLF_BADNESS
664 extra_size += (2 - crlf_count) * 2;
665 #else
666 /* Need the number of LFs, not CRLFs */
667 extra_size += (2 - crlf_count) * 1; /* 2 */
668 #endif
671 r = ftruncate(folder->mb_fd, extra_size + old_size);
672 if (r < 0) {
673 debug_print("ftruncate failed with %d\n", r);
674 claws_mailmbox_map(folder);
675 res = MAILMBOX_ERROR_FILE;
676 goto err;
679 r = claws_mailmbox_map(folder);
680 if (r < 0) {
681 debug_print("claws_mailmbox_map failed with %d\n", r);
682 r = ftruncate(folder->mb_fd, old_size);
683 if (r < 0)
684 debug_print("ftruncate failed with %d\n", r);
685 return MAILMBOX_ERROR_FILE;
688 str = folder->mb_mapping + old_size;
690 if (old_size != 0) {
691 for(i = 0 ; i < 2 - crlf_count ; i ++) {
692 #if CRLF_BADNESS
693 * str = '\r';
694 str ++;
695 #endif
696 * str = '\n';
697 str ++;
701 for(i = 0 ; i < carray_count(append_tab) ; i ++) {
702 struct claws_mailmbox_append_info * info;
704 info = carray_get(append_tab, i);
706 memcpy(str, from_line, from_size);
708 str += strlen(from_line);
710 str = write_fixed_message(str, info->ai_message, info->ai_size,
711 folder->mb_max_uid + i + 1,
712 folder->mb_no_uid);
714 #if CRLF_BADNESS
715 * str = '\r';
716 str ++;
717 #endif
718 * str = '\n';
719 str ++;
722 folder->mb_max_uid += carray_count(append_tab);
724 return MAILMBOX_NO_ERROR;
726 err:
727 return res;
731 claws_mailmbox_append_message_list(struct claws_mailmbox_folder * folder,
732 carray * append_tab)
734 int r;
735 int res;
736 size_t cur_token;
738 r = claws_mailmbox_validate_write_lock(folder);
739 if (r != MAILMBOX_NO_ERROR) {
740 res = r;
741 goto err;
744 r = claws_mailmbox_expunge_no_lock(folder);
745 if (r != MAILMBOX_NO_ERROR) {
746 res = r;
747 goto unlock;
750 cur_token = folder->mb_mapping_size;
752 r = claws_mailmbox_append_message_list_no_lock(folder, append_tab);
753 if (r != MAILMBOX_NO_ERROR) {
754 res = r;
755 goto unlock;
758 claws_mailmbox_sync(folder);
760 r = claws_mailmbox_parse_additionnal(folder, &cur_token);
761 if (r != MAILMBOX_NO_ERROR) {
762 res = r;
763 goto unlock;
766 claws_mailmbox_timestamp(folder);
768 claws_mailmbox_write_unlock(folder);
770 return MAILMBOX_NO_ERROR;
772 unlock:
773 claws_mailmbox_write_unlock(folder);
774 err:
775 return res;
779 claws_mailmbox_append_message(struct claws_mailmbox_folder * folder,
780 const char * data, size_t len)
782 carray * tab;
783 struct claws_mailmbox_append_info * append_info;
784 int res;
785 int r;
787 tab = carray_new(1);
788 if (tab == NULL) {
789 res = MAILMBOX_ERROR_MEMORY;
790 goto err;
793 append_info = claws_mailmbox_append_info_new(data, len);
794 if (append_info == NULL) {
795 res = MAILMBOX_ERROR_MEMORY;
796 goto free_list;
799 r = carray_add(tab, append_info, NULL);
800 if (r < 0) {
801 res = MAILMBOX_ERROR_MEMORY;
802 goto free_append_info;
805 r = claws_mailmbox_append_message_list(folder, tab);
807 claws_mailmbox_append_info_free(append_info);
808 carray_free(tab);
810 return r;
812 free_append_info:
813 claws_mailmbox_append_info_free(append_info);
814 free_list:
815 carray_free(tab);
816 err:
817 return res;
820 /* ********************************************************************** */
822 int claws_mailmbox_fetch_msg_no_lock(struct claws_mailmbox_folder * folder,
823 uint32_t num, const char ** result,
824 size_t * result_len)
826 struct claws_mailmbox_msg_info * info;
827 int res;
828 chashdatum key;
829 chashdatum data;
830 int r;
832 key.data = &num;
833 key.len = sizeof(num);
835 r = chash_get(folder->mb_hash, &key, &data);
836 if (r < 0) {
837 res = MAILMBOX_ERROR_MSG_NOT_FOUND;
838 goto err;
841 info = data.data;
843 if (info->msg_deleted) {
844 res = MAILMBOX_ERROR_MSG_NOT_FOUND;
845 goto err;
848 * result = folder->mb_mapping + info->msg_headers;
849 * result_len = info->msg_size - info->msg_start_len;
851 return MAILMBOX_NO_ERROR;
853 err:
854 return res;
857 int claws_mailmbox_fetch_msg_headers_no_lock(struct claws_mailmbox_folder * folder,
858 uint32_t num, const char ** result,
859 size_t * result_len)
861 struct claws_mailmbox_msg_info * info;
862 int res;
863 chashdatum key;
864 chashdatum data;
865 int r;
867 key.data = &num;
868 key.len = sizeof(num);
870 r = chash_get(folder->mb_hash, &key, &data);
871 if (r < 0) {
872 res = MAILMBOX_ERROR_MSG_NOT_FOUND;
873 goto err;
876 info = data.data;
878 if (info->msg_deleted) {
879 res = MAILMBOX_ERROR_MSG_NOT_FOUND;
880 goto err;
883 * result = folder->mb_mapping + info->msg_headers;
884 * result_len = info->msg_headers_len;
886 return MAILMBOX_NO_ERROR;
888 err:
889 return res;
892 int claws_mailmbox_fetch_msg(struct claws_mailmbox_folder * folder,
893 uint32_t num, const char ** result,
894 size_t * result_len)
896 MMAPString * mmapstr;
897 int res;
898 const char * data;
899 size_t len;
900 int r;
901 size_t fixed_size;
902 char * end;
904 r = claws_mailmbox_validate_read_lock(folder);
905 if (r != MAILMBOX_NO_ERROR) {
906 res = r;
907 goto err;
910 r = claws_mailmbox_fetch_msg_no_lock(folder, num, &data, &len);
911 if (r != MAILMBOX_NO_ERROR) {
912 res = r;
913 goto unlock;
916 /* size with no uid */
917 fixed_size = get_fixed_message_size(data, len, 0, 1 /* force no uid */);
919 #if 0
920 mmapstr = mmap_string_new_len(data, fixed_size);
921 if (mmapstr == NULL) {
922 res = MAILMBOX_ERROR_MEMORY;
923 goto unlock;
925 #endif
926 mmapstr = mmap_string_sized_new(fixed_size);
927 if (mmapstr == NULL) {
928 res = MAILMBOX_ERROR_MEMORY;
929 goto unlock;
932 end = write_fixed_message(mmapstr->str, data, len, 0, 1 /* force no uid */);
933 * end = '\0';
934 mmapstr->len = fixed_size;
936 r = mmap_string_ref(mmapstr);
937 if (r < 0) {
938 mmap_string_free(mmapstr);
939 res = MAILMBOX_ERROR_MEMORY;
940 goto unlock;
943 * result = mmapstr->str;
944 * result_len = mmapstr->len;
946 claws_mailmbox_read_unlock(folder);
948 return MAILMBOX_NO_ERROR;
950 unlock:
951 claws_mailmbox_read_unlock(folder);
952 err:
953 return res;
956 int claws_mailmbox_fetch_msg_headers(struct claws_mailmbox_folder * folder,
957 uint32_t num, const char ** result,
958 size_t * result_len)
960 MMAPString * mmapstr;
961 int res;
962 const char * data;
963 size_t len;
964 int r;
965 size_t fixed_size;
966 char * end;
968 r = claws_mailmbox_validate_read_lock(folder);
969 if (r != MAILMBOX_NO_ERROR) {
970 res = r;
971 goto err;
974 r = claws_mailmbox_fetch_msg_headers_no_lock(folder, num, &data, &len);
975 if (r != MAILMBOX_NO_ERROR) {
976 res = r;
977 goto unlock;
980 #if 0
981 mmapstr = mmap_string_new_len(data, len);
982 if (mmapstr == NULL) {
983 res = MAILMBOX_ERROR_MEMORY;
984 goto unlock;
986 #endif
987 /* size with no uid */
988 fixed_size = get_fixed_message_size(data, len, 0, 1 /* force no uid */);
990 mmapstr = mmap_string_sized_new(fixed_size);
991 if (mmapstr == NULL) {
992 res = MAILMBOX_ERROR_MEMORY;
993 goto unlock;
996 end = write_fixed_message(mmapstr->str, data, len, 0, 1 /* force no uid */);
997 * end = '\0';
998 mmapstr->len = fixed_size;
1000 r = mmap_string_ref(mmapstr);
1001 if (r < 0) {
1002 mmap_string_free(mmapstr);
1003 res = MAILMBOX_ERROR_MEMORY;
1004 goto unlock;
1007 * result = mmapstr->str;
1008 * result_len = mmapstr->len;
1010 claws_mailmbox_read_unlock(folder);
1012 return MAILMBOX_NO_ERROR;
1014 unlock:
1015 claws_mailmbox_read_unlock(folder);
1016 err:
1017 return res;
1020 void claws_mailmbox_fetch_result_free(char * msg)
1022 mmap_string_unref(msg);
1026 int claws_mailmbox_copy_msg_list(struct claws_mailmbox_folder * dest_folder,
1027 struct claws_mailmbox_folder * src_folder,
1028 carray * tab)
1030 int r;
1031 int res;
1032 carray * append_tab;
1033 unsigned int i;
1035 r = claws_mailmbox_validate_read_lock(src_folder);
1036 if (r != MAILMBOX_NO_ERROR) {
1037 res = r;
1038 goto err;
1041 append_tab = carray_new(carray_count(tab));
1042 if (append_tab == NULL) {
1043 res = MAILMBOX_ERROR_MEMORY;
1044 goto src_unlock;
1047 for(i = 0 ; i < carray_count(tab) ; i ++) {
1048 struct claws_mailmbox_append_info * append_info;
1049 const char * data;
1050 size_t len;
1051 uint32_t uid;
1053 uid = * ((uint32_t *) carray_get(tab, i));
1055 r = claws_mailmbox_fetch_msg_no_lock(src_folder, uid, &data, &len);
1056 if (r != MAILMBOX_NO_ERROR) {
1057 res = r;
1058 goto free_list;
1061 append_info = claws_mailmbox_append_info_new(data, len);
1062 if (append_info == NULL) {
1063 res = MAILMBOX_ERROR_MEMORY;
1064 goto free_list;
1067 r = carray_add(append_tab, append_info, NULL);
1068 if (r < 0) {
1069 claws_mailmbox_append_info_free(append_info);
1070 res = MAILMBOX_ERROR_MEMORY;
1071 goto free_list;
1075 r = claws_mailmbox_append_message_list(dest_folder, append_tab);
1076 if (r != MAILMBOX_NO_ERROR) {
1077 res = r;
1078 goto free_list;
1081 for(i = 0 ; i < carray_count(append_tab) ; i ++) {
1082 struct claws_mailmbox_append_info * append_info;
1084 append_info = carray_get(append_tab, i);
1085 claws_mailmbox_append_info_free(append_info);
1087 carray_free(append_tab);
1089 claws_mailmbox_read_unlock(src_folder);
1091 return MAILMBOX_NO_ERROR;
1093 free_list:
1094 for(i = 0 ; i < carray_count(append_tab) ; i ++) {
1095 struct claws_mailmbox_append_info * append_info;
1097 append_info = carray_get(append_tab, i);
1098 claws_mailmbox_append_info_free(append_info);
1100 carray_free(append_tab);
1101 src_unlock:
1102 claws_mailmbox_read_unlock(src_folder);
1103 err:
1104 return res;
1107 int claws_mailmbox_copy_msg(struct claws_mailmbox_folder * dest_folder,
1108 struct claws_mailmbox_folder * src_folder,
1109 uint32_t uid)
1111 carray * tab;
1112 int res;
1113 uint32_t * puid;
1114 int r;
1116 tab = carray_new(1);
1117 if (tab == NULL) {
1118 res = MAILMBOX_ERROR_MEMORY;
1119 goto err;
1122 puid = malloc(sizeof(* puid));
1123 if (puid == NULL) {
1124 res = MAILMBOX_ERROR_MEMORY;
1125 goto free_array;
1127 * puid = uid;
1129 r = claws_mailmbox_copy_msg_list(dest_folder, src_folder, tab);
1130 res = r;
1132 free(puid);
1133 free_array:
1134 carray_free(tab);
1135 err:
1136 return res;
1139 static int claws_mailmbox_expunge_to_file_no_lock(char * dest_filename, int dest_fd,
1140 struct claws_mailmbox_folder * folder,
1141 size_t * result_size)
1143 int r;
1144 int res;
1145 unsigned long i;
1146 size_t cur_offset;
1147 char * dest = NULL;
1148 size_t size;
1150 size = 0;
1151 for(i = 0 ; i < carray_count(folder->mb_tab) ; i ++) {
1152 struct claws_mailmbox_msg_info * info;
1154 info = carray_get(folder->mb_tab, i);
1156 if (!info->msg_deleted) {
1157 size += info->msg_size + info->msg_padding;
1159 if (!folder->mb_no_uid) {
1160 if (!info->msg_written_uid) {
1161 uint32_t uid;
1163 #if CRLF_BADNESS
1164 size += strlen(UID_HEADER " \r\n");
1165 #else
1166 size += strlen(UID_HEADER " \n");
1167 #endif
1168 uid = info->msg_uid;
1169 while (uid >= 10) {
1170 uid /= 10;
1171 size ++;
1173 size ++;
1179 r = ftruncate(dest_fd, size);
1180 if (r < 0) {
1181 res = MAILMBOX_ERROR_FILE;
1182 goto err;
1185 if (size) {
1186 dest = (char *) mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, dest_fd, 0);
1187 if (dest == MAP_FAILED) {
1188 res = MAILMBOX_ERROR_FILE;
1189 goto err;
1193 cur_offset = 0;
1194 for(i = 0 ; i < carray_count(folder->mb_tab) ; i ++) {
1195 struct claws_mailmbox_msg_info * info;
1197 info = carray_get(folder->mb_tab, i);
1199 if (!info->msg_deleted) {
1200 memcpy(dest + cur_offset, folder->mb_mapping + info->msg_start,
1201 info->msg_headers_len + info->msg_start_len);
1202 cur_offset += info->msg_headers_len + info->msg_start_len;
1204 if (!folder->mb_no_uid) {
1205 if (!info->msg_written_uid) {
1206 size_t numlen;
1208 memcpy(dest + cur_offset, UID_HEADER " ", strlen(UID_HEADER " "));
1209 cur_offset += strlen(UID_HEADER " ");
1210 #if CRLF_BADNESS
1211 numlen = snprintf(dest + cur_offset, size - cur_offset,
1212 "%i\r\n", info->msg_uid);
1213 #else
1214 numlen = snprintf(dest + cur_offset, size - cur_offset,
1215 "%i\n", info->msg_uid);
1216 #endif
1217 cur_offset += numlen;
1221 memcpy(dest + cur_offset,
1222 folder->mb_mapping + info->msg_headers + info->msg_headers_len,
1223 info->msg_size - (info->msg_start_len + info->msg_headers_len)
1224 + info->msg_padding);
1226 cur_offset += info->msg_size -
1227 (info->msg_start_len + info->msg_headers_len)
1228 + info->msg_padding;
1231 fflush(stdout);
1233 if (size) {
1234 msync(dest, size, MS_SYNC);
1235 munmap(dest, size);
1238 * result_size = size;
1240 return MAILMBOX_NO_ERROR;
1242 err:
1243 return res;
1246 int claws_mailmbox_expunge_no_lock(struct claws_mailmbox_folder * folder)
1248 char tmpfile[PATH_MAX + 8]; /* for the extra Xs */
1249 int r;
1250 int res;
1251 int dest_fd;
1252 size_t size;
1254 if (folder->mb_read_only)
1255 return MAILMBOX_ERROR_READONLY;
1257 if (((folder->mb_written_uid >= folder->mb_max_uid) || folder->mb_no_uid) &&
1258 (!folder->mb_changed)) {
1259 /* no need to expunge */
1260 return MAILMBOX_NO_ERROR;
1263 snprintf(tmpfile, sizeof(tmpfile), "%sXXXXXX", folder->mb_filename);
1264 dest_fd = g_mkstemp(tmpfile);
1266 if (dest_fd < 0) {
1267 res = MAILMBOX_ERROR_FILE;
1268 goto unlink;
1271 r = claws_mailmbox_expunge_to_file_no_lock(tmpfile, dest_fd,
1272 folder, &size);
1273 if (r != MAILMBOX_NO_ERROR) {
1274 res = r;
1275 goto unlink;
1278 close(dest_fd);
1280 r = rename(tmpfile, folder->mb_filename);
1281 if (r < 0) {
1282 res = r;
1283 goto err;
1286 claws_mailmbox_unmap(folder);
1287 claws_mailmbox_close(folder);
1289 r = claws_mailmbox_open(folder);
1290 if (r != MAILMBOX_NO_ERROR) {
1291 res = r;
1292 goto err;
1295 r = claws_mailmbox_map(folder);
1296 if (r != MAILMBOX_NO_ERROR) {
1297 res = r;
1298 goto err;
1301 r = claws_mailmbox_parse(folder);
1302 if (r != MAILMBOX_NO_ERROR) {
1303 res = r;
1304 goto err;
1307 claws_mailmbox_timestamp(folder);
1309 folder->mb_changed = FALSE;
1310 folder->mb_deleted_count = 0;
1312 return MAILMBOX_NO_ERROR;
1314 unlink:
1315 close(dest_fd);
1316 unlink(tmpfile);
1317 err:
1318 return res;
1321 int claws_mailmbox_expunge(struct claws_mailmbox_folder * folder)
1323 int r;
1324 int res;
1326 r = claws_mailmbox_validate_write_lock(folder);
1327 if (r != MAILMBOX_NO_ERROR) {
1328 res = r;
1329 goto err;
1332 r = claws_mailmbox_expunge_no_lock(folder);
1333 res = r;
1335 claws_mailmbox_write_unlock(folder);
1336 err:
1337 return res;
1340 int claws_mailmbox_delete_msg(struct claws_mailmbox_folder * folder, uint32_t uid)
1342 struct claws_mailmbox_msg_info * info;
1343 int res;
1344 chashdatum key;
1345 chashdatum data;
1346 int r;
1348 if (folder->mb_read_only) {
1349 res = MAILMBOX_ERROR_READONLY;
1350 goto err;
1353 key.data = &uid;
1354 key.len = sizeof(uid);
1356 r = chash_get(folder->mb_hash, &key, &data);
1357 if (r < 0) {
1358 res = MAILMBOX_ERROR_MSG_NOT_FOUND;
1359 goto err;
1362 info = data.data;
1364 if (info->msg_deleted) {
1365 res = MAILMBOX_ERROR_MSG_NOT_FOUND;
1366 goto err;
1369 info->msg_deleted = TRUE;
1370 folder->mb_changed = TRUE;
1371 folder->mb_deleted_count ++;
1373 return MAILMBOX_NO_ERROR;
1375 err:
1376 return res;
1381 INIT of MBOX
1383 - open file
1384 - map the file
1386 - lock the file
1388 - parse memory
1390 - unlock the file
1393 int claws_mailmbox_init(const char * filename,
1394 int force_readonly,
1395 int force_no_uid,
1396 uint32_t default_written_uid,
1397 struct claws_mailmbox_folder ** result_folder)
1399 struct claws_mailmbox_folder * folder;
1400 int r;
1401 int res;
1403 folder = claws_mailmbox_folder_new(filename);
1404 if (folder == NULL) {
1405 debug_print("folder is null for %s\n", filename);
1406 res = MAILMBOX_ERROR_MEMORY;
1407 goto err;
1409 folder->mb_no_uid = force_no_uid;
1410 folder->mb_read_only = force_readonly;
1411 folder->mb_written_uid = default_written_uid;
1413 folder->mb_changed = FALSE;
1414 folder->mb_deleted_count = 0;
1416 r = claws_mailmbox_open(folder);
1417 if (r != MAILMBOX_NO_ERROR) {
1418 debug_print("folder can't be opened %d\n", r);
1419 res = r;
1420 goto free;
1423 r = claws_mailmbox_map(folder);
1424 if (r != MAILMBOX_NO_ERROR) {
1425 debug_print("folder can't be mapped %d\n", r);
1426 res = r;
1427 goto close;
1430 r = claws_mailmbox_validate_read_lock(folder);
1431 if (r != MAILMBOX_NO_ERROR) {
1432 debug_print("folder can't be locked %d\n", r);
1433 res = r;
1434 goto unmap;
1437 claws_mailmbox_read_unlock(folder);
1439 * result_folder = folder;
1441 return MAILMBOX_NO_ERROR;
1443 unmap:
1444 claws_mailmbox_unmap(folder);
1445 close:
1446 claws_mailmbox_close(folder);
1447 free:
1448 claws_mailmbox_folder_free(folder);
1449 err:
1450 return res;
1455 when MBOX is DONE
1457 - check for changes
1459 - unmap the file
1460 - close file
1463 void claws_mailmbox_done(struct claws_mailmbox_folder * folder)
1465 if (!folder->mb_read_only)
1466 claws_mailmbox_expunge(folder);
1468 claws_mailmbox_unmap(folder);
1469 claws_mailmbox_close(folder);
1471 claws_mailmbox_folder_free(folder);