-rw-r--r-- | kmicromail/libetpan/mbox/mailmbox.c | 21 | ||||
-rw-r--r-- | kmicromail/libetpan/mbox/mailmbox.h | 4 | ||||
-rw-r--r-- | kmicromail/libetpan/mbox/mailmbox_types.c | 3 | ||||
-rw-r--r-- | kmicromail/libetpan/mbox/mailmbox_types.h | 1 |
4 files changed, 25 insertions, 4 deletions
diff --git a/kmicromail/libetpan/mbox/mailmbox.c b/kmicromail/libetpan/mbox/mailmbox.c index 280c313..b3fce02 100644 --- a/kmicromail/libetpan/mbox/mailmbox.c +++ b/kmicromail/libetpan/mbox/mailmbox.c @@ -1,1424 +1,1439 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - 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 REGENTS 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 REGENTS 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(struct mailmbox_folder * folder, - const char * data, size_t len) +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; } int mailmbox_expunge_no_lock(struct mailmbox_folder * folder) { char tmpfile[PATH_MAX]; int r; int res; int dest_fd; size_t size; 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); dest_fd = mkstemp(tmpfile); if (dest_fd < 0) { res = MAILMBOX_ERROR_FILE; goto unlink; } 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) { res = r; goto err; } 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/kmicromail/libetpan/mbox/mailmbox.h b/kmicromail/libetpan/mbox/mailmbox.h index 8be086c..0427f1f 100644 --- a/kmicromail/libetpan/mbox/mailmbox.h +++ b/kmicromail/libetpan/mbox/mailmbox.h @@ -1,140 +1,144 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - 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 REGENTS 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 REGENTS 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/kmicromail/libetpan/mbox/mailmbox_types.c b/kmicromail/libetpan/mbox/mailmbox_types.c index 1986182..4e3e521 100644 --- a/kmicromail/libetpan/mbox/mailmbox_types.c +++ b/kmicromail/libetpan/mbox/mailmbox_types.c @@ -1,250 +1,251 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - 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 REGENTS 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 REGENTS 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/kmicromail/libetpan/mbox/mailmbox_types.h b/kmicromail/libetpan/mbox/mailmbox_types.h index dd6758c..bd6ee30 100644 --- a/kmicromail/libetpan/mbox/mailmbox_types.h +++ b/kmicromail/libetpan/mbox/mailmbox_types.h @@ -1,142 +1,143 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - 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 REGENTS 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 REGENTS 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 |