-rw-r--r-- | libetpan/src/low-level/mbox/TODO | 0 | ||||
-rw-r--r-- | libetpan/src/low-level/mbox/mailmbox.c | 1525 | ||||
-rw-r--r-- | libetpan/src/low-level/mbox/mailmbox.h | 144 | ||||
-rw-r--r-- | libetpan/src/low-level/mbox/mailmbox_parse.c | 620 | ||||
-rw-r--r-- | libetpan/src/low-level/mbox/mailmbox_parse.h | 56 | ||||
-rw-r--r-- | libetpan/src/low-level/mbox/mailmbox_types.c | 251 | ||||
-rw-r--r-- | libetpan/src/low-level/mbox/mailmbox_types.h | 143 |
7 files changed, 2739 insertions, 0 deletions
diff --git a/libetpan/src/low-level/mbox/TODO b/libetpan/src/low-level/mbox/TODO new file mode 100644 index 0000000..e69de29 --- a/dev/null +++ b/libetpan/src/low-level/mbox/TODO diff --git a/libetpan/src/low-level/mbox/mailmbox.c b/libetpan/src/low-level/mbox/mailmbox.c new file mode 100644 index 0000000..9937f3a --- a/dev/null +++ b/libetpan/src/low-level/mbox/mailmbox.c @@ -0,0 +1,1525 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "mailmbox.h" + +#include <sys/file.h> +#include <sys/stat.h> +#include <unistd.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <time.h> +#include <sys/types.h> +#include <unistd.h> + +#include <string.h> +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> + +#include "libetpan-config.h" + +#include "mmapstring.h" +#include "mailmbox_parse.h" +#include "maillock.h" + +/* + http://www.qmail.org/qmail-manual-html/man5/mbox.html + RFC 2076 +*/ + +#define TMPDIR "/tmp" + +/* mbox is a file with a corresponding filename */ + +#define UID_HEADER "X-LibEtPan-UID:" + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +int mailmbox_write_lock(struct mailmbox_folder * folder) +{ + int r; + + if (folder->mb_read_only) + return MAILMBOX_ERROR_READONLY; + + r = maillock_write_lock(folder->mb_filename, folder->mb_fd); + if (r == 0) + return MAILMBOX_NO_ERROR; + else + return MAILMBOX_ERROR_FILE; +} + +int mailmbox_write_unlock(struct mailmbox_folder * folder) +{ + int r; + + r = maillock_write_unlock(folder->mb_filename, folder->mb_fd); + if (r == 0) + return MAILMBOX_NO_ERROR; + else + return MAILMBOX_ERROR_FILE; +} + +int mailmbox_read_lock(struct mailmbox_folder * folder) +{ + int r; + + r = maillock_read_lock(folder->mb_filename, folder->mb_fd); + if (r == 0) + return MAILMBOX_NO_ERROR; + else + return MAILMBOX_ERROR_FILE; +} + +int mailmbox_read_unlock(struct mailmbox_folder * folder) +{ + int r; + + r = maillock_read_unlock(folder->mb_filename, folder->mb_fd); + if (r == 0) + return MAILMBOX_NO_ERROR; + else + return MAILMBOX_ERROR_FILE; +} + + +/* + map the file into memory. + the file must be locked. +*/ + +int mailmbox_map(struct mailmbox_folder * folder) +{ + char * str; + struct stat buf; + int res; + int r; + + r = stat(folder->mb_filename, &buf); + if (r < 0) { + res = MAILMBOX_ERROR_FILE; + goto err; + } + + if (folder->mb_read_only) + str = (char *) mmap(0, buf.st_size, PROT_READ, + MAP_PRIVATE, folder->mb_fd, 0); + else + str = (char *) mmap(0, buf.st_size, PROT_READ | PROT_WRITE, + MAP_SHARED, folder->mb_fd, 0); + if (str == MAP_FAILED) { + res = MAILMBOX_ERROR_FILE; + goto err; + } + + folder->mb_mapping = str; + folder->mb_mapping_size = buf.st_size; + + return MAILMBOX_NO_ERROR; + + err: + return res; +} + +/* + unmap the file +*/ + +void mailmbox_unmap(struct mailmbox_folder * folder) +{ + munmap(folder->mb_mapping, folder->mb_mapping_size); + folder->mb_mapping = NULL; + folder->mb_mapping_size = 0; +} + +void mailmbox_sync(struct mailmbox_folder * folder) +{ + msync(folder->mb_mapping, folder->mb_mapping_size, MS_SYNC); +} + +void mailmbox_timestamp(struct mailmbox_folder * folder) +{ + int r; + struct stat buf; + + r = stat(folder->mb_filename, &buf); + if (r < 0) + folder->mb_mtime = (time_t) -1; + else + folder->mb_mtime = buf.st_mtime; +} + +/* + open the file +*/ + +int mailmbox_open(struct mailmbox_folder * folder) +{ + int fd; + int read_only; + + fd = -1; + read_only = TRUE; + + if (!folder->mb_read_only) { + read_only = FALSE; + fd = open(folder->mb_filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); + } + + if (folder->mb_read_only || (fd < 0)) { + read_only = TRUE; + fd = open(folder->mb_filename, O_RDONLY); + if (fd < 0) + return MAILMBOX_ERROR_FILE_NOT_FOUND; + } + + folder->mb_fd = fd; + folder->mb_read_only = read_only; + + return MAILMBOX_NO_ERROR; +} + +/* + close the file +*/ + +void mailmbox_close(struct mailmbox_folder * folder) +{ + close(folder->mb_fd); + folder->mb_fd = -1; +} + + +static int mailmbox_validate_lock(struct mailmbox_folder * folder, + int (* custom_lock)(struct mailmbox_folder *), + int (* custom_unlock)(struct mailmbox_folder *)) +{ + struct stat buf; + int res; + int r; + + r = stat(folder->mb_filename, &buf); + if (r < 0) { + buf.st_mtime = (time_t) -1; + } + + if ((buf.st_mtime != folder->mb_mtime) || + ((size_t) buf.st_size != folder->mb_mapping_size)) { + int r; + + mailmbox_unmap(folder); + mailmbox_close(folder); + + r = mailmbox_open(folder); + if (r != MAILMBOX_NO_ERROR) { + res = r; + goto err; + } + + r = custom_lock(folder); + if (r != MAILMBOX_NO_ERROR) { + res = r; + goto err; + } + + r = mailmbox_map(folder); + if (r != MAILMBOX_NO_ERROR) { + res = r; + goto err_unlock; + } + + r = mailmbox_parse(folder); + if (r != MAILMBOX_NO_ERROR) { + res = r; + goto err_unlock; + } + + folder->mb_mtime = buf.st_mtime; + + return MAILMBOX_NO_ERROR; + } + else { + r = custom_lock(folder); + if (r != MAILMBOX_NO_ERROR) { + res = r; + goto err; + } + } + + return MAILMBOX_NO_ERROR; + + err_unlock: + custom_unlock(folder); + err: + return res; +} + + +int mailmbox_validate_write_lock(struct mailmbox_folder * folder) +{ + return mailmbox_validate_lock(folder, + mailmbox_write_lock, + mailmbox_write_unlock); +} + + +int mailmbox_validate_read_lock(struct mailmbox_folder * folder) +{ + return mailmbox_validate_lock(folder, + mailmbox_read_lock, + mailmbox_read_unlock); +} + + +/* ********************************************************************** */ +/* append messages */ + +#define MAX_FROM_LINE_SIZE 256 + +static inline size_t get_line(const char * line, size_t length, + const char ** pnext_line, size_t * pcount) +{ + size_t count; + + count = 0; + + while (1) { + if (length == 0) + break; + + if (* line == '\r') { + line ++; + + count ++; + length --; + + if (length > 0) { + if (* line == '\n') { + line ++; + + count ++; + length --; + + break; + } + } + } + else if (* line == '\n') { + line ++; + + count ++; + length --; + + break; + } + else { + line ++; + length --; + count ++; + } + } + + * pnext_line = line; + * pcount = count; + + return count; +} + +/* + TODO : should strip \r\n if any + see also in write_fixed_line +*/ + +static inline size_t get_fixed_line_size(const char * line, size_t length, + const char ** pnext_line, size_t * pcount, + size_t * pfixed_count) +{ + size_t count; + const char * next_line; + size_t fixed_count; + + if (!get_line(line, length, &next_line, &count)) + return 0; + + fixed_count = count; + if (count >= 5) { + if (line[0] == 'F') { + if (strncmp(line, "From ", 5) == 0) + fixed_count ++; + } + } + + * pnext_line = next_line; + * pcount = count; + * pfixed_count = fixed_count; + + return count; +} + +static size_t get_fixed_message_size(const char * message, size_t size, + uint32_t uid, int force_no_uid) +{ + size_t fixed_size; + size_t cur_token; + size_t left; + const char * next; + const char * cur; + int end; + int r; + uint32_t tmp_uid; + + cur_token = 0; + + fixed_size = 0; + + /* headers */ + + end = FALSE; + while (!end) { + size_t begin; + int ignore; + + ignore = FALSE; + begin = cur_token; + if (cur_token + strlen(UID_HEADER) <= size) { + if (message[cur_token] == 'X') { + if (strncasecmp(message + cur_token, UID_HEADER, + strlen(UID_HEADER)) == 0) { + ignore = TRUE; + } + } + } + + r = mailimf_ignore_field_parse(message, size, &cur_token); + switch (r) { + case MAILIMF_NO_ERROR: + if (!ignore) + fixed_size += cur_token - begin; + break; + case MAILIMF_ERROR_PARSE: + default: + end = TRUE; + break; + } + } + + if (!force_no_uid) { + /* UID header */ + + fixed_size += strlen(UID_HEADER " \r\n"); + + tmp_uid = uid; + while (tmp_uid >= 10) { + tmp_uid /= 10; + fixed_size ++; + } + fixed_size ++; + } + + /* body */ + + left = size - cur_token; + next = message + cur_token; + while (left > 0) { + size_t count; + size_t fixed_count; + + cur = next; + + if (!get_fixed_line_size(cur, left, &next, &count, &fixed_count)) + break; + + fixed_size += fixed_count; + left -= count; + } + + return fixed_size; +} + +static inline char * write_fixed_line(char * str, + const char * line, size_t length, + const char ** pnext_line, size_t * pcount) +{ + size_t count; + const char * next_line; + + if (!get_line(line, length, &next_line, &count)) + return str; + + if (count >= 5) { + if (line[0] == 'F') { + if (strncmp(line, "From ", 5) == 0) { + * str = '>'; + str ++; + } + } + } + + memcpy(str, line, count); + + * pnext_line = next_line; + * pcount = count; + str += count; + + return str; +} + +static char * write_fixed_message(char * str, + const char * message, size_t size, + uint32_t uid, int force_no_uid) +{ + size_t fixed_size; + size_t cur_token; + size_t left; + int end; + int r; + const char * cur_src; + size_t numlen; + + cur_token = 0; + + fixed_size = 0; + + /* headers */ + + end = FALSE; + while (!end) { + size_t begin; + int ignore; + + ignore = FALSE; + begin = cur_token; + if (cur_token + strlen(UID_HEADER) <= size) { + if (message[cur_token] == 'X') { + if (strncasecmp(message + cur_token, UID_HEADER, + strlen(UID_HEADER)) == 0) { + ignore = TRUE; + } + } + } + + r = mailimf_ignore_field_parse(message, size, &cur_token); + switch (r) { + case MAILIMF_NO_ERROR: + if (!ignore) { + memcpy(str, message + begin, cur_token - begin); + str += cur_token - begin; + } + break; + case MAILIMF_ERROR_PARSE: + default: + end = TRUE; + break; + } + } + + if (!force_no_uid) { + /* UID header */ + + memcpy(str, UID_HEADER " ", strlen(UID_HEADER " ")); + str += strlen(UID_HEADER " "); + numlen = snprintf(str, 20, "%i\r\n", uid); + str += numlen; + } + + /* body */ + + cur_src = message + cur_token; + left = size - cur_token; + while (left > 0) { + size_t count; + const char * next; + + str = write_fixed_line(str, cur_src, left, &next, &count); + + cur_src = next; + left -= count; + } + + return str; +} + +#define DEFAULT_FROM_LINE "From - Wed Jun 30 21:49:08 1993\n" + +int +mailmbox_append_message_list_no_lock(struct mailmbox_folder * folder, + carray * append_tab) +{ + size_t extra_size; + int r; + char from_line[MAX_FROM_LINE_SIZE] = DEFAULT_FROM_LINE; + struct tm time_info; + time_t date; + int res; + size_t old_size; + char * str; + unsigned int i; + size_t from_size; + size_t maxuid; + size_t left; + size_t crlf_count; + + if (folder->mb_read_only) { + res = MAILMBOX_ERROR_READONLY; + goto err; + } + + date = time(NULL); + from_size = strlen(DEFAULT_FROM_LINE); + if (localtime_r(&date, &time_info) != NULL) + from_size = strftime(from_line, MAX_FROM_LINE_SIZE, "From - %c\n", &time_info); + + maxuid = /* */ folder->mb_max_uid; + + extra_size = 0; + for(i = 0 ; i < carray_count(append_tab) ; i ++) { + struct mailmbox_append_info * info; + + info = carray_get(append_tab, i); + extra_size += from_size; + extra_size += get_fixed_message_size(info->ai_message, info->ai_size, + folder->mb_max_uid + i + 1, + folder->mb_no_uid); + extra_size += 2; /* CR LF */ + + info->ai_uid = folder->mb_max_uid + i + 1; + } + + left = folder->mb_mapping_size; + crlf_count = 0; + while (left >= 1) { + if (folder->mb_mapping[left - 1] == '\n') { + crlf_count ++; + left --; + } + else if (folder->mb_mapping[left - 1] == '\r') { + left --; + } + else + break; + + if (crlf_count == 2) + break; + } + + old_size = folder->mb_mapping_size; + mailmbox_unmap(folder); + + if (old_size != 0) { + if (crlf_count != 2) + extra_size += (2 - crlf_count) * 2; + } + + r = ftruncate(folder->mb_fd, extra_size + old_size); + if (r < 0) { + mailmbox_map(folder); + res = MAILMBOX_ERROR_FILE; + goto err; + } + + r = mailmbox_map(folder); + if (r < 0) { + ftruncate(folder->mb_fd, old_size); + return MAILMBOX_ERROR_FILE; + } + + str = folder->mb_mapping + old_size; + + if (old_size != 0) { + for(i = 0 ; i < 2 - crlf_count ; i ++) { + * str = '\r'; + str ++; + * str = '\n'; + str ++; + } + } + + for(i = 0 ; i < carray_count(append_tab) ; i ++) { + struct mailmbox_append_info * info; + + info = carray_get(append_tab, i); + + memcpy(str, from_line, from_size); + + str += strlen(from_line); + + str = write_fixed_message(str, info->ai_message, info->ai_size, + folder->mb_max_uid + i + 1, + folder->mb_no_uid); + + * str = '\r'; + str ++; + * str = '\n'; + str ++; + } + + folder->mb_max_uid += carray_count(append_tab); + + return MAILMBOX_NO_ERROR; + + err: + return res; +} + +int +mailmbox_append_message_list(struct mailmbox_folder * folder, + carray * append_tab) +{ + int r; + int res; + size_t cur_token; + + r = mailmbox_validate_write_lock(folder); + if (r != MAILMBOX_NO_ERROR) { + res = r; + goto err; + } + + r = mailmbox_expunge_no_lock(folder); + if (r != MAILMBOX_NO_ERROR) { + res = r; + goto unlock; + } + + cur_token = folder->mb_mapping_size; + + r = mailmbox_append_message_list_no_lock(folder, append_tab); + if (r != MAILMBOX_NO_ERROR) { + res = r; + goto unlock; + } + + mailmbox_sync(folder); + + r = mailmbox_parse_additionnal(folder, &cur_token); + if (r != MAILMBOX_NO_ERROR) { + res = r; + goto unlock; + } + + mailmbox_timestamp(folder); + + mailmbox_write_unlock(folder); + + return MAILMBOX_NO_ERROR; + + unlock: + mailmbox_write_unlock(folder); + err: + return res; +} + +int +mailmbox_append_message_uid(struct mailmbox_folder * folder, + const char * data, size_t len, unsigned int * puid) +{ + carray * tab; + struct mailmbox_append_info * append_info; + int res; + int r; + + tab = carray_new(1); + if (tab == NULL) { + res = MAILMBOX_ERROR_MEMORY; + goto err; + } + + append_info = mailmbox_append_info_new(data, len); + if (append_info == NULL) { + res = MAILMBOX_ERROR_MEMORY; + goto free_list; + } + + r = carray_add(tab, append_info, NULL); + if (r < 0) { + res = MAILMBOX_ERROR_MEMORY; + goto free_append_info; + } + + r = mailmbox_append_message_list(folder, tab); + + if (puid != NULL) + * puid = append_info->ai_uid; + + mailmbox_append_info_free(append_info); + carray_free(tab); + + return r; + + free_append_info: + mailmbox_append_info_free(append_info); + free_list: + carray_free(tab); + err: + return res; +} + +int +mailmbox_append_message(struct mailmbox_folder * folder, + const char * data, size_t len) +{ + return mailmbox_append_message_uid(folder, data, len, NULL); +} + +/* ********************************************************************** */ + +int mailmbox_fetch_msg_no_lock(struct mailmbox_folder * folder, + uint32_t num, char ** result, + size_t * result_len) +{ + struct mailmbox_msg_info * info; + int res; + chashdatum key; + chashdatum data; + int r; + + key.data = # + key.len = sizeof(num); + + r = chash_get(folder->mb_hash, &key, &data); + if (r < 0) { + res = MAILMBOX_ERROR_MSG_NOT_FOUND; + goto err; + } + + info = data.data; + + if (info->msg_deleted) { + res = MAILMBOX_ERROR_MSG_NOT_FOUND; + goto err; + } + + * result = folder->mb_mapping + info->msg_headers; + * result_len = info->msg_size - info->msg_start_len; + + return MAILMBOX_NO_ERROR; + + err: + return res; +} + +int mailmbox_fetch_msg_headers_no_lock(struct mailmbox_folder * folder, + uint32_t num, char ** result, + size_t * result_len) +{ + struct mailmbox_msg_info * info; + int res; + chashdatum key; + chashdatum data; + int r; + + key.data = # + key.len = sizeof(num); + + r = chash_get(folder->mb_hash, &key, &data); + if (r < 0) { + res = MAILMBOX_ERROR_MSG_NOT_FOUND; + goto err; + } + + info = data.data; + + if (info->msg_deleted) { + res = MAILMBOX_ERROR_MSG_NOT_FOUND; + goto err; + } + + * result = folder->mb_mapping + info->msg_headers; + * result_len = info->msg_headers_len; + + return MAILMBOX_NO_ERROR; + + err: + return res; +} + +int mailmbox_fetch_msg(struct mailmbox_folder * folder, + uint32_t num, char ** result, + size_t * result_len) +{ + MMAPString * mmapstr; + int res; + char * data; + size_t len; + int r; + size_t fixed_size; + char * end; + + r = mailmbox_validate_read_lock(folder); + if (r != MAILMBOX_NO_ERROR) { + res = r; + goto err; + } + + r = mailmbox_fetch_msg_no_lock(folder, num, &data, &len); + if (r != MAILMBOX_NO_ERROR) { + res = r; + goto unlock; + } + + /* size with no uid */ + fixed_size = get_fixed_message_size(data, len, 0, 1 /* force no uid */); + +#if 0 + mmapstr = mmap_string_new_len(data, fixed_size); + if (mmapstr == NULL) { + res = MAILMBOX_ERROR_MEMORY; + goto unlock; + } +#endif + mmapstr = mmap_string_sized_new(fixed_size); + if (mmapstr == NULL) { + res = MAILMBOX_ERROR_MEMORY; + goto unlock; + } + + end = write_fixed_message(mmapstr->str, data, len, 0, 1 /* force no uid */); + * end = '\0'; + mmapstr->len = fixed_size; + + r = mmap_string_ref(mmapstr); + if (r < 0) { + mmap_string_free(mmapstr); + res = MAILMBOX_ERROR_MEMORY; + goto unlock; + } + + * result = mmapstr->str; + * result_len = mmapstr->len; + + mailmbox_read_unlock(folder); + + return MAILMBOX_NO_ERROR; + + unlock: + mailmbox_read_unlock(folder); + err: + return res; +} + +int mailmbox_fetch_msg_headers(struct mailmbox_folder * folder, + uint32_t num, char ** result, + size_t * result_len) +{ + MMAPString * mmapstr; + int res; + char * data; + size_t len; + int r; + size_t fixed_size; + char * end; + + r = mailmbox_validate_read_lock(folder); + if (r != MAILMBOX_NO_ERROR) { + res = r; + goto err; + } + + r = mailmbox_fetch_msg_headers_no_lock(folder, num, &data, &len); + if (r != MAILMBOX_NO_ERROR) { + res = r; + goto unlock; + } + +#if 0 + mmapstr = mmap_string_new_len(data, len); + if (mmapstr == NULL) { + res = MAILMBOX_ERROR_MEMORY; + goto unlock; + } +#endif + /* size with no uid */ + fixed_size = get_fixed_message_size(data, len, 0, 1 /* force no uid */); + + mmapstr = mmap_string_sized_new(fixed_size); + if (mmapstr == NULL) { + res = MAILMBOX_ERROR_MEMORY; + goto unlock; + } + + end = write_fixed_message(mmapstr->str, data, len, 0, 1 /* force no uid */); + * end = '\0'; + mmapstr->len = fixed_size; + + r = mmap_string_ref(mmapstr); + if (r < 0) { + mmap_string_free(mmapstr); + res = MAILMBOX_ERROR_MEMORY; + goto unlock; + } + + * result = mmapstr->str; + * result_len = mmapstr->len; + + mailmbox_read_unlock(folder); + + return MAILMBOX_NO_ERROR; + + unlock: + mailmbox_read_unlock(folder); + err: + return res; +} + +void mailmbox_fetch_result_free(char * msg) +{ + mmap_string_unref(msg); +} + + +int mailmbox_copy_msg_list(struct mailmbox_folder * dest_folder, + struct mailmbox_folder * src_folder, + carray * tab) +{ + int r; + int res; + carray * append_tab; + unsigned int i; + + r = mailmbox_validate_read_lock(src_folder); + if (r != MAILMBOX_NO_ERROR) { + res = r; + goto err; + } + + append_tab = carray_new(carray_count(tab)); + if (append_tab == NULL) { + res = MAILMBOX_ERROR_MEMORY; + goto src_unlock; + } + + for(i = 0 ; i < carray_count(tab) ; i ++) { + struct mailmbox_append_info * append_info; + char * data; + size_t len; + uint32_t uid; + + uid = * ((uint32_t *) carray_get(tab, i)); + + r = mailmbox_fetch_msg_no_lock(src_folder, uid, &data, &len); + if (r != MAILMBOX_NO_ERROR) { + res = r; + goto free_list; + } + + append_info = mailmbox_append_info_new(data, len); + if (append_info == NULL) { + res = MAILMBOX_ERROR_MEMORY; + goto free_list; + } + + r = carray_add(append_tab, append_info, NULL); + if (r < 0) { + mailmbox_append_info_free(append_info); + res = MAILMBOX_ERROR_MEMORY; + goto free_list; + } + } + + r = mailmbox_append_message_list(dest_folder, append_tab); + if (r != MAILMBOX_NO_ERROR) { + res = r; + goto src_unlock; + } + + for(i = 0 ; i < carray_count(append_tab) ; i ++) { + struct mailmbox_append_info * append_info; + + append_info = carray_get(append_tab, i); + mailmbox_append_info_free(append_info); + } + carray_free(append_tab); + + mailmbox_read_unlock(src_folder); + + return MAILMBOX_NO_ERROR; + + free_list: + for(i = 0 ; i < carray_count(append_tab) ; i ++) { + struct mailmbox_append_info * append_info; + + append_info = carray_get(append_tab, i); + mailmbox_append_info_free(append_info); + } + carray_free(append_tab); + src_unlock: + mailmbox_read_unlock(src_folder); + err: + return res; +} + +int mailmbox_copy_msg(struct mailmbox_folder * dest_folder, + struct mailmbox_folder * src_folder, + uint32_t uid) +{ + carray * tab; + int res; + uint32_t * puid; + int r; + + tab = carray_new(1); + if (tab == NULL) { + res = MAILMBOX_ERROR_MEMORY; + goto err; + } + + puid = malloc(sizeof(* puid)); + if (puid == NULL) { + res = MAILMBOX_ERROR_MEMORY; + goto free_array; + } + * puid = uid; + + r = mailmbox_copy_msg_list(dest_folder, src_folder, tab); + res = r; + + free(puid); + free_array: + carray_free(tab); + err: + return res; +} + +static int mailmbox_expunge_to_file_no_lock(char * dest_filename, int dest_fd, + struct mailmbox_folder * folder, + size_t * result_size) +{ + int r; + int res; + unsigned long i; + size_t cur_offset; + char * dest; + size_t size; + + size = 0; + for(i = 0 ; i < carray_count(folder->mb_tab) ; i ++) { + struct mailmbox_msg_info * info; + + info = carray_get(folder->mb_tab, i); + + if (!info->msg_deleted) { + size += info->msg_size + info->msg_padding; + + if (!folder->mb_no_uid) { + if (!info->msg_written_uid) { + uint32_t uid; + + size += strlen(UID_HEADER " \r\n"); + + uid = info->msg_uid; + while (uid >= 10) { + uid /= 10; + size ++; + } + size ++; + } + } + } + } + + r = ftruncate(dest_fd, size); + if (r < 0) { + res = MAILMBOX_ERROR_FILE; + goto err; + } + + dest = (char *) mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, dest_fd, 0); + if (dest == MAP_FAILED) { + res = MAILMBOX_ERROR_FILE; + goto err; + } + + cur_offset = 0; + for(i = 0 ; i < carray_count(folder->mb_tab) ; i ++) { + struct mailmbox_msg_info * info; + + info = carray_get(folder->mb_tab, i); + + if (!info->msg_deleted) { + memcpy(dest + cur_offset, folder->mb_mapping + info->msg_start, + info->msg_headers_len + info->msg_start_len); + cur_offset += info->msg_headers_len + info->msg_start_len; + + if (!folder->mb_no_uid) { + if (!info->msg_written_uid) { + size_t numlen; + + memcpy(dest + cur_offset, UID_HEADER " ", strlen(UID_HEADER " ")); + cur_offset += strlen(UID_HEADER " "); + numlen = snprintf(dest + cur_offset, size - cur_offset, + "%i\r\n", info->msg_uid); + cur_offset += numlen; + } + } + + memcpy(dest + cur_offset, + folder->mb_mapping + info->msg_headers + info->msg_headers_len, + info->msg_size - (info->msg_start_len + info->msg_headers_len) + + info->msg_padding); + + cur_offset += info->msg_size - + (info->msg_start_len + info->msg_headers_len) + + info->msg_padding; + } + } + fflush(stdout); + + msync(dest, size, MS_SYNC); + munmap(dest, size); + + * result_size = size; + + return MAILMBOX_NO_ERROR; + + err: + return res; +} + +static int copy_to_old_file(char * source_filename, + char * destination_filename, size_t size) +{ + int source_fd; + int dest_fd; + char * source; + char * dest; + int res; + int r; + + source_fd = open(source_filename, O_RDONLY); + if (source_fd < 0) { + res = MAILMBOX_ERROR_FILE; + goto err; + } + + source = (char *) mmap(0, size, PROT_READ, MAP_PRIVATE, source_fd, 0); + if (source == MAP_FAILED) { + res = MAILMBOX_ERROR_FILE; + goto close_source; + } + + dest_fd = open(destination_filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); + if (dest_fd < 0) { + res = MAILMBOX_ERROR_FILE; + goto unmap_source; + } + + r = ftruncate(dest_fd, size); + if (r < 0) { + res = MAILMBOX_ERROR_FILE; + goto close_dest; + } + + dest = (char *) mmap(0, size, PROT_READ | PROT_WRITE, + MAP_SHARED, dest_fd, 0); + if (dest == MAP_FAILED) { + res = MAILMBOX_ERROR_FILE; + goto close_dest; + } + + memcpy(dest, source, size); + + munmap(dest, size); + close(source_fd); + munmap(source, size); + close(source_fd); + + return MAILMBOX_NO_ERROR; + + unmap_dest: + munmap(dest, size); + close_dest: + close(source_fd); + unmap_source: + munmap(source, size); + close_source: + close(source_fd); + err: + return res; +} + +int mailmbox_expunge_no_lock(struct mailmbox_folder * folder) +{ + char tmpfile[PATH_MAX]; + int r; + int res; + int dest_fd; + size_t size; + mode_t old_mask; + + if (folder->mb_read_only) + return MAILMBOX_ERROR_READONLY; + + if (((folder->mb_written_uid >= folder->mb_max_uid) || folder->mb_no_uid) && + (!folder->mb_changed)) { + /* no need to expunge */ + return MAILMBOX_NO_ERROR; + } + + snprintf(tmpfile, PATH_MAX, "%sXXXXXX", folder->mb_filename); + old_mask = umask(0077); + dest_fd = mkstemp(tmpfile); + umask(old_mask); + + if (dest_fd < 0) { + /* fallback to tmp dir */ + + snprintf(tmpfile, PATH_MAX, TMPDIR "/etpan-unsafe-XXXXXX"); + + old_mask = umask(0077); + dest_fd = mkstemp(tmpfile); + umask(old_mask); + + if (dest_fd < 0) { + res = MAILMBOX_ERROR_FILE; + goto err; + } + } + + r = mailmbox_expunge_to_file_no_lock(tmpfile, dest_fd, + folder, &size); + if (r != MAILMBOX_NO_ERROR) { + res = r; + goto unlink; + } + + close(dest_fd); + + r = rename(tmpfile, folder->mb_filename); + if (r < 0) { + mailmbox_unmap(folder); + mailmbox_close(folder); + + /* fallback on copy to old file */ + + r = copy_to_old_file(tmpfile, folder->mb_filename, size); + if (r != MAILMBOX_NO_ERROR) { + res = r; + goto err; + } + + unlink(tmpfile); + } + else { + mailmbox_unmap(folder); + mailmbox_close(folder); + } + + r = mailmbox_open(folder); + if (r != MAILMBOX_NO_ERROR) { + res = r; + goto err; + } + + r = mailmbox_map(folder); + if (r != MAILMBOX_NO_ERROR) { + res = r; + goto err; + } + + r = mailmbox_parse(folder); + if (r != MAILMBOX_NO_ERROR) { + res = r; + goto err; + } + + mailmbox_timestamp(folder); + + folder->mb_changed = FALSE; + folder->mb_deleted_count = 0; + + return MAILMBOX_NO_ERROR; + + unlink: + close(dest_fd); + unlink(tmpfile); + err: + return res; +} + +int mailmbox_expunge(struct mailmbox_folder * folder) +{ + int r; + int res; + + r = mailmbox_validate_write_lock(folder); + if (r != MAILMBOX_NO_ERROR) { + res = r; + goto err; + } + + r = mailmbox_expunge_no_lock(folder); + res = r; + + mailmbox_write_unlock(folder); + err: + return res; +} + +int mailmbox_delete_msg(struct mailmbox_folder * folder, uint32_t uid) +{ + struct mailmbox_msg_info * info; + int res; + chashdatum key; + chashdatum data; + int r; + + if (folder->mb_read_only) { + res = MAILMBOX_ERROR_READONLY; + goto err; + } + + key.data = &uid; + key.len = sizeof(uid); + + r = chash_get(folder->mb_hash, &key, &data); + if (r < 0) { + res = MAILMBOX_ERROR_MSG_NOT_FOUND; + goto err; + } + + info = data.data; + + if (info->msg_deleted) { + res = MAILMBOX_ERROR_MSG_NOT_FOUND; + goto err; + } + + info->msg_deleted = TRUE; + folder->mb_changed = TRUE; + folder->mb_deleted_count ++; + + return MAILMBOX_NO_ERROR; + + err: + return res; +} + + +/* + INIT of MBOX + + - open file + - map the file + + - lock the file + + - parse memory + + - unlock the file +*/ + +int mailmbox_init(const char * filename, + int force_readonly, + int force_no_uid, + uint32_t default_written_uid, + struct mailmbox_folder ** result_folder) +{ + struct mailmbox_folder * folder; + int r; + int res; + + folder = mailmbox_folder_new(filename); + if (folder == NULL) { + res = MAILMBOX_ERROR_MEMORY; + goto err; + } + folder->mb_no_uid = force_no_uid; + folder->mb_read_only = force_readonly; + folder->mb_written_uid = default_written_uid; + + folder->mb_changed = FALSE; + folder->mb_deleted_count = 0; + + r = mailmbox_open(folder); + if (r != MAILMBOX_NO_ERROR) { + res = r; + goto free; + } + + r = mailmbox_map(folder); + if (r != MAILMBOX_NO_ERROR) { + res = r; + goto close; + } + + r = mailmbox_validate_read_lock(folder); + if (r != MAILMBOX_NO_ERROR) { + res = r; + goto unmap; + } + + mailmbox_read_unlock(folder); + + * result_folder = folder; + + return MAILMBOX_NO_ERROR; + + unmap: + mailmbox_unmap(folder); + close: + mailmbox_close(folder); + free: + mailmbox_folder_free(folder); + err: + return res; +} + + +/* + when MBOX is DONE + + - check for changes + + - unmap the file + - close file +*/ + +void mailmbox_done(struct mailmbox_folder * folder) +{ + if (!folder->mb_read_only) + mailmbox_expunge(folder); + + mailmbox_unmap(folder); + mailmbox_close(folder); + + mailmbox_folder_free(folder); +} diff --git a/libetpan/src/low-level/mbox/mailmbox.h b/libetpan/src/low-level/mbox/mailmbox.h new file mode 100644 index 0000000..ea21d48 --- a/dev/null +++ b/libetpan/src/low-level/mbox/mailmbox.h @@ -0,0 +1,144 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MAILMBOX_H + +#define MAILMBOX_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <libetpan/mailmbox_types.h> + +int +mailmbox_append_message_list(struct mailmbox_folder * folder, + carray * append_tab); + +int +mailmbox_append_message(struct mailmbox_folder * folder, + const char * data, size_t len); + +int +mailmbox_append_message_uid(struct mailmbox_folder * folder, + const char * data, size_t len, unsigned int * puid); + +int mailmbox_fetch_msg(struct mailmbox_folder * folder, + uint32_t num, char ** result, + size_t * result_len); + +int mailmbox_fetch_msg_headers(struct mailmbox_folder * folder, + uint32_t num, char ** result, + size_t * result_len); + +void mailmbox_fetch_result_free(char * msg); + +int mailmbox_copy_msg_list(struct mailmbox_folder * dest_folder, + struct mailmbox_folder * src_folder, + carray * tab); + +int mailmbox_copy_msg(struct mailmbox_folder * dest_folder, + struct mailmbox_folder * src_folder, + uint32_t uid); + +int mailmbox_expunge(struct mailmbox_folder * folder); + +int mailmbox_delete_msg(struct mailmbox_folder * folder, uint32_t uid); + +int mailmbox_init(const char * filename, + int force_readonly, + int force_no_uid, + uint32_t default_written_uid, + struct mailmbox_folder ** result_folder); + +void mailmbox_done(struct mailmbox_folder * folder); + +/* low-level access primitives */ + +int mailmbox_write_lock(struct mailmbox_folder * folder); + +int mailmbox_write_unlock(struct mailmbox_folder * folder); + +int mailmbox_read_lock(struct mailmbox_folder * folder); + +int mailmbox_read_unlock(struct mailmbox_folder * folder); + + +/* memory map */ + +int mailmbox_map(struct mailmbox_folder * folder); + +void mailmbox_unmap(struct mailmbox_folder * folder); + +void mailmbox_sync(struct mailmbox_folder * folder); + + +/* open & close file */ + +int mailmbox_open(struct mailmbox_folder * folder); + +void mailmbox_close(struct mailmbox_folder * folder); + + +/* validate cache */ + +int mailmbox_validate_write_lock(struct mailmbox_folder * folder); + +int mailmbox_validate_read_lock(struct mailmbox_folder * folder); + + +/* fetch message */ + +int mailmbox_fetch_msg_no_lock(struct mailmbox_folder * folder, + uint32_t num, char ** result, + size_t * result_len); + +int mailmbox_fetch_msg_headers_no_lock(struct mailmbox_folder * folder, + uint32_t num, char ** result, + size_t * result_len); + +/* append message */ + +int +mailmbox_append_message_list_no_lock(struct mailmbox_folder * folder, + carray * append_tab); + +int mailmbox_expunge_no_lock(struct mailmbox_folder * folder); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/low-level/mbox/mailmbox_parse.c b/libetpan/src/low-level/mbox/mailmbox_parse.c new file mode 100644 index 0000000..65642ac --- a/dev/null +++ b/libetpan/src/low-level/mbox/mailmbox_parse.c @@ -0,0 +1,620 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "mailmbox_parse.h" + +#include "mailmbox.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <string.h> +#include <stdlib.h> + +#define UID_HEADER "X-LibEtPan-UID:" + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +enum { + UNSTRUCTURED_START, + UNSTRUCTURED_CR, + UNSTRUCTURED_LF, + UNSTRUCTURED_WSP, + UNSTRUCTURED_OUT +}; + +static inline int +mailmbox_fields_parse(char * str, size_t length, + size_t * index, + uint32_t * puid, + size_t * phlen) +{ + size_t cur_token; + int r; + size_t hlen; + size_t uid; + int end; + + cur_token = * index; + + end = FALSE; + uid = 0; + while (!end) { + size_t begin; + + begin = cur_token; + + r = mailimf_ignore_field_parse(str, length, &cur_token); + switch (r) { + case MAILIMF_NO_ERROR: + if (str[begin] == 'X') { + + if (strncasecmp(str + begin, UID_HEADER, strlen(UID_HEADER)) == 0) { + begin += strlen(UID_HEADER); + + while (str[begin] == ' ') + begin ++; + + uid = strtoul(str + begin, NULL, 10); + } + } + + break; + case MAILIMF_ERROR_PARSE: + default: + end = TRUE; + break; + } + } + + hlen = cur_token - * index; + + * phlen = hlen; + * puid = uid; + * index = cur_token; + + return MAILMBOX_NO_ERROR; +} + +enum { + IN_MAIL, + FIRST_CR, + FIRST_LF, + SECOND_CR, + SECOND_LF, + PARSING_F, + PARSING_R, + PARSING_O, + PARSING_M, + OUT_MAIL +}; + + + + +static inline int +mailmbox_single_parse(char * str, size_t length, + size_t * index, + size_t * pstart, + size_t * pstart_len, + size_t * pheaders, + size_t * pheaders_len, + size_t * pbody, + size_t * pbody_len, + size_t * psize, + size_t * ppadding, + uint32_t * puid) +{ + size_t cur_token; + size_t start; + size_t start_len; + size_t headers; + size_t headers_len; + size_t body; + size_t end; + size_t next; + size_t message_length; + uint32_t uid; + int r; +#if 0 + int in_mail_data; +#endif +#if 0 + size_t begin; +#endif + + int state; + + cur_token = * index; + + if (cur_token >= length) + return MAILMBOX_ERROR_PARSE; + + start = cur_token; + start_len = 0; + headers = cur_token; + + if (cur_token + 5 < length) { + if (strncmp(str + cur_token, "From ", 5) == 0) { + cur_token += 5; + while (str[cur_token] != '\n') { + cur_token ++; + if (cur_token >= length) + break; + } + if (cur_token < length) { + cur_token ++; + headers = cur_token; + start_len = headers - start; + } + } + } + + next = length; + + r = mailmbox_fields_parse(str, length, &cur_token, + &uid, &headers_len); + if (r != MAILMBOX_NO_ERROR) + return r; + + /* save position */ +#if 0 + begin = cur_token; +#endif + + mailimf_crlf_parse(str, length, &cur_token); + +#if 0 + if (str[cur_token] == 'F') { + printf("start !\n"); + printf("%50.50s\n", str + cur_token); + getchar(); + } +#endif + + body = cur_token; + + /* restore position */ + /* cur_token = begin; */ + + state = FIRST_LF; + + end = length; + +#if 0 + in_mail_data = 0; +#endif + while (state != OUT_MAIL) { + + if (cur_token >= length) { + if (state == IN_MAIL) + end = length; + next = length; + break; + } + + switch(state) { + case IN_MAIL: + switch(str[cur_token]) { + case '\r': + state = FIRST_CR; + break; + case '\n': + state = FIRST_LF; + break; + case 'F': + if (cur_token == body) { + end = cur_token; + next = cur_token; + state = PARSING_F; + } + break; +#if 0 + default: + in_mail_data = 1; + break; +#endif + } + break; + + case FIRST_CR: + end = cur_token; + switch(str[cur_token]) { + case '\r': + state = SECOND_CR; + break; + case '\n': + state = FIRST_LF; + break; + default: + state = IN_MAIL; +#if 0 + in_mail_data = 1; +#endif + break; + } + break; + + case FIRST_LF: + end = cur_token; + switch(str[cur_token]) { + case '\r': + state = SECOND_CR; + break; + case '\n': + state = SECOND_LF; + break; + default: + state = IN_MAIL; +#if 0 + in_mail_data = 1; +#endif + break; + } + break; + + case SECOND_CR: + switch(str[cur_token]) { + case '\r': + end = cur_token; + break; + case '\n': + state = SECOND_LF; + break; + case 'F': + next = cur_token; + state = PARSING_F; + break; + default: + state = IN_MAIL; +#if 0 + in_mail_data = 1; +#endif + break; + } + break; + + case SECOND_LF: + switch(str[cur_token]) { + case '\r': + state = SECOND_CR; + break; + case '\n': + end = cur_token; + break; + case 'F': + next = cur_token; + state = PARSING_F; + break; + default: + state = IN_MAIL; +#if 0 + in_mail_data = 1; +#endif + break; + } + break; + + case PARSING_F: + switch(str[cur_token]) { + case 'r': + state = PARSING_R; + break; + default: + state = IN_MAIL; +#if 0 + in_mail_data = 1; +#endif + break; + } + break; + + case PARSING_R: + switch(str[cur_token]) { + case 'o': + state = PARSING_O; + break; + default: + state = IN_MAIL; +#if 0 + in_mail_data = 1; +#endif + break; + } + break; + + case PARSING_O: + switch(str[cur_token]) { + case 'm': + state = PARSING_M; + break; + default: + state = IN_MAIL; +#if 0 + in_mail_data = 1; +#endif + break; + } + break; + + case PARSING_M: + switch(str[cur_token]) { + case ' ': + state = OUT_MAIL; + break; + default: + state = IN_MAIL; + break; + } + break; + } + + cur_token ++; + } + + message_length = end - start; + + * pstart = start; + * pstart_len = start_len; + * pheaders = headers; + * pheaders_len = headers_len; + * pbody = body; + * pbody_len = end - body; + * psize = message_length; + * ppadding = next - end; + * puid = uid; + + * index = next; + + return MAILMBOX_NO_ERROR; +} + + +int +mailmbox_parse_additionnal(struct mailmbox_folder * folder, + size_t * index) +{ + size_t cur_token; + + size_t start; + size_t start_len; + size_t headers; + size_t headers_len; + size_t body; + size_t body_len; + size_t size; + size_t padding; + uint32_t uid; + int r; + int res; + + uint32_t max_uid; + uint32_t first_index; + unsigned int i; + unsigned int j; + + cur_token = * index; + + /* remove temporary UID that we will parse */ + + first_index = carray_count(folder->mb_tab); + + for(i = 0 ; i < carray_count(folder->mb_tab) ; i++) { + struct mailmbox_msg_info * info; + + info = carray_get(folder->mb_tab, i); + + if (info->msg_start < cur_token) { + continue; + } + + if (!info->msg_written_uid) { + chashdatum key; + + key.data = &info->msg_uid; + key.len = sizeof(info->msg_uid); + + chash_delete(folder->mb_hash, &key, NULL); + carray_delete_fast(folder->mb_tab, i); + mailmbox_msg_info_free(info); + if (i < first_index) + first_index = i; + } + } + + /* make a sequence in the table */ + + max_uid = folder->mb_written_uid; + + i = 0; + j = 0; + while (i < carray_count(folder->mb_tab)) { + struct mailmbox_msg_info * info; + + info = carray_get(folder->mb_tab, i); + if (info != NULL) { + carray_set(folder->mb_tab, j, info); + + if (info->msg_uid > max_uid) + max_uid = info->msg_uid; + + info->msg_index = j; + j ++; + } + i ++; + } + carray_set_size(folder->mb_tab, j); + + /* parse content */ + + first_index = j; + + while (1) { + struct mailmbox_msg_info * info; + chashdatum key; + chashdatum data; + + r = mailmbox_single_parse(folder->mb_mapping, folder->mb_mapping_size, + &cur_token, + &start, &start_len, + &headers, &headers_len, + &body, &body_len, + &size, &padding, &uid); + if (r == MAILMBOX_NO_ERROR) { + /* do nothing */ + } + else if (r == MAILMBOX_ERROR_PARSE) + break; + else { + res = r; + goto err; + } + + key.data = &uid; + key.len = sizeof(uid); + + r = chash_get(folder->mb_hash, &key, &data); + if (r == 0) { + info = data.data; + + if (!info->msg_written_uid) { + /* some new mail has been written and override an + existing temporary UID */ + + chash_delete(folder->mb_hash, &key, NULL); + info->msg_uid = 0; + + if (info->msg_index < first_index) + first_index = info->msg_index; + } + else + uid = 0; + } + + if (uid > max_uid) + max_uid = uid; + + r = mailmbox_msg_info_update(folder, + start, start_len, headers, headers_len, + body, body_len, size, padding, uid); + if (r != MAILMBOX_NO_ERROR) { + res = r; + goto err; + } + } + + * index = cur_token; + + folder->mb_written_uid = max_uid; + + /* attribute uid */ + + for(i = first_index ; i < carray_count(folder->mb_tab) ; i ++) { + struct mailmbox_msg_info * info; + chashdatum key; + chashdatum data; + + info = carray_get(folder->mb_tab, i); + + if (info->msg_uid != 0) { + continue; + } + + max_uid ++; + info->msg_uid = max_uid; + + key.data = &info->msg_uid; + key.len = sizeof(info->msg_uid); + data.data = info; + data.len = 0; + + r = chash_set(folder->mb_hash, &key, &data, NULL); + if (r < 0) { + res = MAILMBOX_ERROR_MEMORY; + goto err; + } + } + + folder->mb_max_uid = max_uid; + + return MAILMBOX_NO_ERROR; + + err: + return res; +} + +static void flush_uid(struct mailmbox_folder * folder) +{ + unsigned int i; + + for(i = 0 ; i < carray_count(folder->mb_tab) ; i++) { + struct mailmbox_msg_info * info; + + info = carray_get(folder->mb_tab, i); + if (info != NULL) + mailmbox_msg_info_free(info); + } + + chash_clear(folder->mb_hash); + carray_set_size(folder->mb_tab, 0); +} + +int mailmbox_parse(struct mailmbox_folder * folder) +{ + int r; + int res; + size_t cur_token; + + flush_uid(folder); + + cur_token = 0; + + r = mailmbox_parse_additionnal(folder, &cur_token); + + if (r != MAILMBOX_NO_ERROR) { + res = r; + goto err; + } + + return MAILMBOX_NO_ERROR; + + err: + return res; +} diff --git a/libetpan/src/low-level/mbox/mailmbox_parse.h b/libetpan/src/low-level/mbox/mailmbox_parse.h new file mode 100644 index 0000000..6b533a9 --- a/dev/null +++ b/libetpan/src/low-level/mbox/mailmbox_parse.h @@ -0,0 +1,56 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MAILMBOX_PARSE_H + +#define MAILMBOX_PARSE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "mailmbox_types.h" + +int mailmbox_parse(struct mailmbox_folder * folder); + +int +mailmbox_parse_additionnal(struct mailmbox_folder * folder, + size_t * index); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/low-level/mbox/mailmbox_types.c b/libetpan/src/low-level/mbox/mailmbox_types.c new file mode 100644 index 0000000..aaf76dc --- a/dev/null +++ b/libetpan/src/low-level/mbox/mailmbox_types.c @@ -0,0 +1,251 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "mailmbox_types.h" + +#include <string.h> +#include <stdlib.h> + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +/* *********************************************************************** */ + +int mailmbox_msg_info_update(struct mailmbox_folder * folder, + size_t msg_start, size_t msg_start_len, + size_t msg_headers, size_t msg_headers_len, + size_t msg_body, size_t msg_body_len, + size_t msg_size, size_t msg_padding, + uint32_t msg_uid) +{ + struct mailmbox_msg_info * info; + int res; + chashdatum key; + chashdatum data; + int r; + + key.data = &msg_uid; + key.len = sizeof(msg_uid); + r = chash_get(folder->mb_hash, &key, &data); + if (r < 0) { + unsigned int index; + + info = mailmbox_msg_info_new(msg_start, msg_start_len, + msg_headers, msg_headers_len, + msg_body, msg_body_len, msg_size, msg_padding, msg_uid); + if (info == NULL) { + res = MAILMBOX_ERROR_MEMORY; + goto err; + } + + r = carray_add(folder->mb_tab, info, &index); + if (r < 0) { + mailmbox_msg_info_free(info); + res = MAILMBOX_ERROR_MEMORY; + goto err; + } + + if (msg_uid != 0) { + chashdatum key; + chashdatum data; + + key.data = &msg_uid; + key.len = sizeof(msg_uid); + data.data = info; + data.len = 0; + + r = chash_set(folder->mb_hash, &key, &data, NULL); + if (r < 0) { + mailmbox_msg_info_free(info); + carray_delete(folder->mb_tab, index); + res = MAILMBOX_ERROR_MEMORY; + goto err; + } + } + + info->msg_index = index; + } + else { + info = data.data; + + info->msg_start = msg_start; + info->msg_start_len = msg_start_len; + info->msg_headers = msg_headers; + info->msg_headers_len = msg_headers_len; + info->msg_body = msg_body; + info->msg_body_len = msg_body_len; + info->msg_size = msg_size; + info->msg_padding = msg_padding; + } + + return MAILMBOX_NO_ERROR; + + err: + return res; +} + + +struct mailmbox_msg_info * +mailmbox_msg_info_new(size_t msg_start, size_t msg_start_len, + size_t msg_headers, size_t msg_headers_len, + size_t msg_body, size_t msg_body_len, + size_t msg_size, size_t msg_padding, + uint32_t msg_uid) +{ + struct mailmbox_msg_info * info; + + info = malloc(sizeof(* info)); + if (info == NULL) + return NULL; + + info->msg_index = 0; + info->msg_uid = msg_uid; + if (msg_uid != 0) + info->msg_written_uid = TRUE; + else + info->msg_written_uid = FALSE; + info->msg_deleted = FALSE; + + info->msg_start = msg_start; + info->msg_start_len = msg_start_len; + + info->msg_headers = msg_headers; + info->msg_headers_len = msg_headers_len; + + info->msg_body = msg_body; + info->msg_body_len = msg_body_len; + + info->msg_size = msg_size; + + info->msg_padding = msg_padding; + + return info; +} + +void mailmbox_msg_info_free(struct mailmbox_msg_info * info) +{ + free(info); +} + + +/* append info */ + +struct mailmbox_append_info * +mailmbox_append_info_new(const char * ai_message, size_t ai_size) +{ + struct mailmbox_append_info * info; + + info = malloc(sizeof(* info)); + if (info == NULL) + return NULL; + + info->ai_message = ai_message; + info->ai_size = ai_size; + info->ai_uid = 0; + + return info; +} + +void mailmbox_append_info_free(struct mailmbox_append_info * info) +{ + free(info); +} + +struct mailmbox_folder * mailmbox_folder_new(const char * mb_filename) +{ + struct mailmbox_folder * folder; + + folder = malloc(sizeof(* folder)); + if (folder == NULL) + goto err; + + strncpy(folder->mb_filename, mb_filename, PATH_MAX); + + folder->mb_mtime = (time_t) -1; + + folder->mb_fd = -1; + folder->mb_read_only = TRUE; + folder->mb_no_uid = TRUE; + + folder->mb_changed = FALSE; + folder->mb_deleted_count = 0; + + folder->mb_mapping = NULL; + folder->mb_mapping_size = 0; + + folder->mb_written_uid = 0; + folder->mb_max_uid = 0; + + folder->mb_hash = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY); + if (folder->mb_hash == NULL) + goto free; + + folder->mb_tab = carray_new(128); + if (folder->mb_tab == NULL) + goto free_hash; + + return folder; + + free_hash: + chash_free(folder->mb_hash); + free: + free(folder); + err: + return NULL; +} + +void mailmbox_folder_free(struct mailmbox_folder * folder) +{ + unsigned int i; + + for(i = 0 ; i < carray_count(folder->mb_tab) ; i++) { + struct mailmbox_msg_info * info; + + info = carray_get(folder->mb_tab, i); + if (info != NULL) + mailmbox_msg_info_free(info); + } + + carray_free(folder->mb_tab); + + chash_free(folder->mb_hash); + + free(folder); +} diff --git a/libetpan/src/low-level/mbox/mailmbox_types.h b/libetpan/src/low-level/mbox/mailmbox_types.h new file mode 100644 index 0000000..4ce241d --- a/dev/null +++ b/libetpan/src/low-level/mbox/mailmbox_types.h @@ -0,0 +1,143 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MAILMBOX_TYPES_H + +#define MAILMBOX_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> + +#include <libetpan/libetpan-config.h> + +#include <libetpan/mailimf.h> +#include <libetpan/carray.h> +#include <libetpan/chash.h> + +enum { + MAILMBOX_NO_ERROR = 0, + MAILMBOX_ERROR_PARSE, + MAILMBOX_ERROR_INVAL, + MAILMBOX_ERROR_FILE_NOT_FOUND, + MAILMBOX_ERROR_MEMORY, + MAILMBOX_ERROR_TEMPORARY_FILE, + MAILMBOX_ERROR_FILE, + MAILMBOX_ERROR_MSG_NOT_FOUND, + MAILMBOX_ERROR_READONLY, +}; + + +struct mailmbox_folder { + char mb_filename[PATH_MAX]; + + time_t mb_mtime; + + int mb_fd; + int mb_read_only; + int mb_no_uid; + + int mb_changed; + unsigned int mb_deleted_count; + + char * mb_mapping; + size_t mb_mapping_size; + + uint32_t mb_written_uid; + uint32_t mb_max_uid; + + chash * mb_hash; + carray * mb_tab; +}; + +struct mailmbox_folder * mailmbox_folder_new(const char * mb_filename); +void mailmbox_folder_free(struct mailmbox_folder * folder); + + +struct mailmbox_msg_info { + unsigned int msg_index; + uint32_t msg_uid; + int msg_written_uid; + int msg_deleted; + + size_t msg_start; + size_t msg_start_len; + + size_t msg_headers; + size_t msg_headers_len; + + size_t msg_body; + size_t msg_body_len; + + size_t msg_size; + + size_t msg_padding; +}; + + +int mailmbox_msg_info_update(struct mailmbox_folder * folder, + size_t msg_start, size_t msg_start_len, + size_t msg_headers, size_t msg_headers_len, + size_t msg_body, size_t msg_body_len, + size_t msg_size, size_t msg_padding, + uint32_t msg_uid); + +struct mailmbox_msg_info * +mailmbox_msg_info_new(size_t msg_start, size_t msg_start_len, + size_t msg_headers, size_t msg_headers_len, + size_t msg_body, size_t msg_body_len, + size_t msg_size, size_t msg_padding, + uint32_t msg_uid); + +void mailmbox_msg_info_free(struct mailmbox_msg_info * info); + +struct mailmbox_append_info { + const char * ai_message; + size_t ai_size; + unsigned int ai_uid; +}; + +struct mailmbox_append_info * +mailmbox_append_info_new(const char * ai_message, size_t ai_size); + +void mailmbox_append_info_free(struct mailmbox_append_info * info); + +#ifdef __cplusplus +} +#endif + +#endif |