-rw-r--r-- | kmicromail/libetpan/mh/mailmh.c | 28 | ||||
-rw-r--r-- | kmicromail/libetpan/mh/mailmh.h | 7 |
2 files changed, 29 insertions, 6 deletions
diff --git a/kmicromail/libetpan/mh/mailmh.c b/kmicromail/libetpan/mh/mailmh.c index d6ff950..119f217 100644 --- a/kmicromail/libetpan/mh/mailmh.c +++ b/kmicromail/libetpan/mh/mailmh.c @@ -470,496 +470,512 @@ int mailmh_folder_update(struct mailmh_folder * folder) free(mh_seq); closedir(d); return MAILMH_NO_ERROR; closedir: closedir(d); err: return res; } int mailmh_folder_add_subfolder(struct mailmh_folder * parent, const char * name) { char * foldername; int r; struct mailmh_folder * folder; unsigned int array_index; chashdatum key; chashdatum data; foldername = malloc(strlen(parent->fl_filename) + strlen(name) + 2); if (foldername == NULL) return MAILMH_ERROR_MEMORY; strcpy(foldername, parent->fl_filename); strcat(foldername, MAIL_DIR_SEPARATOR_S); strcat(foldername, name); r = mkdir(foldername, 0700); free(foldername); if (r < 0) return MAILMH_ERROR_FOLDER; folder = mailmh_folder_new(parent, name); if (folder == NULL) return MAILMH_ERROR_MEMORY; r = carray_add(parent->fl_subfolders_tab, folder, &array_index); if (r < 0) { mailmh_folder_free(folder); return MAILMH_ERROR_MEMORY; } folder->fl_array_index = array_index; key.data = folder->fl_filename; key.len = strlen(folder->fl_filename); data.data = folder; data.len = 0; r = chash_set(parent->fl_subfolders_hash, &key, &data, NULL); if (r < 0) { carray_delete_fast(folder->fl_subfolders_tab, folder->fl_array_index); mailmh_folder_free(folder); return MAILMH_ERROR_MEMORY; } return MAILMH_NO_ERROR; } int mailmh_folder_remove_subfolder(struct mailmh_folder * folder) { struct mailmh_folder * parent; chashdatum key; chashdatum data; int r; parent = folder->fl_parent; key.data = folder->fl_filename; key.len = strlen(folder->fl_filename); r = chash_get(parent->fl_subfolders_hash, &key, &data); if (r < 0) return MAILMH_ERROR_FOLDER; chash_delete(parent->fl_subfolders_hash, &key, NULL); carray_delete_fast(parent->fl_subfolders_tab, folder->fl_array_index); mailmh_folder_free(folder); return MAILMH_NO_ERROR; } int mailmh_folder_rename_subfolder(struct mailmh_folder * src_folder, struct mailmh_folder * dst_folder, const char * new_name) { int r; struct mailmh_folder * folder; struct mailmh_folder * parent; char * new_foldername; parent = src_folder->fl_parent; if (parent == NULL) return MAILMH_ERROR_RENAME; new_foldername = malloc(strlen(dst_folder->fl_filename) + 2 + strlen(new_name)); if (new_foldername == NULL) return MAILMH_ERROR_MEMORY; strcpy(new_foldername, dst_folder->fl_filename); strcat(new_foldername, MAIL_DIR_SEPARATOR_S); strcat(new_foldername, new_name); r = rename(src_folder->fl_filename, new_foldername); free(new_foldername); if (r < 0) return MAILMH_ERROR_RENAME; r = mailmh_folder_remove_subfolder(src_folder); if (r != MAILMH_NO_ERROR) return r; folder = mailmh_folder_new(dst_folder, new_name); if (folder == NULL) return MAILMH_ERROR_MEMORY; r = carray_add(parent->fl_subfolders_tab, folder, NULL); if (r < 0) { mailmh_folder_free(folder); return MAILMH_ERROR_MEMORY; } return MAILMH_NO_ERROR; } #define MAX_TRY_ALLOC 32 /* initial file MUST be in the same directory */ static int mailmh_folder_alloc_msg(struct mailmh_folder * folder, char * filename, uint32_t * result) { uint32_t max; uint32_t k; char * new_filename; size_t len; len = strlen(folder->fl_filename) + 20; new_filename = malloc(len); if (new_filename == NULL) return MAILMH_ERROR_MEMORY; max = folder->fl_max_index + 1; k = 0; while (k < MAX_TRY_ALLOC) { snprintf(new_filename, len, "%s%c%lu", folder->fl_filename, MAIL_DIR_SEPARATOR, (unsigned long) (max + k)); if (link(filename, new_filename) == 0) { int r; free(new_filename); unlink(filename); if (k > MAX_TRY_ALLOC / 2) { r = mailmh_folder_update(folder); /* ignore errors */ } * result = max + k; folder->fl_max_index = max + k; return MAILMH_NO_ERROR; } else if (errno == EXDEV) { free(filename); return MAILMH_ERROR_FOLDER; } k ++; } free(new_filename); return MAILMH_ERROR_FOLDER; } int mailmh_folder_get_message_filename(struct mailmh_folder * folder, uint32_t index, char ** result) { char * filename; int len; #if 0 r = mailmh_folder_update(folder); if (r != MAILMH_NO_ERROR) return r; #endif len = strlen(folder->fl_filename) + 20; filename = malloc(len); if (filename == NULL) return MAILMH_ERROR_MEMORY; snprintf(filename, len, "%s%c%lu", folder->fl_filename, MAIL_DIR_SEPARATOR, (unsigned long) index); * result = filename; return MAILMH_NO_ERROR;; } int mailmh_folder_get_message_fd(struct mailmh_folder * folder, uint32_t index, int flags, int * result) { char * filename; int fd; int r; #if 0 r = mailmh_folder_update(folder); if (r != MAILMH_NO_ERROR) return r; #endif r = mailmh_folder_get_message_filename(folder, index, &filename); if (r != MAILMH_NO_ERROR) return r; fd = open(filename, flags); free(filename); if (fd == -1) return MAILMH_ERROR_MSG_NOT_FOUND; * result = fd; return MAILMH_NO_ERROR; } int mailmh_folder_get_message_size(struct mailmh_folder * folder, uint32_t index, size_t * result) { int r; char * filename; struct stat buf; r = mailmh_folder_get_message_filename(folder, index, &filename); if (r != MAILMH_NO_ERROR) return r; r = stat(filename, &buf); free(filename); if (r < 0) return MAILMH_ERROR_FILE; * result = buf.st_size; return MAILMH_NO_ERROR; } -int mailmh_folder_add_message(struct mailmh_folder * folder, - const char * message, size_t size) +int mailmh_folder_add_message_uid(struct mailmh_folder * folder, + const char * message, size_t size, + uint32_t * pindex) { char * tmpname; int fd; size_t namesize; size_t left; ssize_t res; struct mailmh_msg_info * msg_info; uint32_t index; int error; int r; unsigned int array_index; struct stat buf; chashdatum key; chashdatum data; #if 0 r = mailmh_folder_update(folder); if (r != MAILMH_NO_ERROR) { error = r; goto err; } #endif namesize = strlen(folder->fl_filename) + 20; tmpname = malloc(namesize); snprintf(tmpname, namesize, "%s%ctmpXXXXXX", folder->fl_filename, MAIL_DIR_SEPARATOR); fd = mkstemp(tmpname); if (fd < 0) { error = MAILMH_ERROR_FILE; goto free; } left = size; while (left > 0) { res = write(fd, message, left); if (res == -1) { close(fd); error = MAILMH_ERROR_FILE; goto free; } left -= res; } close(fd); r = stat(tmpname, &buf); if (r < 0) { error = MAILMH_ERROR_FILE; goto free; } r = mailmh_folder_alloc_msg(folder, tmpname, &index); if (r != MAILMH_NO_ERROR) { unlink(tmpname); error = MAILMH_ERROR_COULD_NOT_ALLOC_MSG; goto free; } free(tmpname); msg_info = mailmh_msg_info_new(index, size, buf.st_mtime); if (msg_info == NULL) { mailmh_folder_remove_message(folder, index); error = MAILMH_ERROR_MEMORY; goto err; } r = carray_add(folder->fl_msgs_tab, msg_info, &array_index); if (r < 0) { mailmh_folder_remove_message(folder, index); mailmh_msg_info_free(msg_info); error = MAILMH_ERROR_MEMORY; goto err; } msg_info->msg_array_index = array_index; #if 0 r = cinthash_add(folder->fl_msgs_hash, index, msg_info); #endif key.data = &index; key.len = sizeof(index); data.data = msg_info; data.len = 0; + if (pindex != NULL) + * pindex = index; + r = chash_set(folder->fl_msgs_hash, &key, &data, NULL); if (r < 0) { carray_delete_fast(folder->fl_msgs_tab, msg_info->msg_array_index); mailmh_msg_info_free(msg_info); error = MAILMH_ERROR_MEMORY; goto err; } return MAILMH_NO_ERROR; free: free(tmpname); err: return error; } -int mailmh_folder_add_message_file(struct mailmh_folder * folder, - int fd) +int mailmh_folder_add_message(struct mailmh_folder * folder, + const char * message, size_t size) +{ + return mailmh_folder_add_message_uid(folder, message, size, NULL); +} + +int mailmh_folder_add_message_file_uid(struct mailmh_folder * folder, + int fd, uint32_t * pindex) { char * message; struct stat buf; int r; #if 0 r = mailmh_folder_update(folder); if (r != MAILMH_NO_ERROR) return r; #endif if (fstat(fd, &buf) == -1) return MAILMH_ERROR_FILE; message = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (message == MAP_FAILED) return MAILMH_ERROR_FILE; - r = mailmh_folder_add_message(folder, message, buf.st_size); - + r = mailmh_folder_add_message_uid(folder, message, buf.st_size, pindex); + munmap(message, buf.st_size); return r; } +int mailmh_folder_add_message_file(struct mailmh_folder * folder, + int fd) +{ + return mailmh_folder_add_message_file_uid(folder, fd, NULL); +} + int mailmh_folder_remove_message(struct mailmh_folder * folder, uint32_t index) { char * filename; struct mailmh_msg_info * msg_info; int res; int r; chashdatum key; chashdatum data; #if 0 r = mailmh_folder_update(folder); if (r != MAILMH_NO_ERROR) { res = r; goto err; } #endif r = mailmh_folder_get_message_filename(folder, index, &filename); if (filename == NULL) { res = r; goto err; } if (unlink(filename) == -1) { res = MAILMH_ERROR_FILE; goto free; } key.data = &index; key.len = sizeof(index); r = chash_get(folder->fl_msgs_hash, &key, &data); #if 0 msg_info = cinthash_find(folder->fl_msgs_hash, index); #endif if (r == 0) { msg_info = data.data; carray_delete_fast(folder->fl_msgs_tab, msg_info->msg_array_index); #if 0 cinthash_remove(folder->fl_msgs_hash, index); #endif chash_delete(folder->fl_msgs_hash, &key, NULL); } return MAILMH_NO_ERROR; free: free(filename); err: return res; } int mailmh_folder_move_message(struct mailmh_folder * dest_folder, struct mailmh_folder * src_folder, uint32_t index) { int fd; char * filename; int r; #if 0 r = mailmh_folder_update(dest_folder); if (r != MAILMH_NO_ERROR) return r; r = mailmh_folder_update(src_folder); if (r != MAILMH_NO_ERROR) return r; #endif /* move on the same filesystem */ r = mailmh_folder_get_message_filename(src_folder, index, &filename); if (r != MAILMH_NO_ERROR) return r; r = mailmh_folder_alloc_msg(dest_folder, filename, &index); free(filename); if (r == MAILMH_NO_ERROR) return MAILMH_NO_ERROR; /* move on the different filesystems */ r = mailmh_folder_get_message_fd(src_folder, index, O_RDONLY, &fd); if (r != MAILMH_NO_ERROR) return r; r = mailmh_folder_add_message_file(dest_folder, fd); if (r != MAILMH_NO_ERROR) { close(fd); return r; } close(fd); r = mailmh_folder_remove_message(src_folder, index); return MAILMH_NO_ERROR; } unsigned int mailmh_folder_get_message_number(struct mailmh_folder * folder) { unsigned int i; unsigned int count; count = 0; for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i ++) if (carray_get(folder->fl_msgs_tab, i) != NULL) count ++; return count; } diff --git a/kmicromail/libetpan/mh/mailmh.h b/kmicromail/libetpan/mh/mailmh.h index 40432cb..00199b8 100644 --- a/kmicromail/libetpan/mh/mailmh.h +++ b/kmicromail/libetpan/mh/mailmh.h @@ -1,143 +1,150 @@ /* * 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 MAILMH_H #define MAILMH_H #ifdef __cplusplus extern "C" { #endif #include <sys/types.h> #include <inttypes.h> #include <libetpan/carray.h> #include <libetpan/cinthash.h> #include <libetpan/chash.h> enum { MAILMH_NO_ERROR = 0, MAILMH_ERROR_FOLDER, MAILMH_ERROR_MEMORY, MAILMH_ERROR_FILE, MAILMH_ERROR_COULD_NOT_ALLOC_MSG, MAILMH_ERROR_RENAME, MAILMH_ERROR_MSG_NOT_FOUND, }; struct mailmh { struct mailmh_folder * mh_main; }; struct mailmh_msg_info { unsigned int msg_array_index; uint32_t msg_index; size_t msg_size; time_t msg_mtime; }; struct mailmh_folder { char * fl_filename; unsigned int fl_array_index; char * fl_name; time_t fl_mtime; struct mailmh_folder * fl_parent; uint32_t fl_max_index; carray * fl_msgs_tab; #if 0 cinthash_t * fl_msgs_hash; #endif chash * fl_msgs_hash; carray * fl_subfolders_tab; chash * fl_subfolders_hash; }; struct mailmh * mailmh_new(const char * foldername); void mailmh_free(struct mailmh * f); struct mailmh_msg_info * mailmh_msg_info_new(uint32_t index, size_t size, time_t mtime); void mailmh_msg_info_free(struct mailmh_msg_info * msg_info); struct mailmh_folder * mailmh_folder_new(struct mailmh_folder * parent, const char * name); void mailmh_folder_free(struct mailmh_folder * folder); int mailmh_folder_add_subfolder(struct mailmh_folder * parent, const char * name); struct mailmh_folder * mailmh_folder_find(struct mailmh_folder * root, const char * filename); int mailmh_folder_remove_subfolder(struct mailmh_folder * folder); int mailmh_folder_rename_subfolder(struct mailmh_folder * src_folder, struct mailmh_folder * dst_folder, const char * new_name); int mailmh_folder_get_message_filename(struct mailmh_folder * folder, uint32_t index, char ** result); int mailmh_folder_get_message_fd(struct mailmh_folder * folder, uint32_t index, int flags, int * result); int mailmh_folder_get_message_size(struct mailmh_folder * folder, uint32_t index, size_t * result); +int mailmh_folder_add_message_uid(struct mailmh_folder * folder, + const char * message, size_t size, + uint32_t * pindex); + int mailmh_folder_add_message(struct mailmh_folder * folder, const char * message, size_t size); +int mailmh_folder_add_message_file_uid(struct mailmh_folder * folder, + int fd, uint32_t * pindex); + int mailmh_folder_add_message_file(struct mailmh_folder * folder, int fd); int mailmh_folder_remove_message(struct mailmh_folder * folder, uint32_t index); int mailmh_folder_move_message(struct mailmh_folder * dest_folder, struct mailmh_folder * src_folder, uint32_t index); int mailmh_folder_update(struct mailmh_folder * folder); unsigned int mailmh_folder_get_message_number(struct mailmh_folder * folder); #ifdef __cplusplus } #endif #endif |