From 9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf Mon Sep 17 00:00:00 2001 From: zautrix Date: Fri, 18 Mar 2005 20:17:03 +0000 Subject: Initial revision --- (limited to 'libetpan/src/driver/implementation/mh/mhdriver.c') 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} -- cgit v0.9.0.2