Diffstat (limited to 'libetpan/src/driver/implementation/mh') (more/less context) (ignore whitespace changes)
-rw-r--r-- | libetpan/src/driver/implementation/mh/mhdriver.c | 875 | ||||
-rw-r--r-- | libetpan/src/driver/implementation/mh/mhdriver.h | 52 | ||||
-rw-r--r-- | libetpan/src/driver/implementation/mh/mhdriver_cached.c | 1315 | ||||
-rw-r--r-- | libetpan/src/driver/implementation/mh/mhdriver_cached.h | 52 | ||||
-rw-r--r-- | libetpan/src/driver/implementation/mh/mhdriver_cached_message.c | 338 | ||||
-rw-r--r-- | libetpan/src/driver/implementation/mh/mhdriver_cached_message.h | 52 | ||||
-rw-r--r-- | libetpan/src/driver/implementation/mh/mhdriver_message.c | 213 | ||||
-rw-r--r-- | libetpan/src/driver/implementation/mh/mhdriver_message.h | 52 | ||||
-rw-r--r-- | libetpan/src/driver/implementation/mh/mhdriver_tools.c | 484 | ||||
-rw-r--r-- | libetpan/src/driver/implementation/mh/mhdriver_tools.h | 80 | ||||
-rw-r--r-- | libetpan/src/driver/implementation/mh/mhdriver_types.h | 100 | ||||
-rw-r--r-- | libetpan/src/driver/implementation/mh/mhstorage.c | 192 | ||||
-rw-r--r-- | libetpan/src/driver/implementation/mh/mhstorage.h | 67 |
13 files changed, 3872 insertions, 0 deletions
diff --git a/libetpan/src/driver/implementation/mh/mhdriver.c b/libetpan/src/driver/implementation/mh/mhdriver.c new file mode 100644 index 0000000..c44afc9 --- a/dev/null +++ b/libetpan/src/driver/implementation/mh/mhdriver.c @@ -0,0 +1,875 @@ +/* + * 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 "mhdriver.h" + +#include <stdio.h> +#include <sys/types.h> +#include <dirent.h> +#include <unistd.h> +#include <sys/stat.h> +#include <ctype.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <stdlib.h> +#include <string.h> + +#include "mailmh.h" +#include "maildriver_tools.h" +#include "mhdriver_tools.h" +#include "mhdriver_message.h" +#include "mailmessage.h" + +static int mhdriver_initialize(mailsession * session); + +static void mhdriver_uninitialize(mailsession * session); + +static int mhdriver_connect_path(mailsession * session, char * path); +static int mhdriver_logout(mailsession * session); + +static int mhdriver_build_folder_name(mailsession * session, char * mb, + char * name, char ** result); +static int mhdriver_create_folder(mailsession * session, char * mb); + +static int mhdriver_delete_folder(mailsession * session, char * mb); + +static int mhdriver_rename_folder(mailsession * session, char * mb, + char * new_name); + +static int mhdriver_select_folder(mailsession * session, char * mb); + +static int mhdriver_status_folder(mailsession * session, char * mb, + uint32_t * result_messages, uint32_t * result_recent, + uint32_t * result_unseen); + +static int mhdriver_messages_number(mailsession * session, char * mb, + uint32_t * result); + +static int mhdriver_list_folders(mailsession * session, char * mb, + struct mail_list ** result); + +static int mhdriver_lsub_folders(mailsession * session, char * mb, + struct mail_list ** result); + +static int mhdriver_subscribe_folder(mailsession * session, char * mb); + +static int mhdriver_unsubscribe_folder(mailsession * session, char * mb); + +static int mhdriver_append_message(mailsession * session, + char * message, size_t size); +static int mhdriver_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags); +static int mhdriver_copy_message(mailsession * session, + uint32_t num, char * mb); + +static int mhdriver_remove_message(mailsession * session, uint32_t num); + +static int mhdriver_move_message(mailsession * session, + uint32_t num, char * mb); + +static int mhdriver_get_messages_list(mailsession * session, + struct mailmessage_list ** result); + +static int mhdriver_get_message(mailsession * session, + uint32_t num, mailmessage ** result); + +static int mhdriver_get_message_by_uid(mailsession * session, + const char * uid, + mailmessage ** result); + +static mailsession_driver local_mh_session_driver = { + .sess_name = "mh", + + .sess_initialize = mhdriver_initialize, + .sess_uninitialize = mhdriver_uninitialize, + + .sess_parameters = NULL, + + .sess_connect_stream = NULL, + .sess_connect_path = mhdriver_connect_path, + .sess_starttls = NULL, + .sess_login = NULL, + .sess_logout = mhdriver_logout, + .sess_noop = NULL, + + .sess_build_folder_name = mhdriver_build_folder_name, + .sess_create_folder = mhdriver_create_folder, + .sess_delete_folder = mhdriver_delete_folder, + .sess_rename_folder = mhdriver_rename_folder, + .sess_check_folder = NULL, + .sess_examine_folder = NULL, + .sess_select_folder = mhdriver_select_folder, + .sess_expunge_folder = NULL, + .sess_status_folder = mhdriver_status_folder, + .sess_messages_number = mhdriver_messages_number, + .sess_recent_number = mhdriver_messages_number, + .sess_unseen_number = mhdriver_messages_number, + .sess_list_folders = mhdriver_list_folders, + .sess_lsub_folders = mhdriver_lsub_folders, + .sess_subscribe_folder = mhdriver_subscribe_folder, + .sess_unsubscribe_folder = mhdriver_unsubscribe_folder, + + .sess_append_message = mhdriver_append_message, + .sess_append_message_flags = mhdriver_append_message_flags, + .sess_copy_message = mhdriver_copy_message, + .sess_move_message = mhdriver_move_message, + + .sess_get_messages_list = mhdriver_get_messages_list, + .sess_get_envelopes_list = maildriver_generic_get_envelopes_list, + .sess_remove_message = mhdriver_remove_message, +#if 0 + .sess_search_messages = maildriver_generic_search_messages, +#endif + + .sess_get_message = mhdriver_get_message, + .sess_get_message_by_uid = mhdriver_get_message_by_uid, +}; + +mailsession_driver * mh_session_driver = &local_mh_session_driver; + +static inline struct mh_session_state_data * get_data(mailsession * session) +{ + return session->sess_data; +} + +static inline struct mailmh * get_mh_session(mailsession * session) +{ + return get_data(session)->mh_session; +} + +static inline struct mailmh_folder * get_mh_cur_folder(mailsession * session) +{ + return get_data(session)->mh_cur_folder; +} + +static int add_to_list(mailsession * session, char * mb) +{ + char * new_mb; + struct mh_session_state_data * data; + int r; + + data = get_data(session); + + new_mb = strdup(mb); + if (new_mb == NULL) + return -1; + + r = clist_append(data->mh_subscribed_list, new_mb); + if (r < 0) { + free(mb); + return -1; + } + + return 0; +} + +static int remove_from_list(mailsession * session, char * mb) +{ + clistiter * cur; + struct mh_session_state_data * data; + + data = get_data(session); + + for(cur = clist_begin(data->mh_subscribed_list) ; + cur != NULL ; cur = clist_next(cur)) { + char * cur_name; + + cur_name = clist_content(cur); + if (strcmp(cur_name, mb) == 0) { + clist_delete(data->mh_subscribed_list, cur); + free(cur_name); + return 0; + } + } + + return -1; +} + +static int mhdriver_initialize(mailsession * session) +{ + struct mh_session_state_data * data; + + data = malloc(sizeof(* data)); + if (data == NULL) + goto err; + + data->mh_session = NULL; + data->mh_cur_folder = NULL; + + data->mh_subscribed_list = clist_new(); + if (data->mh_subscribed_list == NULL) + goto free; + + session->sess_data = data; + + return MAIL_NO_ERROR; + + free: + free(data); + err: + return MAIL_ERROR_MEMORY; +} + +static void mhdriver_uninitialize(mailsession * session) +{ + struct mh_session_state_data * data; + + data = get_data(session); + + if (data->mh_session != NULL) + mailmh_free(data->mh_session); + + clist_foreach(data->mh_subscribed_list, (clist_func) free, NULL); + clist_free(data->mh_subscribed_list); + + free(data); + + session->sess_data = NULL; +} + + +static int mhdriver_connect_path(mailsession * session, char * path) +{ + struct mailmh * mh; + + if (get_mh_session(session) != NULL) + return MAIL_ERROR_BAD_STATE; + + mh = mailmh_new(path); + if (mh == NULL) + return MAIL_ERROR_MEMORY; + + get_data(session)->mh_session = mh; + + return MAIL_NO_ERROR; +} + +static int mhdriver_logout(mailsession * session) +{ + struct mailmh * mh; + + mh = get_mh_session(session); + + if (mh == NULL) + return MAIL_ERROR_BAD_STATE; + + mailmh_free(mh); + get_data(session)->mh_session = NULL; + + return MAIL_NO_ERROR; +} + +/* folders operations */ + +static int mhdriver_build_folder_name(mailsession * session, char * mb, + char * name, char ** result) +{ + char * folder_name; + + folder_name = malloc(strlen(mb) + 2 + strlen(name)); + if (folder_name == NULL) + return MAIL_ERROR_MEMORY; + + strcpy(folder_name, mb); + strcat(folder_name, "/"); + strcat(folder_name, name); + + * result = folder_name; + + return MAIL_NO_ERROR; +} + +static int get_parent(mailsession * session, char * mb, + struct mailmh_folder ** result_folder, + char ** result_name) +{ + char * name; + size_t length; + int i; + char * parent_name; + struct mailmh_folder * parent; + struct mailmh * mh; + + mh = get_mh_session(session); + if (mh == NULL) + return MAIL_ERROR_BAD_STATE; + + length = strlen(mb); + for(i = length - 1 ; i >= 0 ; i--) + if (mb[i] == '/') + break; + name = mb + i + 1; + + parent_name = malloc(i + 1); + /* strndup(mb, i) */ + if (parent_name == NULL) + return MAIL_ERROR_MEMORY; + + strncpy(parent_name, mb, i); + parent_name[i] = '\0'; + + parent = mailmh_folder_find(mh->mh_main, parent_name); + free(parent_name); + if (parent == NULL) + return MAIL_ERROR_FOLDER_NOT_FOUND; + + * result_folder = parent; + * result_name = name; + + return MAIL_NO_ERROR; +} + +static int mhdriver_create_folder(mailsession * session, char * mb) +{ + int r; + struct mailmh_folder * parent; + char * name; + + r = get_parent(session, mb, &parent, &name); + if (r != MAIL_NO_ERROR) + return r; + + r = mailmh_folder_add_subfolder(parent, name); + + return mhdriver_mh_error_to_mail_error(r); +} + +static int mhdriver_delete_folder(mailsession * session, char * mb) +{ + int r; + struct mailmh_folder * folder; + struct mailmh * mh; + + mh = get_mh_session(session); + if (mh == NULL) + return MAIL_ERROR_BAD_STATE; + + folder = mailmh_folder_find(mh->mh_main, mb); + if (folder == NULL) + return MAIL_ERROR_FOLDER_NOT_FOUND; + + if (get_mh_cur_folder(session) == folder) + get_data(session)->mh_cur_folder = NULL; + + r = mailmh_folder_remove_subfolder(folder); + + return mhdriver_mh_error_to_mail_error(r); +} + +static int mhdriver_rename_folder(mailsession * session, char * mb, + char * new_name) +{ + struct mailmh_folder * src_folder; + struct mailmh_folder * dst_folder; + char * name; + struct mailmh * mh; + int r; + + r = get_parent(session, new_name, &dst_folder, &name); + if (r != MAIL_NO_ERROR) + return r; + + mh = get_mh_session(session); + if (mh == NULL) + return MAIL_ERROR_BAD_STATE; + + src_folder = mailmh_folder_find(mh->mh_main, mb); + if (src_folder == NULL) + return MAIL_ERROR_FOLDER_NOT_FOUND; + + if (get_mh_cur_folder(session) == src_folder) + get_data(session)->mh_cur_folder = NULL; + + r = mailmh_folder_rename_subfolder(src_folder, dst_folder, name); + + return mhdriver_mh_error_to_mail_error(r); +} + +static int mhdriver_select_folder(mailsession * session, char * mb) +{ + struct mailmh_folder * folder; + struct mailmh * mh; + int r; + + mh = get_mh_session(session); + if (mh == NULL) + return MAIL_ERROR_BAD_STATE; + + r = mailmh_folder_update(mh->mh_main); + + folder = mailmh_folder_find(mh->mh_main, mb); + if (folder == NULL) + return MAIL_ERROR_FOLDER_NOT_FOUND; + + get_data(session)->mh_cur_folder = folder; + r = mailmh_folder_update(folder); + + return mhdriver_mh_error_to_mail_error(r); +} + +static int mhdriver_status_folder(mailsession * session, char * mb, + uint32_t * result_messages, uint32_t * result_recent, + uint32_t * result_unseen) +{ + uint32_t count; + int r; + + r = mhdriver_messages_number(session, mb, &count); + if (r != MAIL_NO_ERROR) + return r; + + * result_messages = count; + * result_recent = count; + * result_unseen = count; + + return MAIL_NO_ERROR; +} + +static int mhdriver_messages_number(mailsession * session, char * mb, + uint32_t * result) +{ + struct mailmh_folder * folder; + uint32_t count; + struct mailmh * mh; + unsigned int i; + + mh = get_mh_session(session); + if (mh == NULL) + return MAIL_ERROR_BAD_STATE; + + if (mb != NULL) { + folder = mailmh_folder_find(mh->mh_main, mb); + if (folder == NULL) + return MAIL_ERROR_FOLDER_NOT_FOUND; + } + else { + folder = get_mh_cur_folder(session); + if (folder == NULL) + return MAIL_ERROR_BAD_STATE; + } + + mailmh_folder_update(folder); + count = 0; + for (i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i ++) { + struct mailmh_msg_info * msg_info; + + msg_info = carray_get(folder->fl_msgs_tab, i); + if (msg_info != NULL) + count ++; + } + + * result = count; + + return MAIL_NO_ERROR; +} + + +static int get_list_folders(struct mailmh_folder * folder, clist ** result) +{ + unsigned int i; + clist * list; + char * new_filename; + int res; + int r; + + list = * result; + + new_filename = strdup(folder->fl_filename); + if (new_filename == NULL) { + res = MAIL_ERROR_MEMORY; + goto free; + } + + r = mailmh_folder_update(folder); + + switch (r) { + case MAILMH_NO_ERROR: + break; + + default: + res = mhdriver_mh_error_to_mail_error(r); + goto free; + } + + r = clist_append(list, new_filename); + if (r < 0) { + free(new_filename); + res = MAIL_ERROR_MEMORY; + goto free; + } + + if (folder->fl_subfolders_tab != NULL) { + for(i = 0 ; i < carray_count(folder->fl_subfolders_tab) ; i++) { + struct mailmh_folder * subfolder; + + subfolder = carray_get(folder->fl_subfolders_tab, i); + + r = get_list_folders(subfolder, &list); + if (r != MAIL_NO_ERROR) { + res = MAIL_ERROR_MEMORY; + goto free; + } + } + } + + * result = list; + + return MAIL_NO_ERROR; + + free: + clist_foreach(list, (clist_func) free, NULL); + clist_free(list); + return res; +} + + +static int mhdriver_list_folders(mailsession * session, char * mb, + struct mail_list ** result) +{ + clist * list; + int r; + struct mailmh * mh; + struct mail_list * ml; + + mh = get_mh_session(session); + + if (mh == NULL) + return MAIL_ERROR_BAD_STATE; + + list = clist_new(); + if (list == NULL) + return MAIL_ERROR_MEMORY; + + r = get_list_folders(mh->mh_main, &list); + if (r != MAIL_NO_ERROR) + return r; + + ml = mail_list_new(list); + if (ml == NULL) + goto free; + + * result = ml; + + return MAIL_NO_ERROR; + + free: + clist_foreach(list, (clist_func) free, NULL); + clist_free(list); + return MAIL_ERROR_MEMORY; +} + +static int mhdriver_lsub_folders(mailsession * session, char * mb, + struct mail_list ** result) +{ + clist * subscribed; + clist * lsub_result; + clistiter * cur; + struct mail_list * lsub; + size_t length; + int r; + + length = strlen(mb); + + subscribed = get_data(session)->mh_subscribed_list; + + lsub_result = clist_new(); + if (lsub_result == NULL) + return MAIL_ERROR_MEMORY; + + for(cur = clist_begin(subscribed) ; cur != NULL ; + cur = clist_next(cur)) { + char * cur_mb; + char * new_mb; + + cur_mb = clist_content(cur); + + if (strncmp(mb, cur_mb, length) == 0) { + new_mb = strdup(cur_mb); + if (new_mb == NULL) + goto free_list; + + r = clist_append(lsub_result, new_mb); + if (r < 0) { + free(new_mb); + goto free_list; + } + } + } + + lsub = mail_list_new(lsub_result); + if (lsub == NULL) + goto free_list; + + * result = lsub; + + return MAIL_NO_ERROR; + + free_list: + clist_foreach(lsub_result, (clist_func) free, NULL); + clist_free(lsub_result); + return MAIL_ERROR_MEMORY; +} + +static int mhdriver_subscribe_folder(mailsession * session, char * mb) +{ + int r; + + r = add_to_list(session, mb); + if (r < 0) + return MAIL_ERROR_SUBSCRIBE; + + return MAIL_NO_ERROR; +} + +static int mhdriver_unsubscribe_folder(mailsession * session, char * mb) +{ + int r; + + r = remove_from_list(session, mb); + if (r < 0) + return MAIL_ERROR_UNSUBSCRIBE; + + return MAIL_NO_ERROR; +} + +/* messages operations */ + +static int mhdriver_append_message(mailsession * session, + char * message, size_t size) +{ + int r; + struct mailmh_folder * folder; + + folder = get_mh_cur_folder(session); + if (folder == NULL) + return MAIL_ERROR_BAD_STATE; + + r = mailmh_folder_add_message(folder, message, size); + + switch (r) { + case MAILMH_ERROR_FILE: + return MAIL_ERROR_DISKSPACE; + + default: + return mhdriver_mh_error_to_mail_error(r); + } +} + +static int mhdriver_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags) +{ + return mhdriver_append_message(session, message, size); +} + +static int mhdriver_copy_message(mailsession * session, + uint32_t num, char * mb) +{ + int fd; + int r; + struct mailmh_folder * folder; + struct mailmh * mh; + int res; + + mh = get_mh_session(session); + if (mh == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + folder = get_mh_cur_folder(session); + if (folder == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + r = mailmh_folder_get_message_fd(folder, num, O_RDONLY, &fd); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + folder = mailmh_folder_find(mh->mh_main, mb); + if (folder == NULL) { + res = MAIL_ERROR_FOLDER_NOT_FOUND; + goto close; + } + + r = mailmh_folder_add_message_file(folder, fd); + if (r != MAIL_NO_ERROR) { + res = MAIL_ERROR_COPY; + goto close; + } + + close(fd); + + return MAIL_NO_ERROR; + + close: + close(fd); + err: + return res; +} + +static int mhdriver_remove_message(mailsession * session, uint32_t num) +{ + int r; + struct mailmh_folder * folder; + + folder = get_mh_cur_folder(session); + if (folder == NULL) + return MAIL_ERROR_DELETE; + + r = mailmh_folder_remove_message(folder, num); + + return mhdriver_mh_error_to_mail_error(r); +} + +static int mhdriver_move_message(mailsession * session, + uint32_t num, char * mb) +{ + int r; + struct mailmh_folder * src_folder; + struct mailmh_folder * dest_folder; + struct mailmh * mh; + + mh = get_mh_session(session); + if (mh == NULL) + return MAIL_ERROR_BAD_STATE; + + src_folder = get_mh_cur_folder(session); + if (src_folder == NULL) + return MAIL_ERROR_BAD_STATE; + + dest_folder = mailmh_folder_find(mh->mh_main, mb); + if (dest_folder == NULL) + return MAIL_ERROR_FOLDER_NOT_FOUND; + + r = mailmh_folder_move_message(dest_folder, src_folder, num); + + return mhdriver_mh_error_to_mail_error(r); +} + + +static int mhdriver_get_messages_list(mailsession * session, + struct mailmessage_list ** result) +{ + struct mailmh_folder * folder; + int res; + + folder = get_mh_cur_folder(session); + if (folder == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + mailmh_folder_update(folder); + return mh_get_messages_list(folder, session, mh_message_driver, result); + + err: + return res; +} + +static int mhdriver_get_message(mailsession * session, + uint32_t num, mailmessage ** result) +{ + mailmessage * msg_info; + int r; + + msg_info = mailmessage_new(); + if (msg_info == NULL) + return MAIL_ERROR_MEMORY; + + r = mailmessage_init(msg_info, session, mh_message_driver, num, 0); + if (r != MAIL_NO_ERROR) { + mailmessage_free(msg_info); + return r; + } + + * result = msg_info; + + return MAIL_NO_ERROR; +} + +static int mhdriver_get_message_by_uid(mailsession * session, + const char * uid, + mailmessage ** result) +{ + uint32_t index; + char *p; + struct mailmh_msg_info * mh_msg_info; + struct mh_session_state_data * mh_data; + chashdatum key; + chashdatum data; + int r; + time_t mtime; + char * mtime_p; + + if (uid == NULL) + return MAIL_ERROR_INVAL; + + index = strtoul(uid, &p, 10); + if (p == uid || * p != '-') + return MAIL_ERROR_INVAL; + + mh_data = session->sess_data; +#if 0 + mh_msg_info = cinthash_find(mh_data->mh_cur_folder->fl_msgs_hash, index); +#endif + key.data = &index; + key.len = sizeof(index); + r = chash_get(mh_data->mh_cur_folder->fl_msgs_hash, &key, &data); + if (r < 0) + return MAIL_ERROR_MSG_NOT_FOUND; + + mh_msg_info = data.data; + + mtime_p = p + 1; + + mtime = strtoul(mtime_p, &p, 10); + if ((* p == '-') && (mtime == mh_msg_info->msg_mtime)) { + size_t size; + char *size_p; + + size_p = p + 1; + size = strtoul(size_p, &p, 10); + if ((* p == '\0') && (size == mh_msg_info->msg_size)) + return mhdriver_get_message(session, index, result); + } + else if (* p != '-') { + return MAIL_ERROR_INVAL; + } + + return MAIL_ERROR_MSG_NOT_FOUND; +} diff --git a/libetpan/src/driver/implementation/mh/mhdriver.h b/libetpan/src/driver/implementation/mh/mhdriver.h new file mode 100644 index 0000000..a3f45f5 --- a/dev/null +++ b/libetpan/src/driver/implementation/mh/mhdriver.h @@ -0,0 +1,52 @@ +/* + * 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 MHDRIVER_H + +#define MHDRIVER_H + +#include <libetpan/maildriver.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailsession_driver * mh_session_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/mh/mhdriver_cached.c b/libetpan/src/driver/implementation/mh/mhdriver_cached.c new file mode 100644 index 0000000..1e5c28b --- a/dev/null +++ b/libetpan/src/driver/implementation/mh/mhdriver_cached.c @@ -0,0 +1,1315 @@ +/* + * 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 "mhdriver_cached.h" + +#include <stdio.h> +#include <sys/types.h> +#include <dirent.h> +#include <unistd.h> +#include <sys/stat.h> +#include <ctype.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <stdlib.h> +#include <string.h> + +#include "mail.h" +#include "mail_cache_db.h" + +#include "generic_cache.h" +#include "imfcache.h" +#include "mhdriver.h" + +#include "mhdriver_cached_message.h" +#include "mailmh.h" +#include "maildriver_tools.h" +#include "mhdriver_tools.h" +#include "mailmessage.h" + +static int mhdriver_cached_initialize(mailsession * session); + +static void mhdriver_cached_uninitialize(mailsession * session); + +static int mhdriver_cached_parameters(mailsession * session, + int id, void * value); + +static int mhdriver_cached_connect_path(mailsession * session, char * path); +static int mhdriver_cached_logout(mailsession * session); + +static int mhdriver_cached_build_folder_name(mailsession * session, char * mb, + char * name, char ** result); +static int mhdriver_cached_create_folder(mailsession * session, char * mb); + +static int mhdriver_cached_delete_folder(mailsession * session, char * mb); + +static int mhdriver_cached_rename_folder(mailsession * session, char * mb, + char * new_name); + +static int mhdriver_cached_check_folder(mailsession * session); + +static int mhdriver_cached_select_folder(mailsession * session, char * mb); + +static int mhdriver_cached_expunge_folder(mailsession * session); + +static int mhdriver_cached_status_folder(mailsession * session, char * mb, + uint32_t * result_messages, uint32_t * result_recent, + uint32_t * result_unseen); + +static int mhdriver_cached_messages_number(mailsession * session, char * mb, + uint32_t * result); +static int mhdriver_cached_recent_number(mailsession * session, char * mb, + uint32_t * result); +static int mhdriver_cached_unseen_number(mailsession * session, char * mb, + uint32_t * result); + +static int mhdriver_cached_list_folders(mailsession * session, char * mb, + struct mail_list ** result); + +static int mhdriver_cached_lsub_folders(mailsession * session, char * mb, + struct mail_list ** result); + +static int mhdriver_cached_subscribe_folder(mailsession * session, char * mb); + +static int mhdriver_cached_unsubscribe_folder(mailsession * session, + char * mb); + +static int mhdriver_cached_append_message(mailsession * session, + char * message, size_t size); +static int mhdriver_cached_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags); +static int mhdriver_cached_copy_message(mailsession * session, + uint32_t num, char * mb); + +static int mhdriver_cached_remove_message(mailsession * session, + uint32_t num); + +static int mhdriver_cached_move_message(mailsession * session, + uint32_t num, char * mb); + +static int +mhdriver_cached_get_messages_list(mailsession * session, + struct mailmessage_list ** result); + +static int +mhdriver_cached_get_envelopes_list(mailsession * session, + struct mailmessage_list * env_list); + +static int mhdriver_cached_get_message(mailsession * session, + uint32_t num, mailmessage ** result); + +static int mhdriver_cached_get_message_by_uid(mailsession * session, + const char * uid, + mailmessage ** result); + +static mailsession_driver local_mh_cached_session_driver = { + .sess_name = "mh-cached", + + .sess_initialize = mhdriver_cached_initialize, + .sess_uninitialize = mhdriver_cached_uninitialize, + + .sess_parameters = mhdriver_cached_parameters, + + .sess_connect_stream = NULL, + .sess_connect_path = mhdriver_cached_connect_path, + .sess_starttls = NULL, + .sess_login = NULL, + .sess_logout = mhdriver_cached_logout, + .sess_noop = NULL, + + .sess_build_folder_name = mhdriver_cached_build_folder_name, + .sess_create_folder = mhdriver_cached_create_folder, + .sess_delete_folder = mhdriver_cached_delete_folder, + .sess_rename_folder = mhdriver_cached_rename_folder, + .sess_check_folder = mhdriver_cached_check_folder, + .sess_examine_folder = NULL, + .sess_select_folder = mhdriver_cached_select_folder, + .sess_expunge_folder = mhdriver_cached_expunge_folder, + .sess_status_folder = mhdriver_cached_status_folder, + .sess_messages_number = mhdriver_cached_messages_number, + .sess_recent_number = mhdriver_cached_recent_number, + .sess_unseen_number = mhdriver_cached_unseen_number, + .sess_list_folders = mhdriver_cached_list_folders, + .sess_lsub_folders = mhdriver_cached_lsub_folders, + .sess_subscribe_folder = mhdriver_cached_subscribe_folder, + .sess_unsubscribe_folder = mhdriver_cached_unsubscribe_folder, + + .sess_append_message = mhdriver_cached_append_message, + .sess_append_message_flags = mhdriver_cached_append_message_flags, + .sess_copy_message = mhdriver_cached_copy_message, + .sess_move_message = mhdriver_cached_move_message, + + .sess_get_messages_list = mhdriver_cached_get_messages_list, + .sess_get_envelopes_list = mhdriver_cached_get_envelopes_list, + .sess_remove_message = mhdriver_cached_remove_message, +#if 0 + .sess_search_messages = maildriver_generic_search_messages, +#endif + + .sess_get_message = mhdriver_cached_get_message, + .sess_get_message_by_uid = mhdriver_cached_get_message_by_uid, +}; + +mailsession_driver * mh_cached_session_driver = +&local_mh_cached_session_driver; + +#define ENV_NAME "env.db" +#define FLAGS_NAME "flags.db" + + +static inline struct mh_cached_session_state_data * +get_cached_data(mailsession * session) +{ + return session->sess_data; +} + +static inline mailsession * get_ancestor(mailsession * session) +{ + return get_cached_data(session)->mh_ancestor; +} + +static inline struct mh_session_state_data * +get_ancestor_data(mailsession * session) +{ + return get_ancestor(session)->sess_data; +} + +static inline struct mailmh * +get_mh_session(mailsession * session) +{ + return get_ancestor_data(session)->mh_session; +} + +static inline struct mailmh_folder * +get_mh_cur_folder(mailsession * session) +{ + return get_ancestor_data(session)->mh_cur_folder; +} + + +#define FILENAME_MAX_UID "max-uid" + +/* write max uid current value */ + +static int write_max_uid_value(mailsession * session) +{ + int r; + char filename[PATH_MAX]; + FILE * f; + int res; + struct mh_cached_session_state_data * cached_data; + struct mh_session_state_data * ancestor_data; + int fd; + + MMAPString * mmapstr; + size_t cur_token; + + cached_data = get_cached_data(session); + ancestor_data = get_ancestor_data(session); + + if (cached_data->mh_quoted_mb == NULL) + return MAIL_ERROR_BAD_STATE; + + snprintf(filename, PATH_MAX, "%s/%s/%s", + cached_data->mh_cache_directory, + cached_data->mh_quoted_mb, FILENAME_MAX_UID); + + fd = creat(filename, S_IRUSR | S_IWUSR); + if (fd < 0) { + res = MAIL_ERROR_FILE; + goto err; + } + + f = fdopen(fd, "w"); + if (f == NULL) { + close(fd); + res = MAIL_ERROR_FILE; + goto err; + } + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto close; + } + + r = mail_serialize_clear(mmapstr, &cur_token); + if (r != MAIL_NO_ERROR) { + res = r; + goto free_mmapstr; + } + + r = mailimf_cache_int_write(mmapstr, &cur_token, + ancestor_data->mh_cur_folder->fl_max_index); + if (r != MAIL_NO_ERROR) { + res = r; + goto free_mmapstr; + } + + fwrite(mmapstr->str, 1, mmapstr->len, f); + + mmap_string_free(mmapstr); + fclose(f); + + return MAIL_NO_ERROR; + + free_mmapstr: + mmap_string_free(mmapstr); + close: + fclose(f); + err: + return res; +} + +static int read_max_uid_value(mailsession * session) +{ + int r; + char filename[PATH_MAX]; + FILE * f; + uint32_t written_uid; + int res; + struct mh_cached_session_state_data * cached_data; + struct mh_session_state_data * ancestor_data; + + MMAPString * mmapstr; + size_t cur_token; + char buf[sizeof(uint32_t)]; + size_t read_size; + + cached_data = get_cached_data(session); + ancestor_data = get_ancestor_data(session); + + snprintf(filename, PATH_MAX, "%s/%s/%s", + cached_data->mh_cache_directory, + cached_data->mh_quoted_mb, FILENAME_MAX_UID); + + f = fopen(filename, "r"); + if (f == NULL) { + res = MAIL_ERROR_FILE; + goto err; + } + + read_size = fread(buf, 1, sizeof(uint32_t), f); + + mmapstr = mmap_string_new_len(buf, read_size); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto close; + } + + cur_token = 0; + + r = mailimf_cache_int_read(mmapstr, &cur_token, &written_uid); + if (r != MAIL_NO_ERROR) { + fclose(f); + res = r; + goto free_mmapstr; + } + + mmap_string_free(mmapstr); + fclose(f); + + if (written_uid > ancestor_data->mh_cur_folder->fl_max_index) + ancestor_data->mh_cur_folder->fl_max_index = written_uid; + + return MAIL_NO_ERROR; + + free_mmapstr: + mmap_string_free(mmapstr); + close: + fclose(f); + err: + return res; +} + + +static int mhdriver_cached_initialize(mailsession * session) +{ + struct mh_cached_session_state_data * data; + + data = malloc(sizeof(* data)); + if (data == NULL) + goto err; + + data->mh_flags_store = mail_flags_store_new(); + if (data->mh_flags_store == NULL) + goto free; + + data->mh_ancestor = mailsession_new(mh_session_driver); + if (data->mh_ancestor == NULL) + goto free_store; + + data->mh_quoted_mb = NULL; + + session->sess_data = data; + + return MAIL_NO_ERROR; + + free_store: + mail_flags_store_free(data->mh_flags_store); + free: + free(data); + err: + return MAIL_ERROR_MEMORY; +} + +static void free_state(struct mh_cached_session_state_data * mh_data) +{ + if (mh_data->mh_quoted_mb) { + free(mh_data->mh_quoted_mb); + mh_data->mh_quoted_mb = NULL; + } +} + +static int mh_flags_store_process(char * flags_directory, char * quoted_mb, + struct mail_flags_store * flags_store) +{ + char filename_flags[PATH_MAX]; + struct mail_cache_db * cache_db_flags; + MMAPString * mmapstr; + unsigned int i; + int r; + int res; + + if (carray_count(flags_store->fls_tab) == 0) + return MAIL_NO_ERROR; + + if (quoted_mb == NULL) + return MAIL_NO_ERROR; + + snprintf(filename_flags, PATH_MAX, "%s/%s/%s", + flags_directory, quoted_mb, FLAGS_NAME); + + r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); + if (r < 0) { + res = MAIL_ERROR_FILE; + goto err; + } + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto close_db_flags; + } + + for(i = 0 ; i < carray_count(flags_store->fls_tab) ; i ++) { + mailmessage * msg; + + msg = carray_get(flags_store->fls_tab, i); + + r = mhdriver_write_cached_flags(cache_db_flags, mmapstr, + msg->msg_uid, msg->msg_flags); + } + + mmap_string_free(mmapstr); + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + + mail_flags_store_clear(flags_store); + + return MAIL_NO_ERROR; + + close_db_flags: + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + err: + return res; +} + +static void mhdriver_cached_uninitialize(mailsession * session) +{ + struct mh_cached_session_state_data * data; + + data = get_cached_data(session); + + mh_flags_store_process(data->mh_flags_directory, data->mh_quoted_mb, + data->mh_flags_store); + + mail_flags_store_free(data->mh_flags_store); + + free_state(data); + mailsession_free(data->mh_ancestor); + free(data); + + session->sess_data = NULL; +} + +static int mhdriver_cached_parameters(mailsession * session, + int id, void * value) +{ + struct mh_cached_session_state_data * cached_data; + int r; + + cached_data = get_cached_data(session); + + switch (id) { + case MHDRIVER_CACHED_SET_CACHE_DIRECTORY: + strncpy(cached_data->mh_cache_directory, value, PATH_MAX); + cached_data->mh_cache_directory[PATH_MAX - 1] = '\0'; + + r = generic_cache_create_dir(cached_data->mh_cache_directory); + if (r != MAIL_NO_ERROR) + return r; + + return MAIL_NO_ERROR; + + case MHDRIVER_CACHED_SET_FLAGS_DIRECTORY: + strncpy(cached_data->mh_flags_directory, value, PATH_MAX); + cached_data->mh_flags_directory[PATH_MAX - 1] = '\0'; + + r = generic_cache_create_dir(cached_data->mh_flags_directory); + if (r != MAIL_NO_ERROR) + return r; + + return MAIL_NO_ERROR; + } + + return MAIL_ERROR_INVAL; +} + +static int mhdriver_cached_connect_path(mailsession * session, char * path) +{ + return mailsession_connect_path(get_ancestor(session), path); +} + +static int mhdriver_cached_logout(mailsession * session) +{ + int r; + struct mh_cached_session_state_data * cached_data; + + r = write_max_uid_value(session); + + cached_data = get_cached_data(session); + + mh_flags_store_process(cached_data->mh_flags_directory, + cached_data->mh_quoted_mb, + cached_data->mh_flags_store); + + return mailsession_logout(get_ancestor(session)); +} + +static int mhdriver_cached_check_folder(mailsession * session) +{ + struct mh_cached_session_state_data * cached_data; + + cached_data = get_cached_data(session); + + mh_flags_store_process(cached_data->mh_flags_directory, + cached_data->mh_quoted_mb, + cached_data->mh_flags_store); + + return MAIL_NO_ERROR; +} + +/* folders operations */ + +static int mhdriver_cached_build_folder_name(mailsession * session, char * mb, + char * name, char ** result) +{ + return mailsession_build_folder_name(get_ancestor(session), + mb, name, result); +} + +static int mhdriver_cached_create_folder(mailsession * session, char * mb) +{ + return mailsession_create_folder(get_ancestor(session), mb); +} + +static int mhdriver_cached_delete_folder(mailsession * session, char * mb) +{ + return mailsession_delete_folder(get_ancestor(session), mb); +} + +static int mhdriver_cached_rename_folder(mailsession * session, char * mb, + char * new_name) +{ + return mailsession_rename_folder(get_ancestor(session), mb, new_name); +} + +static int get_cache_directory(mailsession * session, + char * path, char ** result) +{ + char * quoted_mb; + char dirname[PATH_MAX]; + int res; + int r; + struct mh_cached_session_state_data * cached_data; + + cached_data = get_cached_data(session); + + quoted_mb = maildriver_quote_mailbox(path); + if (quoted_mb == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + snprintf(dirname, PATH_MAX, "%s/%s", + cached_data->mh_cache_directory, quoted_mb); + + r = generic_cache_create_dir(dirname); + if (r != MAIL_NO_ERROR) { + res = r; + goto free; + } + + snprintf(dirname, PATH_MAX, "%s/%s", + cached_data->mh_flags_directory, quoted_mb); + + r = generic_cache_create_dir(dirname); + if (r != MAIL_NO_ERROR) { + res = r; + goto free; + } + + * result = quoted_mb; + + return MAIL_NO_ERROR; + + free: + free(quoted_mb); + err: + return res; +} + +static int mhdriver_cached_select_folder(mailsession * session, char * mb) +{ + int r; + int res; + char * quoted_mb; + struct mh_cached_session_state_data * cached_data; + + cached_data = get_cached_data(session); + + mh_flags_store_process(cached_data->mh_flags_directory, + cached_data->mh_quoted_mb, + cached_data->mh_flags_store); + + r = get_cache_directory(session, mb, "ed_mb); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + r = mailsession_select_folder(get_ancestor(session), mb); + if (r != MAIL_NO_ERROR) { + res = r; + goto free; + } + + r = write_max_uid_value(session); + + free_state(cached_data); + cached_data->mh_quoted_mb = quoted_mb; + + r = read_max_uid_value(session); + + return MAIL_NO_ERROR; + + free: + free(quoted_mb); + err: + return res; +} + +static int mhdriver_cached_expunge_folder(mailsession * session) +{ + struct mailmh_folder * folder; + int res; + char filename_flags[PATH_MAX]; + struct mail_cache_db * cache_db_flags; + MMAPString * mmapstr; + struct mh_cached_session_state_data * cached_data; + unsigned int i; + int r; + + cached_data = get_cached_data(session); + if (cached_data->mh_quoted_mb == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + mh_flags_store_process(cached_data->mh_flags_directory, + cached_data->mh_quoted_mb, + cached_data->mh_flags_store); + + folder = get_mh_cur_folder(session); + if (folder == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + snprintf(filename_flags, PATH_MAX, "%s/%s/%s", + cached_data->mh_flags_directory, cached_data->mh_quoted_mb, FLAGS_NAME); + + r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); + if (r < 0) { + res = MAIL_ERROR_FILE; + goto err; + } + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto close_db_flags; + } + + for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i++) { + struct mailmh_msg_info * mh_info; + struct mail_flags * flags; + + mh_info = carray_get(folder->fl_msgs_tab, i); + if (mh_info == NULL) + continue; + + r = mhdriver_get_cached_flags(cache_db_flags, mmapstr, + session, mh_info->msg_index, &flags); + if (r != MAIL_NO_ERROR) + continue; + + if (flags->fl_flags & MAIL_FLAG_DELETED) { + r = mailmh_folder_remove_message(folder, mh_info->msg_index); + } + + mail_flags_free(flags); + } + + mmap_string_free(mmapstr); + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + + mailmh_folder_update(folder); + + return MAIL_NO_ERROR; + + close_db_flags: + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + err: + return res; +} + + +static int mhdriver_cached_status_folder(mailsession * session, char * mb, + uint32_t * result_messages, + uint32_t * result_recent, + uint32_t * result_unseen) +{ + struct mailmh_folder * folder; + int res; + char filename_flags[PATH_MAX]; + struct mail_cache_db * cache_db_flags; + MMAPString * mmapstr; + struct mh_cached_session_state_data * cached_data; + unsigned int i; + int r; + uint32_t count; + uint32_t recent; + uint32_t unseen; + + r = mhdriver_cached_select_folder(session, mb); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + count = 0; + recent = 0; + unseen = 0; + + folder = get_mh_cur_folder(session); + if (folder == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + cached_data = get_cached_data(session); + if (cached_data->mh_quoted_mb == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + snprintf(filename_flags, PATH_MAX, "%s/%s/%s", + cached_data->mh_flags_directory, + cached_data->mh_quoted_mb, FLAGS_NAME); + + r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); + if (r < 0) { + res = MAIL_ERROR_FILE; + goto err; + } + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto close_db_flags; + } + + for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i++) { + struct mailmh_msg_info * mh_info; + struct mail_flags * flags; + + mh_info = carray_get(folder->fl_msgs_tab, i); + if (mh_info == NULL) + continue; + + count ++; + + r = mhdriver_get_cached_flags(cache_db_flags, mmapstr, + session, mh_info->msg_index, + &flags); + + if (r != MAIL_NO_ERROR) { + recent ++; + unseen ++; + continue; + } + + if ((flags->fl_flags & MAIL_FLAG_NEW) != 0) { + recent ++; + } + if ((flags->fl_flags & MAIL_FLAG_SEEN) == 0) { + unseen ++; + } + mail_flags_free(flags); + } + + mmap_string_free(mmapstr); + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + + * result_messages = count; + * result_recent = recent; + * result_unseen = unseen; + + return MAIL_NO_ERROR; + + close_db_flags: + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + err: + return res; +} + +static int mhdriver_cached_messages_number(mailsession * session, char * mb, + uint32_t * result) +{ + return mailsession_messages_number(get_ancestor(session), mb, result); +} + +static int mhdriver_cached_recent_number(mailsession * session, char * mb, + uint32_t * result) +{ + uint32_t messages; + uint32_t recent; + uint32_t unseen; + int r; + + r = mhdriver_cached_status_folder(session, mb, &messages, &recent, &unseen); + if (r != MAIL_NO_ERROR) + return r; + + * result = recent; + + return MAIL_NO_ERROR; +} + + +static int mhdriver_cached_unseen_number(mailsession * session, char * mb, + uint32_t * result) +{ + uint32_t messages; + uint32_t recent; + uint32_t unseen; + int r; + + r = mhdriver_cached_status_folder(session, mb, &messages, &recent, &unseen); + if (r != MAIL_NO_ERROR) + return r; + + * result = recent; + + return MAIL_NO_ERROR; +} + + +static int mhdriver_cached_list_folders(mailsession * session, char * mb, + struct mail_list ** result) +{ + return mailsession_list_folders(get_ancestor(session), mb, result); +} + +static int mhdriver_cached_lsub_folders(mailsession * session, char * mb, + struct mail_list ** result) +{ + return mailsession_lsub_folders(get_ancestor(session), mb, result); +} + +static int mhdriver_cached_subscribe_folder(mailsession * session, char * mb) +{ + return mailsession_subscribe_folder(get_ancestor(session), mb); +} + +static int mhdriver_cached_unsubscribe_folder(mailsession * session, + char * mb) +{ + return mailsession_unsubscribe_folder(get_ancestor(session), mb); +} + +/* messages operations */ + +static int mhdriver_cached_append_message(mailsession * session, + char * message, size_t size) +{ + return mhdriver_cached_append_message_flags(session, + message, size, NULL); +} + +static int mhdriver_cached_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags) +{ + int r; + struct mailmh_folder * folder; + struct mailmh_msg_info * msg_info; + chashdatum key; + chashdatum value; + uint32_t uid; + struct mh_cached_session_state_data * data; + char filename_flags[PATH_MAX]; + struct mail_cache_db * cache_db_flags; + MMAPString * mmapstr; + char keyname[PATH_MAX]; + + folder = get_mh_cur_folder(session); + if (folder == NULL) + return MAIL_ERROR_BAD_STATE; + + r = mailmh_folder_add_message_uid(folder, + message, size, &uid); + + switch (r) { + case MAILMH_ERROR_FILE: + return MAIL_ERROR_DISKSPACE; + + case MAILMH_NO_ERROR: + break; + + default: + return mhdriver_mh_error_to_mail_error(r); + } + + if (flags == NULL) + goto exit; + + key.data = &uid; + key.len = sizeof(uid); + r = chash_get(folder->fl_msgs_hash, &key, &value); + if (r < 0) + return MAIL_ERROR_CACHE_MISS; + + msg_info = value.data; + + data = get_cached_data(session); + + snprintf(filename_flags, PATH_MAX, "%s/%s/%s", + data->mh_flags_directory, data->mh_quoted_mb, FLAGS_NAME); + + r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); + if (r < 0) + goto exit; + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) + goto close_db_flags; + + snprintf(keyname, PATH_MAX, "%u-%lu-%lu-flags", + uid, (unsigned long) msg_info->msg_mtime, + (unsigned long) msg_info->msg_size); + + r = mhdriver_write_cached_flags(cache_db_flags, mmapstr, keyname, flags); + + mmap_string_free(mmapstr); + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + + if (r != MAIL_NO_ERROR) + goto exit; + + return MAIL_NO_ERROR; + + close_db_flags: + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + exit: + return MAIL_NO_ERROR; +} + +static int mhdriver_cached_copy_message(mailsession * session, + uint32_t num, char * mb) +{ + return mailsession_copy_message(get_ancestor(session), num, mb); +} + +static int mhdriver_cached_remove_message(mailsession * session, uint32_t num) +{ + return mailsession_remove_message(get_ancestor(session), num); +} + +static int mhdriver_cached_move_message(mailsession * session, + uint32_t num, char * mb) +{ + return mailsession_move_message(get_ancestor(session), num, mb); +} + +static int +mhdriver_cached_get_messages_list(mailsession * session, + struct mailmessage_list ** result) +{ + struct mailmh_folder * folder; + int res; + + folder = get_mh_cur_folder(session); + if (folder == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + return mh_get_messages_list(folder, session, + mh_cached_message_driver, result); + + err: + return res; +} + + + +static int +get_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr, + mailsession * session, uint32_t num, + struct mailimf_fields ** result) +{ + int r; + char keyname[PATH_MAX]; + struct mailimf_fields * fields; + int res; + struct mailmh_folder * folder; + struct mailmh_msg_info * msg_info; + chashdatum key; + chashdatum data; + + folder = get_mh_cur_folder(session); + +#if 0 + msg_info = cinthash_find(mh_data->mh_cur_folder->fl_msgs_hash, num); + if (msg_info == NULL) + return MAIL_ERROR_CACHE_MISS; +#endif + key.data = # + key.len = sizeof(num); + r = chash_get(folder->fl_msgs_hash, &key, &data); + if (r < 0) + return MAIL_ERROR_CACHE_MISS; + msg_info = data.data; + + snprintf(keyname, PATH_MAX, "%u-%lu-%lu-envelope", + num, (unsigned long) msg_info->msg_mtime, + (unsigned long) msg_info->msg_size); + + r = generic_cache_fields_read(cache_db, mmapstr, keyname, &fields); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + * result = fields; + + return MAIL_NO_ERROR; + + err: + return res; +} + +static int +write_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr, + mailsession * session, uint32_t num, + struct mailimf_fields * fields) +{ + int r; + char keyname[PATH_MAX]; + int res; + struct mailmh_folder * folder; + chashdatum key; + chashdatum data; + struct mailmh_msg_info * msg_info; + + folder = get_mh_cur_folder(session); +#if 0 + msg_info = cinthash_find(mh_data->mh_cur_folder->fl_msgs_hash, num); + if (msg_info == NULL) { + res = MAIL_ERROR_CACHE_MISS; + goto err; + } +#endif + key.data = # + key.len = sizeof(num); + r = chash_get(folder->fl_msgs_hash, &key, &data); + if (r < 0) + return MAIL_ERROR_CACHE_MISS; + msg_info = data.data; + + snprintf(keyname, PATH_MAX, "%u-%lu-%lu-envelope", + num, (unsigned long) msg_info->msg_mtime, + (unsigned long) msg_info->msg_size); + + r = generic_cache_fields_write(cache_db, mmapstr, keyname, fields); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + return MAIL_NO_ERROR; + + err: + return res; +} + +static int +mhdriver_cached_get_envelopes_list(mailsession * session, + struct mailmessage_list * env_list) +{ + int r; + unsigned int i; + char filename_env[PATH_MAX]; + char filename_flags[PATH_MAX]; + struct mail_cache_db * cache_db_env; + struct mail_cache_db * cache_db_flags; + MMAPString * mmapstr; + int res; + struct mh_cached_session_state_data * cached_data; + + cached_data = get_cached_data(session); + if (cached_data->mh_quoted_mb == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + mh_flags_store_process(cached_data->mh_flags_directory, + cached_data->mh_quoted_mb, + cached_data->mh_flags_store); + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + snprintf(filename_env, PATH_MAX, "%s/%s/%s", + cached_data->mh_cache_directory, + cached_data->mh_quoted_mb, ENV_NAME); + + r = mail_cache_db_open_lock(filename_env, &cache_db_env); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_mmapstr; + } + + snprintf(filename_flags, PATH_MAX, "%s/%s/%s", + cached_data->mh_flags_directory, cached_data->mh_quoted_mb, FLAGS_NAME); + + r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto close_db_env; + } + + /* fill with cached */ + + for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { + mailmessage * msg; + struct mailimf_fields * fields; + struct mail_flags * flags; + + msg = carray_get(env_list->msg_tab, i); + + if (msg->msg_fields == NULL) { + r = get_cached_envelope(cache_db_env, mmapstr, + msg->msg_session, msg->msg_index, &fields); + if (r == MAIL_NO_ERROR) { + msg->msg_cached = TRUE; + msg->msg_fields = fields; + } + } + + if (msg->msg_flags == NULL) { + r = mhdriver_get_cached_flags(cache_db_flags, mmapstr, + session, msg->msg_index, &flags); + if (r == MAIL_NO_ERROR) { + msg->msg_flags = flags; + } + } + } + + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + mail_cache_db_close_unlock(filename_env, cache_db_env); + + r = mailsession_get_envelopes_list(get_ancestor(session), env_list); + + if (r != MAIL_NO_ERROR) { + res = r; + goto free_mmapstr; + } + + r = mail_cache_db_open_lock(filename_env, &cache_db_env); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_mmapstr; + } + + r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto close_db_env; + } + + /* add flags */ + + for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { + mailmessage * msg; + + msg = carray_get(env_list->msg_tab, i); + + if (msg->msg_flags == NULL) + msg->msg_flags = mail_flags_new_empty(); + } + + /* must write cache */ + + for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { + mailmessage * msg; + + msg = carray_get(env_list->msg_tab, i); + + if (msg->msg_fields != NULL) { + if (!msg->msg_cached) { + r = write_cached_envelope(cache_db_env, mmapstr, + session, msg->msg_index, msg->msg_fields); + } + } + + if (msg->msg_flags != NULL) { + r = mhdriver_write_cached_flags(cache_db_flags, mmapstr, + msg->msg_uid, msg->msg_flags); + } + } + + /* flush cache */ + + maildriver_cache_clean_up(cache_db_env, cache_db_flags, env_list); + + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + mail_cache_db_close_unlock(filename_env, cache_db_env); + + mmap_string_free(mmapstr); + + return MAIL_NO_ERROR; + + close_db_env: + mail_cache_db_close_unlock(filename_env, cache_db_env); + free_mmapstr: + mmap_string_free(mmapstr); + err: + return res; +} + +static int mhdriver_cached_get_message(mailsession * session, + uint32_t num, mailmessage ** result) +{ + mailmessage * msg_info; + int r; + + msg_info = mailmessage_new(); + if (msg_info == NULL) + return MAIL_ERROR_MEMORY; + + r = mailmessage_init(msg_info, session, mh_cached_message_driver, num, 0); + if (r != MAIL_NO_ERROR) + return r; + + * result = msg_info; + + return MAIL_NO_ERROR; +} + +static int mhdriver_cached_get_message_by_uid(mailsession * session, + const char * uid, + mailmessage ** result) +{ + uint32_t index; + char *p; + struct mailmh_msg_info * mh_msg_info; + struct mailmh_folder * folder; + time_t mtime; + char * mtime_p; + chashdatum key; + chashdatum data; + int r; + + if (uid == NULL) + return MAIL_ERROR_INVAL; + + index = strtoul(uid, &p, 10); + if (p == uid || * p != '-') + return MAIL_ERROR_INVAL; + + folder = get_mh_cur_folder(session); + + mh_msg_info = NULL; + key.data = &index; + key.len = sizeof(index); + r = chash_get(folder->fl_msgs_hash, &key, &data); + if (r < 0) + return MAIL_ERROR_MSG_NOT_FOUND; + + mh_msg_info = data.data; + + mtime_p = p + 1; + + mtime = strtoul(mtime_p, &p, 10); + if ((* p == '-') && (mtime == mh_msg_info->msg_mtime)) { + size_t size; + char *size_p; + + size_p = p + 1; + size = strtoul(size_p, &p, 10); + if ((* p == '\0') && (size == mh_msg_info->msg_size)) + return mhdriver_cached_get_message(session, index, result); + } + else if (*p != '-') { + return MAIL_ERROR_INVAL; + } + + return MAIL_ERROR_MSG_NOT_FOUND; +} diff --git a/libetpan/src/driver/implementation/mh/mhdriver_cached.h b/libetpan/src/driver/implementation/mh/mhdriver_cached.h new file mode 100644 index 0000000..d2e5803 --- a/dev/null +++ b/libetpan/src/driver/implementation/mh/mhdriver_cached.h @@ -0,0 +1,52 @@ +/* + * 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 MHDRIVER_CACHED_H + +#define MHDRIVER_CACHED_H + +#include <libetpan/mhdriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailsession_driver * mh_cached_session_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/mh/mhdriver_cached_message.c b/libetpan/src/driver/implementation/mh/mhdriver_cached_message.c new file mode 100644 index 0000000..a59beea --- a/dev/null +++ b/libetpan/src/driver/implementation/mh/mhdriver_cached_message.c @@ -0,0 +1,338 @@ +/* + * 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 "mhdriver_message.h" + +#include "mailmessage_tools.h" +#include "mhdriver_tools.h" +#include "mhdriver_cached.h" +#include "mailmh.h" +#include "generic_cache.h" + +#include "mail_cache_db.h" + +#include <unistd.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <stdlib.h> + +static int mh_prefetch(mailmessage * msg_info); + +static void mh_prefetch_free(struct generic_message_t * msg); + +static int mh_initialize(mailmessage * msg_info); + +static int mh_fetch_size(mailmessage * msg_info, + size_t * result); + +static int mh_get_flags(mailmessage * msg_info, + struct mail_flags ** result); + +static void mh_uninitialize(mailmessage * msg_info); + +static void mh_flush(mailmessage * msg_info); + +static void mh_check(mailmessage * msg_info); + +static int mh_fetch_header(mailmessage * msg_info, + char ** result, + size_t * result_len); + +static mailmessage_driver local_mh_cached_message_driver = { + .msg_name = "mh-cached", + + .msg_initialize = mh_initialize, + .msg_uninitialize = mh_uninitialize, + + .msg_flush = mh_flush, + .msg_check = mh_check, + + .msg_fetch_result_free = mailmessage_generic_fetch_result_free, + + .msg_fetch = mailmessage_generic_fetch, + .msg_fetch_header = mh_fetch_header, + .msg_fetch_body = mailmessage_generic_fetch_body, + .msg_fetch_size = mh_fetch_size, + .msg_get_bodystructure = mailmessage_generic_get_bodystructure, + .msg_fetch_section = mailmessage_generic_fetch_section, + .msg_fetch_section_header = mailmessage_generic_fetch_section_header, + .msg_fetch_section_mime = mailmessage_generic_fetch_section_mime, + .msg_fetch_section_body = mailmessage_generic_fetch_section_body, + .msg_fetch_envelope = mailmessage_generic_fetch_envelope, + + .msg_get_flags = mh_get_flags, +}; + +mailmessage_driver * mh_cached_message_driver = +&local_mh_cached_message_driver; + +static inline struct mh_cached_session_state_data * +get_cached_session_data(mailmessage * msg) +{ + return msg->msg_session->sess_data; +} + +static inline mailsession * get_ancestor_session(mailmessage * msg) +{ + return get_cached_session_data(msg)->mh_ancestor; +} + +static inline struct mh_session_state_data * +get_ancestor_session_data(mailmessage * msg) +{ + return get_ancestor_session(msg)->sess_data; +} + +static inline struct mailmh * +get_mh_session(mailmessage * msg) +{ + return get_ancestor_session_data(msg)->mh_session; +} + +static inline struct mailmh_folder * +get_mh_cur_folder(mailmessage * msg) +{ + return get_ancestor_session_data(msg)->mh_cur_folder; +} + +static int mh_prefetch(mailmessage * msg_info) +{ + struct generic_message_t * msg; + int r; + char * msg_content; + size_t msg_length; + + r = mhdriver_fetch_message(get_ancestor_session(msg_info), + msg_info->msg_index, &msg_content, &msg_length); + if (r != MAIL_NO_ERROR) + return r; + + msg = msg_info->msg_data; + + msg->msg_message = msg_content; + msg->msg_length = msg_length; + + return MAIL_NO_ERROR; +} + +static void mh_prefetch_free(struct generic_message_t * msg) +{ + if (msg->msg_message != NULL) { + mmap_string_unref(msg->msg_message); + msg->msg_message = NULL; + } +} + +static int mh_initialize(mailmessage * msg_info) +{ + struct generic_message_t * msg; + int r; + char * uid; + char static_uid[PATH_MAX]; + struct mailmh_msg_info * mh_msg_info; + chashdatum key; + chashdatum data; + struct mailmh_folder * folder; + + folder = get_mh_cur_folder(msg_info); + + key.data = &msg_info->msg_index; + key.len = sizeof(msg_info->msg_index); + r = chash_get(folder->fl_msgs_hash, &key, &data); + if (r < 0) + return MAIL_ERROR_INVAL; + + mh_msg_info = data.data; + + snprintf(static_uid, PATH_MAX, "%u-%lu-%lu", msg_info->msg_index, + mh_msg_info->msg_mtime, (unsigned long) mh_msg_info->msg_size); + uid = strdup(static_uid); + if (uid == NULL) + return MAIL_ERROR_MEMORY; + + r = mailmessage_generic_initialize(msg_info); + if (r != MAIL_NO_ERROR) { + free(uid); + return r; + } + + msg = msg_info->msg_data; + msg->msg_prefetch = mh_prefetch; + msg->msg_prefetch_free = mh_prefetch_free; + msg_info->msg_uid = uid; + + return MAIL_NO_ERROR; +} + +static void mh_uninitialize(mailmessage * msg_info) +{ + mailmessage_generic_uninitialize(msg_info); +} + + +#define FLAGS_NAME "flags.db" + +static void mh_flush(mailmessage * msg_info) +{ + mailmessage_generic_flush(msg_info); +} + +static void mh_check(mailmessage * msg_info) +{ + int r; + + if (msg_info->msg_flags != NULL) { + r = mail_flags_store_set(get_cached_session_data(msg_info)->mh_flags_store, + msg_info); + /* ignore errors */ + } +} + +static int mh_fetch_size(mailmessage * msg_info, + size_t * result) +{ + int r; + size_t size; + + r = mhdriver_fetch_size(get_ancestor_session(msg_info), + msg_info->msg_index, &size); + if (r != MAIL_NO_ERROR) + return r; + + * result = size; + + return MAIL_NO_ERROR; +} + +static int mh_get_flags(mailmessage * msg_info, + struct mail_flags ** result) +{ + int r; + struct mail_flags * flags; + struct mail_cache_db * cache_db_flags; + char filename_flags[PATH_MAX]; + int res; + struct mh_cached_session_state_data * cached_data; + MMAPString * mmapstr; + + if (msg_info->msg_flags != NULL) { + * result = msg_info->msg_flags; + + return MAIL_NO_ERROR; + } + + cached_data = get_cached_session_data(msg_info); + + flags = mail_flags_store_get(cached_data->mh_flags_store, + msg_info->msg_index); + + if (flags == NULL) { + if (cached_data->mh_quoted_mb == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + snprintf(filename_flags, PATH_MAX, "%s/%s/%s", + cached_data->mh_flags_directory, + cached_data->mh_quoted_mb, FLAGS_NAME); + + r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto close_db_flags; + } + + r = mhdriver_get_cached_flags(cache_db_flags, mmapstr, + msg_info->msg_session, msg_info->msg_index, &flags); + if (r != MAIL_NO_ERROR) { + flags = mail_flags_new_empty(); + if (flags == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_mmapstr; + } + } + + mmap_string_free(mmapstr); + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + } + + msg_info->msg_flags = flags; + + * result = flags; + + return MAIL_NO_ERROR; + + free_mmapstr: + mmap_string_free(mmapstr); + close_db_flags: + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + err: + return res; +} + +static int mh_fetch_header(mailmessage * msg_info, + char ** result, + size_t * result_len) +{ + struct generic_message_t * msg; + int r; + char * msg_content; + size_t msg_length; + + msg = msg_info->msg_data; + if (msg->msg_message != NULL) { + return mailmessage_generic_fetch_header(msg_info, result, result_len); + } + else { + r = mhdriver_fetch_header(get_ancestor_session(msg_info), + msg_info->msg_index, &msg_content, &msg_length); + if (r != MAIL_NO_ERROR) + return r; + + * result = msg_content; + * result_len = msg_length; + + return MAIL_NO_ERROR; + } +} diff --git a/libetpan/src/driver/implementation/mh/mhdriver_cached_message.h b/libetpan/src/driver/implementation/mh/mhdriver_cached_message.h new file mode 100644 index 0000000..f585708 --- a/dev/null +++ b/libetpan/src/driver/implementation/mh/mhdriver_cached_message.h @@ -0,0 +1,52 @@ +/* + * 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 MHDRIVER_CACHED_MESSAGE_H + +#define MHDRIVER_CACHED_MESSAGE_H + +#include <libetpan/mhdriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailmessage_driver * mh_cached_message_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/mh/mhdriver_message.c b/libetpan/src/driver/implementation/mh/mhdriver_message.c new file mode 100644 index 0000000..0e486b4 --- a/dev/null +++ b/libetpan/src/driver/implementation/mh/mhdriver_message.c @@ -0,0 +1,213 @@ +/* + * 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 "mhdriver_message.h" + +#include "mailmessage_tools.h" +#include "mhdriver_tools.h" +#include "mhdriver.h" +#include "mailmh.h" + +#include <unistd.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <stdlib.h> + +static int mh_prefetch(mailmessage * msg_info); + +static void mh_prefetch_free(struct generic_message_t * msg); + +static int mh_initialize(mailmessage * msg_info); + +static int mh_fetch_size(mailmessage * msg_info, + size_t * result); + +static int mh_fetch_header(mailmessage * msg_info, + char ** result, + size_t * result_len); + +static mailmessage_driver local_mh_message_driver = { + .msg_name = "mh", + + .msg_initialize = mh_initialize, + .msg_uninitialize = mailmessage_generic_uninitialize, + + .msg_flush = mailmessage_generic_flush, + .msg_check = NULL, + + .msg_fetch_result_free = mailmessage_generic_fetch_result_free, + + .msg_fetch = mailmessage_generic_fetch, + .msg_fetch_header = mh_fetch_header, + .msg_fetch_body = mailmessage_generic_fetch_body, + .msg_fetch_size = mh_fetch_size, + .msg_get_bodystructure = mailmessage_generic_get_bodystructure, + .msg_fetch_section = mailmessage_generic_fetch_section, + .msg_fetch_section_header = mailmessage_generic_fetch_section_header, + .msg_fetch_section_mime = mailmessage_generic_fetch_section_mime, + .msg_fetch_section_body = mailmessage_generic_fetch_section_body, + .msg_fetch_envelope = mailmessage_generic_fetch_envelope, + + .msg_get_flags = NULL, +}; + +mailmessage_driver * mh_message_driver = &local_mh_message_driver; + +static int mh_prefetch(mailmessage * msg_info) +{ + struct generic_message_t * msg; + int r; + char * msg_content; + size_t msg_length; + + r = mhdriver_fetch_message(msg_info->msg_session, msg_info->msg_index, + &msg_content, &msg_length); + if (r != MAIL_NO_ERROR) + return r; + + msg = msg_info->msg_data; + + msg->msg_message = msg_content; + msg->msg_length = msg_length; + + return MAIL_NO_ERROR; +} + +static void mh_prefetch_free(struct generic_message_t * msg) +{ + if (msg->msg_message != NULL) { + mmap_string_unref(msg->msg_message); + msg->msg_message = NULL; + } +} + +static inline struct mh_session_state_data * get_data(mailmessage * msg) +{ + return msg->msg_session->sess_data; +} + +static inline struct mailmh_folder * get_mh_cur_folder(mailmessage * msg) +{ + return get_data(msg)->mh_cur_folder; +} + +static int mh_initialize(mailmessage * msg_info) +{ + struct generic_message_t * msg; + int r; + char * uid; + char static_uid[PATH_MAX]; + struct mailmh_msg_info * mh_msg_info; + chashdatum key; + chashdatum value; + + key.data = &msg_info->msg_index; + key.len = sizeof(msg_info->msg_index); + r = chash_get(get_mh_cur_folder(msg_info)->fl_msgs_hash, &key, &value); + if (r < 0) + return MAIL_ERROR_INVAL; + + mh_msg_info = value.data; + + snprintf(static_uid, PATH_MAX, "%u-%lu-%lu", msg_info->msg_index, + (unsigned long) mh_msg_info->msg_mtime, + (unsigned long) mh_msg_info->msg_size); + uid = strdup(static_uid); + if (uid == NULL) + return MAIL_ERROR_MEMORY; + + r = mailmessage_generic_initialize(msg_info); + if (r != MAIL_NO_ERROR) { + free(uid); + return r; + } + + msg = msg_info->msg_data; + msg->msg_prefetch = mh_prefetch; + msg->msg_prefetch_free = mh_prefetch_free; + msg_info->msg_uid = uid; + + return MAIL_NO_ERROR; +} + + +static int mh_fetch_size(mailmessage * msg_info, + size_t * result) +{ + int r; + size_t size; + + r = mhdriver_fetch_size(msg_info->msg_session, msg_info->msg_index, &size); + if (r != MAIL_NO_ERROR) + return r; + + * result = size; + + return MAIL_NO_ERROR; +} + + + + +static int mh_fetch_header(mailmessage * msg_info, + char ** result, + size_t * result_len) +{ + struct generic_message_t * msg; + int r; + char * msg_content; + size_t msg_length; + + msg = msg_info->msg_data; + if (msg->msg_message != NULL) { + + r = mailmessage_generic_fetch_header(msg_info, result, result_len); + return r; + } + else { + r = mhdriver_fetch_header(msg_info->msg_session, msg_info->msg_index, + &msg_content, &msg_length); + if (r != MAIL_NO_ERROR) + return r; + + * result = msg_content; + * result_len = msg_length; + + return MAIL_NO_ERROR; + } +} diff --git a/libetpan/src/driver/implementation/mh/mhdriver_message.h b/libetpan/src/driver/implementation/mh/mhdriver_message.h new file mode 100644 index 0000000..2b11f3e --- a/dev/null +++ b/libetpan/src/driver/implementation/mh/mhdriver_message.h @@ -0,0 +1,52 @@ +/* + * 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 MHDRIVER_MESSAGE_H + +#define MHDRIVER_MESSAGE_H + +#include <libetpan/mhdriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailmessage_driver * mh_message_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/mh/mhdriver_tools.c b/libetpan/src/driver/implementation/mh/mhdriver_tools.c new file mode 100644 index 0000000..b8bcf03 --- a/dev/null +++ b/libetpan/src/driver/implementation/mh/mhdriver_tools.c @@ -0,0 +1,484 @@ +/* + * 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 "mhdriver_tools.h" + +#include "mailmessage.h" +#include "mhdriver.h" +#include "mhdriver_cached.h" +#include "maildriver_types.h" +#include "mailmh.h" +#include "generic_cache.h" +#include "imfcache.h" +#include "mail_cache_db.h" + +#include <unistd.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <stdlib.h> + +int mhdriver_mh_error_to_mail_error(int error) +{ + switch (error) { + case MAILMH_NO_ERROR: + return MAIL_NO_ERROR; + + case MAILMH_ERROR_FOLDER: + return MAIL_ERROR_FOLDER; + + case MAILMH_ERROR_MEMORY: + return MAIL_ERROR_MEMORY; + + case MAILMH_ERROR_FILE: + return MAIL_ERROR_FILE; + + case MAILMH_ERROR_COULD_NOT_ALLOC_MSG: + return MAIL_ERROR_APPEND; + + case MAILMH_ERROR_RENAME: + return MAIL_ERROR_RENAME; + + case MAILMH_ERROR_MSG_NOT_FOUND: + return MAIL_ERROR_MSG_NOT_FOUND; + + default: + return MAIL_ERROR_INVAL; + } +} + + +static inline struct mh_session_state_data * get_data(mailsession * session) +{ + return session->sess_data; +} + +static inline struct mailmh_folder * get_mh_cur_folder(mailsession * session) +{ + return get_data(session)->mh_cur_folder; +} + +static inline struct mh_cached_session_state_data * +cached_get_data(mailsession * session) +{ + return session->sess_data; +} + + +static inline mailsession * cached_get_ancestor(mailsession * session) +{ + return cached_get_data(session)->mh_ancestor; +} + +static inline struct mh_session_state_data * +cached_get_ancestor_data(mailsession * session) +{ + return get_data(cached_get_ancestor(session)); +} + +static inline struct mailmh_folder * +cached_get_mh_cur_folder(mailsession * session) +{ + return get_mh_cur_folder(cached_get_ancestor(session)); +} + +int mhdriver_fetch_message(mailsession * session, uint32_t index, + char ** result, size_t * result_len) +{ + size_t size; + size_t cur_token; + struct mailmh_folder * folder; + int fd; + MMAPString * mmapstr; + char * str; + int res; + int r; + + folder = get_mh_cur_folder(session); + if (folder == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + r = mailmh_folder_get_message_fd(folder, index, O_RDONLY, &fd); + + switch (r) { + case MAILMH_NO_ERROR: + break; + + default: + res = mhdriver_mh_error_to_mail_error(r); + goto close; + } + + r = mhdriver_fetch_size(session, index, &size); + + switch (r) { + case MAILMH_NO_ERROR: + break; + + default: + res = mhdriver_mh_error_to_mail_error(r); + goto close; + } + + str = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); + if (str == MAP_FAILED) { + res = MAIL_ERROR_FETCH; + goto close; + } + + /* strip "From " header for broken implementations */ + /* XXX - called twice, make a function */ + cur_token = 0; + if (strncmp("From ", str, 5) == 0) { + cur_token += 5; + + while (1) { + if (str[cur_token] == '\n') { + cur_token ++; + break; + } + if (cur_token >= size) + break; + cur_token ++; + } + } + + mmapstr = mmap_string_new_len(str + cur_token, size - cur_token); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto unmap; + } + + if (mmap_string_ref(mmapstr) != 0) { + res = MAIL_ERROR_MEMORY; + goto free_str; + } + + munmap(str, size); + close(fd); + + * result = mmapstr->str; + * result_len = mmapstr->len; + + return MAIL_NO_ERROR; + + free_str: + mmap_string_free(mmapstr); + unmap: + munmap(str, size); + close: + close(fd); + err: + return res; +} + + +int mhdriver_fetch_header(mailsession * session, uint32_t index, + char ** result, size_t * result_len) +{ + size_t size; + size_t cur_token; + size_t begin; + struct mailmh_folder * folder; + int fd; + MMAPString * mmapstr; + char * str; + int res; + int r; + + folder = get_mh_cur_folder(session); + if (folder == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + r = mailmh_folder_get_message_fd(folder, index, O_RDONLY, &fd); + + switch (r) { + case MAILMH_NO_ERROR: + break; + + default: + res = mhdriver_mh_error_to_mail_error(r); + goto close; + } + + r = mhdriver_fetch_size(session, index, &size); + + switch (r) { + case MAILMH_NO_ERROR: + break; + + default: + res = mhdriver_mh_error_to_mail_error(r); + goto close; + } + + str = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); + if (str == MAP_FAILED) { + res = MAIL_ERROR_FETCH; + goto close; + } + + /* strip "From " header for broken implementations */ + cur_token = 0; + if (size > 5) { + if (strncmp("From ", str, 5) == 0) { + cur_token += 5; + + while (1) { + if (str[cur_token] == '\n') { + cur_token ++; + break; + } + if (cur_token >= size) + break; + cur_token ++; + } + } + } + + begin = cur_token; + + while (1) { + r = mailimf_ignore_field_parse(str, size, &cur_token); + if (r == MAILIMF_NO_ERROR) { + /* do nothing */ + } + else + break; + } + mailimf_crlf_parse(str, size, &cur_token); + + mmapstr = mmap_string_new_len(str + begin, cur_token - begin); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto unmap; + } + + if (mmap_string_ref(mmapstr) != 0) { + res = MAIL_ERROR_MEMORY; + goto free_str; + } + + munmap(str, size); + close(fd); + + * result = mmapstr->str; + * result_len = mmapstr->len; + + return MAIL_NO_ERROR; + + free_str: + mmap_string_free(mmapstr); + unmap: + munmap(str, size); + close: + close(fd); + err: + return res; +} + + +int mhdriver_fetch_size(mailsession * session, uint32_t index, + size_t * result) +{ + struct mailmh_folder * folder; + int r; + struct stat buf; + char * name; + + folder = get_mh_cur_folder(session); + if (folder == NULL) + return MAIL_ERROR_FETCH; + + r = mailmh_folder_get_message_filename(folder, index, &name); + + switch (r) { + case MAILMH_NO_ERROR: + break; + + default: + return mhdriver_mh_error_to_mail_error(r); + } + + r = stat(name, &buf); + free(name); + if (r == -1) + return MAIL_ERROR_FETCH; + + * result = buf.st_size; + + return MAIL_NO_ERROR; +} + +int +mhdriver_get_cached_flags(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + mailsession * session, + uint32_t num, + struct mail_flags ** result) +{ + int r; + char keyname[PATH_MAX]; + struct mail_flags * flags; + int res; + struct mailmh_msg_info * msg_info; + chashdatum key; + chashdatum data; + struct mailmh_folder * folder; + + folder = cached_get_mh_cur_folder(session); +#if 0 + msg_info = cinthash_find(mh_data->cur_folder->fl_msgs_hash, num); + if (msg_info == NULL) + return MAIL_ERROR_CACHE_MISS; +#endif + key.data = # + key.len = sizeof(num); + r = chash_get(folder->fl_msgs_hash, &key, &data); + if (r < 0) + return MAIL_ERROR_CACHE_MISS; + msg_info = data.data; + + snprintf(keyname, PATH_MAX, "%u-%lu-%lu-flags", + num, (unsigned long) msg_info->msg_mtime, + (unsigned long) msg_info->msg_size); + + r = generic_cache_flags_read(cache_db, mmapstr, keyname, &flags); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + * result = flags; + + return MAIL_NO_ERROR; + + err: + return res; +} + +int +mhdriver_write_cached_flags(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + char * uid, + struct mail_flags * flags) +{ + int r; + char keyname[PATH_MAX]; + int res; + + snprintf(keyname, PATH_MAX, "%s-flags", uid); + + r = generic_cache_flags_write(cache_db, mmapstr, keyname, flags); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + return MAIL_NO_ERROR; + + err: + return res; +} + + +int mh_get_messages_list(struct mailmh_folder * folder, + mailsession * session, mailmessage_driver * driver, + struct mailmessage_list ** result) +{ + unsigned int i; + struct mailmessage_list * env_list; + int r; + carray * tab; + int res; + + tab = carray_new(128); + if (tab == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i++) { + struct mailmh_msg_info * mh_info; + mailmessage * msg; + + mh_info = carray_get(folder->fl_msgs_tab, i); + if (mh_info == NULL) + continue; + + msg = mailmessage_new(); + if (msg == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_list; + } + + r = mailmessage_init(msg, session, driver, + mh_info->msg_index, mh_info->msg_size); + if (r != MAIL_NO_ERROR) { + res = r; + goto free_list; + } + + r = carray_add(tab, msg, NULL); + if (r < 0) { + mailmessage_free(msg); + res = MAIL_ERROR_MEMORY; + goto free_list; + } + } + + env_list = mailmessage_list_new(tab); + if (env_list == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_list; + } + + * result = env_list; + + return MAIL_NO_ERROR; + + free_list: + for(i = 0 ; i < carray_count(tab) ; i ++) + mailmessage_free(carray_get(tab, i)); + carray_free(tab); + err: + return res; +} diff --git a/libetpan/src/driver/implementation/mh/mhdriver_tools.h b/libetpan/src/driver/implementation/mh/mhdriver_tools.h new file mode 100644 index 0000000..7b8928e --- a/dev/null +++ b/libetpan/src/driver/implementation/mh/mhdriver_tools.h @@ -0,0 +1,80 @@ +/* + * 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 MHDRIVER_TOOLS_H + +#define MHDRIVER_TOOLS_H + +#include "maildriver_types.h" +#include "mail_cache_db_types.h" +#include "mailmh.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int mhdriver_mh_error_to_mail_error(int error); + +int mhdriver_fetch_message(mailsession * session, uint32_t index, + char ** result, size_t * result_len); + +int mhdriver_fetch_header(mailsession * session, uint32_t index, + char ** result, size_t * result_len); + +int mhdriver_fetch_size(mailsession * session, uint32_t index, + size_t * result); + +int +mhdriver_get_cached_flags(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + mailsession * session, + uint32_t num, + struct mail_flags ** result); + +int +mhdriver_write_cached_flags(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + char * uid, + struct mail_flags * flags); + +int mh_get_messages_list(struct mailmh_folder * folder, + mailsession * session, mailmessage_driver * driver, + struct mailmessage_list ** result); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/mh/mhdriver_types.h b/libetpan/src/driver/implementation/mh/mhdriver_types.h new file mode 100644 index 0000000..45afb64 --- a/dev/null +++ b/libetpan/src/driver/implementation/mh/mhdriver_types.h @@ -0,0 +1,100 @@ +/* + * 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 MHDRIVER_TYPES_H + +#define MHDRIVER_TYPES_H + +#include <libetpan/libetpan-config.h> + +#include <libetpan/maildriver_types.h> +#include <libetpan/mailmh.h> +#include <libetpan/clist.h> +#include <libetpan/generic_cache_types.h> +#include <libetpan/mailstorage_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct mh_session_state_data { + struct mailmh * mh_session; + + struct mailmh_folder * mh_cur_folder; + + clist * mh_subscribed_list; +}; + +enum { + MHDRIVER_CACHED_SET_CACHE_DIRECTORY = 1, + MHDRIVER_CACHED_SET_FLAGS_DIRECTORY, +}; + +struct mh_cached_session_state_data { + mailsession * mh_ancestor; + char * mh_quoted_mb; + char mh_cache_directory[PATH_MAX]; + char mh_flags_directory[PATH_MAX]; + struct mail_flags_store * mh_flags_store; +}; + +/* mh storage */ + +/* + mh_mailstorage is the state data specific to the MH storage. + + - pathname is the root path of the MH storage. + + - cached if this value is != 0, a persistant cache will be + stored on local system. + + - cache_directory is the location of the cache. + + - flags_directory is the location of the flags. +*/ + +struct mh_mailstorage { + char * mh_pathname; + + int mh_cached; + char * mh_cache_directory; + char * mh_flags_directory; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/mh/mhstorage.c b/libetpan/src/driver/implementation/mh/mhstorage.c new file mode 100644 index 0000000..e7fc2f0 --- a/dev/null +++ b/libetpan/src/driver/implementation/mh/mhstorage.c @@ -0,0 +1,192 @@ +/* + * 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 "mhstorage.h" + +#include "mhdriver.h" +#include "mhdriver_cached.h" +#include "mail.h" + +#include <stdlib.h> +#include <string.h> + +/* mh storage */ + +static int mh_mailstorage_connect(struct mailstorage * storage); +static int mh_mailstorage_get_folder_session(struct mailstorage * storage, + char * pathname, mailsession ** result); +static void mh_mailstorage_uninitialize(struct mailstorage * storage); + +static mailstorage_driver mh_mailstorage_driver = { + .sto_name = "mh", + .sto_connect = mh_mailstorage_connect, + .sto_get_folder_session = mh_mailstorage_get_folder_session, + .sto_uninitialize = mh_mailstorage_uninitialize, +}; + +int mh_mailstorage_init(struct mailstorage * storage, + char * mh_pathname, int mh_cached, + char * mh_cache_directory, char * mh_flags_directory) +{ + struct mh_mailstorage * mh_storage; + + mh_storage = malloc(sizeof(* mh_storage)); + if (mh_storage == NULL) + goto err; + + mh_storage->mh_pathname = strdup(mh_pathname); + if (mh_storage->mh_pathname == NULL) + goto free; + + mh_storage->mh_cached = mh_cached; + + if (mh_cached && (mh_cache_directory != NULL) && + (mh_flags_directory != NULL)) { + mh_storage->mh_cache_directory = strdup(mh_cache_directory); + if (mh_storage->mh_cache_directory == NULL) + goto free_pathname; + mh_storage->mh_flags_directory = strdup(mh_flags_directory); + if (mh_storage->mh_flags_directory == NULL) + goto free_cache_directory; + } + else { + mh_storage->mh_cached = FALSE; + mh_storage->mh_cache_directory = NULL; + mh_storage->mh_flags_directory = NULL; + } + + storage->sto_data = mh_storage; + storage->sto_driver = &mh_mailstorage_driver; + + return MAIL_NO_ERROR; + + free_cache_directory: + free(mh_storage->mh_cache_directory); + free_pathname: + free(mh_storage->mh_pathname); + free: + free(mh_storage); + err: + return MAIL_ERROR_MEMORY; +} + +static void mh_mailstorage_uninitialize(struct mailstorage * storage) +{ + struct mh_mailstorage * mh_storage; + + mh_storage = storage->sto_data; + if (mh_storage->mh_flags_directory != NULL) + free(mh_storage->mh_flags_directory); + if (mh_storage->mh_cache_directory != NULL) + free(mh_storage->mh_cache_directory); + free(mh_storage->mh_pathname); + free(mh_storage); + + storage->sto_data = NULL; +} + +static int mh_mailstorage_connect(struct mailstorage * storage) +{ + struct mh_mailstorage * mh_storage; + mailsession_driver * driver; + int r; + int res; + mailsession * session; + + mh_storage = storage->sto_data; + + if (mh_storage->mh_cached) + driver = mh_cached_session_driver; + else + driver = mh_session_driver; + + session = mailsession_new(driver); + if (session == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + if (mh_storage->mh_cached) { + r = mailsession_parameters(session, + MHDRIVER_CACHED_SET_CACHE_DIRECTORY, + mh_storage->mh_cache_directory); + if (r != MAIL_NO_ERROR) { + res = r; + goto free; + } + + r = mailsession_parameters(session, + MHDRIVER_CACHED_SET_FLAGS_DIRECTORY, + mh_storage->mh_flags_directory); + if (r != MAIL_NO_ERROR) { + res = r; + goto free; + } + } + + r = mailsession_connect_path(session, mh_storage->mh_pathname); + switch (r) { + case MAIL_NO_ERROR_NON_AUTHENTICATED: + case MAIL_NO_ERROR_AUTHENTICATED: + case MAIL_NO_ERROR: + break; + default: + res = r; + goto free; + } + + storage->sto_session = session; + + return MAIL_NO_ERROR; + + free: + mailsession_free(session); + err: + return res; +} + +static int mh_mailstorage_get_folder_session(struct mailstorage * storage, + char * pathname, mailsession ** result) +{ + int r; + + r = mailsession_select_folder(storage->sto_session, pathname); + if (r != MAIL_NO_ERROR) + return r; + + * result = storage->sto_session; + + return MAIL_NO_ERROR; +} diff --git a/libetpan/src/driver/implementation/mh/mhstorage.h b/libetpan/src/driver/implementation/mh/mhstorage.h new file mode 100644 index 0000000..be86007 --- a/dev/null +++ b/libetpan/src/driver/implementation/mh/mhstorage.h @@ -0,0 +1,67 @@ +/* + * 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 MHSTORAGE_H + +#define MHSTORAGE_H + +#include <libetpan/mhdriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + mh_mailstorage_init is the constructor for a MH storage + + @param pathname is the filename the root path of the MH storage. + + @param cached if this value is != 0, a persistant cache will be + stored on local system. + + @param cache_directory is the location of the cache. + + @param flags_directory is the location of the flags. +*/ + +int mh_mailstorage_init(struct mailstorage * storage, + char * mh_pathname, int mh_cached, + char * mh_cache_directory, char * mh_flags_directory); + +#ifdef __cplusplus +} +#endif + +#endif |