38 files changed, 703 insertions, 40 deletions
diff --git a/kmicromail/libetpan/generic/imapdriver.c b/kmicromail/libetpan/generic/imapdriver.c index 0d63319..b3e5982 100644 --- a/kmicromail/libetpan/generic/imapdriver.c +++ b/kmicromail/libetpan/generic/imapdriver.c @@ -1,1130 +1,1158 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "imapdriver.h" #include "mail.h" #include "imapdriver_tools.h" #include "mailmessage.h" #include "imapdriver_message.h" #include "imapdriver_types.h" #include "maildriver.h" #include "maildriver_tools.h" #include "generic_cache.h" #include <stdlib.h> #include <string.h> static int imapdriver_initialize(mailsession * session); static void imapdriver_uninitialize(mailsession * session); static int imapdriver_connect_stream(mailsession * session, mailstream * s); static int imapdriver_starttls(mailsession * session); static int imapdriver_login(mailsession * session, char * userid, char * password); static int imapdriver_logout(mailsession * session); static int imapdriver_noop(mailsession * session); static int imapdriver_build_folder_name(mailsession * session, char * mb, char * name, char ** result); static int imapdriver_create_folder(mailsession * session, char * mb); static int imapdriver_delete_folder(mailsession * session, char * mb); static int imapdriver_rename_folder(mailsession * session, char * mb, char * new_name); static int imapdriver_check_folder(mailsession * session); static int imapdriver_examine_folder(mailsession * session, char * mb); static int imapdriver_select_folder(mailsession * session, char * mb); static int imapdriver_expunge_folder(mailsession * session); static int imapdriver_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); static int imapdriver_messages_number(mailsession * session, char * mb, uint32_t * result); static int imapdriver_recent_number(mailsession * session, char * mb, uint32_t * result); static int imapdriver_unseen_number(mailsession * session, char * mb, uint32_t * result); static int imapdriver_list_folders(mailsession * session, char * mb, struct mail_list ** result); static int imapdriver_lsub_folders(mailsession * session, char * mb, struct mail_list ** result); static int imapdriver_subscribe_folder(mailsession * session, char * mb); static int imapdriver_unsubscribe_folder(mailsession * session, char * mb); static int imapdriver_append_message(mailsession * session, char * message, size_t size); +static int imapdriver_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags); static int imapdriver_copy_message(mailsession * session, uint32_t num, char * mb); static int imapdriver_get_messages_list(mailsession * session, struct mailmessage_list ** result); static int imapdriver_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list); #if 0 static int imapdriver_search_messages(mailsession * session, char * charset, struct mail_search_key * key, struct mail_search_result ** result); #endif static int imapdriver_get_message(mailsession * session, uint32_t num, mailmessage ** result); static int imapdriver_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result); static mailsession_driver local_imap_session_driver = { .sess_name = "imap", .sess_initialize = imapdriver_initialize, .sess_uninitialize = imapdriver_uninitialize, .sess_parameters = NULL, .sess_connect_stream = imapdriver_connect_stream, .sess_connect_path = NULL, .sess_starttls = imapdriver_starttls, .sess_login = imapdriver_login, .sess_logout = imapdriver_logout, .sess_noop = imapdriver_noop, .sess_build_folder_name = imapdriver_build_folder_name, .sess_create_folder = imapdriver_create_folder, .sess_delete_folder = imapdriver_delete_folder, .sess_rename_folder = imapdriver_rename_folder, .sess_check_folder = imapdriver_check_folder, .sess_examine_folder = imapdriver_examine_folder, .sess_select_folder = imapdriver_select_folder, .sess_expunge_folder = imapdriver_expunge_folder, .sess_status_folder = imapdriver_status_folder, .sess_messages_number = imapdriver_messages_number, .sess_recent_number = imapdriver_recent_number, .sess_unseen_number = imapdriver_unseen_number, .sess_list_folders = imapdriver_list_folders, .sess_lsub_folders = imapdriver_lsub_folders, .sess_subscribe_folder = imapdriver_subscribe_folder, .sess_unsubscribe_folder = imapdriver_unsubscribe_folder, .sess_append_message = imapdriver_append_message, + .sess_append_message_flags = imapdriver_append_message_flags, .sess_copy_message = imapdriver_copy_message, .sess_move_message = NULL, .sess_get_messages_list = imapdriver_get_messages_list, .sess_get_envelopes_list = imapdriver_get_envelopes_list, .sess_remove_message = NULL, #if 0 .sess_search_messages = imapdriver_search_messages, #endif .sess_get_message = imapdriver_get_message, .sess_get_message_by_uid = imapdriver_get_message_by_uid, }; mailsession_driver * imap_session_driver = &local_imap_session_driver; static inline struct imap_session_state_data * get_data(mailsession * session) { return session->sess_data; } static mailimap * get_imap_session(mailsession * session) { return get_data(session)->imap_session; } static int imapdriver_initialize(mailsession * session) { struct imap_session_state_data * data; mailimap * imap; struct mail_flags_store * flags_store; imap = mailimap_new(0, NULL); if (imap == NULL) goto err; flags_store = mail_flags_store_new(); if (flags_store == NULL) goto free_session; data = malloc(sizeof(* data)); if (data == NULL) goto free_flags_store; data->imap_mailbox = NULL; data->imap_session = imap; data->imap_flags_store = flags_store; session->sess_data = data; return MAIL_NO_ERROR; free_flags_store: mail_flags_store_free(flags_store); free_session: mailimap_free(imap); err: return MAIL_ERROR_MEMORY; } static void imap_flags_store_process(mailimap * imap, struct mail_flags_store * flags_store) { unsigned int i; int r; mailmessage * first; mailmessage * last; mail_flags_store_sort(flags_store); if (carray_count(flags_store->fls_tab) == 0) return; first = carray_get(flags_store->fls_tab, 0); last = first; for(i = 1 ; i < carray_count(flags_store->fls_tab) ; i ++) { mailmessage * msg; msg = carray_get(flags_store->fls_tab, i); if (last->msg_index + 1 == msg->msg_index) { r = mail_flags_compare(first->msg_flags, msg->msg_flags); if (r == 0) { last = msg; continue; } } r = imap_store_flags(imap, first->msg_index, last->msg_index, first->msg_flags); first = msg; last = msg; } r = imap_store_flags(imap, first->msg_index, last->msg_index, first->msg_flags); mail_flags_store_clear(flags_store); } static void imapdriver_uninitialize(mailsession * session) { struct imap_session_state_data * data; data = get_data(session); imap_flags_store_process(data->imap_session, data->imap_flags_store); mail_flags_store_free(data->imap_flags_store); mailimap_free(data->imap_session); if (data->imap_mailbox != NULL) free(data->imap_mailbox); free(data); session->sess_data = NULL; } static int imapdriver_connect_stream(mailsession * session, mailstream * s) { int r; r = mailimap_connect(get_imap_session(session), s); return imap_error_to_mail_error(r); } static int imapdriver_login(mailsession * session, char * userid, char * password) { int r; r = mailimap_login(get_imap_session(session), userid, password); return imap_error_to_mail_error(r); } static int imapdriver_logout(mailsession * session) { int r; imap_flags_store_process(get_imap_session(session), get_data(session)->imap_flags_store); r = mailimap_logout(get_imap_session(session)); return imap_error_to_mail_error(r); } static int imapdriver_noop(mailsession * session) { int r; r = mailimap_noop(get_imap_session(session)); return imap_error_to_mail_error(r); } static int imapdriver_build_folder_name(mailsession * session, char * mb, char * name, char ** result) { char delimiter[2] = "X"; char * folder_name; mailimap * imap; struct mailimap_mailbox_list * mb_list; int r; clist * imap_list; imap = get_imap_session(session); r = mailimap_list(imap, mb, "", &imap_list); if (r != MAILIMAP_NO_ERROR) return r; if (clist_begin(imap_list) == NULL) return MAIL_ERROR_LIST; mb_list = clist_begin(imap_list)->data; delimiter[0] = mb_list->mb_delimiter; folder_name = malloc(strlen(mb) + strlen(delimiter) + strlen(name) + 1); if (folder_name == NULL) return MAIL_ERROR_MEMORY; strcpy(folder_name, mb); strcat(folder_name, delimiter); strcat(folder_name, name); * result = folder_name; return MAIL_NO_ERROR; } /* folders operations */ static int imapdriver_create_folder(mailsession * session, char * mb) { int r; r = mailimap_create(get_imap_session(session), mb); return imap_error_to_mail_error(r); } static int imapdriver_delete_folder(mailsession * session, char * mb) { int r; r = mailimap_delete(get_imap_session(session), mb); return imap_error_to_mail_error(r); } static int imapdriver_rename_folder(mailsession * session, char * mb, char * new_name) { int r; r = mailimap_rename(get_imap_session(session), mb, new_name); return imap_error_to_mail_error(r); } static int imapdriver_check_folder(mailsession * session) { int r; imap_flags_store_process(get_imap_session(session), get_data(session)->imap_flags_store); r = mailimap_check(get_imap_session(session)); return imap_error_to_mail_error(r); } static int imapdriver_examine_folder(mailsession * session, char * mb) { int r; r = mailimap_examine(get_imap_session(session), mb); return imap_error_to_mail_error(r); } static int imapdriver_select_folder(mailsession * session, char * mb) { int r; char * new_mb; char * old_mb; old_mb = get_data(session)->imap_mailbox; if (old_mb != NULL) if (strcmp(mb, old_mb) == 0) return MAIL_NO_ERROR; imap_flags_store_process(get_imap_session(session), get_data(session)->imap_flags_store); r = mailimap_select(get_imap_session(session), mb); switch (r) { case MAILIMAP_NO_ERROR: new_mb = strdup(mb); if (new_mb == NULL) { if (old_mb != NULL) free(old_mb); get_data(session)->imap_mailbox = NULL; return MAIL_ERROR_MEMORY; } get_data(session)->imap_mailbox = new_mb; return MAIL_NO_ERROR; default: return imap_error_to_mail_error(r); } } static int imapdriver_expunge_folder(mailsession * session) { int r; imap_flags_store_process(get_imap_session(session), get_data(session)->imap_flags_store); r = mailimap_expunge(get_imap_session(session)); return imap_error_to_mail_error(r); } static int status_selected_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { int r; int res; mailimap * imap; uint32_t exists; uint32_t unseen; uint32_t recent; struct mailimap_search_key * search_key; clist * search_result; imap = get_imap_session(session); exists = imap->imap_selection_info->sel_exists; recent = imap->imap_selection_info->sel_recent; search_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_UNSEEN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL); if (search_key == NULL) { res = MAIL_ERROR_MEMORY; goto err; } /* default : use the RECENT count if search fails */ unseen = recent; r = mailimap_search(imap, NULL, search_key, &search_result); mailimap_search_key_free(search_key); if (r == MAILIMAP_NO_ERROR) { /* if this succeed, we use the real count */ unseen = clist_count(search_result); mailimap_mailbox_data_search_free(search_result); } * result_messages = exists; * result_unseen = unseen; * result_recent = recent; return MAIL_NO_ERROR; err: return res; } static int status_unselected_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { struct mailimap_status_att_list * att_list; struct mailimap_mailbox_data_status * status; int r; int res; clistiter * cur; mailimap * imap; imap = get_imap_session(session); att_list = mailimap_status_att_list_new_empty(); if (att_list == NULL) { res = MAIL_ERROR_MEMORY; goto err; } r = mailimap_status_att_list_add(att_list, MAILIMAP_STATUS_ATT_MESSAGES); switch (r) { case MAILIMAP_NO_ERROR: break; default: res = MAIL_ERROR_MEMORY; goto free; } r = mailimap_status_att_list_add(att_list, MAILIMAP_STATUS_ATT_RECENT); switch (r) { case MAILIMAP_NO_ERROR: break; default: res = MAIL_ERROR_MEMORY; goto free; } r = mailimap_status_att_list_add(att_list, MAILIMAP_STATUS_ATT_UNSEEN); switch (r) { case MAILIMAP_NO_ERROR: break; default: res = MAIL_ERROR_MEMORY; goto free; } r = mailimap_status(imap, mb, att_list, &status); switch (r) { case MAILIMAP_NO_ERROR: break; default: res = imap_error_to_mail_error(r); goto free; } * result_messages = 0; * result_recent = 0; * result_unseen = 0; for (cur = clist_begin(status->st_info_list); cur != NULL ; cur = clist_next(cur)) { struct mailimap_status_info * status_info; status_info = clist_content(cur); switch (status_info->st_att) { case MAILIMAP_STATUS_ATT_MESSAGES: * result_messages = status_info->st_value; break; case MAILIMAP_STATUS_ATT_RECENT: * result_recent = status_info->st_value; break; case MAILIMAP_STATUS_ATT_UNSEEN: * result_unseen = status_info->st_value; break; } } mailimap_mailbox_data_status_free(status); mailimap_status_att_list_free(att_list); return MAIL_NO_ERROR; free: mailimap_status_att_list_free(att_list); err: return res; } static int imapdriver_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { int res; int current_folder; char * current_mb; if (mb == NULL) { mb = get_data(session)->imap_mailbox; if (mb == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } } current_mb = get_data(session)->imap_mailbox; if (strcmp(mb, current_mb) == 0) current_folder = 1; else current_folder = 0; if (current_folder) return status_selected_folder(session, mb, result_messages, result_recent, result_unseen); else return status_unselected_folder(session, mb, result_messages, result_recent, result_unseen); err: return res; } /* TODO : more efficient functions */ static int imapdriver_messages_number(mailsession * session, char * mb, uint32_t * result) { uint32_t messages; uint32_t recent; uint32_t unseen; int r; r = imapdriver_status_folder(session, mb, &messages, &recent, &unseen); if (r != MAIL_NO_ERROR) return r; * result = messages; return MAIL_NO_ERROR; } static int imapdriver_recent_number(mailsession * session, char * mb, uint32_t * result) { uint32_t messages; uint32_t recent; uint32_t unseen; int r; r = imapdriver_status_folder(session, mb, &messages, &recent, &unseen); if (r != MAIL_NO_ERROR) return r; * result = recent; return MAIL_NO_ERROR; } static int imapdriver_unseen_number(mailsession * session, char * mb, uint32_t * result) { uint32_t messages; uint32_t recent; uint32_t unseen; int r; r = imapdriver_status_folder(session, mb, &messages, &recent, &unseen); if (r != MAIL_NO_ERROR) return r; * result = unseen; return MAIL_NO_ERROR; } enum { IMAP_LIST, IMAP_LSUB }; static int imapdriver_list_lsub_folders(mailsession * session, int type, char * mb, struct mail_list ** result) { clist * imap_list; struct mail_list * resp; int r; int res; switch (type) { case IMAP_LIST: r = mailimap_list(get_imap_session(session), mb, "*", &imap_list); break; case IMAP_LSUB: r = mailimap_lsub(get_imap_session(session), mb, "*", &imap_list); break; default: res = MAIL_ERROR_LIST; goto err; } switch (r) { case MAILIMAP_NO_ERROR: break; default: res = imap_error_to_mail_error(r); goto err; } r = imap_list_to_list(imap_list, &resp); if (r != MAIL_NO_ERROR) { mailimap_list_result_free(imap_list); res = r; goto err; } mailimap_list_result_free(imap_list); * result = resp; return MAIL_NO_ERROR; err: return res; } static int imapdriver_list_folders(mailsession * session, char * mb, struct mail_list ** result) { return imapdriver_list_lsub_folders(session, IMAP_LIST, mb, result); } static int imapdriver_lsub_folders(mailsession * session, char * mb, struct mail_list ** result) { return imapdriver_list_lsub_folders(session, IMAP_LSUB, mb, result); } static int imapdriver_subscribe_folder(mailsession * session, char * mb) { int r; r = mailimap_subscribe(get_imap_session(session), mb); return imap_error_to_mail_error(r); } static int imapdriver_unsubscribe_folder(mailsession * session, char * mb) { int r; r = mailimap_unsubscribe(get_imap_session(session), mb); return imap_error_to_mail_error(r); } /* messages operations */ static int imapdriver_append_message(mailsession * session, char * message, size_t size) { int r; r = mailimap_append_simple(get_imap_session(session), get_data(session)->imap_mailbox, message, size); return imap_error_to_mail_error(r); } +static int imapdriver_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags) +{ + struct mailimap_flag_list * flag_list; + int r; + + if (flags != NULL) { + r = imap_flags_to_imap_flags(flags, &flag_list); + if (r != MAIL_NO_ERROR) + return r; + } + else { + flag_list = NULL; + } + + r = mailimap_append(get_imap_session(session), + get_data(session)->imap_mailbox, + flag_list, NULL, message, size); + + if (flag_list != NULL) + mailimap_flag_list_free(flag_list); + + return imap_error_to_mail_error(r); +} + static int imapdriver_copy_message(mailsession * session, uint32_t num, char * mb) { int r; struct mailimap_set * set; int res; set = mailimap_set_new_single(num); if (set == NULL) { res = MAIL_ERROR_MEMORY; goto err; } r = mailimap_uid_copy(get_imap_session(session), set, mb); mailimap_set_free(set); return imap_error_to_mail_error(r); err: return res; } static int imapdriver_get_messages_list(mailsession * session, struct mailmessage_list ** result) { return imap_get_messages_list(get_imap_session(session), session, imap_message_driver, 1, result); } static int imapdriver_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list) { struct mailimap_set * set; struct mailimap_fetch_att * fetch_att; struct mailimap_fetch_type * fetch_type; int res; clist * fetch_result; int r; uint32_t exists; clist * msg_list; if (get_imap_session(session)->imap_selection_info == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } imap_flags_store_process(get_imap_session(session), get_data(session)->imap_flags_store); exists = get_imap_session(session)->imap_selection_info->sel_exists; if (exists == 0) return MAIL_NO_ERROR; fetch_type = mailimap_fetch_type_new_fetch_att_list_empty(); if (fetch_type == NULL) { res = MAIL_ERROR_MEMORY; goto err; } fetch_att = mailimap_fetch_att_new_uid(); if (fetch_att == NULL) { res = MAIL_ERROR_MEMORY; goto free_fetch_type; } r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); if (r != MAILIMAP_NO_ERROR) { mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto free_fetch_type; } fetch_att = mailimap_fetch_att_new_flags(); if (fetch_att == NULL) { res = MAIL_ERROR_MEMORY; goto free_fetch_type; } r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); if (r != MAILIMAP_NO_ERROR) { mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto free_fetch_type; } r = imap_add_envelope_fetch_att(fetch_type); if (r != MAIL_NO_ERROR) { res = r; goto free_fetch_type; } r = maildriver_env_list_to_msg_list(env_list, &msg_list); if (r != MAIL_NO_ERROR) { res = MAIL_ERROR_MEMORY; goto free_fetch_type; } if (clist_begin(msg_list) == NULL) { /* no need to fetch envelopes */ mailimap_fetch_type_free(fetch_type); clist_free(msg_list); return MAIL_NO_ERROR; } r = msg_list_to_imap_set(msg_list, &set); if (r != MAIL_NO_ERROR) { clist_foreach(msg_list, (clist_func) free, NULL); clist_free(msg_list); res = MAIL_ERROR_MEMORY; goto free_fetch_type; } clist_foreach(msg_list, (clist_func) free, NULL); clist_free(msg_list); r = mailimap_uid_fetch(get_imap_session(session), set, fetch_type, &fetch_result); mailimap_fetch_type_free(fetch_type); mailimap_set_free(set); switch (r) { case MAILIMAP_NO_ERROR: break; default: return imap_error_to_mail_error(r); } if (clist_begin(fetch_result) == NULL) { res = MAIL_ERROR_FETCH; goto err; } r = imap_fetch_result_to_envelop_list(fetch_result, env_list); mailimap_fetch_list_free(fetch_result); if (r != MAIL_NO_ERROR) { res = MAIL_ERROR_MEMORY; goto err; } return MAIL_NO_ERROR; free_fetch_type: mailimap_fetch_type_free(fetch_type); err: return res; } #if 0 static int imapdriver_search_messages(mailsession * session, char * charset, struct mail_search_key * key, struct mail_search_result ** result) { struct mailimap_search_key * imap_key; int r; clist * imap_result; clist * result_list; struct mail_search_result * search_result; clistiter * cur; r = mail_search_to_imap_search(key, &imap_key); if (r != MAIL_NO_ERROR) return MAIL_ERROR_MEMORY; r = mailimap_uid_search(get_imap_session(session), charset, imap_key, &imap_result); mailimap_search_key_free(imap_key); switch (r) { case MAILIMAP_NO_ERROR: break; default: return imap_error_to_mail_error(r); } result_list = clist_new(); if (result_list == NULL) return MAIL_ERROR_MEMORY; for(cur = clist_begin(imap_result) ; cur != NULL ; cur = clist_next(cur)) { uint32_t val = * (uint32_t *) clist_content(cur); uint32_t * new; new = malloc(sizeof(* new)); if (new == NULL) { goto free_imap_result; } * new = val; r = clist_append(result_list, new); if (r != 0) { free(new); goto free_imap_result; } } search_result = mail_search_result_new(result_list); if (search_result == NULL) goto free_imap_result; mailimap_search_result_free(imap_result); * result = search_result; return MAIL_NO_ERROR; free_imap_result: mailimap_search_result_free(imap_result); return MAIL_ERROR_MEMORY; } #endif static int imapdriver_starttls(mailsession * session) { mailimap * imap; int r; struct mailimap_capability_data * cap_data; clistiter * cur; int starttls; int fd; mailstream_low * low; mailstream_low * new_low; int capability_available; imap = get_imap_session(session); capability_available = FALSE; if (imap->imap_connection_info != NULL) if (imap->imap_connection_info->imap_capability != NULL) { capability_available = TRUE; cap_data = imap->imap_connection_info->imap_capability; } if (!capability_available) { r = mailimap_capability(imap, &cap_data); switch (r) { case MAILIMAP_NO_ERROR: break; default: return imap_error_to_mail_error(r); } } starttls = FALSE; for(cur = clist_begin(cap_data->cap_list) ; cur != NULL ; cur = clist_next(cur)) { struct mailimap_capability * cap; cap = clist_content(cur); if (cap->cap_type == MAILIMAP_CAPABILITY_NAME) if (strcasecmp(cap->cap_data.cap_name, "STARTTLS") == 0) { starttls = TRUE; break; } } if (!capability_available) mailimap_capability_data_free(cap_data); if (!starttls) return MAIL_ERROR_NO_TLS; r = mailimap_starttls(imap); switch (r) { case MAILIMAP_NO_ERROR: break; default: return imap_error_to_mail_error(r); } low = mailstream_get_low(imap->imap_stream); fd = mailstream_low_get_fd(low); if (fd == -1) return MAIL_ERROR_STREAM; new_low = mailstream_low_ssl_open(fd); if (new_low == NULL) return MAIL_ERROR_STREAM; mailstream_low_free(low); mailstream_set_low(imap->imap_stream, new_low); return MAIL_NO_ERROR; } static int imapdriver_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, imap_message_driver, num, 0); if (r != MAIL_NO_ERROR) { mailmessage_free(msg_info); return r; } * result = msg_info; return MAIL_NO_ERROR; } /* Retrieve a message by UID libEtPan! uid format for IMAP is "UIDVALIDITY-UID" where UIDVALIDITY and UID are decimal representation of respectively uidvalidity and uid numbers. Return value: MAIL_ERROR_INVAL if uid is NULL or has an incorrect format. MAIL_ERROR_MSG_NOT_FOUND if uidvalidity has changed or uid was not found MAIL_NO_ERROR if message was found. Result is in result */ static int imapdriver_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result) { uint32_t uidvalidity; uint32_t num; char * p1, * p2; mailimap * imap; if (uid == NULL) return MAIL_ERROR_INVAL; uidvalidity = strtoul(uid, &p1, 10); if (p1 == uid || * p1 != '-') return MAIL_ERROR_INVAL; p1++; num = strtoul(p1, &p2, 10); if (p2 == p1 || * p2 != '\0') return MAIL_ERROR_INVAL; imap = get_imap_session(session); if (imap->imap_selection_info->sel_uidvalidity != uidvalidity) return MAIL_ERROR_MSG_NOT_FOUND; return imapdriver_get_message(session, num, result); } diff --git a/kmicromail/libetpan/generic/imapdriver_cached.c b/kmicromail/libetpan/generic/imapdriver_cached.c index e6af8e8..04044ae 100644 --- a/kmicromail/libetpan/generic/imapdriver_cached.c +++ b/kmicromail/libetpan/generic/imapdriver_cached.c @@ -1,1274 +1,1290 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "imapdriver_cached.h" #include "libetpan-config.h" #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include "mail.h" #include "imapdriver_tools.h" #include "mail_cache_db.h" #include "mailmessage.h" #include "imapdriver_cached_message.h" #include "maildriver.h" #include "imapdriver_types.h" #include "generic_cache.h" #include "imfcache.h" #include "maildriver_tools.h" #include "imapdriver.h" static int imapdriver_cached_initialize(mailsession * session); static void imapdriver_cached_uninitialize(mailsession * session); static int imapdriver_cached_parameters(mailsession * session, int id, void * value); static int imapdriver_cached_connect_stream(mailsession * session, mailstream * s); static int imapdriver_cached_starttls(mailsession * session); static int imapdriver_cached_login(mailsession * session, char * userid, char * password); static int imapdriver_cached_logout(mailsession * session); static int imapdriver_cached_noop(mailsession * session); static int imapdriver_cached_build_folder_name(mailsession * session, char * mb, char * name, char ** result); static int imapdriver_cached_create_folder(mailsession * session, char * mb); static int imapdriver_cached_delete_folder(mailsession * session, char * mb); static int imapdriver_cached_rename_folder(mailsession * session, char * mb, char * new_name); static int imapdriver_cached_check_folder(mailsession * session); static int imapdriver_cached_examine_folder(mailsession * session, char * mb); static int imapdriver_cached_select_folder(mailsession * session, char * mb); static int imapdriver_cached_expunge_folder(mailsession * session); static int imapdriver_cached_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); static int imapdriver_cached_messages_number(mailsession * session, char * mb, uint32_t * result); static int imapdriver_cached_recent_number(mailsession * session, char * mb, uint32_t * result); static int imapdriver_cached_unseen_number(mailsession * session, char * mb, uint32_t * result); static int imapdriver_cached_list_folders(mailsession * session, char * mb, struct mail_list ** result); static int imapdriver_cached_lsub_folders(mailsession * session, char * mb, struct mail_list ** result); static int imapdriver_cached_subscribe_folder(mailsession * session, char * mb); static int imapdriver_cached_unsubscribe_folder(mailsession * session, char * mb); static int imapdriver_cached_append_message(mailsession * session, char * message, size_t size); +static int imapdriver_cached_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags); static int imapdriver_cached_copy_message(mailsession * session, uint32_t num, char * mb); static int imapdriver_cached_get_messages_list(mailsession * session, struct mailmessage_list ** result); static int imapdriver_cached_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list); static int imapdriver_cached_remove_message(mailsession * session, uint32_t num); #if 0 static int imapdriver_cached_search_messages(mailsession * session, char * charset, struct mail_search_key * key, struct mail_search_result ** result); #endif static int imapdriver_cached_get_message(mailsession * session, uint32_t num, mailmessage ** result); static int imapdriver_cached_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result); static mailsession_driver local_imap_cached_session_driver = { .sess_name = "imap-cached", .sess_initialize = imapdriver_cached_initialize, .sess_uninitialize = imapdriver_cached_uninitialize, .sess_parameters = imapdriver_cached_parameters, .sess_connect_stream = imapdriver_cached_connect_stream, .sess_connect_path = NULL, .sess_starttls = imapdriver_cached_starttls, .sess_login = imapdriver_cached_login, .sess_logout = imapdriver_cached_logout, .sess_noop = imapdriver_cached_noop, .sess_build_folder_name = imapdriver_cached_build_folder_name, .sess_create_folder = imapdriver_cached_create_folder, .sess_delete_folder = imapdriver_cached_delete_folder, .sess_rename_folder = imapdriver_cached_rename_folder, .sess_check_folder = imapdriver_cached_check_folder, .sess_examine_folder = imapdriver_cached_examine_folder, .sess_select_folder = imapdriver_cached_select_folder, .sess_expunge_folder = imapdriver_cached_expunge_folder, .sess_status_folder = imapdriver_cached_status_folder, .sess_messages_number = imapdriver_cached_messages_number, .sess_recent_number = imapdriver_cached_recent_number, .sess_unseen_number = imapdriver_cached_unseen_number, .sess_list_folders = imapdriver_cached_list_folders, .sess_lsub_folders = imapdriver_cached_lsub_folders, .sess_subscribe_folder = imapdriver_cached_subscribe_folder, .sess_unsubscribe_folder = imapdriver_cached_unsubscribe_folder, .sess_append_message = imapdriver_cached_append_message, + .sess_append_message_flags = imapdriver_cached_append_message_flags, .sess_copy_message = imapdriver_cached_copy_message, .sess_move_message = NULL, .sess_get_messages_list = imapdriver_cached_get_messages_list, .sess_get_envelopes_list = imapdriver_cached_get_envelopes_list, .sess_remove_message = imapdriver_cached_remove_message, #if 0 .sess_search_messages = imapdriver_cached_search_messages, #endif .sess_get_message = imapdriver_cached_get_message, .sess_get_message_by_uid = imapdriver_cached_get_message_by_uid, }; mailsession_driver * imap_cached_session_driver = &local_imap_cached_session_driver; #define CACHE_MESSAGE_LIST static inline struct imap_cached_session_state_data * get_cached_data(mailsession * session) { return session->sess_data; } static inline mailsession * get_ancestor(mailsession * s) { return get_cached_data(s)->imap_ancestor; } static inline struct imap_session_state_data * get_ancestor_data(mailsession * s) { return get_ancestor(s)->sess_data; } static inline mailimap * get_imap_session(mailsession * session) { return get_ancestor_data(session)->imap_session; } static int imapdriver_cached_initialize(mailsession * session) { struct imap_cached_session_state_data * data; data = malloc(sizeof(* data)); if (data == NULL) goto err; data->imap_ancestor = mailsession_new(imap_session_driver); if (data->imap_ancestor == NULL) goto free_data; data->imap_quoted_mb = NULL; data->imap_cache_directory[0] = '\0'; data->imap_uid_list = carray_new(128); if (data->imap_uid_list == NULL) goto free_session; session->sess_data = data; return MAIL_NO_ERROR; free_session: mailsession_free(data->imap_ancestor); free_data: free(data); err: return MAIL_ERROR_MEMORY; } static void free_quoted_mb(struct imap_cached_session_state_data * imap_cached_data) { if (imap_cached_data->imap_quoted_mb != NULL) { free(imap_cached_data->imap_quoted_mb); imap_cached_data->imap_quoted_mb = NULL; } } struct uid_cache_item { uint32_t uid; uint32_t size; }; static int update_uid_cache(mailsession * session, struct mailmessage_list * env_list) { unsigned int i; int r; struct imap_cached_session_state_data * data; int res; data = get_cached_data(session); /* free all UID cache */ for(i = 0 ; i < carray_count(data->imap_uid_list) ; i ++) { struct uid_cache_item * cache_item; cache_item = carray_get(data->imap_uid_list, i); free(cache_item); } /* build UID cache */ r = carray_set_size(data->imap_uid_list, carray_count(env_list->msg_tab)); if (r < 0) { res = MAIL_ERROR_MEMORY; goto err; } for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { struct uid_cache_item * cache_item; mailmessage * msg; cache_item = malloc(sizeof(* cache_item)); if (cache_item == NULL) { res = MAIL_ERROR_MEMORY; goto err; } msg = carray_get(env_list->msg_tab, i); cache_item->uid = msg->msg_index; cache_item->size = msg->msg_size; carray_set(data->imap_uid_list, i, cache_item); } return MAIL_NO_ERROR; err: return res; } static void check_for_uid_cache(mailsession * session) { #if 0 mailsession * imap; #endif mailimap * imap; #if 0 struct imap_session_state_data * imap_data; #endif clist * list; clistiter * cur; struct imap_cached_session_state_data * data; unsigned int i; unsigned dest; data = get_cached_data(session); #if 0 imap = get_ancestor(session); imap_data = imap->data; #endif imap = get_imap_session(session); if (imap->imap_response_info == NULL) return; list = imap->imap_response_info->rsp_expunged; if (list == NULL) return; dest = 0; i = 0; /* remove expunged */ for(cur = clist_begin(list) ; cur != NULL ; cur = clist_next(cur)) { uint32_t expunged; expunged = * (uint32_t *) clist_content(cur); while (i < carray_count(data->imap_uid_list)) { struct uid_cache_item * cache_item; if (dest + 1 == expunged) { cache_item = carray_get(data->imap_uid_list, i); free(cache_item); i ++; break; } else { cache_item = carray_get(data->imap_uid_list, i); carray_set(data->imap_uid_list, dest, cache_item); i ++; dest ++; } } } /* complete list */ while (i < carray_count(data->imap_uid_list)) { struct uid_cache_item * cache_item; cache_item = carray_get(data->imap_uid_list, i); carray_set(data->imap_uid_list, dest, cache_item); i ++; dest ++; } carray_set_size(data->imap_uid_list, dest); } static void imapdriver_cached_uninitialize(mailsession * session) { struct imap_cached_session_state_data * data; unsigned int i; data = get_cached_data(session); for(i = 0 ; i < carray_count(data->imap_uid_list) ; i ++) { struct uid_cache_item * cache_item; cache_item = carray_get(data->imap_uid_list, i); free(cache_item); } carray_free(data->imap_uid_list); free_quoted_mb(data); mailsession_free(data->imap_ancestor); free(data); session->sess_data = NULL; } static int imapdriver_cached_parameters(mailsession * session, int id, void * value) { struct imap_cached_session_state_data * data; int r; data = get_cached_data(session); switch (id) { case IMAPDRIVER_CACHED_SET_CACHE_DIRECTORY: strncpy(data->imap_cache_directory, value, PATH_MAX); data->imap_cache_directory[PATH_MAX - 1] = '\0'; r = generic_cache_create_dir(data->imap_cache_directory); if (r != MAIL_NO_ERROR) return r; return MAIL_NO_ERROR; } return MAIL_ERROR_INVAL; } static int imapdriver_cached_connect_stream(mailsession * session, mailstream * s) { int r; check_for_uid_cache(session); r = mailsession_connect_stream(get_ancestor(session), s); check_for_uid_cache(session); return r; } static int imapdriver_cached_starttls(mailsession * session) { int r; r = mailsession_starttls(get_ancestor(session)); check_for_uid_cache(session); return r; } static int imapdriver_cached_login(mailsession * session, char * userid, char * password) { int r; r = mailsession_login(get_ancestor(session), userid, password); check_for_uid_cache(session); return r; } static int imapdriver_cached_logout(mailsession * session) { int r; r = mailsession_logout(get_ancestor(session)); check_for_uid_cache(session); if (r == MAIL_NO_ERROR) { struct imap_cached_session_state_data * imap_cached_data; imap_cached_data = get_cached_data(session); free_quoted_mb(imap_cached_data); } return r; } static int imapdriver_cached_noop(mailsession * session) { int r; r = mailsession_noop(get_ancestor(session)); check_for_uid_cache(session); return r; } static int imapdriver_cached_build_folder_name(mailsession * session, char * mb, char * name, char ** result) { int r; r = mailsession_build_folder_name(get_ancestor(session), mb, name, result); check_for_uid_cache(session); return r; } static int imapdriver_cached_create_folder(mailsession * session, char * mb) { int r; r = mailsession_create_folder(get_ancestor(session), mb); check_for_uid_cache(session); return r; } static int imapdriver_cached_delete_folder(mailsession * session, char * mb) { int r; r = mailsession_delete_folder(get_ancestor(session), mb); check_for_uid_cache(session); return r; } static int imapdriver_cached_rename_folder(mailsession * session, char * mb, char * new_name) { int r; r = mailsession_rename_folder(get_ancestor(session), mb, new_name); check_for_uid_cache(session); return r; } static int imapdriver_cached_check_folder(mailsession * session) { int r; r = mailsession_check_folder(get_ancestor(session)); check_for_uid_cache(session); return r; } static int imapdriver_cached_examine_folder(mailsession * session, char * mb) { int r; r = mailsession_examine_folder(get_ancestor(session), mb); check_for_uid_cache(session); return r; } static int get_cache_folder(mailsession * session, char ** result) { #if 0 mailsession * imap_session; #endif mailimap * imap; char * mb; char * cache_dir; char * dirname; char * quoted_mb; int res; int r; char key[PATH_MAX]; #if 0 struct imap_session_state_data * imap_data; struct imap_cached_session_state_data * cached_data; #endif #if 0 imap_session = get_ancestor(session); imap_data = imap_session->data; imap = imap_data->session; #endif imap = get_imap_session(session); mb = get_ancestor_data(session)->imap_mailbox; cache_dir = get_cached_data(session)->imap_cache_directory; if (imap->imap_state != MAILIMAP_STATE_SELECTED) return MAIL_ERROR_BAD_STATE; if (imap->imap_selection_info == NULL) return MAIL_ERROR_BAD_STATE; quoted_mb = maildriver_quote_mailbox(mb); if (quoted_mb == NULL) { res = MAIL_ERROR_MEMORY; goto err; } snprintf(key, PATH_MAX, "%s/%s", cache_dir, quoted_mb); dirname = strdup(key); if (dirname == NULL) { res = MAIL_ERROR_MEMORY; goto free_mb; } r = generic_cache_create_dir(dirname); if (r != MAIL_NO_ERROR) { res = r; goto free_dirname; } free(quoted_mb); * result = dirname; return MAIL_NO_ERROR; free_dirname: free(dirname); free_mb: free(quoted_mb); err: return res; } static int imapdriver_cached_select_folder(mailsession * session, char * mb) { int r; char * quoted_mb; struct imap_cached_session_state_data * data; mailsession * imap; char * old_mb; imap = get_ancestor(session); old_mb = get_ancestor_data(session)->imap_mailbox; if (old_mb != NULL) if (strcmp(mb, old_mb) == 0) return MAIL_NO_ERROR; r = mailsession_select_folder(get_ancestor(session), mb); if (r != MAIL_NO_ERROR) return r; check_for_uid_cache(session); r = get_cache_folder(session, "ed_mb); if (r != MAIL_NO_ERROR) return r; data = get_cached_data(session); if (data->imap_quoted_mb != NULL) free(data->imap_quoted_mb); data->imap_quoted_mb = quoted_mb; /* clear UID cache */ carray_set_size(data->imap_uid_list, 0); return MAIL_NO_ERROR; } static int imapdriver_cached_expunge_folder(mailsession * session) { int r; r = mailsession_expunge_folder(get_ancestor(session)); check_for_uid_cache(session); return r; } static int imapdriver_cached_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { int r; r = mailsession_status_folder(get_ancestor(session), mb, result_messages, result_recent, result_unseen); check_for_uid_cache(session); return r; } static int imapdriver_cached_messages_number(mailsession * session, char * mb, uint32_t * result) { int r; r = mailsession_messages_number(get_ancestor(session), mb, result); check_for_uid_cache(session); return r; } static int imapdriver_cached_recent_number(mailsession * session, char * mb, uint32_t * result) { int r; r = mailsession_recent_number(get_ancestor(session), mb, result); check_for_uid_cache(session); return r; } static int imapdriver_cached_unseen_number(mailsession * session, char * mb, uint32_t * result) { int r; r = mailsession_unseen_number(get_ancestor(session), mb, result); check_for_uid_cache(session); return r; } static int imapdriver_cached_list_folders(mailsession * session, char * mb, struct mail_list ** result) { int r; r = mailsession_list_folders(get_ancestor(session), mb, result); check_for_uid_cache(session); return r; } static int imapdriver_cached_lsub_folders(mailsession * session, char * mb, struct mail_list ** result) { int r; r = mailsession_lsub_folders(get_ancestor(session), mb, result); check_for_uid_cache(session); return r; } static int imapdriver_cached_subscribe_folder(mailsession * session, char * mb) { int r; r = mailsession_subscribe_folder(get_ancestor(session), mb); check_for_uid_cache(session); return r; } static int imapdriver_cached_unsubscribe_folder(mailsession * session, char * mb) { int r; r = mailsession_unsubscribe_folder(get_ancestor(session), mb); check_for_uid_cache(session); return r; } static int imapdriver_cached_append_message(mailsession * session, char * message, size_t size) { int r; r = mailsession_append_message(get_ancestor(session), message, size); check_for_uid_cache(session); return r; } +static int imapdriver_cached_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags) +{ + int r; + + r = mailsession_append_message_flags(get_ancestor(session), + message, size, flags); + + check_for_uid_cache(session); + + return r; +} + static int imapdriver_cached_copy_message(mailsession * session, uint32_t num, char * mb) { int r; r = mailsession_copy_message(get_ancestor(session), num, mb); check_for_uid_cache(session); return r; } static int cmp_uid(uint32_t ** pa, uint32_t ** pb) { uint32_t * a; uint32_t * b; a = * pa; b = * pb; return * a - * b; } static int imapdriver_cached_get_messages_list(mailsession * session, struct mailmessage_list ** result) { #if 0 mailsession * imap_session; #endif mailimap * imap; uint32_t uid_max; struct imap_cached_session_state_data * data; struct mailmessage_list * env_list; unsigned i; int r; int res; carray * tab; #if 0 data = session->data; imap_session = get_ancestor(session); imap = ((struct imap_session_state_data *) (imap_session->data))->session; #endif data = get_cached_data(session); imap = get_imap_session(session); uid_max = 0; #ifdef CACHE_MESSAGE_LIST /* get UID max */ uid_max = 0; for(i = 0 ; i < carray_count(data->imap_uid_list) ; i ++) { struct uid_cache_item * cache_item; cache_item = carray_get(data->imap_uid_list, i); if (cache_item->uid > uid_max) uid_max = cache_item->uid; } #endif r = imap_get_messages_list(imap, session, imap_cached_message_driver, uid_max + 1, &env_list); check_for_uid_cache(session); if (r != MAIL_NO_ERROR) { res = r; goto err; } #ifdef CACHE_MESSAGE_LIST /* remove unsollicited message */ i = 0; while (i < carray_count(env_list->msg_tab)) { mailmessage * msg; msg = carray_get(env_list->msg_tab, i); if (msg->msg_index < uid_max + 1) carray_delete(env_list->msg_tab, i); else i ++; } tab = carray_new(carray_count(env_list->msg_tab) + carray_count(data->imap_uid_list)); if (tab == NULL) { res = MAIL_ERROR_MEMORY; goto free; } carray_set_size(tab, carray_count(env_list->msg_tab) + carray_count(data->imap_uid_list)); /* sort cached data before adding them to the list */ qsort(carray_data(data->imap_uid_list), carray_count(data->imap_uid_list), sizeof(* carray_data(data->imap_uid_list)), (int (*)(const void *, const void *)) cmp_uid); /* adds cached UID */ for(i = 0 ; i < carray_count(data->imap_uid_list) ; i ++) { struct uid_cache_item * cache_item; mailmessage * msg; cache_item = carray_get(data->imap_uid_list, i); msg = mailmessage_new(); if (msg == NULL) { res = MAIL_ERROR_MEMORY; goto free; } r = mailmessage_init(msg, session, imap_cached_message_driver, cache_item->uid, cache_item->size); if (r != MAIL_NO_ERROR) { mailmessage_free(msg); res = r; goto free; } carray_set(tab, i, msg); } /* adds new elements */ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; msg = carray_get(env_list->msg_tab, i); carray_set(tab, carray_count(data->imap_uid_list) + i, msg); } /* replace list of messages in env_list */ carray_free(env_list->msg_tab); env_list->msg_tab = tab; r = update_uid_cache(session, env_list); if (r != MAIL_NO_ERROR) { res = r; goto free; } #endif * result = env_list; return MAIL_NO_ERROR; free: mailmessage_list_free(env_list); err: return res; } static int get_flags_list(mailsession * session, struct mailmessage_list * env_list) { struct mailimap_set * set; struct mailimap_fetch_att * fetch_att; struct mailimap_fetch_type * fetch_type; int res; clist * fetch_result; int r; clist * msg_list; #if 0 struct imap_session_state_data * data; #endif unsigned i; unsigned dest; #if 0 data = session->data; #endif fetch_type = mailimap_fetch_type_new_fetch_att_list_empty(); if (fetch_type == NULL) { res = MAIL_ERROR_MEMORY; goto err; } fetch_att = mailimap_fetch_att_new_uid(); if (fetch_att == NULL) { res = MAIL_ERROR_MEMORY; goto free_fetch_type; } r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); if (r != MAILIMAP_NO_ERROR) { mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto free_fetch_type; } fetch_att = mailimap_fetch_att_new_flags(); if (fetch_att == NULL) { res = MAIL_ERROR_MEMORY; goto free_fetch_type; } r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); if (r != MAILIMAP_NO_ERROR) { mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto free_fetch_type; } r = maildriver_env_list_to_msg_list_no_flags(env_list, &msg_list); if (r != MAIL_NO_ERROR) { res = MAIL_ERROR_MEMORY; goto free_fetch_type; } if (clist_begin(msg_list) == NULL) { /* no need to fetch envelopes */ clist_free(msg_list); mailimap_fetch_type_free(fetch_type); return MAIL_NO_ERROR; } r = msg_list_to_imap_set(msg_list, &set); if (r != MAIL_NO_ERROR) { clist_foreach(msg_list, (clist_func) free, NULL); clist_free(msg_list); res = MAIL_ERROR_MEMORY; goto free_fetch_type; } clist_foreach(msg_list, (clist_func) free, NULL); clist_free(msg_list); r = mailimap_uid_fetch(get_imap_session(session), set, fetch_type, &fetch_result); mailimap_fetch_type_free(fetch_type); mailimap_set_free(set); switch (r) { case MAILIMAP_NO_ERROR: break; default: return imap_error_to_mail_error(r); } r = imap_fetch_result_to_envelop_list(fetch_result, env_list); mailimap_fetch_list_free(fetch_result); if (r != MAIL_NO_ERROR) { res = MAIL_ERROR_MEMORY; goto err; } /* remove messages that don't have flags */ i = 0; dest = 0; while (i < carray_count(env_list->msg_tab)) { mailmessage * msg; msg = carray_get(env_list->msg_tab, i); if (msg->msg_flags != NULL) { carray_set(env_list->msg_tab, dest, msg); dest ++; } else { mailmessage_free(msg); } i ++; } carray_set_size(env_list->msg_tab, dest); return MAIL_NO_ERROR; free_fetch_type: mailimap_fetch_type_free(fetch_type); err: return res; } #define ENV_NAME "env.db" static void get_uid_from_filename(char * filename) { char * p; p = strstr(filename, "-part"); if (p != NULL) * p = 0; p = strstr(filename, "-envelope"); if (p != NULL) * p = 0; p = strstr(filename, "-rfc822"); if (p != NULL) * p = 0; } static int imapdriver_cached_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list) { int r; int res; uint32_t i; struct imap_cached_session_state_data * data; MMAPString * mmapstr; struct mail_cache_db * cache_db; char filename[PATH_MAX]; data = get_cached_data(session); if (data->imap_quoted_mb == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto err; } snprintf(filename, PATH_MAX, "%s/%s", data->imap_quoted_mb, ENV_NAME); r = mail_cache_db_open_lock(filename, &cache_db); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_mmapstr; } /* fill with cached */ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; struct mailimf_fields * fields; msg = carray_get(env_list->msg_tab, i); if (msg->msg_fields == NULL) { r = imapdriver_get_cached_envelope(cache_db, mmapstr, session, msg, &fields); if (r == MAIL_NO_ERROR) { msg->msg_cached = TRUE; msg->msg_fields = fields; } } } mail_cache_db_close_unlock(filename, cache_db); r = mailsession_get_envelopes_list(get_ancestor(session), env_list); check_for_uid_cache(session); if (r != MAIL_NO_ERROR) { res = r; goto free_mmapstr; } r = get_flags_list(session, env_list); if (r != MAIL_NO_ERROR) { res = r; goto free_mmapstr; } #ifdef CACHE_MESSAGE_LIST r = update_uid_cache(session, env_list); if (r != MAIL_NO_ERROR) { res = r; goto free_mmapstr; } #endif /* must write cache */ r = mail_cache_db_open_lock(filename, &cache_db); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_mmapstr; } 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 = imapdriver_write_cached_envelope(cache_db, mmapstr, session, msg, msg->msg_fields); } } } /* flush cache */ maildriver_cache_clean_up(cache_db, NULL, env_list); mail_cache_db_close_unlock(filename, cache_db); mmap_string_free(mmapstr); /* remove cache files */ maildriver_message_cache_clean_up(data->imap_quoted_mb, env_list, get_uid_from_filename); return MAIL_NO_ERROR; free_mmapstr: mmap_string_free(mmapstr); err: return res; } static int imapdriver_cached_remove_message(mailsession * session, uint32_t num) { int r; r = mailsession_remove_message(get_ancestor(session), num); check_for_uid_cache(session); return r; } #if 0 static int imapdriver_cached_search_messages(mailsession * session, char * charset, struct mail_search_key * key, struct mail_search_result ** result) { int r; r = mailsession_search_messages(get_ancestor(session), charset, key, result); check_for_uid_cache(session); return r; } #endif static int imapdriver_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, imap_cached_message_driver, num, 0); if (r != MAIL_NO_ERROR) { mailmessage_free(msg_info); return r; } * result = msg_info; return MAIL_NO_ERROR; } /* Retrieve a message by UID * libEtPan! uid format for IMAP is "UIDVALIDITY-UID" * where UIDVALIDITY and UID are decimal representation of * respectively uidvalidity and uid numbers. * Return value: * MAIL_ERROR_INVAL if uid is NULL or has an incorrect format. * MAIL_ERROR_MSG_NOT_FOUND if uidvalidity has changed or uid was not found * MAIL_NO_ERROR if message was found. Result is in result */ static int imapdriver_cached_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result) { uint32_t uidvalidity; uint32_t num; char * p1, * p2; mailimap *imap; if (uid == NULL) return MAIL_ERROR_INVAL; uidvalidity = strtoul(uid, &p1, 10); if (p1 == uid || * p1 != '-') return MAIL_ERROR_INVAL; p1++; num = strtoul(p1, &p2, 10); if (p2 == p1 || * p2 != '\0') return MAIL_ERROR_INVAL; imap = get_imap_session(session); if (imap->imap_selection_info->sel_uidvalidity != uidvalidity) return MAIL_ERROR_MSG_NOT_FOUND; return imapdriver_cached_get_message(session, num, result); } diff --git a/kmicromail/libetpan/generic/imapdriver_cached_message.c b/kmicromail/libetpan/generic/imapdriver_cached_message.c index c0542a3..c4357a3 100644 --- a/kmicromail/libetpan/generic/imapdriver_cached_message.c +++ b/kmicromail/libetpan/generic/imapdriver_cached_message.c @@ -1,664 +1,664 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "imapdriver_cached_message.h" #include "imapdriver_tools.h" #include "imapdriver_message.h" #include "imapdriver_cached.h" #include "imapdriver_types.h" #include "imapdriver.h" #include "mailmessage.h" #include "generic_cache.h" #include "mail_cache_db.h" #include <string.h> #include <stdlib.h> static int imap_initialize(mailmessage * msg_info); static void imap_uninitialize(mailmessage * msg_info); static void imap_flush(mailmessage * msg_info); static void imap_check(mailmessage * msg_info); static void imap_fetch_result_free(mailmessage * msg_info, char * msg); static int imap_fetch(mailmessage * msg_info, char ** result, size_t * result_len); static int imap_fetch_header(mailmessage * msg_info, char ** result, size_t * result_len); static int imap_fetch_body(mailmessage * msg_info, char ** result, size_t * result_len); static int imap_fetch_size(mailmessage * msg_info, size_t * result); static int imap_get_bodystructure(mailmessage * msg_info, struct mailmime ** result); static int imap_fetch_section(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len); static int imap_fetch_section_header(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len); static int imap_fetch_section_mime(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len); static int imap_fetch_section_body(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len); static int imap_fetch_envelope(mailmessage * msg_info, struct mailimf_fields ** result); static int imap_get_flags(mailmessage * msg_info, struct mail_flags ** result); static mailmessage_driver local_imap_cached_message_driver = { .msg_name = "imap-cached", .msg_initialize = imap_initialize, .msg_uninitialize = imap_uninitialize, .msg_flush = imap_flush, .msg_check = imap_check, .msg_fetch_result_free = imap_fetch_result_free, .msg_fetch = imap_fetch, .msg_fetch_header = imap_fetch_header, .msg_fetch_body = imap_fetch_body, .msg_fetch_size = imap_fetch_size, .msg_get_bodystructure = imap_get_bodystructure, .msg_fetch_section = imap_fetch_section, .msg_fetch_section_header = imap_fetch_section_header, .msg_fetch_section_mime = imap_fetch_section_mime, .msg_fetch_section_body = imap_fetch_section_body, .msg_fetch_envelope = imap_fetch_envelope, .msg_get_flags = imap_get_flags, }; mailmessage_driver * imap_cached_message_driver = &local_imap_cached_message_driver; static inline struct imap_cached_session_state_data * get_cached_session_data(mailmessage * msg) { return msg->msg_session->sess_data; } static inline mailmessage * get_ancestor(mailmessage * msg_info) { return msg_info->msg_data; } static inline struct imap_cached_session_state_data * cached_session_get_data(mailsession * s) { return s->sess_data; } static inline mailsession * cached_session_get_ancestor(mailsession * s) { return cached_session_get_data(s)->imap_ancestor; } static inline struct imap_session_state_data * cached_session_get_ancestor_data(mailsession * s) { return cached_session_get_ancestor(s)->sess_data; } static inline mailimap * cached_session_get_imap_session(mailsession * session) { return cached_session_get_ancestor_data(session)->imap_session; } static inline mailimap * get_imap_session(mailmessage * msg) { return cached_session_get_imap_session(msg->msg_session); } static inline mailsession * get_ancestor_session(mailmessage * msg_info) { return cached_session_get_ancestor(msg_info->msg_session); } static void generate_key_from_mime_section(char * key, size_t size, struct mailmime * mime) { clistiter * cur; MMAPString * gstr; struct mailmime_section * part; int r; snprintf(key, size, "unvalid"); r = mailmime_get_section_id(mime, &part); if (r != MAILIMF_NO_ERROR) goto err; gstr = mmap_string_new("part"); if (gstr == NULL) goto free_section; for(cur = clist_begin(part->sec_list) ; cur != NULL ; cur = clist_next(cur)) { char s[20]; snprintf(s, 20, ".%u", * (uint32_t *) clist_content(cur)); if (mmap_string_append(gstr, s) == NULL) goto free_str; } snprintf(key, size, "%s", gstr->str); mmap_string_free(gstr); mailmime_section_free(part); return; free_str: mmap_string_free(gstr); free_section: mailmime_section_free(part); - err: + err:; } static void generate_key_from_section(char * key, size_t size, mailmessage * msg_info, struct mailmime * mime, int type) { char section_str[PATH_MAX]; generate_key_from_mime_section(section_str, PATH_MAX, mime); switch (type) { case IMAP_SECTION_MESSAGE: snprintf(key, size, "%s-%s", msg_info->msg_uid, section_str); break; case IMAP_SECTION_HEADER: snprintf(key, size, "%s-%s-header", msg_info->msg_uid, section_str); break; case IMAP_SECTION_MIME: snprintf(key, size, "%s-%s-mime", msg_info->msg_uid, section_str); break; case IMAP_SECTION_BODY: snprintf(key, size, "%s-%s-text", msg_info->msg_uid, section_str); break; } } static void generate_key_from_message(char * key, size_t size, mailmessage * msg_info, int type) { switch (type) { case MAILIMAP_MSG_ATT_RFC822: snprintf(key, size, "%s-rfc822", msg_info->msg_uid); break; case MAILIMAP_MSG_ATT_RFC822_HEADER: snprintf(key, size, "%s-rfc822-header", msg_info->msg_uid); break; case MAILIMAP_MSG_ATT_RFC822_TEXT: snprintf(key, size, "%s-rfc822-text", msg_info->msg_uid); break; case MAILIMAP_MSG_ATT_ENVELOPE: snprintf(key, size, "%s-envelope", msg_info->msg_uid); break; } } static void build_cache_name(char * filename, size_t size, mailmessage * msg, char * key) { char * quoted_mb; quoted_mb = get_cached_session_data(msg)->imap_quoted_mb; snprintf(filename, size, "%s/%s", quoted_mb, key); } static int imap_initialize(mailmessage * msg_info) { mailmessage * ancestor; int r; char key[PATH_MAX]; char * uid; mailimap * imap; ancestor = mailmessage_new(); if (ancestor == NULL) return MAIL_ERROR_MEMORY; r = mailmessage_init(ancestor, get_ancestor_session(msg_info), imap_message_driver, msg_info->msg_index, 0); if (r != MAIL_NO_ERROR) { mailmessage_free(ancestor); return r; } imap = get_imap_session(msg_info); snprintf(key, PATH_MAX, "%u-%u", imap->imap_selection_info->sel_uidvalidity, msg_info->msg_index); uid = strdup(key); if (uid == NULL) { mailmessage_free(ancestor); return MAIL_ERROR_MEMORY; } msg_info->msg_data = ancestor; msg_info->msg_uid = uid; return MAIL_NO_ERROR; } static void imap_uninitialize(mailmessage * msg_info) { mailmessage_free(get_ancestor(msg_info)); msg_info->msg_data = NULL; } static void imap_flush(mailmessage * msg_info) { if (msg_info->msg_mime != NULL) { mailmime_free(msg_info->msg_mime); msg_info->msg_mime = NULL; } } static void imap_check(mailmessage * msg_info) { get_ancestor(msg_info)->msg_flags = msg_info->msg_flags; mailmessage_check(get_ancestor(msg_info)); get_ancestor(msg_info)->msg_flags = NULL; } static void imap_fetch_result_free(mailmessage * msg_info, char * msg) { mailmessage_fetch_result_free(get_ancestor(msg_info), msg); } static int imap_fetch(mailmessage * msg_info, char ** result, size_t * result_len) { char key[PATH_MAX]; char filename[PATH_MAX]; int r; char * str; size_t len; generate_key_from_message(key, PATH_MAX, msg_info, MAILIMAP_MSG_ATT_RFC822); build_cache_name(filename, PATH_MAX, msg_info, key); r = generic_cache_read(filename, &str, &len); if (r == MAIL_NO_ERROR) { * result = str; * result_len = len; return MAIL_NO_ERROR; } r = mailmessage_fetch(get_ancestor(msg_info), result, result_len); if (r == MAIL_NO_ERROR) generic_cache_store(filename, * result, strlen(* result)); return r; } static int imap_fetch_header(mailmessage * msg_info, char ** result, size_t * result_len) { char key[PATH_MAX]; char filename[PATH_MAX]; int r; char * str; size_t len; generate_key_from_message(key, PATH_MAX, msg_info, MAILIMAP_MSG_ATT_RFC822_HEADER); build_cache_name(filename, PATH_MAX, msg_info, key); r = generic_cache_read(filename, &str, &len); if (r == MAIL_NO_ERROR) { * result = str; * result_len = len; return MAIL_NO_ERROR; } r = mailmessage_fetch_header(get_ancestor(msg_info), result, result_len); if (r == MAIL_NO_ERROR) generic_cache_store(filename, * result, * result_len); return r; } static int imap_fetch_body(mailmessage * msg_info, char ** result, size_t * result_len) { char key[PATH_MAX]; char filename[PATH_MAX]; int r; char * str; size_t len; generate_key_from_message(key, PATH_MAX, msg_info, MAILIMAP_MSG_ATT_RFC822_TEXT); build_cache_name(filename, PATH_MAX, msg_info, key); r = generic_cache_read(filename, &str, &len); if (r == MAIL_NO_ERROR) { * result = str; * result_len = len; return MAIL_NO_ERROR; } r = mailmessage_fetch_body(get_ancestor(msg_info), result, result_len); if (r == MAIL_NO_ERROR) generic_cache_store(filename, * result, * result_len); return r; } static int imap_fetch_size(mailmessage * msg_info, size_t * result) { return mailmessage_fetch_size(get_ancestor(msg_info), result); } static int imap_get_bodystructure(mailmessage * msg_info, struct mailmime ** result) { int r; if (msg_info->msg_mime != NULL) { * result = msg_info->msg_mime; return MAIL_NO_ERROR; } r = mailmessage_get_bodystructure(get_ancestor(msg_info), result); if (r == MAIL_NO_ERROR) { msg_info->msg_mime = get_ancestor(msg_info)->msg_mime; get_ancestor(msg_info)->msg_mime = NULL; } return r; } static int imap_fetch_section(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len) { char key[PATH_MAX]; char filename[PATH_MAX]; int r; char * str; size_t len; generate_key_from_section(key, PATH_MAX, msg_info, mime, IMAP_SECTION_MESSAGE); build_cache_name(filename, PATH_MAX, msg_info, key); r = generic_cache_read(filename, &str, &len); if (r == MAIL_NO_ERROR) { * result = str; * result_len = len; return MAIL_NO_ERROR; } r = mailmessage_fetch_section(get_ancestor(msg_info), mime, result, result_len); if (r == MAIL_NO_ERROR) generic_cache_store(filename, * result, * result_len); return r; } static int imap_fetch_section_header(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len) { char key[PATH_MAX]; char filename[PATH_MAX]; int r; char * str; size_t len; generate_key_from_section(key, PATH_MAX, msg_info, mime, IMAP_SECTION_HEADER); build_cache_name(filename, PATH_MAX, msg_info, key); r = generic_cache_read(filename, &str, &len); if (r == MAIL_NO_ERROR) { * result = str; * result_len = len; return MAIL_NO_ERROR; } r = mailmessage_fetch_section_header(get_ancestor(msg_info), mime, result, result_len); if (r == MAIL_NO_ERROR) generic_cache_store(filename, * result, * result_len); return r; } static int imap_fetch_section_mime(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len) { char key[PATH_MAX]; char filename[PATH_MAX]; int r; char * str; size_t len; generate_key_from_section(key, PATH_MAX, msg_info, mime, IMAP_SECTION_MIME); build_cache_name(filename, PATH_MAX, msg_info, key); r = generic_cache_read(filename, &str, &len); if (r == MAIL_NO_ERROR) { * result = str; * result_len = len; return MAIL_NO_ERROR; } r = mailmessage_fetch_section_mime(get_ancestor(msg_info), mime, result, result_len); if (r == MAIL_NO_ERROR) generic_cache_store(filename, * result, * result_len); return r; } static int imap_fetch_section_body(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len) { char key[PATH_MAX]; char filename[PATH_MAX]; int r; char * str; size_t len; generate_key_from_section(key, PATH_MAX, msg_info, mime, IMAP_SECTION_BODY); build_cache_name(filename, PATH_MAX, msg_info, key); r = generic_cache_read(filename, &str, &len); if (r == MAIL_NO_ERROR) { * result = str; * result_len = len; return MAIL_NO_ERROR; } r = mailmessage_fetch_section_body(get_ancestor(msg_info), mime, result, result_len); if (r == MAIL_NO_ERROR) generic_cache_store(filename, * result, * result_len); return r; } static int imap_get_flags(mailmessage * msg_info, struct mail_flags ** result) { int r; struct mail_flags * flags; if (msg_info->msg_flags != NULL) { * result = msg_info->msg_flags; return MAIL_NO_ERROR; } r = mailmessage_get_flags(get_ancestor(msg_info), &flags); if (r != MAIL_NO_ERROR) return r; get_ancestor(msg_info)->msg_flags = NULL; msg_info->msg_flags = flags; * result = flags; return MAIL_NO_ERROR; } #define ENV_NAME "env.db" static int imap_fetch_envelope(mailmessage * msg_info, struct mailimf_fields ** result) { struct mailimf_fields * fields; int r; struct mail_cache_db * cache_db; MMAPString * mmapstr; char filename[PATH_MAX]; struct imap_cached_session_state_data * data; int res; data = get_cached_session_data(msg_info); if (data->imap_quoted_mb == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } snprintf(filename, PATH_MAX, "%s/%s", data->imap_quoted_mb, ENV_NAME); r = mail_cache_db_open_lock(filename, &cache_db); if (r < 0) { res = MAIL_ERROR_MEMORY; goto err; } mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto close_db; } r = imapdriver_get_cached_envelope(cache_db, mmapstr, msg_info->msg_session, msg_info, &fields); if ((r != MAIL_ERROR_CACHE_MISS) && (r != MAIL_NO_ERROR)) { res = r; goto close_db; } r = mailmessage_fetch_envelope(get_ancestor(msg_info), &fields); if (r != MAIL_NO_ERROR) { res = r; goto close_db; } r = imapdriver_write_cached_envelope(cache_db, mmapstr, msg_info->msg_session, msg_info, fields); * result = fields; mmap_string_free(mmapstr); mail_cache_db_close_unlock(filename, cache_db); return MAIL_NO_ERROR; close_db: mail_cache_db_close_unlock(filename, cache_db); err: return res; } diff --git a/kmicromail/libetpan/generic/imapdriver_tools.c b/kmicromail/libetpan/generic/imapdriver_tools.c index 3d737f3..de4008f 100644 --- a/kmicromail/libetpan/generic/imapdriver_tools.c +++ b/kmicromail/libetpan/generic/imapdriver_tools.c @@ -1,3599 +1,3623 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "imapdriver_tools.h" #include "maildriver.h" #include <stdlib.h> #include <string.h> #include "mail.h" #include "imapdriver_types.h" #include "maildriver_tools.h" #include "generic_cache.h" #include "mailmessage.h" #include "mail_cache_db.h" static inline struct imap_session_state_data * session_get_data(mailsession * session) { return session->sess_data; } static inline struct imap_cached_session_state_data * cached_session_get_data(mailsession * session) { return session->sess_data; } static inline mailsession * cached_session_get_ancestor(mailsession * session) { return cached_session_get_data(session)->imap_ancestor; } static inline struct imap_session_state_data * cached_session_get_ancestor_data(mailsession * session) { return session_get_data(cached_session_get_ancestor(session)); } static inline mailimap * cached_session_get_imap_session(mailsession * session) { return cached_session_get_ancestor_data(session)->imap_session; } static int imap_flags_to_flags(struct mailimap_msg_att_dynamic * att_dyn, struct mail_flags ** result); int imap_error_to_mail_error(int error) { switch (error) { case MAILIMAP_NO_ERROR: return MAIL_NO_ERROR; case MAILIMAP_NO_ERROR_AUTHENTICATED: return MAIL_NO_ERROR_AUTHENTICATED; case MAILIMAP_NO_ERROR_NON_AUTHENTICATED: return MAIL_NO_ERROR_NON_AUTHENTICATED; case MAILIMAP_ERROR_BAD_STATE: return MAIL_ERROR_BAD_STATE; case MAILIMAP_ERROR_STREAM: return MAIL_ERROR_STREAM; case MAILIMAP_ERROR_PARSE: return MAIL_ERROR_PARSE; case MAILIMAP_ERROR_CONNECTION_REFUSED: return MAIL_ERROR_CONNECT; case MAILIMAP_ERROR_MEMORY: return MAIL_ERROR_MEMORY; case MAILIMAP_ERROR_FATAL: return MAIL_ERROR_FATAL; case MAILIMAP_ERROR_PROTOCOL: return MAIL_ERROR_PROTOCOL; case MAILIMAP_ERROR_DONT_ACCEPT_CONNECTION: return MAIL_ERROR_CONNECT; case MAILIMAP_ERROR_APPEND: return MAIL_ERROR_APPEND; case MAILIMAP_ERROR_NOOP: return MAIL_ERROR_NOOP; case MAILIMAP_ERROR_LOGOUT: return MAIL_ERROR_LOGOUT; case MAILIMAP_ERROR_CAPABILITY: return MAIL_ERROR_CAPABILITY; case MAILIMAP_ERROR_CHECK: return MAIL_ERROR_CHECK; case MAILIMAP_ERROR_CLOSE: return MAIL_ERROR_CLOSE; case MAILIMAP_ERROR_EXPUNGE: return MAIL_ERROR_EXPUNGE; case MAILIMAP_ERROR_COPY: case MAILIMAP_ERROR_UID_COPY: return MAIL_ERROR_COPY; case MAILIMAP_ERROR_CREATE: return MAIL_ERROR_CREATE; case MAILIMAP_ERROR_DELETE: return MAIL_ERROR_DELETE; case MAILIMAP_ERROR_EXAMINE: return MAIL_ERROR_EXAMINE; case MAILIMAP_ERROR_FETCH: case MAILIMAP_ERROR_UID_FETCH: return MAIL_ERROR_FETCH; case MAILIMAP_ERROR_LIST: return MAIL_ERROR_LIST; case MAILIMAP_ERROR_LOGIN: return MAIL_ERROR_LOGIN; case MAILIMAP_ERROR_LSUB: return MAIL_ERROR_LSUB; case MAILIMAP_ERROR_RENAME: return MAIL_ERROR_RENAME; case MAILIMAP_ERROR_SEARCH: case MAILIMAP_ERROR_UID_SEARCH: return MAIL_ERROR_SEARCH; case MAILIMAP_ERROR_SELECT: return MAIL_ERROR_SELECT; case MAILIMAP_ERROR_STATUS: return MAIL_ERROR_STATUS; case MAILIMAP_ERROR_STORE: case MAILIMAP_ERROR_UID_STORE: return MAIL_ERROR_STORE; case MAILIMAP_ERROR_SUBSCRIBE: return MAIL_ERROR_SUBSCRIBE; case MAILIMAP_ERROR_UNSUBSCRIBE: return MAIL_ERROR_UNSUBSCRIBE; case MAILIMAP_ERROR_STARTTLS: return MAIL_ERROR_STARTTLS; case MAILIMAP_ERROR_INVAL: return MAIL_ERROR_INVAL; default: return MAIL_ERROR_INVAL; } } static int imap_body_parameter_to_content(struct mailimap_body_fld_param * body_parameter, char * subtype, struct mailmime_type * mime_type, struct mailmime_content ** result); static int imap_body_type_text_to_content_type(char * subtype, struct mailimap_body_fld_param * body_parameter, struct mailmime_content ** result); int imap_list_to_list(clist * imap_list, struct mail_list ** result) { clistiter * cur; clist * list; struct mail_list * resp; int r; int res; list = clist_new(); if (list == NULL) { res = MAIL_ERROR_MEMORY; goto err; } for(cur = clist_begin(imap_list) ; cur != NULL ; cur = clist_next(cur)) { struct mailimap_mailbox_list * mb_list; char * new_mb; mb_list = clist_content(cur); new_mb = strdup(mb_list->mb_name); if (new_mb == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, new_mb); if (r != 0) { free(new_mb); res = MAIL_ERROR_MEMORY; goto free_list; } } resp = mail_list_new(list); if (resp == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } * result = resp; return MAIL_NO_ERROR; free_list: clist_foreach(list, (clist_func) free, NULL); clist_free(list); err: return res; } int section_to_imap_section(struct mailmime_section * section, int type, struct mailimap_section ** result) { struct mailimap_section_part * section_part; struct mailimap_section * imap_section; clist * list; clistiter * cur; int r; int res; list = clist_new(); if (list == NULL) { res = MAIL_ERROR_MEMORY; goto err; } for(cur = clist_begin(section->sec_list) ; cur != NULL ; cur = clist_next(cur)) { uint32_t value; uint32_t * id; value = * (uint32_t *) clist_content(cur); id = malloc(sizeof(* id)); if (id == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } * id = value; r = clist_append(list, id); if (r != 0) { res = MAIL_ERROR_MEMORY; free(id); goto free_list; } } section_part = mailimap_section_part_new(list); if (section_part == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } imap_section = NULL; switch (type) { case IMAP_SECTION_MESSAGE: imap_section = mailimap_section_new_part(section_part); break; case IMAP_SECTION_HEADER: imap_section = mailimap_section_new_part_header(section_part); break; case IMAP_SECTION_MIME: imap_section = mailimap_section_new_part_mime(section_part); break; case IMAP_SECTION_BODY: imap_section = mailimap_section_new_part_text(section_part); break; } if (imap_section == NULL) { res = MAIL_ERROR_MEMORY; goto free_part; } * result = imap_section; return MAIL_NO_ERROR; free_part: mailimap_section_part_free(section_part); free_list: if (list != NULL) { clist_foreach(list, (clist_func) free, NULL); clist_free(list); } err: return res; } static int imap_body_media_basic_to_content_type(struct mailimap_media_basic * media_basic, struct mailimap_body_fld_param * body_parameter, struct mailmime_content ** result) { struct mailmime_content * content; struct mailmime_type * mime_type; struct mailmime_discrete_type * discrete_type; struct mailmime_composite_type * composite_type; char * discrete_type_extension; int discrete_type_type; int composite_type_type; int mime_type_type; char * subtype; int r; int res; discrete_type = NULL; composite_type = NULL; discrete_type_extension = NULL; subtype = NULL; discrete_type_type = 0; composite_type_type = 0; mime_type_type = 0; switch (media_basic->med_type) { case MAILIMAP_MEDIA_BASIC_APPLICATION: mime_type_type = MAILMIME_TYPE_DISCRETE_TYPE; discrete_type_type = MAILMIME_DISCRETE_TYPE_APPLICATION; break; case MAILIMAP_MEDIA_BASIC_AUDIO: mime_type_type = MAILMIME_TYPE_DISCRETE_TYPE; discrete_type_type = MAILMIME_DISCRETE_TYPE_APPLICATION; break; case MAILIMAP_MEDIA_BASIC_IMAGE: mime_type_type = MAILMIME_TYPE_DISCRETE_TYPE; discrete_type_type = MAILMIME_DISCRETE_TYPE_IMAGE; break; case MAILIMAP_MEDIA_BASIC_MESSAGE: mime_type_type = MAILMIME_TYPE_COMPOSITE_TYPE; composite_type_type = MAILMIME_COMPOSITE_TYPE_MESSAGE; break; case MAILIMAP_MEDIA_BASIC_VIDEO: mime_type_type = MAILMIME_TYPE_DISCRETE_TYPE; discrete_type_type = MAILMIME_DISCRETE_TYPE_VIDEO; break; case MAILIMAP_MEDIA_BASIC_OTHER: mime_type_type = MAILMIME_TYPE_DISCRETE_TYPE; discrete_type_type = MAILMIME_DISCRETE_TYPE_EXTENSION; discrete_type_extension = media_basic->med_basic_type; if (discrete_type_extension == NULL) { res = MAIL_ERROR_INVAL; goto err; } break; default: res = MAIL_ERROR_INVAL; goto err; } switch (mime_type_type) { case MAILMIME_TYPE_DISCRETE_TYPE: if (discrete_type_extension != NULL) { discrete_type_extension = strdup(discrete_type_extension); if (discrete_type_extension == NULL) { res = MAIL_ERROR_MEMORY; goto err; } } discrete_type = mailmime_discrete_type_new(discrete_type_type, discrete_type_extension); if (discrete_type == NULL) { if (discrete_type_extension != NULL) free(discrete_type_extension); res = MAIL_ERROR_MEMORY; goto err; } break; case MAILMIME_TYPE_COMPOSITE_TYPE: composite_type = mailmime_composite_type_new(composite_type_type, NULL); if (composite_type == NULL) { res = MAIL_ERROR_MEMORY; goto err; } break; default: res = MAIL_ERROR_INVAL; goto err; } mime_type = mailmime_type_new(mime_type_type, discrete_type, composite_type); if (mime_type == NULL) { res = MAIL_ERROR_MEMORY; goto free; } r = imap_body_parameter_to_content(body_parameter, media_basic->med_subtype, mime_type, &content); if (r != MAIL_NO_ERROR) { res = r; goto free_type; } * result = content; return MAIL_NO_ERROR; free_type: mailmime_type_free(mime_type); free: if (discrete_type != NULL) mailmime_discrete_type_free(discrete_type); if (composite_type != NULL) mailmime_composite_type_free(composite_type); err: return res; } static int imap_disposition_to_mime_disposition(struct mailimap_body_fld_dsp * imap_dsp, struct mailmime_disposition ** result) { size_t cur_token; int r; struct mailmime_disposition_type * dsp_type; struct mailmime_disposition * dsp; clist * parameters; int res; cur_token = 0; r = mailmime_disposition_type_parse(imap_dsp->dsp_type, strlen(imap_dsp->dsp_type), &cur_token, &dsp_type); if (r != MAILIMF_NO_ERROR) { res = MAILIMF_ERROR_PARSE; goto err; } parameters = clist_new(); if (parameters == NULL) { res = MAIL_ERROR_MEMORY; goto err; } if (imap_dsp->dsp_attributes != NULL) { clistiter * cur; for(cur = clist_begin(imap_dsp->dsp_attributes->pa_list) ; cur != NULL ; cur = clist_next(cur)) { struct mailimap_single_body_fld_param * imap_param; struct mailmime_disposition_parm * dsp_param; struct mailmime_parameter * param; char * filename; char * creation_date; char * modification_date; char * read_date; size_t size; int type; imap_param = clist_content(cur); filename = NULL; creation_date = NULL; modification_date = NULL; read_date = NULL; size = 0; param = NULL; type = mailmime_disposition_guess_type(imap_param->pa_name, strlen(imap_param->pa_name), 0); switch (type) { case MAILMIME_DISPOSITION_PARM_FILENAME: if (strcasecmp(imap_param->pa_name, "filename") != 0) { type = MAILMIME_DISPOSITION_PARM_PARAMETER; break; } filename = strdup(imap_param->pa_value); if (filename == NULL) { res = MAIL_ERROR_MEMORY; goto free_dsp_type; } break; case MAILMIME_DISPOSITION_PARM_CREATION_DATE: if (strcasecmp(imap_param->pa_name, "creation-date") != 0) { type = MAILMIME_DISPOSITION_PARM_PARAMETER; break; } creation_date = strdup(imap_param->pa_value); if (creation_date == NULL) { res = MAIL_ERROR_MEMORY; goto free_dsp_type; } break; case MAILMIME_DISPOSITION_PARM_MODIFICATION_DATE: if (strcasecmp(imap_param->pa_name, "modification-date") != 0) { type = MAILMIME_DISPOSITION_PARM_PARAMETER; break; } modification_date = strdup(imap_param->pa_value); if (modification_date == NULL) { res = MAIL_ERROR_MEMORY; goto free_dsp_type; } break; case MAILMIME_DISPOSITION_PARM_READ_DATE: if (strcasecmp(imap_param->pa_name, "read-date") != 0) { type = MAILMIME_DISPOSITION_PARM_PARAMETER; break; } read_date = strdup(imap_param->pa_value); if (read_date == NULL) { res = MAIL_ERROR_MEMORY; goto free_dsp_type; } break; case MAILMIME_DISPOSITION_PARM_SIZE: if (strcasecmp(imap_param->pa_name, "size") != 0) { type = MAILMIME_DISPOSITION_PARM_PARAMETER; break; } size = strtoul(imap_param->pa_value, NULL, 10); break; } if (type == MAILMIME_DISPOSITION_PARM_PARAMETER) { char * name; char * value; name = strdup(imap_param->pa_name); if (name == NULL) { res = MAIL_ERROR_MEMORY; goto free_dsp_type; } value = strdup(imap_param->pa_value); if (value == NULL) { res = MAIL_ERROR_MEMORY; free(name); goto free_dsp_type; } param = mailmime_parameter_new(name, value); if (param == NULL) { free(value); free(name); res = MAIL_ERROR_MEMORY; goto free_dsp_type; } } dsp_param = mailmime_disposition_parm_new(type, filename, creation_date, modification_date, read_date, size, param); if (dsp_param == NULL) { if (filename != NULL) free(filename); if (creation_date != NULL) free(creation_date); if (modification_date != NULL) free(modification_date); if (read_date != NULL) free(read_date); if (param != NULL) mailmime_parameter_free(param); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(parameters, dsp_param); if (r != 0) { mailmime_disposition_parm_free(dsp_param); res = MAIL_ERROR_MEMORY; goto free_list; } } } dsp = mailmime_disposition_new(dsp_type, parameters); if (dsp == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } * result = dsp; return MAIL_NO_ERROR; free_list: clist_foreach(parameters, (clist_func) mailmime_disposition_parm_free, NULL); clist_free(parameters); free_dsp_type: mailmime_disposition_type_free(dsp_type); err: return res; } static int imap_language_to_mime_language(struct mailimap_body_fld_lang * imap_lang, struct mailmime_language ** result) { clist * list; clistiter * cur; int res; char * single; int r; struct mailmime_language * lang; list = clist_new(); if (list == NULL) { res = MAIL_ERROR_MEMORY; goto err; } switch (imap_lang->lg_type) { case MAILIMAP_BODY_FLD_LANG_SINGLE: if (imap_lang->lg_data.lg_single != NULL) { single = strdup(imap_lang->lg_data.lg_single); if (single == NULL) { res = MAIL_ERROR_MEMORY; goto free; } r = clist_append(list, single); if (r < 0) { free(single); res = MAIL_ERROR_MEMORY; goto free; } } break; case MAILIMAP_BODY_FLD_LANG_LIST: for(cur = clist_begin(imap_lang->lg_data.lg_list) ; cur != NULL ; cur = clist_next(cur)) { single = strdup(clist_content(cur)); if (single == NULL) { res = MAIL_ERROR_MEMORY; goto free; } r = clist_append(list, single); if (r < 0) { free(single); res = MAIL_ERROR_MEMORY; goto free; } } } lang = mailmime_language_new(list); if (lang == NULL) { res = MAIL_ERROR_MEMORY; goto free; } * result = lang; return MAIL_NO_ERROR; free: clist_foreach(list, (clist_func) free, NULL); clist_free(list); err: return res; } static int imap_body_fields_to_mime_fields(struct mailimap_body_fields * body_fields, struct mailimap_body_fld_dsp * imap_dsp, struct mailimap_body_fld_lang * imap_lang, struct mailmime_fields ** result, uint32_t * pbody_size) { struct mailmime_field * mime_field; struct mailmime_fields * mime_fields; clist * list; char * id; struct mailmime_mechanism * encoding; char * description; struct mailmime_disposition * dsp; struct mailmime_language * lang; int type; int r; int res; list = clist_new(); if (list == NULL) { res = MAIL_ERROR_MEMORY; goto err; } if (body_fields != NULL) { if (pbody_size != NULL) * pbody_size = body_fields->bd_size; if (body_fields->bd_id != NULL) { type = MAILMIME_FIELD_ID; id = strdup(body_fields->bd_id); if (id == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } mime_field = mailmime_field_new(type, NULL, NULL, id, NULL, 0, NULL, NULL); if (mime_field == NULL) { free(id); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, mime_field); if (r != 0) { mailmime_field_free(mime_field); res = MAIL_ERROR_MEMORY; goto free_list; } } if (body_fields->bd_description != NULL) { type = MAILMIME_FIELD_DESCRIPTION; description = strdup(body_fields->bd_description); if (description == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } mime_field = mailmime_field_new(type, NULL, NULL, NULL, description, 0, NULL, NULL); if (mime_field == NULL) { free(description); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, mime_field); if (r != 0) { mailmime_field_free(mime_field); res = MAIL_ERROR_MEMORY; goto free_list; } } if (body_fields->bd_encoding != NULL) { char * encoding_value; int encoding_type; type = MAILMIME_FIELD_TRANSFER_ENCODING; encoding_value = NULL; switch (body_fields->bd_encoding->enc_type) { case MAILIMAP_BODY_FLD_ENC_7BIT: encoding_type = MAILMIME_MECHANISM_7BIT; break; case MAILIMAP_BODY_FLD_ENC_8BIT: encoding_type = MAILMIME_MECHANISM_8BIT; break; case MAILIMAP_BODY_FLD_ENC_BINARY: encoding_type = MAILMIME_MECHANISM_BINARY; break; case MAILIMAP_BODY_FLD_ENC_BASE64: encoding_type = MAILMIME_MECHANISM_BASE64; break; case MAILIMAP_BODY_FLD_ENC_QUOTED_PRINTABLE: encoding_type = MAILMIME_MECHANISM_QUOTED_PRINTABLE; break; case MAILIMAP_BODY_FLD_ENC_OTHER: encoding_type = MAILMIME_MECHANISM_TOKEN; encoding_value = strdup(body_fields->bd_encoding->enc_value); if (encoding_value == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } break; default: res = MAIL_ERROR_INVAL; goto free_list; } encoding = mailmime_mechanism_new(encoding_type, encoding_value); if (encoding == NULL) { if (encoding_value != NULL) free(encoding_value); res = MAIL_ERROR_MEMORY; goto free_list; } mime_field = mailmime_field_new(type, NULL, encoding, NULL, NULL, 0, NULL, NULL); if (mime_field == NULL) { mailmime_mechanism_free(encoding); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, mime_field); if (r != 0) { mailmime_field_free(mime_field); res = MAIL_ERROR_MEMORY; goto free_list; } } } if (imap_dsp != NULL) { r = imap_disposition_to_mime_disposition(imap_dsp, &dsp); if (r != MAIL_ERROR_PARSE) { if (r != MAIL_NO_ERROR) { res = MAIL_ERROR_MEMORY; goto free_list; } type = MAILMIME_FIELD_DISPOSITION; mime_field = mailmime_field_new(type, NULL, NULL, NULL, NULL, 0, dsp, NULL); if (mime_field == NULL) { mailmime_disposition_free(dsp); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, mime_field); if (r != 0) { mailmime_field_free(mime_field); res = MAIL_ERROR_MEMORY; goto free_list; } } } if (imap_lang != NULL) { r = imap_language_to_mime_language(imap_lang, &lang); if (r != MAIL_NO_ERROR) { res = MAIL_ERROR_MEMORY; goto free_list; } type = MAILMIME_FIELD_LANGUAGE; mime_field = mailmime_field_new(type, NULL, NULL, NULL, NULL, 0, NULL, lang); if (mime_field == NULL) { mailmime_language_free(lang); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, mime_field); if (r != 0) { mailmime_field_free(mime_field); res = MAIL_ERROR_MEMORY; goto free_list; } } mime_fields = mailmime_fields_new(list); if (mime_fields == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } * result = mime_fields; return MAIL_NO_ERROR; free_list: clist_foreach(list, (clist_func) mailmime_fields_free, NULL); clist_free(list); err: return res; } static int imap_body_type_basic_to_body(struct mailimap_body_type_basic * imap_type_basic, struct mailimap_body_ext_1part * body_ext_1part, struct mailmime ** result) { struct mailmime_content * content; struct mailmime_fields * mime_fields; struct mailmime * body; int r; int res; uint32_t mime_size; r = imap_body_media_basic_to_content_type(imap_type_basic->bd_media_basic, imap_type_basic->bd_fields->bd_parameter, &content); if (r != MAIL_NO_ERROR) { res = r; goto err; } if (body_ext_1part != NULL) r = imap_body_fields_to_mime_fields(imap_type_basic->bd_fields, body_ext_1part->bd_disposition, body_ext_1part->bd_language, &mime_fields, &mime_size); else r = imap_body_fields_to_mime_fields(imap_type_basic->bd_fields, NULL, NULL, &mime_fields, &mime_size); if (r != MAIL_NO_ERROR) { res = r; goto free_content; } body = mailmime_new(MAILMIME_SINGLE, NULL, mime_size, mime_fields, content, NULL, NULL, NULL, NULL, NULL, NULL); if (body == NULL) { res = MAIL_ERROR_MEMORY; goto free_fields; } * result = body; return MAIL_NO_ERROR; free_fields: mailmime_fields_free(mime_fields); free_content: mailmime_content_free(content); err: return res; } static int imap_body_type_text_to_body(struct mailimap_body_type_text * imap_type_text, struct mailimap_body_ext_1part * body_ext_1part, struct mailmime ** result) { struct mailmime_content * content; struct mailmime_fields * mime_fields; struct mailmime * body; int r; int res; uint32_t mime_size; r = imap_body_type_text_to_content_type(imap_type_text->bd_media_text, imap_type_text->bd_fields->bd_parameter, &content); if (r != MAIL_NO_ERROR) { res = r; goto err; } if (body_ext_1part == NULL) { r = imap_body_fields_to_mime_fields(imap_type_text->bd_fields, NULL, NULL, &mime_fields, &mime_size); } else { r = imap_body_fields_to_mime_fields(imap_type_text->bd_fields, body_ext_1part->bd_disposition, body_ext_1part->bd_language, &mime_fields, &mime_size); } if (r != MAIL_NO_ERROR) { res = r; goto free_content; } body = mailmime_new(MAILMIME_SINGLE, NULL, mime_size, mime_fields, content, NULL, NULL, NULL, NULL, NULL, NULL); if (body == NULL) { res = MAIL_ERROR_MEMORY; goto free_fields; } * result = body; return MAIL_NO_ERROR; free_fields: mailmime_fields_free(mime_fields); free_content: mailmime_content_free(content); err: return res; } static int imap_body_parameter_to_content(struct mailimap_body_fld_param * body_parameter, char * subtype, struct mailmime_type * mime_type, struct mailmime_content ** result) { clist * parameters; char * new_subtype; struct mailmime_content * content; int r; int res; new_subtype = strdup(subtype); if (new_subtype == NULL) { res = MAIL_ERROR_MEMORY; goto err; } parameters = clist_new(); if (parameters == NULL) { res = MAIL_ERROR_MEMORY; goto free_subtype; } if (body_parameter != NULL) { clistiter * cur; for(cur = clist_begin(body_parameter->pa_list) ; cur != NULL ; cur = clist_next(cur)) { struct mailimap_single_body_fld_param * imap_param; struct mailmime_parameter * param; char * name; char * value; imap_param = clist_content(cur); name = strdup(imap_param->pa_name); if (name == NULL) { res = MAIL_ERROR_MEMORY; goto free_parameters; } value = strdup(imap_param->pa_value); if (value == NULL) { free(name); res = MAIL_ERROR_MEMORY; goto free_parameters; } param = mailmime_parameter_new(name, value); if (param == NULL) { free(value); free(name); res = MAIL_ERROR_MEMORY; goto free_parameters; } r = clist_append(parameters, param); if (r != 0) { mailmime_parameter_free(param); res = MAIL_ERROR_MEMORY; goto free_parameters; } } } content = mailmime_content_new(mime_type, new_subtype, parameters); if (content == NULL) { res = MAIL_ERROR_MEMORY; goto free_parameters; } * result = content; return MAIL_NO_ERROR; free_parameters: clist_foreach(parameters, (clist_func) mailmime_parameter_free, NULL); clist_free(parameters); free_subtype: free(new_subtype); err: return res; } static int imap_body_type_text_to_content_type(char * subtype, struct mailimap_body_fld_param * body_parameter, struct mailmime_content ** result) { struct mailmime_content * content; struct mailmime_type * mime_type; struct mailmime_discrete_type * discrete_type; int r; int res; discrete_type = NULL; discrete_type = mailmime_discrete_type_new(MAILMIME_DISCRETE_TYPE_TEXT, NULL); if (discrete_type == NULL) { res = MAIL_ERROR_MEMORY; goto err; } mime_type = mailmime_type_new(MAILMIME_TYPE_DISCRETE_TYPE, discrete_type, NULL); if (mime_type == NULL) { mailmime_discrete_type_free(discrete_type); res = MAIL_ERROR_MEMORY; goto err; } r = imap_body_parameter_to_content(body_parameter, subtype, mime_type, &content); if (r != MAIL_NO_ERROR) { res = r; goto free_type; } * result = content; return MAIL_NO_ERROR; free_type: mailmime_type_free(mime_type); err: return res; } static int imap_body_type_msg_to_body(struct mailimap_body_type_msg * imap_type_msg, struct mailimap_body_ext_1part * body_ext_1part, struct mailmime ** result) { struct mailmime * body; struct mailmime * msg_body; struct mailmime_fields * mime_fields; struct mailmime_composite_type * composite_type; struct mailmime_type * mime_type; struct mailmime_content * content_type; struct mailimf_fields * fields; int r; int res; uint32_t mime_size; r = imap_body_fields_to_mime_fields(imap_type_msg->bd_fields, body_ext_1part->bd_disposition, body_ext_1part->bd_language, &mime_fields, &mime_size); if (r != MAIL_NO_ERROR) { res = r; goto err; } r = imap_env_to_fields(imap_type_msg->bd_envelope, NULL, 0, &fields); if (r != MAIL_NO_ERROR) { res = r; goto free_mime_fields; } r = imap_body_to_body(imap_type_msg->bd_body, &msg_body); if (r != MAIL_NO_ERROR) { res = r; goto free_fields; } composite_type = mailmime_composite_type_new(MAILMIME_COMPOSITE_TYPE_MESSAGE, NULL); if (composite_type == NULL) { res = MAIL_ERROR_MEMORY; goto free_fields; } mime_type = mailmime_type_new(MAILMIME_TYPE_COMPOSITE_TYPE, NULL, composite_type); if (mime_type == NULL) { mailmime_composite_type_free(composite_type); res = MAIL_ERROR_MEMORY; goto free_fields; } r = imap_body_parameter_to_content(imap_type_msg->bd_fields->bd_parameter, "rfc822", mime_type, &content_type); if (r != MAIL_NO_ERROR) { mailmime_type_free(mime_type); res = MAIL_ERROR_MEMORY; goto free_fields; } body = mailmime_new(MAILMIME_MESSAGE, NULL, mime_size, mime_fields, content_type, NULL, NULL, NULL, NULL, fields, msg_body); if (body == NULL) { res = MAIL_ERROR_MEMORY; goto free_content; } * result = body; return MAIL_NO_ERROR; free_content: mailmime_content_free(content_type); free_fields: mailimf_fields_free(fields); free_mime_fields: mailmime_fields_free(mime_fields); err: return res; } static int imap_body_type_1part_to_body(struct mailimap_body_type_1part * type_1part, struct mailmime ** result) { struct mailmime * body; int r; int res; switch (type_1part->bd_type) { case MAILIMAP_BODY_TYPE_1PART_BASIC: r = imap_body_type_basic_to_body(type_1part->bd_data.bd_type_basic, type_1part->bd_ext_1part, &body); if (r != MAIL_NO_ERROR) { res = r; goto err; } break; case MAILIMAP_BODY_TYPE_1PART_MSG: r = imap_body_type_msg_to_body(type_1part->bd_data.bd_type_msg, type_1part->bd_ext_1part, &body); if (r != MAIL_NO_ERROR) { res = r; goto err; } break; case MAILIMAP_BODY_TYPE_1PART_TEXT: r = imap_body_type_text_to_body(type_1part->bd_data.bd_type_text, type_1part->bd_ext_1part, &body); if (r != MAIL_NO_ERROR) { res = r; goto err; } break; } * result = body; return MAIL_NO_ERROR; err: return res; } static int imap_body_type_mpart_to_body(struct mailimap_body_type_mpart * type_mpart, struct mailmime ** result) { struct mailmime_fields * mime_fields; struct mailmime_composite_type * composite_type; struct mailmime_type * mime_type; struct mailmime_content * content_type; struct mailmime * body; clistiter * cur; clist * list; int r; int res; uint32_t mime_size; r = imap_body_fields_to_mime_fields(NULL, type_mpart->bd_ext_mpart->bd_disposition, type_mpart->bd_ext_mpart->bd_language, &mime_fields, &mime_size); if (r != MAIL_NO_ERROR) { res = r; goto err; } composite_type = mailmime_composite_type_new(MAILMIME_COMPOSITE_TYPE_MULTIPART, NULL); if (composite_type == NULL) { res = MAIL_ERROR_MEMORY; goto free_fields; } mime_type = mailmime_type_new(MAILMIME_TYPE_COMPOSITE_TYPE, NULL, composite_type); if (mime_type == NULL) { mailmime_composite_type_free(composite_type); res = MAIL_ERROR_MEMORY; goto free_fields; } r = imap_body_parameter_to_content(type_mpart->bd_ext_mpart->bd_parameter, type_mpart->bd_media_subtype, mime_type, &content_type); if (r != MAIL_NO_ERROR) { mailmime_type_free(mime_type); res = r; goto free_fields; } list = clist_new(); if (list == NULL) { res = MAIL_ERROR_MEMORY; goto free_content; } for(cur = clist_begin(type_mpart->bd_list) ; cur != NULL ; cur = clist_next(cur)) { struct mailimap_body * imap_body; struct mailmime * sub_body; imap_body = clist_content(cur); r = imap_body_to_body(imap_body, &sub_body); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } r = clist_append(list, sub_body); if (r != 0) { mailmime_free(sub_body); res = r; goto free_list; } } body = mailmime_new(MAILMIME_MULTIPLE, NULL, mime_size, mime_fields, content_type, NULL, NULL, NULL, list, NULL, NULL); if (body == NULL) { res = MAIL_ERROR_MEMORY; goto err; } * result = body; return MAIL_NO_ERROR; free_list: clist_foreach(list, (clist_func) mailmime_free, NULL); clist_free(list); free_content: mailmime_content_free(content_type); free_fields: mailmime_fields_free(mime_fields); err: return res; } int imap_body_to_body(struct mailimap_body * imap_body, struct mailmime ** result) { struct mailmime * body; int r; int res; switch (imap_body->bd_type) { case MAILIMAP_BODY_1PART: r = imap_body_type_1part_to_body(imap_body->bd_data.bd_body_1part, &body); if (r != MAIL_NO_ERROR) { res = r; goto err; } break; case MAILIMAP_BODY_MPART: r = imap_body_type_mpart_to_body(imap_body->bd_data.bd_body_mpart, &body); if (r != MAIL_NO_ERROR) { res = r; goto err; } break; default: return MAIL_ERROR_INVAL; } * result = body; return MAIL_NO_ERROR; err: return res; } int imap_address_to_mailbox(struct mailimap_address * imap_addr, struct mailimf_mailbox ** result) { char * dsp_name; char * addr; struct mailimf_mailbox * mb; int res; if (imap_addr->ad_personal_name == NULL) dsp_name = NULL; else { dsp_name = strdup(imap_addr->ad_personal_name); if (dsp_name == NULL) { res = MAIL_ERROR_MEMORY; goto err; } } if (imap_addr->ad_host_name == NULL) { addr = strdup(imap_addr->ad_mailbox_name); if (addr == NULL) { res = MAIL_ERROR_MEMORY; goto free_name; } } else { addr = malloc(strlen(imap_addr->ad_mailbox_name) + strlen(imap_addr->ad_host_name) + 2); if (addr == NULL) { res = MAIL_ERROR_MEMORY; goto free_name; } strcpy(addr, imap_addr->ad_mailbox_name); strcat(addr, "@"); strcat(addr, imap_addr->ad_host_name); } mb = mailimf_mailbox_new(dsp_name, addr); if (mb == NULL) { res = MAIL_ERROR_MEMORY; goto free_addr; } * result = mb; return MAIL_NO_ERROR; free_addr: free(addr); free_name: free(dsp_name); err: return res; } int imap_address_to_address(struct mailimap_address * imap_addr, struct mailimf_address ** result) { struct mailimf_address * addr; struct mailimf_mailbox * mb; int r; int res; r = imap_address_to_mailbox(imap_addr, &mb); if (r != MAIL_NO_ERROR) { res = r; goto err; } addr = mailimf_address_new(MAILIMF_ADDRESS_MAILBOX, mb, NULL); if (addr == NULL) { res = MAIL_ERROR_MEMORY; goto free_mb; } * result = addr; return MAIL_NO_ERROR; free_mb: mailimf_mailbox_free(mb); err: return res; } int imap_mailbox_list_to_mailbox_list(clist * imap_mailbox_list, struct mailimf_mailbox_list ** result) { clistiter * cur; clist * list; struct mailimf_mailbox_list * mb_list; int r; int res; list = clist_new(); if (list == NULL) { res = MAIL_ERROR_MEMORY; goto err; } for(cur = clist_begin(imap_mailbox_list) ; cur != NULL ; cur = clist_next(cur)) { struct mailimap_address * imap_addr; struct mailimf_mailbox * mb; imap_addr = clist_content(cur); if (imap_addr->ad_mailbox_name == NULL) continue; r = imap_address_to_mailbox(imap_addr, &mb); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } r = clist_append(list, mb); if (r != 0) { mailimf_mailbox_free(mb); res = MAIL_ERROR_MEMORY; goto free_list; } } mb_list = mailimf_mailbox_list_new(list); if (mb_list == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } * result = mb_list; return MAIL_NO_ERROR; free_list: clist_foreach(list, (clist_func) mailimf_mailbox_free, NULL); clist_free(list); err: return MAIL_ERROR_MEMORY; } /* at exit, imap_mb_list will fall on the last element of the group, where mailbox name will be NIL, so that imap_mailbox_list_to_address_list can continue */ static int imap_mailbox_list_to_group(clist * imap_mb_list, clistiter ** iter, struct mailimf_group ** result) { clistiter * imap_mailbox_listiter; clist * list; struct mailimf_group * group; struct mailimap_address * imap_addr; char * group_name; clistiter * cur; struct mailimf_mailbox_list * mb_list; int r; int res; imap_mailbox_listiter = * iter; imap_addr = clist_content(imap_mailbox_listiter); if (imap_addr->ad_mailbox_name == NULL) { res = MAIL_ERROR_INVAL; goto err; } group_name = strdup(imap_addr->ad_mailbox_name); if (group_name == NULL) { res = MAIL_ERROR_MEMORY; goto err; } list = clist_new(); if (list == NULL) { res = MAIL_ERROR_MEMORY; goto free_group_name; } for(cur = clist_next(imap_mailbox_listiter) ; cur != NULL ; cur = clist_next(cur)) { struct mailimf_mailbox * mb; imap_addr = clist_content(cur); if (imap_addr->ad_mailbox_name == NULL) { break; } r = imap_address_to_mailbox(imap_addr, &mb); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } r = clist_append(list, mb); if (r != 0) { mailimf_mailbox_free(mb); res = MAIL_ERROR_MEMORY; goto free_list; } } mb_list = mailimf_mailbox_list_new(list); if (mb_list == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } group = mailimf_group_new(group_name, mb_list); if (group == NULL) { mailimf_mailbox_list_free(mb_list); res = MAIL_ERROR_MEMORY; goto free_group_name; } * result = group; * iter = cur; return MAIL_NO_ERROR; free_list: clist_foreach(list, (clist_func) mailimf_mailbox_free, NULL); clist_free(list); free_group_name: free(group_name); err: return res; } int imap_mailbox_list_to_address_list(clist * imap_mailbox_list, struct mailimf_address_list ** result) { clistiter * cur; clist * list; struct mailimf_address_list * addr_list; int r; int res; list = clist_new(); if (list == NULL) { res = MAIL_ERROR_MEMORY; goto err; } for(cur = clist_begin(imap_mailbox_list) ; cur != NULL ; cur = clist_next(cur)) { struct mailimap_address * imap_addr; struct mailimf_address * addr; imap_addr = clist_content(cur); if (imap_addr->ad_mailbox_name == NULL) continue; if ((imap_addr->ad_host_name == NULL) && (imap_addr->ad_mailbox_name != NULL)) { struct mailimf_group * group; r = imap_mailbox_list_to_group(imap_mailbox_list, &cur, &group); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } addr = mailimf_address_new(MAILIMF_ADDRESS_GROUP, NULL, group); if (addr == NULL) { mailimf_group_free(group); res = MAIL_ERROR_MEMORY; goto free_list; } } else { r = imap_address_to_address(imap_addr, &addr); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } } r = clist_append(list, addr); if (r != 0) { mailimf_address_free(addr); res = MAIL_ERROR_MEMORY; goto free_list; } } addr_list = mailimf_address_list_new(list); if (addr_list == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } * result = addr_list; return MAIL_NO_ERROR; free_list: clist_foreach(list, (clist_func) mailimf_address_free, NULL); clist_free(list); err: return res; } int imap_add_envelope_fetch_att(struct mailimap_fetch_type * fetch_type) { struct mailimap_fetch_att * fetch_att; int res; int r; char * header; clist * hdrlist; struct mailimap_header_list * imap_hdrlist; struct mailimap_section * section; fetch_att = mailimap_fetch_att_new_envelope(); if (fetch_att == NULL) { res = MAIL_ERROR_MEMORY; goto err; } r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); if (r != MAILIMAP_NO_ERROR) { mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto err; } header = strdup("References"); if (header == NULL) { mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto err; } hdrlist = clist_new(); if (hdrlist == NULL) { free(header); mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto err; } r = clist_append(hdrlist, header); if (r < 0) { free(header); clist_foreach(hdrlist, (clist_func) free, NULL); clist_free(hdrlist); mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto err; } imap_hdrlist = mailimap_header_list_new(hdrlist); if (imap_hdrlist == 0) { clist_foreach(hdrlist, (clist_func) free, NULL); clist_free(hdrlist); mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto err; } section = mailimap_section_new_header_fields(imap_hdrlist); if (section == NULL) { mailimap_header_list_free(imap_hdrlist); mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto err; } fetch_att = mailimap_fetch_att_new_body_peek_section(section); if (fetch_att == NULL) { mailimap_section_free(section); res = MAIL_ERROR_MEMORY; goto err; } r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); if (r != MAILIMAP_NO_ERROR) { mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto err; } return MAIL_NO_ERROR; err: return res; } int imap_env_to_fields(struct mailimap_envelope * env, char * ref_str, size_t ref_size, struct mailimf_fields ** result) { clist * list; struct mailimf_field * field; int r; struct mailimf_fields * fields; int res; list = clist_new(); if (list == NULL) { res = MAIL_ERROR_MEMORY; goto err; } if (env->env_date != NULL) { size_t cur_token; struct mailimf_date_time * date_time; cur_token = 0; r = mailimf_date_time_parse(env->env_date, strlen(env->env_date), &cur_token, &date_time); if (r == MAILIMF_NO_ERROR) { struct mailimf_orig_date * orig; orig = mailimf_orig_date_new(date_time); if (orig == NULL) { mailimf_date_time_free(date_time); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_ORIG_DATE, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, orig, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (field == NULL) { mailimf_orig_date_free(orig); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r != 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } } } if (env->env_subject != NULL) { char * subject; struct mailimf_subject * subject_field; subject = strdup(env->env_subject); if (subject == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } subject_field = mailimf_subject_new(subject); if (subject_field == NULL) { free(subject); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_SUBJECT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, subject_field, NULL, NULL, NULL); if (field == NULL) { mailimf_subject_free(subject_field); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r != 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } } if (env->env_from != NULL) { if (env->env_from->frm_list != NULL) { struct mailimf_mailbox_list * mb_list; struct mailimf_from * from; r = imap_mailbox_list_to_mailbox_list(env->env_from->frm_list, &mb_list); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } from = mailimf_from_new(mb_list); if (from == NULL) { mailimf_mailbox_list_free(mb_list); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_FROM, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, from, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (field == NULL) { mailimf_from_free(from); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r != 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } } } if (env->env_sender != NULL) { if (env->env_sender->snd_list != NULL) { struct mailimf_sender * sender; struct mailimf_mailbox * mb; r = imap_address_to_mailbox(clist_begin(env->env_sender->snd_list)->data, &mb); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } sender = mailimf_sender_new(mb); if (sender == NULL) { mailimf_mailbox_free(mb); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_SENDER, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, sender, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (field == NULL) { mailimf_sender_free(sender); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r != 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } } } if (env->env_reply_to != NULL) { if (env->env_reply_to->rt_list != NULL) { struct mailimf_address_list * addr_list; struct mailimf_reply_to * reply_to; r = imap_mailbox_list_to_address_list(env->env_reply_to->rt_list, &addr_list); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } reply_to = mailimf_reply_to_new(addr_list); if (reply_to == NULL) { mailimf_address_list_free(addr_list); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_REPLY_TO, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, reply_to, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (field == NULL) { mailimf_reply_to_free(reply_to); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r != 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } } } if (env->env_to != NULL) { if (env->env_to->to_list != NULL) { struct mailimf_address_list * addr_list; struct mailimf_to * to; r = imap_mailbox_list_to_address_list(env->env_to->to_list, &addr_list); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } to = mailimf_to_new(addr_list); if (to == NULL) { mailimf_address_list_free(addr_list); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_TO, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, to, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (field == NULL) { mailimf_to_free(to); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r != 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } } } if (env->env_cc != NULL) { if (env->env_cc->cc_list != NULL) { struct mailimf_address_list * addr_list; struct mailimf_cc * cc; r = imap_mailbox_list_to_address_list(env->env_cc->cc_list, &addr_list); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } cc = mailimf_cc_new(addr_list); if (cc == NULL) { mailimf_address_list_free(addr_list); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_CC, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, cc, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (field == NULL) { mailimf_cc_free(cc); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r != 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } } } if (env->env_bcc != NULL) { if (env->env_bcc->bcc_list != NULL) { struct mailimf_address_list * addr_list; struct mailimf_bcc * bcc; r = imap_mailbox_list_to_address_list(env->env_bcc->bcc_list, &addr_list); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } bcc = mailimf_bcc_new(addr_list); if (bcc == NULL) { mailimf_address_list_free(addr_list); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_BCC, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, bcc, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (field == NULL) { mailimf_bcc_free(bcc); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r != 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } } } if (env->env_in_reply_to != NULL) { struct mailimf_in_reply_to * in_reply_to; size_t cur_token; clist * msg_id_list; cur_token = 0; r = mailimf_msg_id_list_parse(env->env_in_reply_to, strlen(env->env_in_reply_to), &cur_token, &msg_id_list); switch (r) { case MAILIMF_NO_ERROR: in_reply_to = mailimf_in_reply_to_new(msg_id_list); if (in_reply_to == NULL) { clist_foreach(msg_id_list, (clist_func) mailimf_msg_id_free, NULL); clist_free(msg_id_list); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_IN_REPLY_TO, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, in_reply_to, NULL, NULL, NULL, NULL, NULL); if (field == NULL) { mailimf_in_reply_to_free(in_reply_to); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r != 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } break; case MAILIMF_ERROR_PARSE: break; default: res = maildriver_imf_error_to_mail_error(r); goto free_list; } } if (env->env_message_id != NULL) { char * id; struct mailimf_message_id * msg_id; size_t cur_token; cur_token = 0; r = mailimf_msg_id_parse(env->env_message_id, strlen(env->env_message_id), &cur_token, &id); switch (r) { case MAILIMF_NO_ERROR: msg_id = mailimf_message_id_new(id); if (msg_id == NULL) { mailimf_msg_id_free(id); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_MESSAGE_ID, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, msg_id, NULL, NULL, NULL, NULL, NULL, NULL); if (field == NULL) { mailimf_message_id_free(msg_id); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r != 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } break; case MAILIMF_ERROR_PARSE: break; default: res = maildriver_imf_error_to_mail_error(r); goto free_list; } } if (ref_str != NULL) { struct mailimf_references * references; size_t cur_token; cur_token = 0; r = mailimf_references_parse(ref_str, ref_size, &cur_token, &references); switch (r) { case MAILIMF_NO_ERROR: field = mailimf_field_new(MAILIMF_FIELD_REFERENCES, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, references, NULL, NULL, NULL, NULL); if (field == NULL) { mailimf_references_free(references); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r < 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } break; case MAILIMF_ERROR_PARSE: break; default: res = maildriver_imf_error_to_mail_error(r); goto free_list; } } fields = mailimf_fields_new(list); if (fields == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } * result = fields; return MAIL_NO_ERROR; free_list: clist_foreach(list, (clist_func) mailimf_field_free, NULL); clist_free(list); err: return res; } int imap_get_msg_att_info(struct mailimap_msg_att * msg_att, uint32_t * puid, struct mailimap_envelope ** pimap_envelope, char ** preferences, size_t * pref_size, struct mailimap_msg_att_dynamic ** patt_dyn, struct mailimap_body ** pimap_body) { clistiter * item_cur; uint32_t uid; struct mailimap_envelope * imap_envelope; char * references; size_t ref_size; struct mailimap_msg_att_dynamic * att_dyn; struct mailimap_body * imap_body; uid = 0; imap_envelope = NULL; references = NULL; ref_size = 0; att_dyn = NULL; imap_body = NULL; for(item_cur = clist_begin(msg_att->att_list) ; item_cur != NULL ; item_cur = clist_next(item_cur)) { struct mailimap_msg_att_item * item; item = clist_content(item_cur); switch (item->att_type) { case MAILIMAP_MSG_ATT_ITEM_STATIC: switch (item->att_data.att_static->att_type) { case MAILIMAP_MSG_ATT_BODYSTRUCTURE: if (imap_body == NULL) imap_body = item->att_data.att_static->att_data.att_bodystructure; break; case MAILIMAP_MSG_ATT_ENVELOPE: if (imap_envelope == NULL) { imap_envelope = item->att_data.att_static->att_data.att_env; } break; case MAILIMAP_MSG_ATT_UID: uid = item->att_data.att_static->att_data.att_uid; break; case MAILIMAP_MSG_ATT_BODY_SECTION: if (references == NULL) { references = item->att_data.att_static->att_data.att_body_section->sec_body_part; ref_size = item->att_data.att_static->att_data.att_body_section->sec_length; } break; } break; case MAILIMAP_MSG_ATT_ITEM_DYNAMIC: if (att_dyn == NULL) { att_dyn = item->att_data.att_dyn; } break; } } if (puid != NULL) * puid = uid; if (pimap_envelope != NULL) * pimap_envelope = imap_envelope; if (preferences != NULL) * preferences = references; if (pref_size != NULL) * pref_size = ref_size; if (patt_dyn != NULL) * patt_dyn = att_dyn; if (pimap_body != NULL) * pimap_body = imap_body; return MAIL_NO_ERROR; } int imap_fetch_result_to_envelop_list(clist * fetch_result, struct mailmessage_list * env_list) { clistiter * cur; int r; unsigned int i; i = 0; for(cur = clist_begin(fetch_result) ; cur != NULL ; cur = clist_next(cur)) { struct mailimap_msg_att * msg_att; uint32_t uid; struct mailimap_envelope * imap_envelope; struct mailimap_msg_att_dynamic * att_dyn; char * references; size_t ref_size; msg_att = clist_content(cur); r = imap_get_msg_att_info(msg_att, &uid, &imap_envelope, &references, &ref_size, &att_dyn, NULL); if (r == MAIL_NO_ERROR) { if (uid != 0) { while (i < carray_count(env_list->msg_tab)) { mailmessage * msg; msg = carray_get(env_list->msg_tab, i); if (uid == msg->msg_index) { struct mailimf_fields * fields; struct mail_flags * flags; if (imap_envelope != NULL) { r = imap_env_to_fields(imap_envelope, references, ref_size, &fields); if (r == MAIL_NO_ERROR) { msg->msg_fields = fields; } } if (att_dyn != NULL) { r = imap_flags_to_flags(att_dyn, &flags); if (r == MAIL_NO_ERROR) { msg->msg_flags = flags; } } i ++; break; } i ++; } } } } return MAIL_NO_ERROR; } int mailimf_date_time_to_imap_date(struct mailimf_date_time * date, struct mailimap_date ** result) { struct mailimap_date * imap_date; imap_date = mailimap_date_new(date->dt_day, date->dt_month, date->dt_year); if (imap_date == NULL) return MAIL_ERROR_MEMORY; * result = imap_date; return MAIL_NO_ERROR; } #if 0 int mail_search_to_imap_search(struct mail_search_key * key, struct mailimap_search_key ** result) { struct mailimap_search_key * imap_key; char * bcc; struct mailimap_date * before; char * body; char * cc; char * from; struct mailimap_date * on; struct mailimap_date * since; char * subject; char * text; char * to; char * header_name; char * header_value; size_t larger; struct mailimap_search_key * not; struct mailimap_search_key * or1; struct mailimap_search_key * or2; size_t smaller; clist * multiple; int type; clistiter * cur; int r; int res; bcc = NULL; before = NULL; body = NULL; cc = NULL; from = NULL; on = NULL; since = NULL; subject = NULL; text = NULL; to = NULL; header_name = NULL; header_value = NULL; not = NULL; or1 = NULL; or2 = NULL; multiple = NULL; larger = 0; smaller = 0; switch (key->sk_type) { case MAIL_SEARCH_KEY_ALL: type = MAILIMAP_SEARCH_KEY_ALL; break; case MAIL_SEARCH_KEY_ANSWERED: type = MAILIMAP_SEARCH_KEY_ANSWERED; break; case MAIL_SEARCH_KEY_BCC: type = MAILIMAP_SEARCH_KEY_BCC; bcc = strdup(key->sk_bcc); if (bcc == NULL) { res = MAIL_ERROR_MEMORY; goto err; } break; case MAIL_SEARCH_KEY_BEFORE: type = MAILIMAP_SEARCH_KEY_BEFORE; r = mailimf_date_time_to_imap_date(key->sk_before, &before); if (r != MAIL_NO_ERROR) { res = r; goto err; } break; case MAIL_SEARCH_KEY_BODY: type = MAILIMAP_SEARCH_KEY_BODY; body = strdup(key->sk_body); if (body == NULL) { res = MAIL_ERROR_MEMORY; goto err; } break; case MAIL_SEARCH_KEY_CC: type = MAILIMAP_SEARCH_KEY_CC; cc = strdup(key->sk_cc); if (cc == NULL) { res = MAIL_ERROR_MEMORY; goto err; } break; case MAIL_SEARCH_KEY_DELETED: type = MAILIMAP_SEARCH_KEY_DELETED; break; case MAIL_SEARCH_KEY_FLAGGED: type = MAILIMAP_SEARCH_KEY_FLAGGED; break; case MAIL_SEARCH_KEY_FROM: type = MAILIMAP_SEARCH_KEY_FROM; from = strdup(key->sk_from); if (from == NULL) { res = MAIL_ERROR_MEMORY; goto err; } break; case MAIL_SEARCH_KEY_NEW: type = MAILIMAP_SEARCH_KEY_NEW; break; case MAIL_SEARCH_KEY_OLD: type = MAILIMAP_SEARCH_KEY_OLD; break; case MAIL_SEARCH_KEY_ON: type = MAILIMAP_SEARCH_KEY_ON; r = mailimf_date_time_to_imap_date(key->sk_on, &on); if (r != MAIL_NO_ERROR) { res = r; goto err; } break; case MAIL_SEARCH_KEY_RECENT: type = MAILIMAP_SEARCH_KEY_RECENT; break; case MAIL_SEARCH_KEY_SEEN: type = MAILIMAP_SEARCH_KEY_SEEN; break; case MAIL_SEARCH_KEY_SINCE: type = MAILIMAP_SEARCH_KEY_SINCE; r = mailimf_date_time_to_imap_date(key->sk_since, &since); if (r != MAIL_NO_ERROR) { res = r; goto err; } break; case MAIL_SEARCH_KEY_SUBJECT: type = MAILIMAP_SEARCH_KEY_SUBJECT; subject = strdup(key->sk_subject); if (subject == NULL) { res = MAIL_ERROR_MEMORY; goto err; } break; case MAIL_SEARCH_KEY_TEXT: type = MAILIMAP_SEARCH_KEY_TEXT; text = strdup(key->sk_text); if (text == NULL) { res = MAIL_ERROR_MEMORY; goto err; } break; case MAIL_SEARCH_KEY_TO: type = MAILIMAP_SEARCH_KEY_TO; to = strdup(key->sk_to); if (to == NULL) { return MAIL_ERROR_MEMORY; goto err; } break; case MAIL_SEARCH_KEY_UNANSWERED: type = MAILIMAP_SEARCH_KEY_UNANSWERED; break; case MAIL_SEARCH_KEY_UNDELETED: type = MAILIMAP_SEARCH_KEY_UNFLAGGED; break; case MAIL_SEARCH_KEY_UNFLAGGED: type = MAILIMAP_SEARCH_KEY_UNANSWERED; break; case MAIL_SEARCH_KEY_UNSEEN: type = MAILIMAP_SEARCH_KEY_UNSEEN; break; case MAIL_SEARCH_KEY_HEADER: type = MAILIMAP_SEARCH_KEY_HEADER; header_name = strdup(key->sk_header_name); if (header_name == NULL) { res = MAIL_ERROR_MEMORY; goto err; } header_value = strdup(key->sk_header_value); if (header_value == NULL) { free(header_name); res = MAIL_ERROR_MEMORY; goto err; } break; case MAIL_SEARCH_KEY_LARGER: type = MAILIMAP_SEARCH_KEY_LARGER; larger = key->sk_larger; break; case MAIL_SEARCH_KEY_NOT: type = MAILIMAP_SEARCH_KEY_NOT; r = mail_search_to_imap_search(key->sk_not, ¬); if (r != MAIL_NO_ERROR) { res = r; goto err; } break; case MAIL_SEARCH_KEY_OR: type = MAILIMAP_SEARCH_KEY_OR; r = mail_search_to_imap_search(key->sk_or1, &or1); if (r != MAIL_NO_ERROR) { res = r; goto err; } r = mail_search_to_imap_search(key->sk_or2, &or2); if (r != MAIL_NO_ERROR) { mailimap_search_key_free(or1); res = r; goto err; } break; case MAIL_SEARCH_KEY_SMALLER: type = MAILIMAP_SEARCH_KEY_SMALLER; smaller = key->sk_smaller; break; case MAIL_SEARCH_KEY_MULTIPLE: multiple = clist_new(); if (multiple == NULL) { res = MAIL_ERROR_MEMORY; goto err; } type = MAILIMAP_SEARCH_KEY_MULTIPLE; for(cur = clist_begin(key->sk_multiple) ; cur != NULL ; cur = clist_next(cur)) { struct mail_search_key * key_elt; struct mailimap_search_key * imap_key_elt; key_elt = clist_content(cur); r = mail_search_to_imap_search(key_elt, &imap_key_elt); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } r = clist_append(multiple, imap_key_elt); if (r != 0) { mailimap_search_key_free(imap_key_elt); res = MAIL_ERROR_MEMORY; goto free_list; } } break; free_list: clist_foreach(multiple, (clist_func) mailimap_search_key_free, NULL); clist_free(multiple); goto err; default: return MAIL_ERROR_INVAL; } imap_key = mailimap_search_key_new(type, bcc, before, body, cc, from, NULL, on, since, subject, text, to, NULL, header_name, header_value, larger, not, or1, or2, NULL, NULL, NULL, smaller, NULL, NULL, multiple); if (imap_key == NULL) { res = MAIL_ERROR_MEMORY; goto free; } * result = imap_key; return MAIL_NO_ERROR; free: if (bcc != NULL) free(bcc); if (before != NULL) mailimap_date_free(before); if (body != NULL) free(body); if (cc != NULL) free(cc); if (from != NULL) free(from); if (on != NULL) mailimap_date_free(on); if (since != NULL) mailimap_date_free(since); if (subject != NULL) free(subject); if (text != NULL) free(text); if (to != NULL) free(to); if (header_name != NULL) free(header_name); if (header_value != NULL) free(header_value); if (not != NULL) mailimap_search_key_free(not); if (or1 != NULL) mailimap_search_key_free(or1); if (or2 != NULL) mailimap_search_key_free(or2); clist_foreach(multiple, (clist_func) mailimap_search_key_free, NULL); clist_free(multiple); err: return res; } #endif int msg_list_to_imap_set(clist * msg_list, struct mailimap_set ** result) { struct mailimap_set * imap_set; clistiter * cur; int previous_valid; uint32_t first_seq; uint32_t previous; int r; int res; imap_set = mailimap_set_new_empty(); if (imap_set == NULL) { res = MAIL_ERROR_MEMORY; goto err; } cur = clist_begin(msg_list); previous_valid = FALSE; first_seq = 0; previous = 0; while (1) { uint32_t * pindex; if ((cur == NULL) && (previous_valid)) { if (first_seq == previous) { r = mailimap_set_add_single(imap_set, first_seq); if (r != MAILIMAP_NO_ERROR) { res = r; goto free; } } else { r = mailimap_set_add_interval(imap_set, first_seq, previous); if (r != MAILIMAP_NO_ERROR) { res = r; goto free; } } break; } pindex = clist_content(cur); if (!previous_valid) { first_seq = * pindex; previous_valid = TRUE; previous = * pindex; cur = clist_next(cur); } else { if (* pindex != previous + 1) { if (first_seq == previous) { r = mailimap_set_add_single(imap_set, first_seq); if (r != MAILIMAP_NO_ERROR) { res = r; goto free; } } else { r = mailimap_set_add_interval(imap_set, first_seq, previous); if (r != MAILIMAP_NO_ERROR) { res = r; goto free; } } previous_valid = FALSE; } else { previous = * pindex; cur = clist_next(cur); } } } * result = imap_set; return MAIL_NO_ERROR; free: mailimap_set_free(imap_set); err: return res; } static int uid_list_to_env_list(clist * fetch_result, struct mailmessage_list ** result, mailsession * session, mailmessage_driver * driver) { clistiter * cur; struct mailmessage_list * env_list; int r; int res; carray * tab; unsigned int i; mailmessage * msg; tab = carray_new(128); if (tab == NULL) { res = MAIL_ERROR_MEMORY; goto err; } for(cur = clist_begin(fetch_result) ; cur != NULL ; cur = clist_next(cur)) { struct mailimap_msg_att * msg_att; clistiter * item_cur; uint32_t uid; size_t size; msg_att = clist_content(cur); uid = 0; size = 0; for(item_cur = clist_begin(msg_att->att_list) ; item_cur != NULL ; item_cur = clist_next(item_cur)) { struct mailimap_msg_att_item * item; item = clist_content(item_cur); switch (item->att_type) { case MAILIMAP_MSG_ATT_ITEM_STATIC: switch (item->att_data.att_static->att_type) { case MAILIMAP_MSG_ATT_UID: uid = item->att_data.att_static->att_data.att_uid; break; case MAILIMAP_MSG_ATT_RFC822_SIZE: size = item->att_data.att_static->att_data.att_rfc822_size; break; } break; } } msg = mailmessage_new(); if (msg == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } r = mailmessage_init(msg, session, driver, uid, size); if (r != MAIL_NO_ERROR) { res = r; goto free_msg; } r = carray_add(tab, msg, NULL); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_msg; } } 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_msg: mailmessage_free(msg); free_list: for(i = 0 ; i < carray_count(tab) ; i++) mailmessage_free(carray_get(tab, i)); err: return res; } /* MAILIMAP_FLAG_FETCH_RECENT, MAILIMAP_FLAG_FETCH_OTHER MAILIMAP_FLAG_ANSWERED, MAILIMAP_FLAG_FLAGGED, MAILIMAP_FLAG_DELETED, MAILIMAP_FLAG_SEEN, MAILIMAP_FLAG_DRAFT, MAILIMAP_FLAG_KEYWORD, MAILIMAP_FLAG_EXTENSION */ static int imap_flags_to_flags(struct mailimap_msg_att_dynamic * att_dyn, struct mail_flags ** result) { struct mail_flags * flags; clist * flag_list; clistiter * cur; flags = mail_flags_new_empty(); if (flags == NULL) goto err; flags->fl_flags = 0; flag_list = att_dyn->att_list; if (flag_list != NULL) { for(cur = clist_begin(flag_list) ; cur != NULL ; cur = clist_next(cur)) { struct mailimap_flag_fetch * flag_fetch; flag_fetch = clist_content(cur); if (flag_fetch->fl_type == MAILIMAP_FLAG_FETCH_RECENT) flags->fl_flags |= MAIL_FLAG_NEW; else { char * keyword; int r; switch (flag_fetch->fl_flag->fl_type) { case MAILIMAP_FLAG_ANSWERED: flags->fl_flags |= MAIL_FLAG_ANSWERED; break; case MAILIMAP_FLAG_FLAGGED: flags->fl_flags |= MAIL_FLAG_FLAGGED; break; case MAILIMAP_FLAG_DELETED: flags->fl_flags |= MAIL_FLAG_DELETED; break; case MAILIMAP_FLAG_SEEN: flags->fl_flags |= MAIL_FLAG_SEEN; break; case MAILIMAP_FLAG_DRAFT: keyword = strdup("Draft"); if (keyword == NULL) goto free; r = clist_append(flags->fl_extension, keyword); if (r < 0) { free(keyword); goto free; } break; case MAILIMAP_FLAG_KEYWORD: if (strcasecmp(flag_fetch->fl_flag->fl_data.fl_keyword, "$Forwarded") == 0) { flags->fl_flags |= MAIL_FLAG_FORWARDED; } else { keyword = strdup(flag_fetch->fl_flag->fl_data.fl_keyword); if (keyword == NULL) goto free; r = clist_append(flags->fl_extension, keyword); if (r < 0) { free(keyword); goto free; } } break; case MAILIMAP_FLAG_EXTENSION: /* do nothing */ break; } } } /* MAIL_FLAG_NEW was set for \Recent messages. Correct this flag for \Seen messages by unsetting it. */ if ((flags->fl_flags & MAIL_FLAG_SEEN) && (flags->fl_flags & MAIL_FLAG_NEW)) { flags->fl_flags &= ~MAIL_FLAG_NEW; } } * result = flags; return MAIL_NO_ERROR; free: mail_flags_free(flags); err: return MAIL_ERROR_MEMORY; } -static int flags_to_imap_flags(struct mail_flags * flags, - struct mailimap_store_att_flags ** result) +int imap_flags_to_imap_flags(struct mail_flags * flags, + struct mailimap_flag_list ** result) { struct mailimap_flag * flag; struct mailimap_flag_list * flag_list; - struct mailimap_store_att_flags * att_flags; int res; clistiter * cur; int r; - + flag_list = mailimap_flag_list_new_empty(); if (flag_list == NULL) { res = MAIL_ERROR_MEMORY; goto err; } if ((flags->fl_flags & MAIL_FLAG_DELETED) != 0) { flag = mailimap_flag_new_deleted(); if (flag == NULL) { res = MAIL_ERROR_MEMORY; goto free_flag_list; } r = mailimap_flag_list_add(flag_list, flag); if (r != MAILIMAP_NO_ERROR) { mailimap_flag_free(flag); res = MAIL_ERROR_MEMORY; goto free_flag_list; } } if ((flags->fl_flags & MAIL_FLAG_FLAGGED) != 0) { flag = mailimap_flag_new_flagged(); if (flag == NULL) { res = MAIL_ERROR_MEMORY; goto free_flag_list; } r = mailimap_flag_list_add(flag_list, flag); if (r != MAILIMAP_NO_ERROR) { mailimap_flag_free(flag); res = MAIL_ERROR_MEMORY; goto free_flag_list; } } if ((flags->fl_flags & MAIL_FLAG_SEEN) != 0) { flag = mailimap_flag_new_seen(); if (flag == NULL) { res = MAIL_ERROR_MEMORY; goto free_flag_list; } r = mailimap_flag_list_add(flag_list, flag); if (r != MAILIMAP_NO_ERROR) { res = MAIL_ERROR_MEMORY; goto free_flag_list; } } if ((flags->fl_flags & MAIL_FLAG_ANSWERED) != 0) { flag = mailimap_flag_new_answered(); if (flag == NULL) { res = MAIL_ERROR_MEMORY; goto free_flag_list; } r = mailimap_flag_list_add(flag_list, flag); if (r != MAILIMAP_NO_ERROR) { mailimap_flag_free(flag); res = MAIL_ERROR_MEMORY; goto free_flag_list; } } if ((flags->fl_flags & MAIL_FLAG_FORWARDED) != 0) { char * flag_str; flag_str = strdup("$Forwarded"); if (flag_str == NULL) { res = MAIL_ERROR_MEMORY; goto free_flag_list; } flag = mailimap_flag_new_flag_keyword(flag_str); if (flag == NULL) { free(flag_str); res = MAIL_ERROR_MEMORY; goto free_flag_list; } r = mailimap_flag_list_add(flag_list, flag); if (r != MAILIMAP_NO_ERROR) { mailimap_flag_free(flag); res = MAIL_ERROR_MEMORY; goto free_flag_list; } } for(cur = clist_begin(flags->fl_extension) ; cur != NULL ; cur = clist_next(cur)) { char * flag_str; flag_str = clist_content(cur); if (strcasecmp(flag_str, "Draft") == 0) { flag = mailimap_flag_new_draft(); if (flag == NULL) { res = MAIL_ERROR_MEMORY; goto free_flag_list; } r = mailimap_flag_list_add(flag_list, flag); if (r != MAILIMAP_NO_ERROR) { mailimap_flag_free(flag); res = MAIL_ERROR_MEMORY; goto free_flag_list; } } else { flag_str = strdup(flag_str); if (flag_str == NULL) { res = MAIL_ERROR_MEMORY; goto free_flag_list; } flag = mailimap_flag_new_flag_keyword(flag_str); if (flag == NULL) { free(flag_str); res = MAIL_ERROR_MEMORY; goto free_flag_list; } r = mailimap_flag_list_add(flag_list, flag); if (r != MAILIMAP_NO_ERROR) { mailimap_flag_free(flag); res = MAIL_ERROR_MEMORY; goto free_flag_list; } } } + + * result = flag_list; + + return MAIL_NO_ERROR; + + free_flag_list: + mailimap_flag_list_free(flag_list); + err: + return res; +} +static int flags_to_imap_flags(struct mail_flags * flags, + struct mailimap_store_att_flags ** result) +{ + struct mailimap_flag_list * flag_list; + struct mailimap_store_att_flags * att_flags; + int res; + int r; + + r = imap_flags_to_imap_flags(flags, + &flag_list); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + att_flags = mailimap_store_att_flags_new_set_flags_silent(flag_list); if (att_flags == NULL) { res = MAIL_ERROR_MEMORY; goto free_flag_list; } - + * result = att_flags; - + return MAIL_NO_ERROR; - + free_flag_list: mailimap_flag_list_free(flag_list); err: return res; } static int imap_fetch_result_to_flags(clist * fetch_result, uint32_t index, struct mail_flags ** result) { clistiter * cur; int r; for(cur = clist_begin(fetch_result) ; cur != NULL ; cur = clist_next(cur)) { struct mailimap_msg_att * msg_att; clistiter * item_cur; uint32_t uid; struct mailimap_msg_att_dynamic * att_dyn; msg_att = clist_content(cur); uid = 0; att_dyn = NULL; for(item_cur = clist_begin(msg_att->att_list) ; item_cur != NULL ; item_cur = clist_next(item_cur)) { struct mailimap_msg_att_item * item; item = clist_content(item_cur); if (item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) { switch (item->att_data.att_static->att_type) { case MAILIMAP_MSG_ATT_UID: uid = item->att_data.att_static->att_data.att_uid; break; } } else if (item->att_type == MAILIMAP_MSG_ATT_ITEM_DYNAMIC) { if (att_dyn == NULL) { att_dyn = item->att_data.att_dyn; } } } if (uid != 0) { if (uid == index) { struct mail_flags * flags; if (att_dyn != NULL) { r = imap_flags_to_flags(att_dyn, &flags); if (r == MAIL_NO_ERROR) { * result = flags; return MAIL_NO_ERROR; } } } } } return MAIL_ERROR_MSG_NOT_FOUND; } int imap_fetch_flags(mailimap * imap, uint32_t index, struct mail_flags ** result) { struct mailimap_fetch_att * fetch_att; struct mailimap_fetch_type * fetch_type; struct mailimap_set * set; int r; int res; clist * fetch_result; struct mail_flags * flags; fetch_type = mailimap_fetch_type_new_fetch_att_list_empty(); if (fetch_type == NULL) { res = MAIL_ERROR_MEMORY; goto err; } fetch_att = mailimap_fetch_att_new_uid(); if (fetch_att == NULL) { res = MAIL_ERROR_MEMORY; goto free_fetch_type; } r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); if (r != MAILIMAP_NO_ERROR) { mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto free_fetch_type; } fetch_att = mailimap_fetch_att_new_flags(); if (fetch_att == NULL) { res = MAIL_ERROR_MEMORY; goto free_fetch_type; } r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); if (r != MAILIMAP_NO_ERROR) { mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto free_fetch_type; } set = mailimap_set_new_single(index); if (set == NULL) { res = MAIL_ERROR_MEMORY; goto free_fetch_type; } r = mailimap_uid_fetch(imap, set, fetch_type, &fetch_result); mailimap_fetch_type_free(fetch_type); mailimap_set_free(set); switch (r) { case MAILIMAP_NO_ERROR: break; default: return imap_error_to_mail_error(r); } r = imap_fetch_result_to_flags(fetch_result, index, &flags); mailimap_fetch_list_free(fetch_result); if (r != MAIL_NO_ERROR) { res = r; goto err; } * result = flags; return MAIL_NO_ERROR; free_fetch_type: mailimap_fetch_type_free(fetch_type); err: return res; } int imap_store_flags(mailimap * imap, uint32_t first, uint32_t last, struct mail_flags * flags) { struct mailimap_store_att_flags * att_flags; struct mailimap_set * set; int r; int res; set = mailimap_set_new_interval(first, last); if (set == NULL) { res = MAIL_ERROR_MEMORY; goto err; } r = flags_to_imap_flags(flags, &att_flags); if (r != MAIL_NO_ERROR) { res = r; goto free_set; } r = mailimap_uid_store(imap, set, att_flags); if (r != MAILIMAP_NO_ERROR) { res = imap_error_to_mail_error(r); goto free_flag; } mailimap_store_att_flags_free(att_flags); mailimap_set_free(set); return MAIL_NO_ERROR; free_flag: mailimap_store_att_flags_free(att_flags); free_set: mailimap_set_free(set); err: return res; } int imap_get_messages_list(mailimap * imap, mailsession * session, mailmessage_driver * driver, uint32_t first_index, struct mailmessage_list ** result) { struct mailmessage_list * env_list; int r; struct mailimap_fetch_att * fetch_att; struct mailimap_fetch_type * fetch_type; struct mailimap_set * set; clist * fetch_result; int res; set = mailimap_set_new_interval(first_index, 0); if (set == NULL) { res = MAIL_ERROR_MEMORY; goto err; } fetch_type = mailimap_fetch_type_new_fetch_att_list_empty(); if (fetch_type == NULL) { res = MAIL_ERROR_MEMORY; goto free_set; } fetch_att = mailimap_fetch_att_new_uid(); if (fetch_att == NULL) { res = MAIL_ERROR_MEMORY; goto free_fetch_type; } r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); if (r != MAILIMAP_NO_ERROR) { mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto free_fetch_type; } fetch_att = mailimap_fetch_att_new_rfc822_size(); if (fetch_att == NULL) { res = MAIL_ERROR_MEMORY; goto free_fetch_type; } r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); if (r != MAILIMAP_NO_ERROR) { mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto free_fetch_type; } r = mailimap_uid_fetch(imap, set, fetch_type, &fetch_result); mailimap_fetch_type_free(fetch_type); mailimap_set_free(set); if (r != MAILIMAP_NO_ERROR) { res = imap_error_to_mail_error(r); goto err; } r = uid_list_to_env_list(fetch_result, &env_list, session, driver); mailimap_fetch_list_free(fetch_result); * result = env_list; return MAIL_NO_ERROR; free_fetch_type: mailimap_fetch_type_free(fetch_type); free_set: mailimap_set_free(set); err: return res; } static void generate_key_from_message(char * key, size_t size, mailmessage * msg_info, int type) { switch (type) { case MAILIMAP_MSG_ATT_RFC822: snprintf(key, size, "%s-rfc822", msg_info->msg_uid); break; case MAILIMAP_MSG_ATT_RFC822_HEADER: snprintf(key, size, "%s-rfc822-header", msg_info->msg_uid); break; case MAILIMAP_MSG_ATT_RFC822_TEXT: snprintf(key, size, "%s-rfc822-text", msg_info->msg_uid); break; case MAILIMAP_MSG_ATT_ENVELOPE: snprintf(key, size, "%s-envelope", msg_info->msg_uid); break; } } int imapdriver_get_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr, mailsession * session, mailmessage * msg, struct mailimf_fields ** result) { #if 0 mailsession * imap_session; #endif mailimap * imap; int r; struct mailimf_fields * fields; int res; char keyname[PATH_MAX]; #if 0 imap_session = cached_session_get_ancestor(session); imap = ((struct imap_session_state_data *) (imap_session->data))->session; #endif imap = cached_session_get_imap_session(session); generate_key_from_message(keyname, PATH_MAX, msg, MAILIMAP_MSG_ATT_ENVELOPE); 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; } int imapdriver_write_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr, mailsession * session, mailmessage * msg, struct mailimf_fields * fields) { char keyname[PATH_MAX]; int r; int res; generate_key_from_message(keyname, PATH_MAX, msg, MAILIMAP_MSG_ATT_ENVELOPE); 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; } diff --git a/kmicromail/libetpan/generic/imapdriver_tools.h b/kmicromail/libetpan/generic/imapdriver_tools.h index 6582a31..59c993e 100644 --- a/kmicromail/libetpan/generic/imapdriver_tools.h +++ b/kmicromail/libetpan/generic/imapdriver_tools.h @@ -1,113 +1,116 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #ifndef IMAPDRIVER_TOOLS_H #define IMAPDRIVER_TOOLS_H #include "mailimap.h" #include "mailmime.h" #include "imapdriver_types.h" #include "mail_cache_db.h" #ifdef __cplusplus extern "C" { #endif int imap_list_to_list(clist * imap_list, struct mail_list ** result); int section_to_imap_section(struct mailmime_section * section, int type, struct mailimap_section ** result); int imap_get_msg_att_info(struct mailimap_msg_att * msg_att, uint32_t * puid, struct mailimap_envelope ** pimap_envelope, char ** preferences, size_t * pref_size, struct mailimap_msg_att_dynamic ** patt_dyn, struct mailimap_body ** pimap_body); int imap_add_envelope_fetch_att(struct mailimap_fetch_type * fetch_type); int imap_env_to_fields(struct mailimap_envelope * env, char * ref_str, size_t ref_size, struct mailimf_fields ** result); int imap_fetch_result_to_envelop_list(clist * fetch_result, struct mailmessage_list * env_list); int imap_body_to_body(struct mailimap_body * imap_body, struct mailmime ** result); #if 0 int mail_search_to_imap_search(struct mail_search_key * key, struct mailimap_search_key ** result); #endif int msg_list_to_imap_set(clist * msg_list, struct mailimap_set ** result); int imap_error_to_mail_error(int error); int imap_store_flags(mailimap * imap, uint32_t first, uint32_t last, struct mail_flags * flags); int imap_fetch_flags(mailimap * imap, uint32_t index, struct mail_flags ** result); int imap_get_messages_list(mailimap * imap, mailsession * session, mailmessage_driver * driver, uint32_t first_index, struct mailmessage_list ** result); int imapdriver_get_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr, mailsession * session, mailmessage * msg, struct mailimf_fields ** result); int imapdriver_write_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr, mailsession * session, mailmessage * msg, struct mailimf_fields * fields); +int imap_flags_to_imap_flags(struct mail_flags * flags, + struct mailimap_flag_list ** result); + #ifdef __cplusplus } #endif #endif diff --git a/kmicromail/libetpan/generic/imapstorage.c b/kmicromail/libetpan/generic/imapstorage.c index e8683d8..972b6dd 100644 --- a/kmicromail/libetpan/generic/imapstorage.c +++ b/kmicromail/libetpan/generic/imapstorage.c @@ -1,297 +1,297 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "imapstorage.h" #include <stdlib.h> #include <string.h> #include "mail.h" #include "imapdriver.h" #include "imapdriver_cached.h" #include "mailstorage_tools.h" #include "maildriver.h" /* imap storage */ #define IMAP_DEFAULT_PORT 143 #define IMAPS_DEFAULT_PORT 993 static int imap_mailstorage_connect(struct mailstorage * storage); static int imap_mailstorage_get_folder_session(struct mailstorage * storage, char * pathname, mailsession ** result); static void imap_mailstorage_uninitialize(struct mailstorage * storage); static mailstorage_driver imap_mailstorage_driver = { .sto_name = "imap", .sto_connect = imap_mailstorage_connect, .sto_get_folder_session = imap_mailstorage_get_folder_session, .sto_uninitialize = imap_mailstorage_uninitialize, }; int imap_mailstorage_init(struct mailstorage * storage, char * imap_servername, uint16_t imap_port, char * imap_command, int imap_connection_type, int imap_auth_type, char * imap_login, char * imap_password, int imap_cached, char * imap_cache_directory) { struct imap_mailstorage * imap_storage; - imap_storage = malloc(sizeof(struct imap_mailstorage)); + imap_storage = malloc(sizeof(* imap_storage)); if (imap_storage == NULL) goto err; imap_storage->imap_servername = strdup(imap_servername); if (imap_storage->imap_servername == NULL) goto free; imap_storage->imap_connection_type = imap_connection_type; if (imap_port == 0) { switch (imap_connection_type) { case CONNECTION_TYPE_PLAIN: case CONNECTION_TYPE_TRY_STARTTLS: case CONNECTION_TYPE_STARTTLS: case CONNECTION_TYPE_COMMAND: case CONNECTION_TYPE_COMMAND_TRY_STARTTLS: case CONNECTION_TYPE_COMMAND_STARTTLS: imap_port = IMAP_DEFAULT_PORT; break; case CONNECTION_TYPE_TLS: case CONNECTION_TYPE_COMMAND_TLS: imap_port = IMAPS_DEFAULT_PORT; break; } } imap_storage->imap_port = imap_port; if (imap_command != NULL) { imap_storage->imap_command = strdup(imap_command); if (imap_storage->imap_command == NULL) goto free_servername; } else imap_storage->imap_command = NULL; imap_storage->imap_auth_type = imap_auth_type; if (imap_login != NULL) { imap_storage->imap_login = strdup(imap_login); if (imap_storage->imap_login == NULL) goto free_command; } else imap_storage->imap_login = NULL; if (imap_password != NULL) { imap_storage->imap_password = strdup(imap_password); if (imap_storage->imap_password == NULL) goto free_login; } else imap_storage->imap_password = NULL; imap_storage->imap_cached = imap_cached; if (imap_cached && (imap_cache_directory != NULL)) { imap_storage->imap_cache_directory = strdup(imap_cache_directory); if (imap_storage->imap_cache_directory == NULL) goto free_password; } else { imap_storage->imap_cached = FALSE; imap_storage->imap_cache_directory = NULL; } storage->sto_data = imap_storage; storage->sto_driver = &imap_mailstorage_driver; return MAIL_NO_ERROR; free_password: free(imap_storage->imap_password); free_login: free(imap_storage->imap_login); free_command: free(imap_storage->imap_command); free_servername: free(imap_storage->imap_servername); free: free(imap_storage); err: return MAIL_ERROR_MEMORY; } static void imap_mailstorage_uninitialize(struct mailstorage * storage) { struct imap_mailstorage * imap_storage; imap_storage = storage->sto_data; if (imap_storage->imap_cache_directory != NULL) free(imap_storage->imap_cache_directory); if (imap_storage->imap_password != NULL) free(imap_storage->imap_password); if (imap_storage->imap_login != NULL) free(imap_storage->imap_login); if (imap_storage->imap_command != NULL) free(imap_storage->imap_command); free(imap_storage->imap_servername); free(imap_storage); storage->sto_data = NULL; } static int imap_connect(struct mailstorage * storage, mailsession ** result) { struct imap_mailstorage * imap_storage; mailsession_driver * driver; int r; int res; mailsession * session; imap_storage = storage->sto_data; if (imap_storage->imap_cached) driver = imap_cached_session_driver; else driver = imap_session_driver; r = mailstorage_generic_connect(driver, imap_storage->imap_servername, imap_storage->imap_port, imap_storage->imap_command, imap_storage->imap_connection_type, IMAPDRIVER_CACHED_SET_CACHE_DIRECTORY, imap_storage->imap_cache_directory, 0, NULL, &session); switch (r) { case MAIL_NO_ERROR_NON_AUTHENTICATED: case MAIL_NO_ERROR_AUTHENTICATED: case MAIL_NO_ERROR: break; default: res = r; goto err; } r = mailstorage_generic_auth(session, r, imap_storage->imap_connection_type, imap_storage->imap_login, imap_storage->imap_password); if (r != MAIL_NO_ERROR) { res = r; goto free; } * result = session; return MAIL_NO_ERROR; free: mailsession_free(session); err: return res; } static int imap_mailstorage_connect(struct mailstorage * storage) { mailsession * session; int r; int res; r = imap_connect(storage, &session); if (r != MAIL_NO_ERROR) { res = r; goto err; } r = mailsession_select_folder(session, "INBOX"); if (r != MAIL_NO_ERROR) { mailsession_logout(session); res = r; goto err; } storage->sto_session = session; storage->sto_driver = &imap_mailstorage_driver; return MAIL_NO_ERROR; err: return res; } static int imap_mailstorage_get_folder_session(struct mailstorage * storage, char * pathname, mailsession ** result) { mailsession * session; int r; int res; if (strcasecmp(pathname, "INBOX") == 0) { session = storage->sto_session; } else { r = imap_connect(storage, &session); if (r != MAIL_NO_ERROR) { res = r; goto err; } r = mailsession_select_folder(session, pathname); if (r != MAIL_NO_ERROR) { mailsession_logout(session); res = r; goto free; } } * result = session; return MAIL_NO_ERROR; free: mailsession_free(session); err: return res; } diff --git a/kmicromail/libetpan/generic/maildirdriver.c b/kmicromail/libetpan/generic/maildirdriver.c index 7830ceb..5f21422 100644 --- a/kmicromail/libetpan/generic/maildirdriver.c +++ b/kmicromail/libetpan/generic/maildirdriver.c @@ -1,625 +1,676 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ /* flags directory MUST be kept so that we can have other flags than standards */ #include "maildirdriver.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 "maildir.h" #include "maildriver_tools.h" #include "maildirdriver_message.h" #include "maildirdriver_tools.h" #include "mailmessage.h" #include "generic_cache.h" static int initialize(mailsession * session); static void uninitialize(mailsession * session); static int connect_path(mailsession * session, char * path); static int logout(mailsession * session); static int expunge_folder(mailsession * session); static int status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); static int recent_number(mailsession * session, char * mb, uint32_t * result); static int unseen_number(mailsession * session, char * mb, uint32_t * result); static int messages_number(mailsession * session, char * mb, uint32_t * result); static int append_message(mailsession * session, char * message, size_t size); +static int append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags); + static int get_messages_list(mailsession * session, struct mailmessage_list ** result); static int get_envelopes_list(mailsession * session, struct mailmessage_list * env_list); static int check_folder(mailsession * session); static int get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result); static mailsession_driver local_maildir_session_driver = { .sess_name = "maildir", .sess_initialize = initialize, .sess_uninitialize = uninitialize, .sess_parameters = NULL, .sess_connect_stream = NULL, .sess_connect_path = connect_path, .sess_starttls = NULL, .sess_login = NULL, .sess_logout = logout, .sess_noop = NULL, .sess_build_folder_name = NULL, .sess_create_folder = NULL, .sess_delete_folder = NULL, .sess_rename_folder = NULL, .sess_check_folder = check_folder, .sess_examine_folder = NULL, .sess_select_folder = NULL, .sess_expunge_folder = expunge_folder, .sess_status_folder = status_folder, .sess_messages_number = messages_number, .sess_recent_number = recent_number, .sess_unseen_number = unseen_number, .sess_list_folders = NULL, .sess_lsub_folders = NULL, .sess_subscribe_folder = NULL, .sess_unsubscribe_folder = NULL, .sess_append_message = append_message, + .sess_append_message_flags = append_message_flags, .sess_copy_message = NULL, .sess_move_message = NULL, .sess_get_messages_list = get_messages_list, .sess_get_envelopes_list = get_envelopes_list, .sess_remove_message = NULL, #if 0 .sess_search_messages = maildriver_generic_search_messages, #endif .sess_get_message = NULL, .sess_get_message_by_uid = get_message_by_uid, }; mailsession_driver * maildir_session_driver = &local_maildir_session_driver; static int flags_store_process(struct maildir * md, struct mail_flags_store * flags_store); static inline struct maildir_session_state_data * get_data(mailsession * session) { return session->sess_data; } static struct maildir * get_maildir_session(mailsession * session) { return get_data(session)->md_session; } static int initialize(mailsession * session) { struct maildir_session_state_data * data; data = malloc(sizeof(* data)); if (data == NULL) goto err; data->md_session = NULL; data->md_flags_store = mail_flags_store_new(); if (data->md_flags_store == NULL) goto free; session->sess_data = data; return MAIL_NO_ERROR; free: free(data); err: return MAIL_ERROR_MEMORY; } static void uninitialize(mailsession * session) { struct maildir_session_state_data * data; data = get_data(session); if (data->md_session != NULL) flags_store_process(data->md_session, data->md_flags_store); mail_flags_store_free(data->md_flags_store); if (data->md_session != NULL) maildir_free(data->md_session); free(data); session->sess_data = NULL; } static int connect_path(mailsession * session, char * path) { struct maildir * md; int res; int r; if (get_maildir_session(session) != NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } md = maildir_new(path); if (md == NULL) { res = MAIL_ERROR_MEMORY; goto err; } r = maildir_update(md); if (r != MAILDIR_NO_ERROR) { res = maildirdriver_maildir_error_to_mail_error(r); goto free; } get_data(session)->md_session = md; return MAIL_NO_ERROR; free: maildir_free(md); err: return res; } static int logout(mailsession * session) { struct maildir * md; check_folder(session); md = get_maildir_session(session); if (md == NULL) return MAIL_ERROR_BAD_STATE; maildir_free(md); get_data(session)->md_session = NULL; return MAIL_NO_ERROR; } /* folders operations */ static int status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { int r; struct maildir * md; unsigned int i; uint32_t messages; uint32_t recent; uint32_t unseen; check_folder(session); md = get_maildir_session(session); if (md == NULL) return MAIL_ERROR_BAD_STATE; r = maildir_update(md); if (r != MAILDIR_NO_ERROR) return maildirdriver_maildir_error_to_mail_error(r); messages = 0; recent = 0; unseen = 0; for(i = 0 ; i < carray_count(md->mdir_msg_list) ; i ++) { struct maildir_msg * msg; msg = carray_get(md->mdir_msg_list, i); if ((msg->msg_flags & MAILDIR_FLAG_NEW) != 0) recent ++; if ((msg->msg_flags & MAILDIR_FLAG_SEEN) == 0) unseen ++; messages ++; } * result_messages = messages; * result_recent = recent; * result_unseen = unseen; return MAIL_NO_ERROR; } static int messages_number(mailsession * session, char * mb, uint32_t * result) { struct maildir * md; int r; md = get_maildir_session(session); if (md == NULL) return MAIL_ERROR_BAD_STATE; r = maildir_update(md); if (r != MAILDIR_NO_ERROR) return maildirdriver_maildir_error_to_mail_error(r); * result = carray_count(md->mdir_msg_list); return MAIL_NO_ERROR; } static int unseen_number(mailsession * session, char * mb, uint32_t * result) { uint32_t messages; uint32_t recent; uint32_t unseen; int r; r = status_folder(session, mb, &messages, &recent, &unseen); if (r != MAIL_NO_ERROR) return r; * result = unseen; return MAIL_NO_ERROR; } static int recent_number(mailsession * session, char * mb, uint32_t * result) { uint32_t messages; uint32_t recent; uint32_t unseen; int r; r = status_folder(session, mb, &messages, &recent, &unseen); if (r != MAIL_NO_ERROR) return r; * result = recent; return MAIL_NO_ERROR; } /* messages operations */ static int append_message(mailsession * session, char * message, size_t size) { +#if 0 struct maildir * md; int r; md = get_maildir_session(session); if (md == NULL) return MAIL_ERROR_BAD_STATE; r = maildir_message_add(md, message, size); if (r != MAILDIR_NO_ERROR) return maildirdriver_maildir_error_to_mail_error(r); return MAIL_NO_ERROR; +#endif + + return append_message_flags(session, message, size, NULL); +} + +static int append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags) +{ + struct maildir * md; + int r; + char uid[PATH_MAX]; + struct maildir_msg * md_msg; + chashdatum key; + chashdatum value; + uint32_t md_flags; + + md = get_maildir_session(session); + if (md == NULL) + return MAIL_ERROR_BAD_STATE; + + r = maildir_message_add_uid(md, message, size, + uid, sizeof(uid)); + if (r != MAILDIR_NO_ERROR) + return maildirdriver_maildir_error_to_mail_error(r); + + if (flags == NULL) + goto exit; + + key.data = uid; + key.len = strlen(uid); + r = chash_get(md->mdir_msg_hash, &key, &value); + if (r < 0) + goto exit; + + md_msg = value.data; + + md_flags = maildirdriver_flags_to_maildir_flags(flags->fl_flags); + + r = maildir_message_change_flags(md, uid, md_flags); + if (r != MAILDIR_NO_ERROR) + goto exit; + + return MAIL_NO_ERROR; + + exit: + return MAIL_NO_ERROR; } static int get_messages_list(mailsession * session, struct mailmessage_list ** result) { struct maildir * md; int r; struct mailmessage_list * env_list; int res; md = get_maildir_session(session); if (md == NULL) return MAIL_ERROR_BAD_STATE; r = maildir_update(md); if (r != MAILDIR_NO_ERROR) { res = maildirdriver_maildir_error_to_mail_error(r); goto err; } r = maildir_get_messages_list(session, md, maildir_message_driver, &env_list); if (r != MAILDIR_NO_ERROR) { res = r; goto free_list; } * result = env_list; return MAIL_NO_ERROR; free_list: mailmessage_list_free(env_list); err: return res; } static int get_envelopes_list(mailsession * session, struct mailmessage_list * env_list) { int r; struct maildir * md; unsigned int i; int res; check_folder(session); md = get_maildir_session(session); if (md == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } r = maildir_update(md); if (r != MAILDIR_NO_ERROR) { res = maildirdriver_maildir_error_to_mail_error(r); goto err; } r = maildriver_generic_get_envelopes_list(session, env_list); if (r != MAIL_NO_ERROR) { res = r; goto err; } for(i = 0 ; i < carray_count(env_list->msg_tab) ; i++) { struct maildir_msg * md_msg; mailmessage * msg; uint32_t driver_flags; clist * ext; chashdatum key; chashdatum value; msg = carray_get(env_list->msg_tab, i); key.data = msg->msg_uid; key.len = strlen(msg->msg_uid); r = chash_get(md->mdir_msg_hash, &key, &value); if (r < 0) continue; md_msg = value.data; driver_flags = maildirdriver_maildir_flags_to_flags(md_msg->msg_flags); if (msg->msg_flags == NULL) { ext = clist_new(); if (ext == NULL) { res = MAIL_ERROR_MEMORY; continue; } msg->msg_flags = mail_flags_new(driver_flags, ext); if (msg->msg_flags == NULL) { clist_free(ext); res = MAIL_ERROR_MEMORY; continue; } if ((md_msg->msg_flags & MAILDIR_FLAG_NEW) != 0) { mail_flags_store_set(get_data(session)->md_flags_store, msg); } } else { msg->msg_flags->fl_flags &= MAIL_FLAG_FORWARDED; msg->msg_flags->fl_flags |= driver_flags; } } return MAIL_NO_ERROR; err: return res; } static int expunge_folder(mailsession * session) { unsigned int i; int r; int res; struct maildir * md; check_folder(session); md = get_maildir_session(session); if (md == NULL) return MAIL_ERROR_BAD_STATE; r = maildir_update(md); if (r != MAILDIR_NO_ERROR) { res = maildirdriver_maildir_error_to_mail_error(r); goto err; } for(i = 0 ; i < carray_count(md->mdir_msg_list) ; i++) { struct maildir_msg * md_msg; md_msg = carray_get(md->mdir_msg_list, i); if ((md_msg->msg_flags & MAILDIR_FLAG_TRASHED) != 0) maildir_message_remove(md, md_msg->msg_uid); } return MAIL_NO_ERROR; err: return res; } static int flags_store_process(struct maildir * md, struct mail_flags_store * flags_store) { unsigned int i; if (carray_count(flags_store->fls_tab) == 0) return MAIL_NO_ERROR; for(i = 0 ; i < carray_count(flags_store->fls_tab) ; i ++) { mailmessage * msg; uint32_t md_flags; msg = carray_get(flags_store->fls_tab, i); md_flags = maildirdriver_flags_to_maildir_flags(msg->msg_flags->fl_flags); md_flags &= ~MAILDIR_FLAG_NEW; maildir_message_change_flags(md, msg->msg_uid, md_flags); } mail_flags_store_clear(flags_store); return MAIL_NO_ERROR; } static int check_folder(mailsession * session) { struct mail_flags_store * flags_store; struct maildir_session_state_data * data; struct maildir * md; md = get_maildir_session(session); if (md == NULL) return MAIL_ERROR_BAD_STATE; data = get_data(session); flags_store = data->md_flags_store; return flags_store_process(md, flags_store); } static int get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result) { int r; struct maildir * md; int res; mailmessage * msg; char * msg_filename; struct stat stat_info; md = get_maildir_session(session); /* update maildir data */ r = maildir_update(md); if (r != MAILDIR_NO_ERROR) { res = maildirdriver_maildir_error_to_mail_error(r); goto err; } msg_filename = maildir_message_get(md, uid); if (msg_filename == NULL) { res = MAIL_ERROR_INVAL; goto err; } r = stat(msg_filename, &stat_info); free(msg_filename); if (r < 0) { res = MAIL_ERROR_INVAL; goto err; } /* create message */ msg = mailmessage_new(); if (msg == NULL) { res = MAIL_ERROR_MEMORY; goto err; } r = mailmessage_init(msg, session, maildir_message_driver, 0, stat_info.st_size); if (r != MAIL_NO_ERROR) { mailmessage_free(msg); res = r; goto err; } msg->msg_uid = strdup(uid); if (msg->msg_uid == NULL) { mailmessage_free(msg); res = r; goto err; } * result = msg; return MAIL_NO_ERROR; err: return res; } diff --git a/kmicromail/libetpan/generic/maildirdriver_cached.c b/kmicromail/libetpan/generic/maildirdriver_cached.c index 503d1c9..8a5e206 100644 --- a/kmicromail/libetpan/generic/maildirdriver_cached.c +++ b/kmicromail/libetpan/generic/maildirdriver_cached.c @@ -1,1080 +1,1158 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "maildirdriver.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 "maildir.h" #include "maildriver_tools.h" #include "maildirdriver_tools.h" #include "maildirdriver_cached_message.h" #include "mailmessage.h" #include "generic_cache.h" #include "imfcache.h" #include "mail_cache_db.h" #include "libetpan-config.h" static int initialize(mailsession * session); static void uninitialize(mailsession * session); static int parameters(mailsession * session, int id, void * value); static int connect_path(mailsession * session, char * path); static int logout(mailsession * session); static int expunge_folder(mailsession * session); static int status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); static int recent_number(mailsession * session, char * mb, uint32_t * result); static int unseen_number(mailsession * session, char * mb, uint32_t * result); static int messages_number(mailsession * session, char * mb, uint32_t * result); static int append_message(mailsession * session, char * message, size_t size); +static int append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags); + static int get_messages_list(mailsession * session, struct mailmessage_list ** result); static int get_envelopes_list(mailsession * session, struct mailmessage_list * env_list); static int check_folder(mailsession * session); static int get_message(mailsession * session, uint32_t num, mailmessage ** result); static int get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result); static mailsession_driver local_maildir_cached_session_driver = { .sess_name = "maildir-cached", .sess_initialize = initialize, .sess_uninitialize = uninitialize, .sess_parameters = parameters, .sess_connect_stream = NULL, .sess_connect_path = connect_path, .sess_starttls = NULL, .sess_login = NULL, .sess_logout = logout, .sess_noop = NULL, .sess_build_folder_name = NULL, .sess_create_folder = NULL, .sess_delete_folder = NULL, .sess_rename_folder = NULL, .sess_check_folder = check_folder, .sess_examine_folder = NULL, .sess_select_folder = NULL, .sess_expunge_folder = expunge_folder, .sess_status_folder = status_folder, .sess_messages_number = messages_number, .sess_recent_number = recent_number, .sess_unseen_number = unseen_number, .sess_list_folders = NULL, .sess_lsub_folders = NULL, .sess_subscribe_folder = NULL, .sess_unsubscribe_folder = NULL, .sess_append_message = append_message, + .sess_append_message_flags = append_message_flags, .sess_copy_message = NULL, .sess_move_message = NULL, .sess_get_messages_list = get_messages_list, .sess_get_envelopes_list = get_envelopes_list, .sess_remove_message = NULL, #if 0 .sess_search_messages = maildriver_generic_search_messages, #endif .sess_get_message = get_message, .sess_get_message_by_uid = get_message_by_uid, }; mailsession_driver * maildir_cached_session_driver = &local_maildir_cached_session_driver; static inline struct maildir_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)->md_ancestor; } static inline struct maildir_session_state_data * get_ancestor_data(mailsession * session) { return get_ancestor(session)->sess_data; } static struct maildir * get_maildir_session(mailsession * session) { return get_ancestor_data(session)->md_session; } static int initialize(mailsession * session) { struct maildir_cached_session_state_data * data; data = malloc(sizeof(* data)); if (data == NULL) goto err; data->md_ancestor = mailsession_new(maildir_session_driver); if (data->md_ancestor == NULL) goto free; data->md_flags_store = mail_flags_store_new(); if (data->md_flags_store == NULL) goto free_session; data->md_quoted_mb = NULL; data->md_cache_directory[0] = '\0'; data->md_flags_directory[0] = '\0'; session->sess_data = data; return MAIL_NO_ERROR; free_session: mailsession_free(data->md_ancestor); free: free(data); err: return MAIL_ERROR_MEMORY; } static void free_quoted_mb(struct maildir_cached_session_state_data * maildir_cached_data) { if (maildir_cached_data->md_quoted_mb != NULL) { free(maildir_cached_data->md_quoted_mb); maildir_cached_data->md_quoted_mb = NULL; } } static int write_cached_flags(struct mail_cache_db * cache_db, MMAPString * mmapstr, char * uid, struct mail_flags * flags); #define ENV_NAME "env.db" #define FLAGS_NAME "flags.db" static int 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%c%s%c%s", flags_directory, MAIL_DIR_SEPARATOR, quoted_mb, MAIL_DIR_SEPARATOR, 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 = write_cached_flags(cache_db_flags, mmapstr, msg->msg_uid, msg->msg_flags); if (r != MAIL_NO_ERROR) { /* ignore errors */ } } 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 uninitialize(mailsession * session) { struct maildir_cached_session_state_data * data; data = get_cached_data(session); flags_store_process(data->md_flags_directory, data->md_quoted_mb, data->md_flags_store); mail_flags_store_free(data->md_flags_store); mailsession_free(data->md_ancestor); free_quoted_mb(data); free(data); session->sess_data = data; } static int parameters(mailsession * session, int id, void * value) { struct maildir_cached_session_state_data * data; int r; data = get_cached_data(session); switch (id) { case MAILDIRDRIVER_CACHED_SET_CACHE_DIRECTORY: strncpy(data->md_cache_directory, value, PATH_MAX); data->md_cache_directory[PATH_MAX - 1] = '\0'; r = generic_cache_create_dir(data->md_cache_directory); if (r != MAIL_NO_ERROR) return r; return MAIL_NO_ERROR; case MAILDIRDRIVER_CACHED_SET_FLAGS_DIRECTORY: strncpy(data->md_flags_directory, value, PATH_MAX); data->md_flags_directory[PATH_MAX - 1] = '\0'; r = generic_cache_create_dir(data->md_flags_directory); if (r != MAIL_NO_ERROR) return r; return MAIL_NO_ERROR; default: return mailsession_parameters(data->md_ancestor, id, value); } } static int get_cache_folder(mailsession * session, char ** result) { struct maildir * md; char * quoted_mb; int res; int r; char key[PATH_MAX]; struct maildir_cached_session_state_data * data; md = get_maildir_session(session); data = get_cached_data(session); quoted_mb = maildriver_quote_mailbox(md->mdir_path); if (quoted_mb == NULL) { res = MAIL_ERROR_MEMORY; goto err; } snprintf(key, PATH_MAX, "%s/%s", data->md_cache_directory, quoted_mb); r = generic_cache_create_dir(key); if (r != MAIL_NO_ERROR) { res = r; goto free_quoted_mb; } snprintf(key, PATH_MAX, "%s/%s", data->md_flags_directory, quoted_mb); r = generic_cache_create_dir(key); if (r != MAIL_NO_ERROR) { res = r; goto free_quoted_mb; } * result = quoted_mb; return MAIL_NO_ERROR; free_quoted_mb: free(quoted_mb); err: return res; } static int connect_path(mailsession * session, char * path) { int r; int res; char * quoted_mb; r = mailsession_connect_path(get_ancestor(session), path); if (r != MAIL_NO_ERROR) { res = r; goto err; } r = get_cache_folder(session, "ed_mb); if (r != MAIL_NO_ERROR) { res = r; goto logout; } get_cached_data(session)->md_quoted_mb = quoted_mb; return MAILDIR_NO_ERROR; logout: mailsession_logout(get_ancestor(session)); err: return res; } static int logout(mailsession * session) { struct maildir_cached_session_state_data * data; int r; data = get_cached_data(session); flags_store_process(data->md_flags_directory, data->md_quoted_mb, data->md_flags_store); r = mailsession_logout(get_ancestor(session)); if (r != MAIL_NO_ERROR) return r; free_quoted_mb(get_cached_data(session)); return MAIL_NO_ERROR; } static int status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { return mailsession_status_folder(get_ancestor(session), mb, result_messages, result_recent, result_unseen); } static int messages_number(mailsession * session, char * mb, uint32_t * result) { return mailsession_messages_number(get_ancestor(session), mb, result); } static int unseen_number(mailsession * session, char * mb, uint32_t * result) { return mailsession_unseen_number(get_ancestor(session), mb, result); } static int recent_number(mailsession * session, char * mb, uint32_t * result) { return mailsession_recent_number(get_ancestor(session), mb, result); } static int append_message(mailsession * session, char * message, size_t size) { +#if 0 return mailsession_append_message(get_ancestor(session), message, size); +#endif + return append_message_flags(session, message, size, NULL); } +static int append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags) +{ + struct maildir * md; + int r; + char uid[PATH_MAX]; + struct maildir_msg * md_msg; + chashdatum key; + chashdatum value; + uint32_t md_flags; + struct mail_cache_db * cache_db_flags; + char filename_flags[PATH_MAX]; + MMAPString * mmapstr; + struct maildir_cached_session_state_data * data; + + md = get_maildir_session(session); + if (md == NULL) + return MAIL_ERROR_BAD_STATE; + + r = maildir_message_add_uid(md, message, size, + uid, sizeof(uid)); + if (r != MAILDIR_NO_ERROR) + return maildirdriver_maildir_error_to_mail_error(r); + + if (flags == NULL) + goto exit; + + data = get_cached_data(session); + + snprintf(filename_flags, PATH_MAX, "%s%c%s%c%s", + data->md_flags_directory, MAIL_DIR_SEPARATOR, data->md_quoted_mb, + MAIL_DIR_SEPARATOR, 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; + + r = write_cached_flags(cache_db_flags, mmapstr, + uid, flags); + + mmap_string_free(mmapstr); + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + + if (r != MAIL_NO_ERROR) + goto exit; + + key.data = uid; + key.len = strlen(uid); + r = chash_get(md->mdir_msg_hash, &key, &value); + if (r < 0) + goto exit; + + md_msg = value.data; + + md_flags = maildirdriver_flags_to_maildir_flags(flags->fl_flags); + + r = maildir_message_change_flags(md, uid, md_flags); + if (r != MAILDIR_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; +} #define UID_NAME "uid.db" static int uid_clean_up(struct mail_cache_db * uid_db, struct mailmessage_list * env_list) { chash * hash_exist; int res; int r; unsigned int i; chashdatum key; chashdatum value; char key_str[PATH_MAX]; /* flush cache */ hash_exist = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYALL); if (hash_exist == NULL) { res = MAIL_ERROR_MEMORY; goto err; } value.data = NULL; value.len = 0; key.data = "max-uid"; key.len = strlen("max-uid"); r = chash_set(hash_exist, &key, &value, NULL); for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; msg = carray_get(env_list->msg_tab, i); value.data = NULL; value.len = 0; key.data = msg->msg_uid; key.len = strlen(msg->msg_uid); r = chash_set(hash_exist, &key, &value, NULL); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free; } snprintf(key_str, sizeof(key_str), "uid-%lu", (unsigned long) msg->msg_index); key.data = key_str; key.len = strlen(key_str); r = chash_set(hash_exist, &key, &value, NULL); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free; } } mail_cache_db_clean_up(uid_db, hash_exist); chash_free(hash_exist); return MAIL_NO_ERROR; free: chash_free(hash_exist); err: return res; } static int get_messages_list(mailsession * session, struct mailmessage_list ** result) { struct maildir * md; int r; struct mailmessage_list * env_list; int res; uint32_t max_uid; char filename[PATH_MAX]; struct mail_cache_db * uid_db; void * value; size_t value_len; unsigned long i; struct maildir_cached_session_state_data * data; char key[PATH_MAX]; data = get_cached_data(session); md = get_maildir_session(session); if (md == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } check_folder(session); r = maildir_update(md); if (r != MAILDIR_NO_ERROR) { res = maildirdriver_maildir_error_to_mail_error(r); goto err; } r = maildir_get_messages_list(session, md, maildir_cached_message_driver, &env_list); if (r != MAILDIR_NO_ERROR) { res = r; goto err; } /* read/write DB */ snprintf(filename, sizeof(filename), "%s%c%s%c%s", data->md_flags_directory, MAIL_DIR_SEPARATOR, data->md_quoted_mb, MAIL_DIR_SEPARATOR, UID_NAME); r = mail_cache_db_open_lock(filename, &uid_db); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_list; } max_uid = 0; r = mail_cache_db_get(uid_db, "max-uid", sizeof("max-uid") - 1, &value, &value_len); if (r == 0) { memcpy(&max_uid, value, sizeof(max_uid)); } for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; uint32_t index; msg = carray_get(env_list->msg_tab, i); r = mail_cache_db_get(uid_db, msg->msg_uid, strlen(msg->msg_uid), &value, &value_len); if (r < 0) { max_uid ++; msg->msg_index = max_uid; mail_cache_db_put(uid_db, msg->msg_uid, strlen(msg->msg_uid), &msg->msg_index, sizeof(msg->msg_index)); snprintf(key, sizeof(key), "uid-%lu", (unsigned long) msg->msg_index); mail_cache_db_put(uid_db, key, strlen(key), msg->msg_uid, strlen(msg->msg_uid)); } else { memcpy(&index, value, sizeof(index)); msg->msg_index = index; } } mail_cache_db_put(uid_db, "max-uid", sizeof("max-uid") - 1, &max_uid, sizeof(max_uid)); uid_clean_up(uid_db, env_list); mail_cache_db_close_unlock(filename, uid_db); * result = env_list; return MAIL_NO_ERROR; free_list: mailmessage_list_free(env_list); err: return res; } static int get_cached_flags(struct mail_cache_db * cache_db, MMAPString * mmapstr, mailsession * session, char * uid, struct mail_flags ** result) { int r; char keyname[PATH_MAX]; struct mail_flags * flags; int res; snprintf(keyname, PATH_MAX, "%s-flags", uid); 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; } static int get_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr, mailsession * session, char * uid, struct mailimf_fields ** result) { int r; char keyname[PATH_MAX]; struct mailimf_fields * fields; int res; snprintf(keyname, PATH_MAX, "%s-envelope", uid); 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, char * uid, struct mailimf_fields * fields) { int r; char keyname[PATH_MAX]; int res; snprintf(keyname, PATH_MAX, "%s-envelope", uid); 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 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; } static int get_envelopes_list(mailsession * session, struct mailmessage_list * env_list) { int r; unsigned int i; int res; struct maildir_cached_session_state_data * data; 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; data = get_cached_data(session); flags_store_process(data->md_flags_directory, data->md_quoted_mb, data->md_flags_store); mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto err; } snprintf(filename_env, PATH_MAX, "%s%c%s%c%s", data->md_cache_directory, MAIL_DIR_SEPARATOR, data->md_quoted_mb, MAIL_DIR_SEPARATOR, 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%c%s%c%s", data->md_flags_directory, MAIL_DIR_SEPARATOR, data->md_quoted_mb, MAIL_DIR_SEPARATOR, FLAGS_NAME); r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_FILE; goto close_db_env; } 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, session, msg->msg_uid, &fields); if (r == MAIL_NO_ERROR) { msg->msg_cached = TRUE; msg->msg_fields = fields; } } if (msg->msg_flags == NULL) { r = get_cached_flags(cache_db_flags, mmapstr, session, msg->msg_uid, &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_FILE; goto close_db_env; } /* 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) { /* msg->index is the numerical UID of the message */ r = write_cached_envelope(cache_db_env, mmapstr, session, msg->msg_uid, msg->msg_fields); } } if (msg->msg_flags != NULL) { r = 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 expunge_folder(mailsession * session) { return mailsession_expunge_folder(get_ancestor(session)); } static int check_folder(mailsession * session) { struct maildir_cached_session_state_data * data; data = get_cached_data(session); flags_store_process(data->md_flags_directory, data->md_quoted_mb, data->md_flags_store); return mailsession_check_folder(get_ancestor(session)); } static int get_message(mailsession * session, uint32_t num, mailmessage ** result) { struct maildir * md; int res; mailmessage * msg; char filename[PATH_MAX]; struct mail_cache_db * uid_db; char * msg_filename; struct stat stat_info; char key_str[PATH_MAX]; void * value; size_t value_len; char uid[PATH_MAX]; struct maildir_cached_session_state_data * data; int r; data = get_cached_data(session); md = get_maildir_session(session); /* a get_messages_list() should have been done once before */ /* read DB */ snprintf(filename, sizeof(filename), "%s%c%s%c%s", data->md_flags_directory, MAIL_DIR_SEPARATOR, data->md_quoted_mb, MAIL_DIR_SEPARATOR, UID_NAME); r = mail_cache_db_open_lock(filename, &uid_db); if (r < 0) { res = MAIL_ERROR_MEMORY; goto err; } snprintf(key_str, sizeof(key_str), "uid-%lu", (unsigned long) num); r = mail_cache_db_get(uid_db, key_str, strlen(key_str), &value, &value_len); if (r < 0) { res = MAIL_ERROR_INVAL; goto close_db; } if (value_len >= PATH_MAX) { res = MAIL_ERROR_INVAL; goto close_db; } memcpy(uid, value, value_len); uid[value_len] = '\0'; mail_cache_db_close_unlock(filename, uid_db); /* update maildir data */ r = maildir_update(md); if (r != MAILDIR_NO_ERROR) { res = maildirdriver_maildir_error_to_mail_error(r); goto err; } msg_filename = maildir_message_get(md, uid); if (msg_filename == NULL) { res = MAIL_ERROR_INVAL; goto err; } r = stat(msg_filename, &stat_info); free(msg_filename); if (r < 0) { res = MAIL_ERROR_INVAL; goto err; } /* create message */ msg = mailmessage_new(); if (msg == NULL) { res = MAIL_ERROR_MEMORY; goto err; } r = mailmessage_init(msg, session, maildir_cached_message_driver, num, stat_info.st_size); if (r != MAIL_NO_ERROR) { mailmessage_free(msg); res = r; goto err; } msg->msg_uid = strdup(uid); if (msg->msg_uid == NULL) { mailmessage_free(msg); res = r; goto err; } * result = msg; return MAIL_NO_ERROR; close_db: mail_cache_db_close_unlock(filename, uid_db); err: return res; } static int get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result) { int r; struct maildir * md; int res; mailmessage * msg; char filename[PATH_MAX]; struct mail_cache_db * uid_db; char * msg_filename; struct stat stat_info; void * value; size_t value_len; struct maildir_cached_session_state_data * data; uint32_t index; data = get_cached_data(session); md = get_maildir_session(session); /* a get_messages_list() should have been done once before */ /* read DB */ snprintf(filename, sizeof(filename), "%s%c%s%c%s", data->md_flags_directory, MAIL_DIR_SEPARATOR, data->md_quoted_mb, MAIL_DIR_SEPARATOR, UID_NAME); r = mail_cache_db_open_lock(filename, &uid_db); if (r < 0) { res = MAIL_ERROR_MEMORY; goto err; } r = mail_cache_db_get(uid_db, uid, strlen(uid), &value, &value_len); if (r < 0) { res = MAIL_ERROR_INVAL; goto close_db; } memcpy(&index, value, sizeof(index)); mail_cache_db_close_unlock(filename, uid_db); /* update maildir data */ r = maildir_update(md); if (r != MAILDIR_NO_ERROR) { res = maildirdriver_maildir_error_to_mail_error(r); goto err; } msg_filename = maildir_message_get(md, uid); if (msg_filename == NULL) { res = MAIL_ERROR_INVAL; goto err; } r = stat(msg_filename, &stat_info); free(msg_filename); if (r < 0) { res = MAIL_ERROR_INVAL; goto err; } /* create message */ msg = mailmessage_new(); if (msg == NULL) { res = MAIL_ERROR_MEMORY; goto err; } r = mailmessage_init(msg, session, maildir_cached_message_driver, index, stat_info.st_size); if (r != MAIL_NO_ERROR) { mailmessage_free(msg); res = r; goto err; } msg->msg_uid = strdup(uid); if (msg->msg_uid == NULL) { mailmessage_free(msg); res = r; goto err; } * result = msg; return MAIL_NO_ERROR; close_db: mail_cache_db_close_unlock(filename, uid_db); err: return res; } diff --git a/kmicromail/libetpan/generic/maildirdriver_cached_message.c b/kmicromail/libetpan/generic/maildirdriver_cached_message.c index 51866aa..34de351 100644 --- a/kmicromail/libetpan/generic/maildirdriver_cached_message.c +++ b/kmicromail/libetpan/generic/maildirdriver_cached_message.c @@ -1,248 +1,334 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "maildirdriver_message.h" #include "mailmessage_tools.h" #include "maildirdriver.h" #include "maildir.h" #include "generic_cache.h" +#include "mail_cache_db.h" +#include "maildirdriver_tools.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 get_flags(mailmessage * msg_info, + struct mail_flags ** result); + static int prefetch(mailmessage * msg_info); static void prefetch_free(struct generic_message_t * msg); static int initialize(mailmessage * msg_info); static void check(mailmessage * msg_info); static mailmessage_driver local_maildir_cached_message_driver = { .msg_name = "maildir-cached", .msg_initialize = initialize, .msg_uninitialize = mailmessage_generic_uninitialize, .msg_flush = mailmessage_generic_flush, .msg_check = check, .msg_fetch_result_free = mailmessage_generic_fetch_result_free, .msg_fetch = mailmessage_generic_fetch, .msg_fetch_header = mailmessage_generic_fetch_header, .msg_fetch_body = mailmessage_generic_fetch_header, .msg_fetch_size = NULL, .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, + .msg_get_flags = get_flags, }; mailmessage_driver * maildir_cached_message_driver = &local_maildir_cached_message_driver; struct maildir_msg_data { int fd; }; #if 0 static inline struct maildir_cached_session_state_data * get_cached_session_data(mailmessage * msg) { return msg->session->data; } static inline mailsession * cached_session_get_ancestor(mailsession * session) { return get_data(session)->session; } static inline struct maildir_session_state_data * cached_session_get_ancestor_data(mailsession * session) { return get_ancestor(session)->data; } static struct maildir * get_maildir_session(mailmessage * msg) { return cached_session_get_ancestor_data(msg->session)->session; } #endif static inline struct maildir_cached_session_state_data * get_cached_session_data(mailmessage * msg) { return msg->msg_session->sess_data; } static inline struct maildir_cached_session_state_data * cached_session_get_data(mailsession * s) { return s->sess_data; } static inline mailsession * cached_session_get_ancestor(mailsession * s) { return cached_session_get_data(s)->md_ancestor; } static inline struct maildir_session_state_data * cached_session_get_ancestor_data(mailsession * s) { return cached_session_get_ancestor(s)->sess_data; } static inline struct maildir_session_state_data * get_session_ancestor_data(mailmessage * msg) { return cached_session_get_ancestor_data(msg->msg_session); } static inline struct maildir * cached_session_get_maildir_session(mailsession * session) { return cached_session_get_ancestor_data(session)->md_session; } static inline struct maildir * get_maildir_session(mailmessage * msg) { return cached_session_get_maildir_session(msg->msg_session); } static int prefetch(mailmessage * msg_info) { struct generic_message_t * msg; int res; struct maildir_msg_data * data; char * filename; int fd; char * mapping; struct maildir * md; md = get_maildir_session(msg_info); filename = maildir_message_get(md, msg_info->msg_uid); if (filename == NULL) { res = MAIL_ERROR_MEMORY; goto err; } fd = open(filename, O_RDONLY); free(filename); if (fd == -1) { res = MAIL_ERROR_FILE; goto err; } mapping = mmap(NULL, msg_info->msg_size, PROT_READ, MAP_PRIVATE, fd, 0); if (mapping == MAP_FAILED) { res = MAIL_ERROR_FILE; goto close; } data = malloc(sizeof(* data)); if (data == NULL) { res = MAIL_ERROR_MEMORY; goto unmap; } data->fd = fd; msg = msg_info->msg_data; msg->msg_data = data; msg->msg_message = mapping; msg->msg_length = msg_info->msg_size; return MAIL_NO_ERROR; unmap: munmap(mapping, msg_info->msg_size); close: close(fd); err: return res; } static void prefetch_free(struct generic_message_t * msg) { if (msg->msg_message != NULL) { struct maildir_msg_data * data; munmap(msg->msg_message, msg->msg_length); msg->msg_message = NULL; data = msg->msg_data; close(data->fd); free(data); } } static int initialize(mailmessage * msg_info) { struct generic_message_t * msg; int r; r = mailmessage_generic_initialize(msg_info); if (r != MAIL_NO_ERROR) return r; msg = msg_info->msg_data; msg->msg_prefetch = prefetch; msg->msg_prefetch_free = prefetch_free; return MAIL_NO_ERROR; } static void check(mailmessage * msg_info) { int r; if (msg_info->msg_flags != NULL) { r = mail_flags_store_set(get_session_ancestor_data(msg_info)->md_flags_store, msg_info); r = mail_flags_store_set(get_cached_session_data(msg_info)->md_flags_store, msg_info); /* ignore errors */ } } + +#define FLAGS_NAME "flags.db" + +static int get_flags(mailmessage * msg_info, + struct mail_flags ** result) +{ + struct mail_cache_db * cache_db_flags; + chashdatum key; + chashdatum value; + struct maildir * md; + struct mail_flags * flags; + struct maildir_cached_session_state_data * data; + struct maildir_msg * md_msg; + int r; + uint32_t driver_flags; + char filename_flags[PATH_MAX]; + char keyname[PATH_MAX]; + MMAPString * mmapstr; + + if (msg_info->msg_flags != NULL) { + * result = msg_info->msg_flags; + return MAIL_NO_ERROR; + } + + data = get_cached_session_data(msg_info); + flags = mail_flags_store_get(data->md_flags_store, + msg_info->msg_index); + if (flags != NULL) { + msg_info->msg_flags = flags; + * result = msg_info->msg_flags; + return MAIL_NO_ERROR; + } + + snprintf(filename_flags, PATH_MAX, "%s%c%s%c%s", + data->md_flags_directory, MAIL_DIR_SEPARATOR, data->md_quoted_mb, + MAIL_DIR_SEPARATOR, FLAGS_NAME); + + r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); + if (r < 0) + return MAIL_ERROR_FILE; + + snprintf(keyname, PATH_MAX, "%s-flags", msg_info->msg_uid); + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) { + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + return MAIL_ERROR_MEMORY; + } + + r = generic_cache_flags_read(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) { + flags = mail_flags_new_empty(); + if (flags == NULL) + return MAIL_ERROR_MEMORY; + } + + md = get_maildir_session(msg_info); + if (md == NULL) + return MAIL_ERROR_BAD_STATE; + + key.data = msg_info->msg_uid; + key.len = strlen(msg_info->msg_uid); + r = chash_get(md->mdir_msg_hash, &key, &value); + if (r < 0) + return MAIL_ERROR_MSG_NOT_FOUND; + + md_msg = value.data; + + driver_flags = maildirdriver_maildir_flags_to_flags(md_msg->msg_flags); + + flags->fl_flags = driver_flags; + msg_info->msg_flags = flags; + + * result = msg_info->msg_flags; + + return MAIL_NO_ERROR; +} diff --git a/kmicromail/libetpan/generic/maildirdriver_message.c b/kmicromail/libetpan/generic/maildirdriver_message.c index 7cf9dd1..613fc39 100644 --- a/kmicromail/libetpan/generic/maildirdriver_message.c +++ b/kmicromail/libetpan/generic/maildirdriver_message.c @@ -1,199 +1,255 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "maildirdriver_message.h" +#include "maildirdriver_tools.h" #include "mailmessage_tools.h" #include "maildirdriver.h" #include "maildir.h" #include "generic_cache.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 get_flags(mailmessage * msg_info, + struct mail_flags ** result); + static int prefetch(mailmessage * msg_info); static void prefetch_free(struct generic_message_t * msg); static int initialize(mailmessage * msg_info); static void check(mailmessage * msg_info); static mailmessage_driver local_maildir_message_driver = { .msg_name = "maildir", .msg_initialize = initialize, .msg_uninitialize = mailmessage_generic_uninitialize, .msg_flush = mailmessage_generic_flush, .msg_check = check, .msg_fetch_result_free = mailmessage_generic_fetch_result_free, .msg_fetch = mailmessage_generic_fetch, .msg_fetch_header = mailmessage_generic_fetch_header, .msg_fetch_body = mailmessage_generic_fetch_header, .msg_fetch_size = NULL, .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, + .msg_get_flags = get_flags, }; mailmessage_driver * maildir_message_driver = &local_maildir_message_driver; struct maildir_msg_data { int fd; }; static inline struct maildir_session_state_data * get_session_data(mailmessage * msg) { return msg->msg_session->sess_data; } static struct maildir * get_maildir_session(mailmessage * msg) { return get_session_data(msg)->md_session; } static int prefetch(mailmessage * msg_info) { struct generic_message_t * msg; int res; struct maildir_msg_data * data; char * filename; int fd; char * mapping; struct maildir * md; md = get_maildir_session(msg_info); if (msg_info->msg_uid == NULL) { res = MAIL_ERROR_INVAL; goto err; } filename = maildir_message_get(md, msg_info->msg_uid); if (filename == NULL) { res = MAIL_ERROR_MEMORY; goto err; } fd = open(filename, O_RDONLY); free(filename); if (fd == -1) { res = MAIL_ERROR_FILE; goto err; } mapping = mmap(NULL, msg_info->msg_size, PROT_READ, MAP_PRIVATE, fd, 0); if (mapping == MAP_FAILED) { res = MAIL_ERROR_FILE; goto close; } data = malloc(sizeof(* data)); if (data == NULL) { res = MAIL_ERROR_MEMORY; goto unmap; } data->fd = fd; msg = msg_info->msg_data; msg->msg_data = data; msg->msg_message = mapping; msg->msg_length = msg_info->msg_size; return MAIL_NO_ERROR; unmap: munmap(mapping, msg_info->msg_size); close: close(fd); err: return res; } static void prefetch_free(struct generic_message_t * msg) { if (msg->msg_message != NULL) { struct maildir_msg_data * data; munmap(msg->msg_message, msg->msg_length); msg->msg_message = NULL; data = msg->msg_data; close(data->fd); free(data); } } static int initialize(mailmessage * msg_info) { struct generic_message_t * msg; int r; r = mailmessage_generic_initialize(msg_info); if (r != MAIL_NO_ERROR) return r; msg = msg_info->msg_data; msg->msg_prefetch = prefetch; msg->msg_prefetch_free = prefetch_free; return MAIL_NO_ERROR; } static void check(mailmessage * msg_info) { int r; if (msg_info->msg_flags != NULL) { r = mail_flags_store_set(get_session_data(msg_info)->md_flags_store, msg_info); /* ignore errors */ } } + +static int get_flags(mailmessage * msg_info, + struct mail_flags ** result) +{ + chashdatum key; + chashdatum value; + struct maildir * md; + struct mail_flags * flags; + struct maildir_session_state_data * data; + struct maildir_msg * md_msg; + int r; + uint32_t driver_flags; + clist * ext; + + if (msg_info->msg_flags != NULL) { + * result = msg_info->msg_flags; + return MAIL_NO_ERROR; + } + + data = get_session_data(msg_info); + flags = mail_flags_store_get(data->md_flags_store, + msg_info->msg_index); + if (flags != NULL) { + msg_info->msg_flags = flags; + * result = msg_info->msg_flags; + return MAIL_NO_ERROR; + } + + md = get_maildir_session(msg_info); + if (md == NULL) + return MAIL_ERROR_BAD_STATE; + + key.data = msg_info->msg_uid; + key.len = strlen(msg_info->msg_uid); + r = chash_get(md->mdir_msg_hash, &key, &value); + if (r < 0) + return MAIL_ERROR_MSG_NOT_FOUND; + + md_msg = value.data; + + driver_flags = maildirdriver_maildir_flags_to_flags(md_msg->msg_flags); + + ext = clist_new(); + if (ext == NULL) + return MAIL_ERROR_MEMORY; + + msg_info->msg_flags = mail_flags_new(driver_flags, ext); + + * result = msg_info->msg_flags; + + return MAIL_NO_ERROR; +} diff --git a/kmicromail/libetpan/generic/maildirstorage.c b/kmicromail/libetpan/generic/maildirstorage.c index 7e6b461..e37f591 100644 --- a/kmicromail/libetpan/generic/maildirstorage.c +++ b/kmicromail/libetpan/generic/maildirstorage.c @@ -1,192 +1,193 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ +#include "maildirstorage.h" #include "mailstorage.h" #include "mail.h" #include "mailmessage.h" #include "maildirdriver.h" #include "maildirdriver_cached.h" #include "maildriver.h" #include <stdlib.h> #include <string.h> /* maildir storage */ static int maildir_mailstorage_connect(struct mailstorage * storage); static int maildir_mailstorage_get_folder_session(struct mailstorage * storage, char * pathname, mailsession ** result); static void maildir_mailstorage_uninitialize(struct mailstorage * storage); static mailstorage_driver maildir_mailstorage_driver = { .sto_name = "maildir", .sto_connect = maildir_mailstorage_connect, .sto_get_folder_session = maildir_mailstorage_get_folder_session, .sto_uninitialize = maildir_mailstorage_uninitialize, }; int maildir_mailstorage_init(struct mailstorage * storage, char * md_pathname, int md_cached, char * md_cache_directory, char * md_flags_directory) { struct maildir_mailstorage * maildir_storage; - maildir_storage = malloc(sizeof(struct maildir_mailstorage)); + maildir_storage = malloc(sizeof(* maildir_storage)); if (maildir_storage == NULL) goto err; maildir_storage->md_pathname = strdup(md_pathname); if (maildir_storage->md_pathname == NULL) goto free; maildir_storage->md_cached = md_cached; if (md_cached && (md_cache_directory != NULL) && (md_flags_directory != NULL)) { maildir_storage->md_cache_directory = strdup(md_cache_directory); if (maildir_storage->md_cache_directory == NULL) goto free_pathname; maildir_storage->md_flags_directory = strdup(md_flags_directory); if (maildir_storage->md_flags_directory == NULL) goto free_cache_directory; } else { maildir_storage->md_cached = FALSE; maildir_storage->md_cache_directory = NULL; maildir_storage->md_flags_directory = NULL; } storage->sto_data = maildir_storage; storage->sto_driver = &maildir_mailstorage_driver; return MAIL_NO_ERROR; free_cache_directory: free(maildir_storage->md_cache_directory); free_pathname: free(maildir_storage->md_pathname); free: free(maildir_storage); err: return MAIL_ERROR_MEMORY; } static void maildir_mailstorage_uninitialize(struct mailstorage * storage) { struct maildir_mailstorage * maildir_storage; maildir_storage = storage->sto_data; if (maildir_storage->md_flags_directory != NULL) free(maildir_storage->md_flags_directory); if (maildir_storage->md_cache_directory != NULL) free(maildir_storage->md_cache_directory); free(maildir_storage->md_pathname); free(maildir_storage); storage->sto_data = NULL; } static int maildir_mailstorage_connect(struct mailstorage * storage) { struct maildir_mailstorage * maildir_storage; mailsession_driver * driver; int r; int res; mailsession * session; maildir_storage = storage->sto_data; if (maildir_storage->md_cached) driver = maildir_cached_session_driver; else driver = maildir_session_driver; session = mailsession_new(driver); if (session == NULL) { res = MAIL_ERROR_MEMORY; goto err; } if (maildir_storage->md_cached) { r = mailsession_parameters(session, MAILDIRDRIVER_CACHED_SET_CACHE_DIRECTORY, maildir_storage->md_cache_directory); if (r != MAIL_NO_ERROR) { res = r; goto free; } r = mailsession_parameters(session, MAILDIRDRIVER_CACHED_SET_FLAGS_DIRECTORY, maildir_storage->md_flags_directory); if (r != MAIL_NO_ERROR) { res = r; goto free; } } r = mailsession_connect_path(session, maildir_storage->md_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 maildir_mailstorage_get_folder_session(struct mailstorage * storage, char * pathname, mailsession ** result) { * result = storage->sto_session; return MAIL_NO_ERROR; } diff --git a/kmicromail/libetpan/generic/maildirstorage.h b/kmicromail/libetpan/generic/maildirstorage.h index d17ea2c..73d7b20 100644 --- a/kmicromail/libetpan/generic/maildirstorage.h +++ b/kmicromail/libetpan/generic/maildirstorage.h @@ -1,69 +1,69 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #ifndef MAILDIRSTORAGE_H #define MAILDIRSTORAGE_H #include <libetpan/maildirdriver_types.h> #ifdef __cplusplus extern "C" { #endif /* - maildir_mailstorage_init is the constructor for a mbox storage. + maildir_mailstorage_init is the constructor for a maildir storage. @param storage this is the storage to initialize. @param pathname is the directory that contains the mailbox. @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 maildir_mailstorage_init(struct mailstorage * storage, char * md_pathname, int md_cached, char * md_cache_directory, char * md_flags_directory); #ifdef __cplusplus } #endif #endif diff --git a/kmicromail/libetpan/generic/maildriver.c b/kmicromail/libetpan/generic/maildriver.c index 01e3e34..1fc478a 100644 --- a/kmicromail/libetpan/generic/maildriver.c +++ b/kmicromail/libetpan/generic/maildriver.c @@ -1,373 +1,383 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "maildriver.h" #include <ctype.h> #include <string.h> #include <stdlib.h> /* *********************************************************************** */ /* mail session */ mailsession * mailsession_new(mailsession_driver * sess_driver) { mailsession * session; int r; session = malloc(sizeof(* session)); session->sess_data = NULL; if (sess_driver->sess_initialize != NULL) { r = sess_driver->sess_initialize(session); if (r != MAIL_NO_ERROR) goto free; } session->sess_driver = sess_driver; return session; free: free(session); return NULL; } void mailsession_free(mailsession * session) { if (session->sess_driver->sess_uninitialize != NULL) session->sess_driver->sess_uninitialize(session); free(session); } int mailsession_parameters(mailsession * session, int id, void * value) { if (session->sess_driver->sess_parameters == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_parameters(session, id, value); } int mailsession_connect_stream(mailsession * session, mailstream * s) { if (session->sess_driver->sess_connect_stream == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_connect_stream(session, s); } int mailsession_connect_path(mailsession * session, char * path) { if (session->sess_driver->sess_connect_path == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_connect_path(session, path); } int mailsession_starttls(mailsession * session) { if (session->sess_driver->sess_starttls == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_starttls(session); } int mailsession_login(mailsession * session, char * userid, char * password) { if (session->sess_driver->sess_login == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_login(session, userid, password); } int mailsession_logout(mailsession * session) { if (session->sess_driver->sess_logout == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_logout(session); } int mailsession_noop(mailsession * session) { if (session->sess_driver->sess_noop == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_noop(session); } /* folders operations */ int mailsession_build_folder_name(mailsession * session, char * mb, char * name, char ** result) { if (session->sess_driver->sess_build_folder_name == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_build_folder_name(session, mb, name, result); } int mailsession_create_folder(mailsession * session, char * mb) { if (session->sess_driver->sess_create_folder == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_create_folder(session, mb); } int mailsession_delete_folder(mailsession * session, char * mb) { if (session->sess_driver->sess_delete_folder == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_delete_folder(session, mb); } int mailsession_rename_folder(mailsession * session, char * mb, char * new_name) { if (session->sess_driver->sess_rename_folder == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_rename_folder(session, mb, new_name); } int mailsession_check_folder(mailsession * session) { if (session->sess_driver->sess_check_folder == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_check_folder(session); } int mailsession_examine_folder(mailsession * session, char * mb) { if (session->sess_driver->sess_examine_folder == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_examine_folder(session, mb); } int mailsession_select_folder(mailsession * session, char * mb) { if (session->sess_driver->sess_select_folder == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_select_folder(session, mb); } int mailsession_expunge_folder(mailsession * session) { if (session->sess_driver->sess_expunge_folder == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_expunge_folder(session); } int mailsession_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { if (session->sess_driver->sess_status_folder == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_status_folder(session, mb, result_messages, result_recent, result_unseen); } int mailsession_messages_number(mailsession * session, char * mb, uint32_t * result) { if (session->sess_driver->sess_messages_number == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_messages_number(session, mb, result); } int mailsession_recent_number(mailsession * session, char * mb, uint32_t * result) { if (session->sess_driver->sess_recent_number == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_recent_number(session, mb, result); } int mailsession_unseen_number(mailsession * session, char * mb, uint32_t * result) { if (session->sess_driver->sess_unseen_number == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_recent_number(session, mb, result); } int mailsession_list_folders(mailsession * session, char * mb, struct mail_list ** result) { if (session->sess_driver->sess_list_folders == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_list_folders(session, mb, result); } int mailsession_lsub_folders(mailsession * session, char * mb, struct mail_list ** result) { if (session->sess_driver->sess_lsub_folders == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_lsub_folders(session, mb, result); } int mailsession_subscribe_folder(mailsession * session, char * mb) { if (session->sess_driver->sess_subscribe_folder == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_subscribe_folder(session, mb); } int mailsession_unsubscribe_folder(mailsession * session, char * mb) { if (session->sess_driver->sess_unsubscribe_folder == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_unsubscribe_folder(session, mb); } /* message */ int mailsession_append_message(mailsession * session, char * message, size_t size) { if (session->sess_driver->sess_append_message == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_append_message(session, message, size); } +int mailsession_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags) +{ + if (session->sess_driver->sess_append_message_flags == NULL) + return MAIL_ERROR_NOT_IMPLEMENTED; + + return session->sess_driver->sess_append_message_flags(session, + message, size, flags); +} + int mailsession_copy_message(mailsession * session, uint32_t num, char * mb) { if (session->sess_driver->sess_copy_message == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_copy_message(session, num, mb); } int mailsession_move_message(mailsession * session, uint32_t num, char * mb) { if (session->sess_driver->sess_move_message == NULL) { int r; if ((session->sess_driver->sess_copy_message == NULL) && (session->sess_driver->sess_remove_message == NULL)) return MAIL_ERROR_NOT_IMPLEMENTED; r = mailsession_copy_message(session, num, mb); if (r != MAIL_NO_ERROR) return r; r = mailsession_remove_message(session, num); if (r != MAIL_NO_ERROR) return r; return MAIL_NO_ERROR; } return session->sess_driver->sess_move_message(session, num, mb); } int mailsession_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list) { if (session->sess_driver->sess_get_envelopes_list == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_get_envelopes_list(session, env_list); } int mailsession_get_messages_list(mailsession * session, struct mailmessage_list ** result) { if (session->sess_driver->sess_get_messages_list == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_get_messages_list(session, result); } int mailsession_remove_message(mailsession * session, uint32_t num) { if (session->sess_driver->sess_remove_message == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_remove_message(session, num); } #if 0 int mailsession_search_messages(mailsession * session, char * charset, struct mail_search_key * key, struct mail_search_result ** result) { if (session->sess_driver->sess_search_messages == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_search_messages(session, charset, key, result); } #endif int mailsession_get_message(mailsession * session, uint32_t num, mailmessage ** result) { if (session->sess_driver->sess_get_message == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_get_message(session, num, result); } int mailsession_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result) { if (session->sess_driver->sess_get_message_by_uid == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_get_message_by_uid(session, uid, result); } diff --git a/kmicromail/libetpan/generic/maildriver.h b/kmicromail/libetpan/generic/maildriver.h index 7da9aea..c773190 100644 --- a/kmicromail/libetpan/generic/maildriver.h +++ b/kmicromail/libetpan/generic/maildriver.h @@ -1,543 +1,546 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #ifndef MAILDRIVER_H #define MAILDRIVER_H #include <libetpan/maildriver_types.h> #include <libetpan/maildriver_types_helper.h> #ifdef __cplusplus extern "C" { #endif /* mailsession */ /* mailsession_new creates a new session, using the given driver @return the created session is returned */ mailsession * mailsession_new(mailsession_driver * sess_driver); /* mailsession_free release the memory used by the session */ void mailsession_free(mailsession * session); /* mailsession_parameters is used to make calls specific to the driver @param id is the command to send to the driver, usually, commands can be found in the header of the driver @param value is the parameter of the specific call @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_parameters(mailsession * session, int id, void * value); /* There are drivers of two kinds : stream drivers (driver that connects to servers through TCP or other means of connection) and file drivers (driver that are based on filesystem) The following function can only be used by stream drivers. mailsession_connect_stream connects a stream to the session @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_connect_stream(mailsession * session, mailstream * s); /* The following function can only be used by file drivers. mailsession_connect_path selects the main path of the session @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_connect_path(mailsession * session, char * path); /* NOTE: works only on stream drivers mailsession_starttls switches the current connection to TLS (secure layer) @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_starttls(mailsession * session); /* mailsession_login notifies the login and the password to authenticate to the session @param userid the given string is only needed at this function call (it will be duplicated if necessary) @param password the given string is only needed at this function call (it will be duplicated if necessary) @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_login(mailsession * session, char * userid, char * password); /* NOTE: this function doesn't often work on filsystem drivers mailsession_logout deconnects the session and closes the stream. @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_logout(mailsession * session); /* mailsession_noop does no operation on the session, but it can be used to poll for the status of the connection. @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_noop(mailsession * session); /* NOTE: driver's specific should be used mailsession_build_folder_name will return an allocated string with that contains the complete path of the folder to create @param session the sesion @param mb is the parent mailbox @param name is the name of the folder to create @param result the complete path of the folder to create will be stored in (* result), this name have to be freed with free() @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_build_folder_name(mailsession * session, char * mb, char * name, char ** result); /* NOTE: driver's specific should be used mailsession_create_folder creates the folder that corresponds to the given name @param session the session @param mb is the name of the mailbox @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_create_folder(mailsession * session, char * mb); /* NOTE: driver's specific should be used mailsession_delete_folder deletes the folder that corresponds to the given name @param session the session @param mb is the name of the mailbox @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_delete_folder(mailsession * session, char * mb); /* mailsession_rename_folder changes the name of the folder @param session the session @param mb is the name of the mailbox whose name has to be changed @param new_name is the destination name (the parent of the new folder folder can be other) @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_rename_folder(mailsession * session, char * mb, char * new_name); /* mailsession_check_folder makes a checkpoint of the session @param session the session @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_check_folder(mailsession * session); /* NOTE: this function is not implemented in most drivers mailsession_examine_folder selects a mailbox as readonly @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_examine_folder(mailsession * session, char * mb); /* mailsession_select_folder selects a mailbox @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_select_folder(mailsession * session, char * mb); /* mailsession_expunge_folder deletes all messages marked \Deleted @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_expunge_folder(mailsession * session); /* mailsession_status_folder queries the status of the folder (number of messages, number of recent messages, number of unseen messages) @param session the session @param mb mailbox to query @param result_messages the number of messages is stored in (* result_messages) @param result_recent the number of messages is stored in (* result_recent) @param result_unseen the number of messages is stored in (* result_unseen) @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); /* mailsession_messages_number queries the number of messages in the folder @param session the session @param mb mailbox to query @param result the number of messages is stored in (* result) @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_messages_number(mailsession * session, char * mb, uint32_t * result); /* mailsession_recent_number queries the number of recent messages in the folder @param session the session @param mb mailbox to query @param result the number of recent messages is stored in (* result) @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_recent_number(mailsession * session, char * mb, uint32_t * result); /* mailsession_unseen_number queries the number of unseen messages in the folder @param session the session @param mb mailbox to query @param result the number of unseen messages is stored in (* result) @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_unseen_number(mailsession * session, char * mb, uint32_t * result); /* NOTE: driver's specific should be used mailsession_list_folders returns the list of all sub-mailboxes of the given mailbox @param session the session @param mb the mailbox @param result list of mailboxes if stored in (* result), this structure have to be freed with mail_list_free() @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_list_folders(mailsession * session, char * mb, struct mail_list ** result); /* NOTE: driver's specific should be used mailsession_lsub_folders returns the list of subscribed sub-mailboxes of the given mailbox @param session the session @param mb the mailbox @param result list of mailboxes if stored in (* result), this structure have to be freed with mail_list_free() @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_lsub_folders(mailsession * session, char * mb, struct mail_list ** result); /* NOTE: driver's specific should be used mailsession_subscribe_folder subscribes to the given mailbox @param session the session @param mb the mailbox @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_subscribe_folder(mailsession * session, char * mb); /* NOTE: driver's specific should be used mailsession_unsubscribe_folder unsubscribes to the given mailbox @param session the session @param mb the mailbox @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_unsubscribe_folder(mailsession * session, char * mb); /* mailsession_append_message adds a RFC 2822 message to the current given mailbox @param session the session @param message is a string that contains the RFC 2822 message @param size this is the size of the message @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_append_message(mailsession * session, char * message, size_t size); +int mailsession_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags); + /* NOTE: some drivers does not implement this mailsession_copy_message copies a message whose number is given to a given mailbox. The mailbox must be accessible from the same session. @param session the session @param num the message number @param mb the destination mailbox @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_copy_message(mailsession * session, uint32_t num, char * mb); /* NOTE: some drivers does not implement this mailsession_move_message copies a message whose number is given to a given mailbox. The mailbox must be accessible from the same session. @param session the session @param num the message number @param mb the destination mailbox @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_move_message(mailsession * session, uint32_t num, char * mb); /* mailsession_get_messages_list returns the list of message numbers of the current mailbox. @param session the session @param result the list of message numbers will be stored in (* result), this structure have to be freed with mailmessage_list_free() @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_get_messages_list(mailsession * session, struct mailmessage_list ** result); /* mailsession_get_envelopes_list fills the parsed fields in the mailmessage structures of the mailmessage_list. @param session the session @param result this is the list of mailmessage structures @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_get_envelopes_list(mailsession * session, struct mailmessage_list * result); /* NOTE: some drivers does not implement this mailsession_remove_message removes the given message from the mailbox. The message is permanently deleted. @param session the session @param num is the message number @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_remove_message(mailsession * session, uint32_t num); /* NOTE: this function is not implemented in most drivers mailsession_search_message returns a list of message numbers that corresponds to the given criteria. @param session the session @param charset is the charset to use (it can be NULL) @param key is the list of criteria @param result the search result is stored in (* result), this structure have to be freed with mail_search_result_free() @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ #if 0 int mailsession_search_messages(mailsession * session, char * charset, struct mail_search_key * key, struct mail_search_result ** result); #endif /* mailsession_get_message returns a mailmessage structure that corresponds to the given message number. * WARNING * mailsession_get_message_by_uid() should be used instead. @param session the session @param num the message number @param result the allocated mailmessage structure will be stored in (* result), this structure have to be freed with mailmessage_free() @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_get_message(mailsession * session, uint32_t num, mailmessage ** result); /* mailsession_get_message_by_uid returns a mailmessage structure that corresponds to the given message unique identifier. This is currently implemented only for cached drivers. * WARNING * That will deprecates the use of mailsession_get_message() @param session the session @param uid the message unique identifier @param result the allocated mailmessage structure will be stored in (* result), this structure have to be freed with mailmessage_free() @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result); #ifdef __cplusplus } #endif #endif diff --git a/kmicromail/libetpan/generic/maildriver_types.h b/kmicromail/libetpan/generic/maildriver_types.h index 3ff9440..9eab4d6 100644 --- a/kmicromail/libetpan/generic/maildriver_types.h +++ b/kmicromail/libetpan/generic/maildriver_types.h @@ -1,793 +1,795 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #ifndef MAILDRIVER_TYPES_H #define MAILDRIVER_TYPES_H #include <inttypes.h> #include <sys/types.h> #include <libetpan/mailstream.h> #include <libetpan/mailimf.h> #include <libetpan/mailmime.h> #include <libetpan/carray.h> #include <libetpan/mailthread_types.h> #include <libetpan/maildriver_errors.h> #ifdef __cplusplus extern "C" { #endif typedef struct mailsession_driver mailsession_driver; typedef struct mailsession mailsession; typedef struct mailmessage_driver mailmessage_driver; typedef struct mailmessage mailmessage; /* mailmessage_list is a list of mailmessage - tab is an array of mailmessage structures */ struct mailmessage_list { carray * msg_tab; /* elements are (mailmessage *) */ }; struct mailmessage_list * mailmessage_list_new(carray * msg_tab); void mailmessage_list_free(struct mailmessage_list * env_list); /* mail_list is a list of mailbox names - list is a list of mailbox names */ struct mail_list { clist * mb_list; /* elements are (char *) */ }; struct mail_list * mail_list_new(clist * mb_list); void mail_list_free(struct mail_list * resp); /* This is a flag value. Flags can be combined with OR operation */ enum { MAIL_FLAG_NEW = 1 << 0, MAIL_FLAG_SEEN = 1 << 1, MAIL_FLAG_FLAGGED = 1 << 2, MAIL_FLAG_DELETED = 1 << 3, MAIL_FLAG_ANSWERED = 1 << 4, MAIL_FLAG_FORWARDED = 1 << 5, MAIL_FLAG_CANCELLED = 1 << 6, }; /* mail_flags is the value of a flag related to a message. - flags is the standard flags value - extension is a list of unknown flags for libEtPan! */ struct mail_flags { uint32_t fl_flags; clist * fl_extension; /* elements are (char *) */ }; struct mail_flags * mail_flags_new(uint32_t fl_flags, clist * fl_ext); void mail_flags_free(struct mail_flags * flags); /* This function creates a flag for a new message */ struct mail_flags * mail_flags_new_empty(void); /* mailimf_date_time_comp compares two dates */ int32_t mailimf_date_time_comp(struct mailimf_date_time * date1, struct mailimf_date_time * date2); /* this is type type of the search criteria */ enum { MAIL_SEARCH_KEY_ALL, /* all messages correspond */ MAIL_SEARCH_KEY_ANSWERED, /* messages with flag \Answered */ MAIL_SEARCH_KEY_BCC, /* messages which Bcc field contains a given string */ MAIL_SEARCH_KEY_BEFORE, /* messages which internal date is earlier than the specified date */ MAIL_SEARCH_KEY_BODY, /* message that contains the given string (in header and text parts) */ MAIL_SEARCH_KEY_CC, /* messages whose Cc field contains the given string */ MAIL_SEARCH_KEY_DELETED, /* messages with the flag \Deleted */ MAIL_SEARCH_KEY_FLAGGED, /* messages with the flag \Flagged */ MAIL_SEARCH_KEY_FROM, /* messages whose From field contains the given string */ MAIL_SEARCH_KEY_NEW, /* messages with the flag \Recent and not the \Seen flag */ MAIL_SEARCH_KEY_OLD, /* messages that do not have the \Recent flag set */ MAIL_SEARCH_KEY_ON, /* messages whose internal date is the specified date */ MAIL_SEARCH_KEY_RECENT, /* messages with the flag \Recent */ MAIL_SEARCH_KEY_SEEN, /* messages with the flag \Seen */ MAIL_SEARCH_KEY_SINCE, /* messages whose internal date is later than specified date */ MAIL_SEARCH_KEY_SUBJECT, /* messages whose Subject field contains the given string */ MAIL_SEARCH_KEY_TEXT, /* messages whose text part contains the given string */ MAIL_SEARCH_KEY_TO, /* messages whose To field contains the given string */ MAIL_SEARCH_KEY_UNANSWERED, /* messages with no flag \Answered */ MAIL_SEARCH_KEY_UNDELETED, /* messages with no flag \Deleted */ MAIL_SEARCH_KEY_UNFLAGGED, /* messages with no flag \Flagged */ MAIL_SEARCH_KEY_UNSEEN, /* messages with no flag \Seen */ MAIL_SEARCH_KEY_HEADER, /* messages whose given field contains the given string */ MAIL_SEARCH_KEY_LARGER, /* messages whose size is larger then the given size */ MAIL_SEARCH_KEY_NOT, /* not operation of the condition */ MAIL_SEARCH_KEY_OR, /* or operation between two conditions */ MAIL_SEARCH_KEY_SMALLER, /* messages whose size is smaller than the given size */ MAIL_SEARCH_KEY_MULTIPLE /* the boolean operator between the conditions is AND */ }; /* mail_search_key is the condition on the messages to return - type is the type of the condition - bcc is the text to search in the Bcc field when type is MAIL_SEARCH_KEY_BCC, should be allocated with malloc() - before is a date when type is MAIL_SEARCH_KEY_BEFORE - body is the text to search in the message when type is MAIL_SEARCH_KEY_BODY, should be allocated with malloc() - cc is the text to search in the Cc field when type is MAIL_SEARCH_KEY_CC, should be allocated with malloc() - from is the text to search in the From field when type is MAIL_SEARCH_KEY_FROM, should be allocated with malloc() - on is a date when type is MAIL_SEARCH_KEY_ON - since is a date when type is MAIL_SEARCH_KEY_SINCE - subject is the text to search in the Subject field when type is MAILIMAP_SEARCH_KEY_SUBJECT, should be allocated with malloc() - text is the text to search in the text part of the message when type is MAILIMAP_SEARCH_KEY_TEXT, should be allocated with malloc() - to is the text to search in the To field when type is MAILIMAP_SEARCH_KEY_TO, should be allocated with malloc() - header_name is the header name when type is MAILIMAP_SEARCH_KEY_HEADER, should be allocated with malloc() - header_value is the text to search in the given header when type is MAILIMAP_SEARCH_KEY_HEADER, should be allocated with malloc() - larger is a size when type is MAILIMAP_SEARCH_KEY_LARGER - not is a condition when type is MAILIMAP_SEARCH_KEY_NOT - or1 is a condition when type is MAILIMAP_SEARCH_KEY_OR - or2 is a condition when type is MAILIMAP_SEARCH_KEY_OR - sentbefore is a date when type is MAILIMAP_SEARCH_KEY_SENTBEFORE - senton is a date when type is MAILIMAP_SEARCH_KEY_SENTON - sentsince is a date when type is MAILIMAP_SEARCH_KEY_SENTSINCE - smaller is a size when type is MAILIMAP_SEARCH_KEY_SMALLER - multiple is a set of message when type is MAILIMAP_SEARCH_KEY_MULTIPLE */ #if 0 struct mail_search_key { int sk_type; union { char * sk_bcc; struct mailimf_date_time * sk_before; char * sk_body; char * sk_cc; char * sk_from; struct mailimf_date_time * sk_on; struct mailimf_date_time * sk_since; char * sk_subject; char * sk_text; char * sk_to; char * sk_header_name; char * sk_header_value; size_t sk_larger; struct mail_search_key * sk_not; struct mail_search_key * sk_or1; struct mail_search_key * sk_or2; size_t sk_smaller; clist * sk_multiple; /* list of (struct mailimap_search_key *) */ } sk_data; }; struct mail_search_key * mail_search_key_new(int sk_type, char * sk_bcc, struct mailimf_date_time * sk_before, char * sk_body, char * sk_cc, char * sk_from, struct mailimf_date_time * sk_on, struct mailimf_date_time * sk_since, char * sk_subject, char * sk_text, char * sk_to, char * sk_header_name, char * sk_header_value, size_t sk_larger, struct mail_search_key * sk_not, struct mail_search_key * sk_or1, struct mail_search_key * sk_or2, size_t sk_smaller, clist * sk_multiple); void mail_search_key_free(struct mail_search_key * key); #endif /* mail_search_result is a list of message numbers that is returned by the mailsession_search_messages function() */ #if 0 struct mail_search_result { clist * sr_list; /* list of (uint32_t *) */ }; struct mail_search_result * mail_search_result_new(clist * sr_list); void mail_search_result_free(struct mail_search_result * search_result); #endif /* There is three kinds of identities : - storage - folders - session A storage (struct mailstorage) represents whether a server or a main path, A storage can be an IMAP server, the root path of a MH or a mbox file. Folders (struct mailfolder) are the mailboxes we can choose in the server or as sub-folder of the main path. Folders for IMAP are the IMAP mailboxes, for MH this is one of the folder of the MH storage, for mbox, there is only one folder, the mbox file content; A mail session (struct mailsession) is whether a connection to a server or a path that is open. It is the abstraction lower folders and storage. It allow us to send commands. We have a session driver for mail session for each kind of storage. From a session, we can get a message (struct mailmessage) to read. We have a message driver for each kind of storage. */ /* maildriver is the driver structure for mail sessions - name is the name of the driver - initialize() is the function that will initializes a data structure specific to the driver, it returns a value that will be stored in the field data of the session. The field data of the session is the state of the session, the internal data structure used by the driver. It is called when creating the mailsession structure with mailsession_new(). - uninitialize() frees the structure created with initialize() - parameters() implements functions specific to the given mail access - connect_stream() connects a stream to the session - connect_path() notify a main path to the session - starttls() changes the current stream to a TLS stream - login() notifies the user and the password to authenticate to the session - logout() exits the session and closes the stream - noop() does no operation on the session, but it can be used to poll for the status of the connection. - build_folder_name() will return an allocated string with that contains the complete path of the folder to create - create_folder() creates the folder that corresponds to the given name - delete_folder() deletes the folder that corresponds to the given name - rename_folder() change the name of the folder - check_folder() makes a checkpoint of the session - examine_folder() selects a mailbox as readonly - select_folder() selects a mailbox - expunge_folder() deletes all messages marked \Deleted - status_folder() queries the status of the folder (number of messages, number of recent messages, number of unseen messages) - messages_number() queries the number of messages in the folder - recent_number() queries the number of recent messages in the folder - unseen_number() queries the number of unseen messages in the folder - list_folders() returns the list of all sub-mailboxes of the given mailbox - lsub_folders() returns the list of subscribed sub-mailboxes of the given mailbox - subscribe_folder() subscribes to the given mailbox - unsubscribe_folder() unsubscribes to the given mailbox - append_message() adds a RFC 2822 message to the current given mailbox - copy_message() copies a message whose number is given to a given mailbox. The mailbox must be accessible from the same session. - move_message() copies a message whose number is given to a given mailbox. The mailbox must be accessible from the same session. - get_messages_list() returns the list of message numbers of the current mailbox. - get_envelopes_list() fills the parsed fields in the mailmessage structures of the mailmessage_list. - remove_message() removes the given message from the mailbox. The message is permanently deleted. - search_message() returns a list of message numbers that corresponds to the given criteria. - get_message returns a mailmessage structure that corresponds to the given message number. - get_message_by_uid returns a mailmessage structure that corresponds to the given message unique identifier. * mandatory functions are the following : - connect_stream() of connect_path() - logout() - get_messages_list() - get_envelopes_list() * we advise you to implement these functions : - select_folder() (in case a session can access several folders) - noop() (to check if the server is responding) - check_folder() (to make a checkpoint of the session) - status_folder(), messages_number(), recent_number(), unseen_number() (to get stat of the folder) - append_message() (but can't be done in the case of POP3 at least) - login() in a case of an authenticated driver. - starttls() in a case of a stream driver, if the procotol supports STARTTLS. - get_message_by_uid() so that the application can remember the message by UID and build its own list of messages. * drivers' specific : Everything that is specific to the driver will be implemented in this function : - parameters() */ struct mailsession_driver { char * sess_name; int (* sess_initialize)(mailsession * session); void (* sess_uninitialize)(mailsession * session); int (* sess_parameters)(mailsession * session, int id, void * value); int (* sess_connect_stream)(mailsession * session, mailstream * s); int (* sess_connect_path)(mailsession * session, char * path); int (* sess_starttls)(mailsession * session); int (* sess_login)(mailsession * session, char * userid, char * password); int (* sess_logout)(mailsession * session); int (* sess_noop)(mailsession * session); /* folders operations */ int (* sess_build_folder_name)(mailsession * session, char * mb, char * name, char ** result); int (* sess_create_folder)(mailsession * session, char * mb); int (* sess_delete_folder)(mailsession * session, char * mb); int (* sess_rename_folder)(mailsession * session, char * mb, char * new_name); int (* sess_check_folder)(mailsession * session); int (* sess_examine_folder)(mailsession * session, char * mb); int (* sess_select_folder)(mailsession * session, char * mb); int (* sess_expunge_folder)(mailsession * session); int (* sess_status_folder)(mailsession * session, char * mb, uint32_t * result_num, uint32_t * result_recent, uint32_t * result_unseen); int (* sess_messages_number)(mailsession * session, char * mb, uint32_t * result); int (* sess_recent_number)(mailsession * session, char * mb, uint32_t * result); int (* sess_unseen_number)(mailsession * session, char * mb, uint32_t * result); int (* sess_list_folders)(mailsession * session, char * mb, struct mail_list ** result); int (* sess_lsub_folders)(mailsession * session, char * mb, struct mail_list ** result); int (* sess_subscribe_folder)(mailsession * session, char * mb); int (* sess_unsubscribe_folder)(mailsession * session, char * mb); /* messages operations */ int (* sess_append_message)(mailsession * session, char * message, size_t size); + int (* sess_append_message_flags)(mailsession * session, + char * message, size_t size, struct mail_flags * flags); int (* sess_copy_message)(mailsession * session, uint32_t num, char * mb); int (* sess_move_message)(mailsession * session, uint32_t num, char * mb); int (* sess_get_message)(mailsession * session, uint32_t num, mailmessage ** result); int (* sess_get_message_by_uid)(mailsession * session, const char * uid, mailmessage ** result); int (* sess_get_messages_list)(mailsession * session, struct mailmessage_list ** result); int (* sess_get_envelopes_list)(mailsession * session, struct mailmessage_list * env_list); int (* sess_remove_message)(mailsession * session, uint32_t num); #if 0 int (* sess_search_messages)(mailsession * session, char * charset, struct mail_search_key * key, struct mail_search_result ** result); #endif }; /* session is the data structure for a mail session. - data is the internal data structure used by the driver It is called when initializing the mailsession structure. - driver is the driver used for the session */ struct mailsession { void * sess_data; mailsession_driver * sess_driver; }; /* mailmessage_driver is the driver structure to get information from messages. - name is the name of the driver - initialize() is the function that will initializes a data structure specific to the driver, it returns a value that will be stored in the field data of the mailsession. The field data of the session is the state of the session, the internal data structure used by the driver. It is called when initializing the mailmessage structure with mailmessage_init(). - uninitialize() frees the structure created with initialize(). It will be called by mailmessage_free(). - flush() will free from memory all temporary structures of the message (for example, the MIME structure of the message). - fetch_result_free() will free all strings resulted by fetch() or any fetch_xxx() functions that returns a string. - fetch() returns the content of the message (headers and text). - fetch_header() returns the content of the headers. - fetch_body() returns the message text (message content without headers) - fetch_size() returns the size of the message content. - get_bodystructure() returns the MIME structure of the message. - fetch_section() returns the content of a given MIME part - fetch_section_header() returns the header of the message contained by the given MIME part. - fetch_section_mime() returns the MIME headers of the given MIME part. - fetch_section_body() returns the text (if this is a message, this is the message content without headers) of the given MIME part. - fetch_envelope() returns a mailimf_fields structure, with a list of fields chosen by the driver. - get_flags() returns a the flags related to the message. When you want to get flags of a message, you have to make sure to call get_flags() at least once before using directly message->flags. */ #define LIBETPAN_MAIL_MESSAGE_CHECK struct mailmessage_driver { char * msg_name; int (* msg_initialize)(mailmessage * msg_info); void (* msg_uninitialize)(mailmessage * msg_info); void (* msg_flush)(mailmessage * msg_info); void (* msg_check)(mailmessage * msg_info); void (* msg_fetch_result_free)(mailmessage * msg_info, char * msg); int (* msg_fetch)(mailmessage * msg_info, char ** result, size_t * result_len); int (* msg_fetch_header)(mailmessage * msg_info, char ** result, size_t * result_len); int (* msg_fetch_body)(mailmessage * msg_info, char ** result, size_t * result_len); int (* msg_fetch_size)(mailmessage * msg_info, size_t * result); int (* msg_get_bodystructure)(mailmessage * msg_info, struct mailmime ** result); int (* msg_fetch_section)(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len); int (* msg_fetch_section_header)(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len); int (* msg_fetch_section_mime)(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len); int (* msg_fetch_section_body)(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len); int (* msg_fetch_envelope)(mailmessage * msg_info, struct mailimf_fields ** result); int (* msg_get_flags)(mailmessage * msg_info, struct mail_flags ** result); }; /* mailmessage is a data structure to get information from messages - session is the session linked to the given message, it can be NULL - driver is the message driver - index is the message number - uid, when it is not NULL, it means that the folder the folder has persistant message numbers, the string is the unique message number in the folder. uid should be implemented if possible. for drivers where we cannot generate real uid, a suggestion is "AAAA-IIII" where AAAA is some random session number and IIII the content of index field. - size, when it is not 0, is the size of the message content. - fields, when it is not NULL, are the header fields of the message. - flags, when it is not NULL, are the flags related to the message. - single_fields, when resolved != 0, is filled with the data of fields. - mime, when it is not NULL - cached is != 0 when the header fields were read from the cache. - data is data specific to the driver, this is internal data structure, some state of the message. */ struct mailmessage { mailsession * msg_session; mailmessage_driver * msg_driver; uint32_t msg_index; char * msg_uid; size_t msg_size; struct mailimf_fields * msg_fields; struct mail_flags * msg_flags; int msg_resolved; struct mailimf_single_fields msg_single_fields; struct mailmime * msg_mime; /* internal data */ int msg_cached; void * msg_data; /* msg_folder field : used to reference the mailfolder, this is a workaround due to the problem with initial conception, where folder notion did not exist. */ void * msg_folder; /* user data */ void * msg_user_data; }; /* mailmessage_tree is a node in the messages tree (thread) - parent is the parent of the message, it is NULL if the message is the root of the message tree. - date is the date of the message in number of second elapsed since 00:00:00 on January 1, 1970, Coordinated Universal Time (UTC). - msg is the message structure that is stored referenced by the node. is msg is NULL, this is a dummy node. - children is an array that contains all the children of the node. children are mailmessage_tree structures. - is_reply is != 0 when the message is a reply or a forward - base_subject is the extracted subject of the message. - index is the message number. */ struct mailmessage_tree { struct mailmessage_tree * node_parent; char * node_msgid; time_t node_date; mailmessage * node_msg; carray * node_children; /* array of (struct mailmessage_tree *) */ /* private, used for threading */ int node_is_reply; char * node_base_subject; }; struct mailmessage_tree * mailmessage_tree_new(char * node_msgid, time_t node_date, mailmessage * node_msg); void mailmessage_tree_free(struct mailmessage_tree * tree); /* mailmessage_tree_free_recursive if you want to release memory of the given tree and all the sub-trees, you can use this function. */ void mailmessage_tree_free_recursive(struct mailmessage_tree * tree); struct generic_message_t { int (* msg_prefetch)(mailmessage * msg_info); void (* msg_prefetch_free)(struct generic_message_t * msg); int msg_fetched; char * msg_message; size_t msg_length; void * msg_data; }; const char * maildriver_strerror(int err); #ifdef __cplusplus } #endif #endif diff --git a/kmicromail/libetpan/generic/mailfolder.c b/kmicromail/libetpan/generic/mailfolder.c index 2ddc37d..89ba891 100644 --- a/kmicromail/libetpan/generic/mailfolder.c +++ b/kmicromail/libetpan/generic/mailfolder.c @@ -1,96 +1,103 @@ #include "mailfolder.h" #include "maildriver.h" int mailfolder_noop(struct mailfolder * folder) { return mailsession_noop(folder->fld_session); } int mailfolder_check(struct mailfolder * folder) { return mailsession_check_folder(folder->fld_session); } int mailfolder_expunge(struct mailfolder * folder) { return mailsession_expunge_folder(folder->fld_session); } int mailfolder_status(struct mailfolder * folder, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { return mailsession_status_folder(folder->fld_session, folder->fld_pathname, result_messages, result_recent, result_unseen); } int mailfolder_append_message(struct mailfolder * folder, char * message, size_t size) { return mailsession_append_message(folder->fld_session, message, size); } +int mailfolder_append_message_flags(struct mailfolder * folder, + char * message, size_t size, struct mail_flags * flags) +{ + return mailsession_append_message_flags(folder->fld_session, message, + size, flags); +} + int mailfolder_get_messages_list(struct mailfolder * folder, struct mailmessage_list ** result) { int r; struct mailmessage_list * msg_list; unsigned int i; r = mailsession_get_messages_list(folder->fld_session, &msg_list); if (r != MAIL_NO_ERROR) return r; for(i = 0 ; i < carray_count(msg_list->msg_tab) ; i ++) { mailmessage * msg; msg = carray_get(msg_list->msg_tab, i); msg->msg_folder = folder; } * result = msg_list; return MAIL_NO_ERROR; } int mailfolder_get_envelopes_list(struct mailfolder * folder, struct mailmessage_list * result) { return mailsession_get_envelopes_list(folder->fld_session, result); } int mailfolder_get_message(struct mailfolder * folder, uint32_t num, mailmessage ** result) { mailmessage * msg; int r; r = mailsession_get_message(folder->fld_session, num, &msg); if (r != MAIL_NO_ERROR) return r; msg->msg_folder = folder; * result = msg; return MAIL_NO_ERROR; } int mailfolder_get_message_by_uid(struct mailfolder * folder, const char * uid, mailmessage ** result) { mailmessage * msg; int r; r = mailsession_get_message_by_uid(folder->fld_session, uid, &msg); if (r != MAIL_NO_ERROR) return r; msg->msg_folder = folder; * result = msg; return MAIL_NO_ERROR; } diff --git a/kmicromail/libetpan/generic/mailfolder.h b/kmicromail/libetpan/generic/mailfolder.h index 3ecad23..ff53470 100644 --- a/kmicromail/libetpan/generic/mailfolder.h +++ b/kmicromail/libetpan/generic/mailfolder.h @@ -1,32 +1,35 @@ #ifndef MAILFOLDER_H #define MAILFOLDER_H #include "mailstorage_types.h" int mailfolder_noop(struct mailfolder * folder); int mailfolder_check(struct mailfolder * folder); int mailfolder_expunge(struct mailfolder * folder); int mailfolder_status(struct mailfolder * folder, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); int mailfolder_append_message(struct mailfolder * folder, char * message, size_t size); +int mailfolder_append_message_flags(struct mailfolder * folder, + char * message, size_t size, struct mail_flags * flags); + int mailfolder_get_messages_list(struct mailfolder * folder, struct mailmessage_list ** result); int mailfolder_get_envelopes_list(struct mailfolder * folder, struct mailmessage_list * result); int mailfolder_get_message(struct mailfolder * folder, uint32_t num, mailmessage ** result); int mailfolder_get_message_by_uid(struct mailfolder * folder, const char * uid, mailmessage ** result); #endif diff --git a/kmicromail/libetpan/generic/mailstorage.c b/kmicromail/libetpan/generic/mailstorage.c index 25e561e..dc91744 100644 --- a/kmicromail/libetpan/generic/mailstorage.c +++ b/kmicromail/libetpan/generic/mailstorage.c @@ -1,334 +1,341 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "mailstorage.h" #include "maildriver.h" #include <stdlib.h> #include <string.h> static int mailstorage_get_folder(struct mailstorage * storage, char * pathname, mailsession ** result); struct mailfolder * mailfolder_new(struct mailstorage * storage, char * pathname, char * virtual_name) { struct mailfolder * folder; folder = malloc(sizeof(struct mailfolder)); if (folder == NULL) goto err; if (pathname != NULL) { folder->fld_pathname = strdup(pathname); if (folder->fld_pathname == NULL) goto free; } else folder->fld_pathname = NULL; if (virtual_name != NULL) { folder->fld_virtual_name = strdup(virtual_name); if (folder->fld_virtual_name == NULL) goto free_pathname; } else folder->fld_virtual_name = NULL; folder->fld_storage = storage; folder->fld_session = NULL; folder->fld_shared_session = 0; folder->fld_pos = NULL; folder->fld_parent = NULL; folder->fld_sibling_index = 0; folder->fld_children = carray_new(128); if (folder->fld_children == NULL) goto free_virtualname; return folder; free_virtualname: if (folder->fld_virtual_name != NULL) free(folder->fld_virtual_name); free_pathname: if (folder->fld_pathname != NULL) free(folder->fld_pathname); free: free(folder); err: return NULL; } void mailfolder_free(struct mailfolder * folder) { if (folder->fld_parent != NULL) mailfolder_detach_parent(folder); while (carray_count(folder->fld_children) > 0) { struct mailfolder * child; child = carray_get(folder->fld_children, 0); mailfolder_detach_parent(child); } carray_free(folder->fld_children); if (folder->fld_session != NULL) mailfolder_disconnect(folder); if (folder->fld_virtual_name != NULL) free(folder->fld_virtual_name); if (folder->fld_pathname != NULL) free(folder->fld_pathname); free(folder); } int mailfolder_connect(struct mailfolder * folder) { mailsession * session; int res; int r; if (folder->fld_storage == NULL) { res = MAIL_ERROR_INVAL; goto err; } if (folder->fld_storage->sto_session == NULL) { r = mailstorage_connect(folder->fld_storage); if (r != MAIL_NO_ERROR) { res = r; goto err; } } if (folder->fld_session != NULL) { if ((folder->fld_pathname != NULL) && (folder->fld_shared_session)) { if (folder->fld_session->sess_driver->sess_select_folder != NULL) { r = mailsession_select_folder(folder->fld_session, folder->fld_pathname); if (r != MAIL_NO_ERROR) { res = r; goto err; } } } return MAIL_NO_ERROR; } r = mailstorage_get_folder(folder->fld_storage, folder->fld_pathname, &session); if (r != MAIL_NO_ERROR) { res = r; goto err; } folder->fld_session = session; folder->fld_shared_session = (session == folder->fld_storage->sto_session); if (folder->fld_shared_session) { r = clist_append(folder->fld_storage->sto_shared_folders, folder); if (r < 0) { folder->fld_session = NULL; res = MAIL_ERROR_MEMORY; goto err; } folder->fld_pos = clist_end(folder->fld_storage->sto_shared_folders); } return MAIL_NO_ERROR; err: return res; } void mailfolder_disconnect(struct mailfolder * folder) { if (folder->fld_session == NULL) return; if (folder->fld_shared_session) { clist_delete(folder->fld_storage->sto_shared_folders, folder->fld_pos); folder->fld_pos = NULL; } else { mailsession_logout(folder->fld_session); mailsession_free(folder->fld_session); } folder->fld_session = NULL; } int mailfolder_add_child(struct mailfolder * parent, struct mailfolder * child) { unsigned int index; int r; r = carray_add(parent->fld_children, child, &index); if (r < 0) return MAIL_ERROR_MEMORY; child->fld_sibling_index = index; child->fld_parent = parent; return MAIL_NO_ERROR; } int mailfolder_detach_parent(struct mailfolder * folder) { unsigned int i; int r; if (folder->fld_parent == NULL) return MAIL_ERROR_INVAL; r = carray_delete_slow(folder->fld_parent->fld_children, folder->fld_sibling_index); if (r < 0) return MAIL_ERROR_INVAL; for(i = 0 ; i < carray_count(folder->fld_parent->fld_children) ; i ++) { struct mailfolder * child; child = carray_get(folder->fld_parent->fld_children, i); child->fld_sibling_index = i; } folder->fld_parent = NULL; folder->fld_sibling_index = 0; return MAIL_NO_ERROR; } struct mailstorage * mailstorage_new(char * sto_id) { struct mailstorage * storage; storage = malloc(sizeof(struct mailstorage)); if (storage == NULL) goto err; if (sto_id != NULL) { storage->sto_id = strdup(sto_id); if (storage->sto_id == NULL) goto free; } else storage->sto_id = NULL; storage->sto_data = NULL; storage->sto_session = NULL; storage->sto_driver = NULL; storage->sto_shared_folders = clist_new(); if (storage->sto_shared_folders == NULL) goto free_id; return storage; free_id: if (storage->sto_id != NULL) free(storage->sto_id); free: free(storage); err: return NULL; } void mailstorage_free(struct mailstorage * storage) { if (storage->sto_session != NULL) mailstorage_disconnect(storage); if (storage->sto_driver != NULL) { if (storage->sto_driver->sto_uninitialize != NULL) storage->sto_driver->sto_uninitialize(storage); } clist_free(storage->sto_shared_folders); if (storage->sto_id != NULL) free(storage->sto_id); free(storage); } int mailstorage_connect(struct mailstorage * storage) { if (storage->sto_session != NULL) return MAIL_NO_ERROR; if (!clist_isempty(storage->sto_shared_folders)) return MAIL_ERROR_BAD_STATE; if (storage->sto_driver->sto_connect == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return storage->sto_driver->sto_connect(storage); } void mailstorage_disconnect(struct mailstorage * storage) { int r; clistiter * cur; while ((cur = clist_begin(storage->sto_shared_folders)) != NULL) { struct mailfolder * folder; folder = cur->data; mailfolder_disconnect(folder); } if (storage->sto_session == NULL) return; r = mailsession_logout(storage->sto_session); mailsession_free(storage->sto_session); storage->sto_session = NULL; } + +int mailstorage_noop(struct mailstorage * storage) +{ + return mailsession_noop(storage->sto_session); +} + + static int mailstorage_get_folder(struct mailstorage * storage, char * pathname, mailsession ** result) { if (storage->sto_driver->sto_get_folder_session == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return storage->sto_driver->sto_get_folder_session(storage, pathname, result); } diff --git a/kmicromail/libetpan/generic/mailstorage.h b/kmicromail/libetpan/generic/mailstorage.h index d56aef1..4c57883 100644 --- a/kmicromail/libetpan/generic/mailstorage.h +++ b/kmicromail/libetpan/generic/mailstorage.h @@ -1,98 +1,99 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #ifndef MAIL_STORAGE_H #define MAIL_STORAGE_H #include <libetpan/maildriver_types.h> #include <libetpan/mailstorage_types.h> #ifdef __cplusplus extern "C" { #endif /* storage */ /* mailstorage_new This function creates an empty storage. This storage have to be initialized. The "driver" and "data" fields should be initialized. @param id is the name of the storage. It can be NULL. The given parameter is no more needed when the creation is finished. The given string is duplicated. @return The mail storage is returned. */ struct mailstorage * mailstorage_new(char * sto_id); void mailstorage_free(struct mailstorage * storage); /* session will be initialized on success. */ int mailstorage_connect(struct mailstorage * storage); void mailstorage_disconnect(struct mailstorage * storage); +int mailstorage_noop(struct mailstorage * storage); + /* folder */ struct mailfolder * mailfolder_new(struct mailstorage * fld_storage, char * fld_pathname, char * fld_virtual_name); void mailfolder_free(struct mailfolder * folder); int mailfolder_add_child(struct mailfolder * parent, struct mailfolder * child); int mailfolder_detach_parent(struct mailfolder * folder); int mailfolder_connect(struct mailfolder * folder); void mailfolder_disconnect(struct mailfolder * folder); - #ifdef __cplusplus } #endif #endif diff --git a/kmicromail/libetpan/generic/mboxdriver.c b/kmicromail/libetpan/generic/mboxdriver.c index fa3e2ea..c19a668 100644 --- a/kmicromail/libetpan/generic/mboxdriver.c +++ b/kmicromail/libetpan/generic/mboxdriver.c @@ -1,505 +1,515 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "mboxdriver.h" #include <stdio.h> #include <string.h> #include <sys/types.h> #include <dirent.h> #include <unistd.h> #include <sys/stat.h> #include <ctype.h> #include <stdlib.h> #include <sys/times.h> #include "mail.h" #include "maildriver_tools.h" #include "mailmbox.h" #include "mboxdriver_tools.h" #include "maildriver.h" #include "carray.h" #include "mboxdriver_message.h" #include "mailmessage.h" static int mboxdriver_initialize(mailsession * session); static void mboxdriver_uninitialize(mailsession * session); static int mboxdriver_parameters(mailsession * session, int id, void * value); static int mboxdriver_connect_path(mailsession * session, char * path); static int mboxdriver_logout(mailsession * session); static int mboxdriver_expunge_folder(mailsession * session); static int mboxdriver_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); static int mboxdriver_messages_number(mailsession * session, char * mb, uint32_t * result); static int mboxdriver_append_message(mailsession * session, char * message, size_t size); +static int mboxdriver_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags); + static int mboxdriver_get_messages_list(mailsession * session, struct mailmessage_list ** result); static int mboxdriver_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list); static int mboxdriver_remove_message(mailsession * session, uint32_t num); static int mboxdriver_get_message(mailsession * session, uint32_t num, mailmessage ** result); static int mboxdriver_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result); static mailsession_driver local_mbox_session_driver = { .sess_name = "mbox", .sess_initialize = mboxdriver_initialize, .sess_uninitialize = mboxdriver_uninitialize, .sess_parameters = mboxdriver_parameters, .sess_connect_path = mboxdriver_connect_path, .sess_connect_stream = NULL, .sess_starttls = NULL, .sess_login = NULL, .sess_logout = mboxdriver_logout, .sess_noop = NULL, .sess_build_folder_name = NULL, .sess_create_folder = NULL, .sess_delete_folder = NULL, .sess_rename_folder = NULL, .sess_check_folder = NULL, .sess_examine_folder = NULL, .sess_select_folder = NULL, .sess_expunge_folder = mboxdriver_expunge_folder, .sess_status_folder = mboxdriver_status_folder, .sess_messages_number = mboxdriver_messages_number, .sess_recent_number = mboxdriver_messages_number, .sess_unseen_number = mboxdriver_messages_number, .sess_list_folders = NULL, .sess_lsub_folders = NULL, .sess_subscribe_folder = NULL, .sess_unsubscribe_folder = NULL, .sess_append_message = mboxdriver_append_message, + .sess_append_message_flags = mboxdriver_append_message_flags, .sess_copy_message = NULL, .sess_move_message = NULL, .sess_get_messages_list = mboxdriver_get_messages_list, .sess_get_envelopes_list = mboxdriver_get_envelopes_list, .sess_remove_message = mboxdriver_remove_message, #if 0 .sess_search_messages = maildriver_generic_search_messages, #endif .sess_get_message = mboxdriver_get_message, .sess_get_message_by_uid = mboxdriver_get_message_by_uid, }; mailsession_driver * mbox_session_driver = &local_mbox_session_driver; static inline struct mbox_session_state_data * get_data(mailsession * session) { return session->sess_data; } static inline struct mailmbox_folder * get_mbox_session(mailsession * session) { return get_data(session)->mbox_folder; } static int mboxdriver_initialize(mailsession * session) { struct mbox_session_state_data * data; data = malloc(sizeof(* data)); if (data == NULL) goto err; data->mbox_folder = NULL; data->mbox_force_read_only = FALSE; data->mbox_force_no_uid = TRUE; session->sess_data = data; return MAIL_NO_ERROR; err: return MAIL_ERROR_MEMORY; } static void free_state(struct mbox_session_state_data * mbox_data) { if (mbox_data->mbox_folder != NULL) { mailmbox_done(mbox_data->mbox_folder); mbox_data->mbox_folder = NULL; } } static void mboxdriver_uninitialize(mailsession * session) { struct mbox_session_state_data * data; data = get_data(session); free_state(data); free(data); } static int mboxdriver_parameters(mailsession * session, int id, void * value) { struct mbox_session_state_data * data; data = get_data(session); switch (id) { case MBOXDRIVER_SET_READ_ONLY: { int * param; param = value; data->mbox_force_read_only = * param; return MAIL_NO_ERROR; } case MBOXDRIVER_SET_NO_UID: { int * param; param = value; data->mbox_force_no_uid = * param; return MAIL_NO_ERROR; } } return MAIL_ERROR_INVAL; } static int mboxdriver_connect_path(mailsession * session, char * path) { struct mbox_session_state_data * mbox_data; struct mailmbox_folder * folder; int r; mbox_data = get_data(session); if (mbox_data->mbox_folder != NULL) return MAIL_ERROR_BAD_STATE; r = mailmbox_init(path, mbox_data->mbox_force_read_only, mbox_data->mbox_force_no_uid, 0, &folder); if (r != MAILMBOX_NO_ERROR) return mboxdriver_mbox_error_to_mail_error(r); mbox_data->mbox_folder = folder; return MAIL_NO_ERROR; } static int mboxdriver_logout(mailsession * session) { struct mbox_session_state_data * mbox_data; mbox_data = get_data(session); if (mbox_data->mbox_folder == NULL) return MAIL_ERROR_BAD_STATE; free_state(mbox_data); mbox_data->mbox_folder = NULL; return MAIL_NO_ERROR; } static int mboxdriver_expunge_folder(mailsession * session) { int r; struct mbox_session_state_data * mbox_data; mbox_data = get_data(session); if (mbox_data->mbox_folder == NULL) return MAIL_ERROR_BAD_STATE; r = mailmbox_expunge(mbox_data->mbox_folder); if (r != MAILMBOX_NO_ERROR) return mboxdriver_mbox_error_to_mail_error(r); return MAIL_NO_ERROR; } static int mboxdriver_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { uint32_t count; int r; r = mboxdriver_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 mboxdriver_messages_number(mailsession * session, char * mb, uint32_t * result) { struct mailmbox_folder * folder; int r; folder = get_mbox_session(session); if (folder == NULL) return MAIL_ERROR_STATUS; r = mailmbox_validate_read_lock(folder); if (r != MAIL_NO_ERROR) return r; mailmbox_read_unlock(folder); * result = carray_count(folder->mb_tab) - folder->mb_deleted_count; return MAILMBOX_NO_ERROR; } /* messages operations */ static int mboxdriver_append_message(mailsession * session, char * message, size_t size) { int r; struct mailmbox_folder * folder; folder = get_mbox_session(session); if (folder == NULL) return MAIL_ERROR_APPEND; r = mailmbox_append_message(folder, message, size); switch (r) { case MAILMBOX_ERROR_FILE: return MAIL_ERROR_DISKSPACE; default: return mboxdriver_mbox_error_to_mail_error(r); } } +static int mboxdriver_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags) +{ + return mboxdriver_append_message(session, message, size); +} + static int mboxdriver_get_messages_list(mailsession * session, struct mailmessage_list ** result) { struct mailmbox_folder * folder; int res; folder = get_mbox_session(session); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } return mbox_get_messages_list(folder, session, mbox_message_driver, result); err: return res; } static int mboxdriver_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list) { struct mailmbox_folder * folder; unsigned int i; int r; int res; folder = get_mbox_session(session); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } r = mailmbox_validate_read_lock(folder); if (r != MAILMBOX_NO_ERROR) { res = mboxdriver_mbox_error_to_mail_error(r); goto err; } for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; struct mailimf_fields * fields; char * headers; size_t headers_len; size_t cur_token; msg = carray_get(env_list->msg_tab, i); if (msg == NULL) continue; if (msg->msg_fields != NULL) continue; r = mailmbox_fetch_msg_headers_no_lock(folder, msg->msg_index, &headers, &headers_len); if (r != MAILMBOX_NO_ERROR) { res = mboxdriver_mbox_error_to_mail_error(r); goto unlock; } cur_token = 0; r = mailimf_envelope_fields_parse(headers, headers_len, &cur_token, &fields); if (r != MAILIMF_NO_ERROR) continue; msg->msg_fields = fields; } mailmbox_read_unlock(folder); return MAIL_NO_ERROR; unlock: mailmbox_read_unlock(folder); err: return res; } static int mboxdriver_remove_message(mailsession * session, uint32_t num) { int r; struct mailmbox_folder * folder; folder = get_mbox_session(session); if (folder == NULL) return MAIL_ERROR_DELETE; r = mailmbox_delete_msg(folder, num); return mboxdriver_mbox_error_to_mail_error(r); } static int mboxdriver_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, mbox_message_driver, num, 0); if (r != MAIL_NO_ERROR) { mailmessage_free(msg_info); return r; } * result = msg_info; return MAIL_NO_ERROR; } static int mboxdriver_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result) { uint32_t num; char * p; chashdatum key; chashdatum data; struct mailmbox_msg_info * info; struct mailmbox_folder * folder; int r; if (uid == NULL) return MAIL_ERROR_INVAL; num = strtoul(uid, &p, 10); if (p == uid || * p != '-') return MAIL_ERROR_INVAL; folder = get_mbox_session(session); if (folder == NULL) return MAIL_ERROR_BAD_STATE; key.data = # key.len = sizeof(num); r = chash_get(folder->mb_hash, &key, &data); if (r == 0) { char * body_len_p = p + 1; size_t body_len; info = data.data; /* Check if the cached message has the same UID */ body_len = strtoul(body_len_p, &p, 10); if (p == body_len_p || * p != '\0') return MAIL_ERROR_INVAL; if (body_len == info->msg_body_len) return mboxdriver_get_message(session, num, result); } return MAIL_ERROR_MSG_NOT_FOUND; } diff --git a/kmicromail/libetpan/generic/mboxdriver_cached.c b/kmicromail/libetpan/generic/mboxdriver_cached.c index 07871fa..3af7fb9 100644 --- a/kmicromail/libetpan/generic/mboxdriver_cached.c +++ b/kmicromail/libetpan/generic/mboxdriver_cached.c @@ -1,1253 +1,1337 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "mboxdriver_cached.h" #include <stdio.h> #include <string.h> #include <dirent.h> #include <unistd.h> #include <ctype.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include "mail.h" #include "mail_cache_db.h" #include "mboxdriver.h" #include "mboxdriver_tools.h" #include "maildriver_tools.h" #include "mailmbox.h" #include "maildriver.h" #include "carray.h" #include "generic_cache.h" #include "imfcache.h" #include "mboxdriver_cached_message.h" #include "libetpan-config.h" static int mboxdriver_cached_initialize(mailsession * session); static void mboxdriver_cached_uninitialize(mailsession * session); static int mboxdriver_cached_parameters(mailsession * session, int id, void * value); static int mboxdriver_cached_connect_path(mailsession * session, char * path); static int mboxdriver_cached_logout(mailsession * session); static int mboxdriver_cached_check_folder(mailsession * session); static int mboxdriver_cached_expunge_folder(mailsession * session); static int mboxdriver_cached_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); static int mboxdriver_cached_messages_number(mailsession * session, char * mb, uint32_t * result); static int mboxdriver_cached_recent_number(mailsession * session, char * mb, uint32_t * result); static int mboxdriver_cached_unseen_number(mailsession * session, char * mb, uint32_t * result); static int mboxdriver_cached_append_message(mailsession * session, char * message, size_t size); +static int mboxdriver_cached_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags); + static int mboxdriver_cached_get_messages_list(mailsession * session, struct mailmessage_list ** result); static int mboxdriver_cached_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list); static int mboxdriver_cached_remove_message(mailsession * session, uint32_t num); static int mboxdriver_cached_get_message(mailsession * session, uint32_t num, mailmessage ** result); static int mboxdriver_cached_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result); static mailsession_driver local_mbox_cached_session_driver = { .sess_name = "mbox-cached", .sess_initialize = mboxdriver_cached_initialize, .sess_uninitialize = mboxdriver_cached_uninitialize, .sess_parameters = mboxdriver_cached_parameters, .sess_connect_path = mboxdriver_cached_connect_path, .sess_connect_stream = NULL, .sess_starttls = NULL, .sess_login = NULL, .sess_logout = mboxdriver_cached_logout, .sess_noop = NULL, .sess_build_folder_name = NULL, .sess_create_folder = NULL, .sess_delete_folder = NULL, .sess_rename_folder = NULL, .sess_check_folder = mboxdriver_cached_check_folder, .sess_examine_folder = NULL, .sess_select_folder = NULL, .sess_expunge_folder = mboxdriver_cached_expunge_folder, .sess_status_folder = mboxdriver_cached_status_folder, .sess_messages_number = mboxdriver_cached_messages_number, .sess_recent_number = mboxdriver_cached_recent_number, .sess_unseen_number = mboxdriver_cached_unseen_number, .sess_list_folders = NULL, .sess_lsub_folders = NULL, .sess_subscribe_folder = NULL, .sess_unsubscribe_folder = NULL, .sess_append_message = mboxdriver_cached_append_message, + .sess_append_message_flags = mboxdriver_cached_append_message_flags, + .sess_copy_message = NULL, .sess_move_message = NULL, .sess_get_messages_list = mboxdriver_cached_get_messages_list, .sess_get_envelopes_list = mboxdriver_cached_get_envelopes_list, .sess_remove_message = mboxdriver_cached_remove_message, #if 0 .sess_search_messages = maildriver_generic_search_messages, #endif .sess_get_message = mboxdriver_cached_get_message, .sess_get_message_by_uid = mboxdriver_cached_get_message_by_uid, }; mailsession_driver * mbox_cached_session_driver = &local_mbox_cached_session_driver; #define ENV_NAME "env.db" #define FLAGS_NAME "flags.db" static int mbox_error_to_mail_error(int error) { switch (error) { case MAILMBOX_NO_ERROR: return MAIL_NO_ERROR; case MAILMBOX_ERROR_PARSE: return MAIL_ERROR_PARSE; case MAILMBOX_ERROR_INVAL: return MAIL_ERROR_INVAL; case MAILMBOX_ERROR_FILE_NOT_FOUND: return MAIL_ERROR_PARSE; case MAILMBOX_ERROR_MEMORY: return MAIL_ERROR_MEMORY; case MAILMBOX_ERROR_TEMPORARY_FILE: return MAIL_ERROR_PARSE; case MAILMBOX_ERROR_FILE: return MAIL_ERROR_FILE; case MAILMBOX_ERROR_MSG_NOT_FOUND: return MAIL_ERROR_MSG_NOT_FOUND; case MAILMBOX_ERROR_READONLY: return MAIL_ERROR_READONLY; default: return MAIL_ERROR_INVAL; } } static inline struct mbox_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)->mbox_ancestor; } static inline struct mbox_session_state_data * get_ancestor_data(mailsession * session) { return get_ancestor(session)->sess_data; } static inline struct mailmbox_folder * get_mbox_session(mailsession * session) { return get_ancestor_data(session)->mbox_folder; } static int mboxdriver_cached_initialize(mailsession * session) { struct mbox_cached_session_state_data * cached_data; struct mbox_session_state_data * mbox_data; cached_data = malloc(sizeof(* cached_data)); if (cached_data == NULL) goto err; cached_data->mbox_flags_store = mail_flags_store_new(); if (cached_data->mbox_flags_store == NULL) goto free; cached_data->mbox_ancestor = mailsession_new(mbox_session_driver); if (cached_data->mbox_ancestor == NULL) goto free_store; cached_data->mbox_quoted_mb = NULL; /* UID must be enabled to take advantage of the cache */ mbox_data = cached_data->mbox_ancestor->sess_data; mbox_data->mbox_force_no_uid = FALSE; session->sess_data = cached_data; return MAIL_NO_ERROR; free_store: mail_flags_store_free(cached_data->mbox_flags_store); free: free(cached_data); err: return MAIL_ERROR_MEMORY; } static void free_state(struct mbox_cached_session_state_data * mbox_data) { if (mbox_data->mbox_quoted_mb) { free(mbox_data->mbox_quoted_mb); mbox_data->mbox_quoted_mb = NULL; } } static int mbox_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%c%s%c%s", flags_directory, MAIL_DIR_SEPARATOR, quoted_mb, MAIL_DIR_SEPARATOR, 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 = mboxdriver_write_cached_flags(cache_db_flags, mmapstr, msg->msg_uid, msg->msg_flags); if (r != MAIL_NO_ERROR) { /* ignore errors */ } } 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 mboxdriver_cached_uninitialize(mailsession * session) { struct mbox_cached_session_state_data * data; data = get_cached_data(session); mbox_flags_store_process(data->mbox_flags_directory, data->mbox_quoted_mb, data->mbox_flags_store); mail_flags_store_free(data->mbox_flags_store); free_state(data); mailsession_free(data->mbox_ancestor); free(data); session->sess_data = NULL; } static int mboxdriver_cached_parameters(mailsession * session, int id, void * value) { struct mbox_cached_session_state_data * data; int r; data = get_cached_data(session); switch (id) { case MBOXDRIVER_CACHED_SET_CACHE_DIRECTORY: strncpy(data->mbox_cache_directory, value, PATH_MAX); data->mbox_cache_directory[PATH_MAX - 1] = '\0'; r = generic_cache_create_dir(data->mbox_cache_directory); if (r != MAIL_NO_ERROR) return r; return MAIL_NO_ERROR; case MBOXDRIVER_CACHED_SET_FLAGS_DIRECTORY: strncpy(data->mbox_flags_directory, value, PATH_MAX); data->mbox_flags_directory[PATH_MAX - 1] = '\0'; r = generic_cache_create_dir(data->mbox_flags_directory); if (r != MAIL_NO_ERROR) return r; return MAIL_NO_ERROR; case MBOXDRIVER_SET_NO_UID: return MAIL_ERROR_INVAL; default: return mailsession_parameters(data->mbox_ancestor, id, value); } } static int get_cache_directory(mailsession * session, char * path, char ** result) { char * quoted_mb; char dirname[PATH_MAX]; int res; int r; struct mbox_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%c%s", cached_data->mbox_cache_directory, MAIL_DIR_SEPARATOR, quoted_mb); r = generic_cache_create_dir(dirname); if (r != MAIL_NO_ERROR) { res = r; goto free; } snprintf(dirname, PATH_MAX, "%s%c%s", cached_data->mbox_flags_directory, MAIL_DIR_SEPARATOR, 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; } #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; #if 0 struct mbox_session_state_data * mbox_data; #endif struct mbox_cached_session_state_data * cached_data; int fd; MMAPString * mmapstr; size_t cur_token; struct mailmbox_folder * folder; /* expunge the mailbox */ #if 0 mbox_data = get_ancestor(session)->data; #endif folder = get_mbox_session(session); r = mailmbox_validate_write_lock(folder); if (r != MAILMBOX_NO_ERROR) { res = mbox_error_to_mail_error(r); goto err; } r = mailmbox_expunge_no_lock(folder); if (r != MAILMBOX_NO_ERROR) { res = r; goto unlock; } cached_data = get_cached_data(session); snprintf(filename, PATH_MAX, "%s%c%s%c%s", cached_data->mbox_flags_directory, MAIL_DIR_SEPARATOR, cached_data->mbox_quoted_mb, MAIL_DIR_SEPARATOR, 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 unlock; } 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, folder->mb_written_uid); if (r != MAIL_NO_ERROR) { res = r; goto free_mmapstr; } fwrite(mmapstr->str, 1, mmapstr->len, f); mmap_string_free(mmapstr); fclose(f); mailmbox_write_unlock(folder); return MAIL_NO_ERROR; free_mmapstr: mmap_string_free(mmapstr); close: fclose(f); unlock: mailmbox_read_unlock(folder); err: return res; } static int read_max_uid_value(mailsession * session, uint32_t * result) { int r; char filename[PATH_MAX]; FILE * f; uint32_t written_uid; int res; struct mbox_cached_session_state_data * cached_data; MMAPString * mmapstr; size_t cur_token; char buf[sizeof(uint32_t)]; size_t read_size; cached_data = get_cached_data(session); snprintf(filename, PATH_MAX, "%s%c%s%c%s", cached_data->mbox_flags_directory, MAIL_DIR_SEPARATOR, cached_data->mbox_quoted_mb, MAIL_DIR_SEPARATOR, 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); * result = written_uid; return MAIL_NO_ERROR; free_mmapstr: mmap_string_free(mmapstr); close: fclose(f); err: return res; } static int mboxdriver_cached_connect_path(mailsession * session, char * path) { int r; int res; char * quoted_mb; struct mbox_cached_session_state_data * cached_data; struct mbox_session_state_data * ancestor_data; struct mailmbox_folder * folder; uint32_t written_uid; folder = get_mbox_session(session); if (folder != NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } r = get_cache_directory(session, path, "ed_mb); if (r != MAIL_NO_ERROR) { res = r; goto err; } cached_data = get_cached_data(session); free_state(cached_data); cached_data->mbox_quoted_mb = quoted_mb; written_uid = 0; r = read_max_uid_value(session, &written_uid); /* ignore errors */ ancestor_data = get_ancestor_data(session); r = mailmbox_init(path, ancestor_data->mbox_force_read_only, ancestor_data->mbox_force_no_uid, written_uid, &folder); if (r != MAILMBOX_NO_ERROR) { cached_data->mbox_quoted_mb = NULL; res = mboxdriver_mbox_error_to_mail_error(r); goto free; } ancestor_data->mbox_folder = folder; return MAIL_NO_ERROR; free: free(quoted_mb); err: return res; } static int mboxdriver_cached_logout(mailsession * session) { struct mbox_cached_session_state_data * cached_data; int r; r = write_max_uid_value(session); cached_data = get_cached_data(session); mbox_flags_store_process(cached_data->mbox_flags_directory, cached_data->mbox_quoted_mb, cached_data->mbox_flags_store); r = mailsession_logout(get_ancestor(session)); if (r != MAIL_NO_ERROR) return r; free_state(cached_data); return MAIL_NO_ERROR; } static int mboxdriver_cached_check_folder(mailsession * session) { struct mbox_cached_session_state_data * cached_data; cached_data = get_cached_data(session); mbox_flags_store_process(cached_data->mbox_flags_directory, cached_data->mbox_quoted_mb, cached_data->mbox_flags_store); return MAIL_NO_ERROR; } static int mboxdriver_cached_expunge_folder(mailsession * session) { struct mailmbox_folder * folder; int res; char filename_flags[PATH_MAX]; struct mail_cache_db * cache_db_flags; MMAPString * mmapstr; struct mbox_cached_session_state_data * data; int r; unsigned int i; folder = get_mbox_session(session); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } data = get_cached_data(session); if (data->mbox_quoted_mb == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } mbox_flags_store_process(data->mbox_flags_directory, data->mbox_quoted_mb, data->mbox_flags_store); snprintf(filename_flags, PATH_MAX, "%s%c%s%c%s", data->mbox_flags_directory, MAIL_DIR_SEPARATOR, data->mbox_quoted_mb, MAIL_DIR_SEPARATOR, 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->mb_tab) ; i ++) { struct mailmbox_msg_info * msg_info; struct mail_flags * flags; msg_info = carray_get(folder->mb_tab, i); if (msg_info == NULL) continue; if (msg_info->msg_deleted) continue; r = mboxdriver_get_cached_flags(cache_db_flags, mmapstr, session, msg_info->msg_uid, &flags); if (r != MAIL_NO_ERROR) continue; if (flags->fl_flags & MAIL_FLAG_DELETED) { r = mailmbox_delete_msg(folder, msg_info->msg_uid); } mail_flags_free(flags); } mmap_string_free(mmapstr); mail_cache_db_close_unlock(filename_flags, cache_db_flags); r = mailmbox_expunge(folder); return MAIL_NO_ERROR; close_db_flags: mail_cache_db_close_unlock(filename_flags, cache_db_flags); err: return res; } static int mboxdriver_cached_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { struct mailmbox_folder * folder; int res; char filename_flags[PATH_MAX]; struct mail_cache_db * cache_db_flags; MMAPString * mmapstr; struct mbox_cached_session_state_data * data; int r; unsigned int i; uint32_t recent; uint32_t unseen; uint32_t num; num = 0; recent = 0; unseen = 0; folder = get_mbox_session(session); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } data = get_cached_data(session); if (data->mbox_quoted_mb == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } r = mailmbox_validate_read_lock(folder); if (r != MAIL_NO_ERROR) { res = MAIL_ERROR_BAD_STATE; goto err; } mailmbox_read_unlock(folder); mbox_flags_store_process(data->mbox_flags_directory, data->mbox_quoted_mb, data->mbox_flags_store); snprintf(filename_flags, PATH_MAX, "%s%c%s%c%s", data->mbox_flags_directory, MAIL_DIR_SEPARATOR, data->mbox_quoted_mb, MAIL_DIR_SEPARATOR, 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->mb_tab) ; i ++) { struct mailmbox_msg_info * msg_info; struct mail_flags * flags; msg_info = carray_get(folder->mb_tab, i); if (msg_info == NULL) continue; if (msg_info->msg_deleted) continue; r = mboxdriver_get_cached_flags(cache_db_flags, mmapstr, session, msg_info->msg_uid, &flags); if (r != MAIL_NO_ERROR) { recent ++; unseen ++; num ++; continue; } if ((flags->fl_flags & MAIL_FLAG_NEW) != 0) { recent ++; } if ((flags->fl_flags & MAIL_FLAG_SEEN) == 0) { unseen ++; } num ++; mail_flags_free(flags); } mmap_string_free(mmapstr); mail_cache_db_close_unlock(filename_flags, cache_db_flags); * result_messages = num; * 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 mboxdriver_cached_messages_number(mailsession * session, char * mb, uint32_t * result) { return mailsession_messages_number(get_ancestor(session), mb, result); } static int mboxdriver_cached_recent_number(mailsession * session, char * mb, uint32_t * result) { uint32_t messages; uint32_t recent; uint32_t unseen; int r; r = mboxdriver_cached_status_folder(session, mb, &messages, &recent, &unseen); if (r != MAIL_NO_ERROR) return r; * result = recent; return MAIL_NO_ERROR; } static int mboxdriver_cached_unseen_number(mailsession * session, char * mb, uint32_t * result) { uint32_t messages; uint32_t recent; uint32_t unseen; int r; r = mboxdriver_cached_status_folder(session, mb, &messages, &recent, &unseen); if (r != MAIL_NO_ERROR) return r; * result = unseen; return MAIL_NO_ERROR; } /* messages operations */ static int mboxdriver_cached_append_message(mailsession * session, char * message, size_t size) { - return mailsession_append_message(get_ancestor(session), message, size); + return mboxdriver_cached_append_message_flags(session, + message, size, NULL); +} + +static int mboxdriver_cached_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags) +{ + int r; + struct mailmbox_folder * folder; + struct mbox_cached_session_state_data * data; + unsigned int uid; + struct mailmbox_msg_info * msg_info; + chashdatum key; + chashdatum value; + struct mail_cache_db * cache_db_flags; + char filename_flags[PATH_MAX]; + MMAPString * mmapstr; + char keyname[PATH_MAX]; + + folder = get_mbox_session(session); + if (folder == NULL) + return MAIL_ERROR_APPEND; + + r = mailmbox_append_message_uid(folder, message, size, &uid); + + switch (r) { + case MAILMBOX_ERROR_FILE: + return MAIL_ERROR_DISKSPACE; + case MAILMBOX_NO_ERROR: + break; + default: + return mboxdriver_mbox_error_to_mail_error(r); + } + + /* could store in flags store instead */ + + if (flags == NULL) + goto exit; + + key.data = &uid; + key.len = sizeof(uid); + r = chash_get(folder->mb_hash, &key, &value); + if (r < 0) + goto exit; + + msg_info = value.data; + + data = get_cached_data(session); + + snprintf(filename_flags, PATH_MAX, "%s%c%s%c%s", + data->mbox_flags_directory, MAIL_DIR_SEPARATOR, data->mbox_quoted_mb, + MAIL_DIR_SEPARATOR, 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", uid, + (unsigned long) msg_info->msg_body_len); + + r = mboxdriver_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 mboxdriver_cached_get_messages_list(mailsession * session, struct mailmessage_list ** result) { struct mailmbox_folder * folder; int res; folder = get_mbox_session(session); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } return mbox_get_uid_messages_list(folder, session, mbox_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 mailmbox_msg_info * info; struct mailmbox_folder * folder; chashdatum key; chashdatum data; folder = get_mbox_session(session); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } key.data = # key.len = sizeof(num); r = chash_get(folder->mb_hash, &key, &data); if (r < 0) { res = MAIL_ERROR_MSG_NOT_FOUND; goto err; } info = data.data; - snprintf(keyname, PATH_MAX, "%u-%u-envelope", num, info->msg_body_len); + snprintf(keyname, PATH_MAX, "%u-%lu-envelope", num, + (unsigned long) info->msg_body_len); 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 mailmbox_msg_info * info; struct mailmbox_folder * folder; chashdatum key; chashdatum data; folder = get_mbox_session(session); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } key.data = # key.len = sizeof(num); r = chash_get(folder->mb_hash, &key, &data); if (r < 0) { res = MAIL_ERROR_MSG_NOT_FOUND; goto err; } info = data.data; - snprintf(keyname, PATH_MAX, "%u-%u-envelope", num, info->msg_body_len); + snprintf(keyname, PATH_MAX, "%u-%lu-envelope", num, + (unsigned long) info->msg_body_len); 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 mboxdriver_cached_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list) { int r; unsigned int i; struct mbox_cached_session_state_data * cached_data; 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 mailmbox_folder * folder; folder = get_mbox_session(session); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } cached_data = get_cached_data(session); if (cached_data->mbox_quoted_mb == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } mbox_flags_store_process(cached_data->mbox_flags_directory, cached_data->mbox_quoted_mb, cached_data->mbox_flags_store); mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto err; } snprintf(filename_env, PATH_MAX, "%s%c%s%c%s", cached_data->mbox_cache_directory, MAIL_DIR_SEPARATOR, cached_data->mbox_quoted_mb, MAIL_DIR_SEPARATOR, 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%c%s%c%s", cached_data->mbox_flags_directory, MAIL_DIR_SEPARATOR, cached_data->mbox_quoted_mb, MAIL_DIR_SEPARATOR, FLAGS_NAME); r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_FILE; 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, session, msg->msg_index, &fields); if (r == MAIL_NO_ERROR) { msg->msg_cached = TRUE; msg->msg_fields = fields; } } if (msg->msg_flags == NULL) { r = mboxdriver_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; } /* 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(); } 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_FILE; goto close_db_env; } /* 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) { /* msg->msg_index is the numerical UID of the message */ r = write_cached_envelope(cache_db_env, mmapstr, session, msg->msg_index, msg->msg_fields); } } if (msg->msg_flags != NULL) { r = mboxdriver_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 mboxdriver_cached_remove_message(mailsession * session, uint32_t num) { return mailsession_remove_message(get_ancestor(session), num); } static int mboxdriver_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, mbox_cached_message_driver, num, 0); if (r != MAIL_NO_ERROR) { mailmessage_free(msg_info); return r; } * result = msg_info; return MAIL_NO_ERROR; } static int mboxdriver_cached_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result) { uint32_t num; char * p; chashdatum key; chashdatum data; struct mailmbox_msg_info * info; struct mailmbox_folder * folder; int r; if (uid == NULL) return MAIL_ERROR_INVAL; num = strtoul(uid, &p, 10); if (p == uid || * p != '-') return MAIL_ERROR_INVAL; folder = get_mbox_session(session); if (folder == NULL) return MAIL_ERROR_BAD_STATE; key.data = # key.len = sizeof(num); r = chash_get(folder->mb_hash, &key, &data); if (r == 0) { char * body_len_p = p + 1; size_t body_len; info = data.data; /* Check if the cached message has the same UID */ body_len = strtoul(body_len_p, &p, 10); if (p == body_len_p || * p != '\0') return MAIL_ERROR_INVAL; if (body_len == info->msg_body_len) return mboxdriver_cached_get_message(session, num, result); } return MAIL_ERROR_MSG_NOT_FOUND; } diff --git a/kmicromail/libetpan/generic/mboxdriver_cached_message.c b/kmicromail/libetpan/generic/mboxdriver_cached_message.c index 6d92b22..828396b 100644 --- a/kmicromail/libetpan/generic/mboxdriver_cached_message.c +++ b/kmicromail/libetpan/generic/mboxdriver_cached_message.c @@ -1,360 +1,361 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "mboxdriver_cached_message.h" #include "mailmessage_tools.h" #include "mboxdriver_tools.h" #include "mboxdriver_cached.h" #include "mboxdriver.h" #include "mailmbox.h" #include "mail_cache_db.h" #include "generic_cache.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 mbox_prefetch(mailmessage * msg_info); static void mbox_prefetch_free(struct generic_message_t * msg); static int mbox_initialize(mailmessage * msg_info); static void mbox_uninitialize(mailmessage * msg_info); static void mbox_flush(mailmessage * msg_info); static void mbox_check(mailmessage * msg_info); static int mbox_fetch_size(mailmessage * msg_info, size_t * result); static int mbox_get_flags(mailmessage * msg_info, struct mail_flags ** result); static int mbox_fetch_header(mailmessage * msg_info, char ** result, size_t * result_len); static mailmessage_driver local_mbox_cached_message_driver = { .msg_name = "mbox-cached", .msg_initialize = mbox_initialize, .msg_uninitialize = mbox_uninitialize, .msg_flush = mbox_flush, .msg_check = mbox_check, .msg_fetch_result_free = mailmessage_generic_fetch_result_free, .msg_fetch = mailmessage_generic_fetch, .msg_fetch_header = mbox_fetch_header, .msg_fetch_body = mailmessage_generic_fetch_body, .msg_fetch_size = mbox_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 = mbox_get_flags, }; mailmessage_driver * mbox_cached_message_driver = &local_mbox_cached_message_driver; static inline struct mbox_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)->mbox_ancestor; } static inline struct mbox_session_state_data * get_ancestor_session_data(mailmessage * msg) { return get_ancestor_session(msg)->sess_data; } static inline struct mailmbox_folder * get_mbox_session(mailmessage * msg) { return get_ancestor_session_data(msg)->mbox_folder; } static int mbox_prefetch(mailmessage * msg_info) { struct generic_message_t * msg; int r; char * msg_content; size_t msg_length; r = mboxdriver_fetch_msg(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 mbox_prefetch_free(struct generic_message_t * msg) { if (msg->msg_message != NULL) { mmap_string_unref(msg->msg_message); msg->msg_message = NULL; } } static int mbox_initialize(mailmessage * msg_info) { struct generic_message_t * msg; int r; char * uid; char static_uid[PATH_MAX]; struct mailmbox_msg_info * info; struct mailmbox_folder * folder; int res; chashdatum key; chashdatum data; folder = get_mbox_session(msg_info); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } key.data = (char *) &msg_info->msg_index; key.len = sizeof(msg_info->msg_index); r = chash_get(folder->mb_hash, &key, &data); if (r < 0) { res = MAIL_ERROR_MSG_NOT_FOUND; goto err; } info = (struct mailmbox_msg_info *) data.data; - snprintf(static_uid, PATH_MAX, "%u-%u", msg_info->msg_index, info->msg_body_len); + snprintf(static_uid, PATH_MAX, "%u-%lu", + msg_info->msg_index, (unsigned long) info->msg_body_len); uid = strdup(static_uid); if (uid == NULL) { res = MAIL_ERROR_MEMORY; goto err; } r = mailmessage_generic_initialize(msg_info); if (r != MAIL_NO_ERROR) { free(uid); res = r; goto err; } msg = msg_info->msg_data; msg->msg_prefetch = mbox_prefetch; msg->msg_prefetch_free = mbox_prefetch_free; msg_info->msg_uid = uid; return MAIL_NO_ERROR; err: return res; } static void mbox_uninitialize(mailmessage * msg_info) { mailmessage_generic_uninitialize(msg_info); } #define FLAGS_NAME "flags.db" static void mbox_flush(mailmessage * msg_info) { mailmessage_generic_flush(msg_info); } static void mbox_check(mailmessage * msg_info) { int r; if (msg_info->msg_flags != NULL) { r = mail_flags_store_set(get_cached_session_data(msg_info)->mbox_flags_store, msg_info); /* ignore errors */ } } static int mbox_fetch_size(mailmessage * msg_info, size_t * result) { int r; size_t size; r = mboxdriver_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 mbox_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 mbox_cached_session_state_data * cached_data; MMAPString * mmapstr; struct mailmbox_folder * folder; if (msg_info->msg_flags != NULL) { * result = msg_info->msg_flags; return MAIL_NO_ERROR; } flags = mail_flags_store_get(get_cached_session_data(msg_info)->mbox_flags_store, msg_info->msg_index); if (flags == NULL) { folder = get_mbox_session(msg_info); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } cached_data = get_cached_session_data(msg_info); if (cached_data->mbox_quoted_mb == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } snprintf(filename_flags, PATH_MAX, "%s/%s/%s", cached_data->mbox_flags_directory, cached_data->mbox_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; } if (msg_info->msg_index > folder->mb_written_uid) { flags = mail_flags_new_empty(); } else { r = mboxdriver_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 mbox_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 = mboxdriver_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/kmicromail/libetpan/generic/mboxdriver_message.c b/kmicromail/libetpan/generic/mboxdriver_message.c index da9a65d..6922625 100644 --- a/kmicromail/libetpan/generic/mboxdriver_message.c +++ b/kmicromail/libetpan/generic/mboxdriver_message.c @@ -1,225 +1,225 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ -#include "mhdriver_message.h" +#include "mboxdriver_message.h" #include "mailmessage_tools.h" #include "mboxdriver_tools.h" #include "mboxdriver.h" #include "mailmbox.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 mbox_prefetch(mailmessage * msg_info); static void mbox_prefetch_free(struct generic_message_t * msg); static int mbox_initialize(mailmessage * msg_info); static int mbox_fetch_size(mailmessage * msg_info, size_t * result); static int mbox_fetch_header(mailmessage * msg_info, char ** result, size_t * result_len); static mailmessage_driver local_mbox_message_driver = { .msg_name = "mbox", .msg_initialize = mbox_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 = mbox_fetch_header, .msg_fetch_body = mailmessage_generic_fetch_body, .msg_fetch_size = mbox_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 * mbox_message_driver = &local_mbox_message_driver; static inline struct mbox_session_state_data * get_data(mailmessage * msg) { return msg->msg_session->sess_data; } static inline struct mailmbox_folder * get_mbox_session(mailmessage * msg) { return get_data(msg)->mbox_folder; } static int mbox_prefetch(mailmessage * msg_info) { struct generic_message_t * msg; int r; char * msg_content; size_t msg_length; r = mboxdriver_fetch_msg(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 mbox_prefetch_free(struct generic_message_t * msg) { if (msg->msg_message != NULL) { mmap_string_unref(msg->msg_message); msg->msg_message = NULL; } } static int mbox_initialize(mailmessage * msg_info) { struct generic_message_t * msg; int r; char * uid; char static_uid[PATH_MAX]; struct mailmbox_msg_info * info; struct mailmbox_folder * folder; int res; chashdatum key; chashdatum data; folder = get_mbox_session(msg_info); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } key.data = &msg_info->msg_index; key.len = sizeof(msg_info->msg_index); r = chash_get(folder->mb_hash, &key, &data); if (r < 0) { res = MAIL_ERROR_MSG_NOT_FOUND; goto err; } info = data.data; - snprintf(static_uid, PATH_MAX, "%u-%u", - msg_info->msg_index, info->msg_body_len); + snprintf(static_uid, PATH_MAX, "%u-%lu", + msg_info->msg_index, (unsigned long) info->msg_body_len); uid = strdup(static_uid); if (uid == NULL) { res = MAIL_ERROR_MEMORY; goto err; } r = mailmessage_generic_initialize(msg_info); if (r != MAIL_NO_ERROR) { free(uid); res = r; goto err; } msg = msg_info->msg_data; msg->msg_prefetch = mbox_prefetch; msg->msg_prefetch_free = mbox_prefetch_free; msg_info->msg_uid = uid; return MAIL_NO_ERROR; err: return res; } static int mbox_fetch_size(mailmessage * msg_info, size_t * result) { int r; size_t size; r = mboxdriver_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 mbox_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 = mboxdriver_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/kmicromail/libetpan/generic/mboxdriver_tools.c b/kmicromail/libetpan/generic/mboxdriver_tools.c index 1e27798..252a20b 100644 --- a/kmicromail/libetpan/generic/mboxdriver_tools.c +++ b/kmicromail/libetpan/generic/mboxdriver_tools.c @@ -1,434 +1,435 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "mboxdriver_tools.h" #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include "maildriver_types.h" #include "mailmbox.h" #include "mboxdriver_cached.h" #include "mboxdriver.h" #include "generic_cache.h" #include "mailmessage.h" #include "imfcache.h" #include "mail_cache_db.h" static inline struct mbox_session_state_data * session_get_data(mailsession * session) { return session->sess_data; } static inline struct mailmbox_folder * session_get_mbox_session(mailsession * session) { return session_get_data(session)->mbox_folder; } static inline struct mbox_cached_session_state_data * cached_session_get_data(mailsession * session) { return session->sess_data; } static inline mailsession * cached_session_get_ancestor(mailsession * session) { return cached_session_get_data(session)->mbox_ancestor; } static inline struct mbox_session_state_data * cached_session_get_ancestor_data(mailsession * session) { return cached_session_get_ancestor(session)->sess_data; } static inline struct mailmbox_folder * cached_session_get_mbox_session(mailsession * session) { return session_get_mbox_session(cached_session_get_ancestor(session)); } int mboxdriver_mbox_error_to_mail_error(int error) { switch (error) { case MAILMBOX_NO_ERROR: return MAIL_NO_ERROR; case MAILMBOX_ERROR_PARSE: return MAIL_ERROR_PARSE; case MAILMBOX_ERROR_INVAL: return MAIL_ERROR_INVAL; case MAILMBOX_ERROR_FILE_NOT_FOUND: return MAIL_ERROR_PARSE; case MAILMBOX_ERROR_MEMORY: return MAIL_ERROR_MEMORY; case MAILMBOX_ERROR_TEMPORARY_FILE: return MAIL_ERROR_PARSE; case MAILMBOX_ERROR_FILE: return MAIL_ERROR_FILE; case MAILMBOX_ERROR_MSG_NOT_FOUND: return MAIL_ERROR_MSG_NOT_FOUND; case MAILMBOX_ERROR_READONLY: return MAIL_ERROR_READONLY; default: return MAIL_ERROR_INVAL; } } int mboxdriver_fetch_msg(mailsession * session, uint32_t index, char ** result, size_t * result_len) { int r; char * msg_content; size_t msg_length; struct mailmbox_folder * folder; folder = session_get_mbox_session(session); if (folder == NULL) return MAIL_ERROR_BAD_STATE; r = mailmbox_fetch_msg(folder, index, &msg_content, &msg_length); if (r != MAILMBOX_NO_ERROR) return mboxdriver_mbox_error_to_mail_error(r); * result = msg_content; * result_len = msg_length; return MAIL_NO_ERROR; } int mboxdriver_fetch_size(mailsession * session, uint32_t index, size_t * result) { struct mailmbox_folder * folder; int r; char * data; size_t len; int res; folder = session_get_mbox_session(session); if (folder == NULL) { res = MAIL_ERROR_FETCH; goto err; } r = mailmbox_validate_read_lock(folder); if (r != MAILMBOX_NO_ERROR) { res = mboxdriver_mbox_error_to_mail_error(r); goto err; } r = mailmbox_fetch_msg_no_lock(folder, index, &data, &len); if (r != MAILMBOX_NO_ERROR) { res = mboxdriver_mbox_error_to_mail_error(r); goto unlock; } mailmbox_read_unlock(folder); * result = len; return MAIL_NO_ERROR; unlock: mailmbox_read_unlock(folder); err: return res; } int mboxdriver_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 mailmbox_msg_info * info; struct mailmbox_folder * folder; chashdatum key; chashdatum data; folder = cached_session_get_mbox_session(session); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } key.data = # key.len = sizeof(num); r = chash_get(folder->mb_hash, &key, &data); if (r < 0) { res = MAIL_ERROR_MSG_NOT_FOUND; goto err; } info = data.data; - snprintf(keyname, PATH_MAX, "%u-%u-flags", num, info->msg_body_len); + snprintf(keyname, PATH_MAX, "%u-%lu-flags", num, + (unsigned long) info->msg_body_len); 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 mboxdriver_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 mboxdriver_fetch_header(mailsession * session, uint32_t index, char ** result, size_t * result_len) { int r; char * msg_content; size_t msg_length; struct mailmbox_folder * folder; folder = session_get_mbox_session(session); if (folder == NULL) return MAIL_ERROR_BAD_STATE; r = mailmbox_fetch_msg_headers(folder, index, &msg_content, &msg_length); if (r != MAILMBOX_NO_ERROR) return mboxdriver_mbox_error_to_mail_error(r); * result = msg_content; * result_len = msg_length; return MAIL_NO_ERROR; } int mbox_get_locked_messages_list(struct mailmbox_folder * folder, mailsession * session, mailmessage_driver * driver, int (* lock)(struct mailmbox_folder *), int (* unlock)(struct mailmbox_folder *), struct mailmessage_list ** result) { struct mailmessage_list * env_list; unsigned int i; int r; int res; carray * tab; tab = carray_new(128); if (tab == NULL) { res = MAIL_ERROR_MEMORY; goto err; } r = lock(folder); if (r != MAIL_NO_ERROR) { res = r; goto free; } for(i = 0 ; i < carray_count(folder->mb_tab) ; i ++) { struct mailmbox_msg_info * msg_info; mailmessage * msg; msg_info = carray_get(folder->mb_tab, i); if (msg_info == NULL) continue; if (msg_info->msg_deleted) continue; msg = mailmessage_new(); if (msg == NULL) { res = MAIL_ERROR_MEMORY; goto unlock; } r = mailmessage_init(msg, session, driver, msg_info->msg_uid, msg_info->msg_size - msg_info->msg_start_len); if (r != MAIL_NO_ERROR) { res = r; goto unlock; } r = carray_add(tab, msg, NULL); if (r < 0) { mailmessage_free(msg); res = MAIL_ERROR_MEMORY; goto unlock; } } env_list = mailmessage_list_new(tab); if (env_list == NULL) { res = MAIL_ERROR_MEMORY; goto unlock; } unlock(folder); * result = env_list; return MAIL_NO_ERROR; unlock: unlock(folder); free: for(i = 0 ; i < carray_count(tab) ; i ++) mailmessage_free(carray_get(tab, i)); carray_free(tab); err: return res; } static int release_read_mbox(struct mailmbox_folder * folder) { int r; r = mailmbox_read_unlock(folder); return mboxdriver_mbox_error_to_mail_error(r); } static int acquire_read_mbox(struct mailmbox_folder * folder) { int r; r = mailmbox_validate_read_lock(folder); return mboxdriver_mbox_error_to_mail_error(r); } static int release_write_mbox(struct mailmbox_folder * folder) { int r; r = mailmbox_write_unlock(folder); return mboxdriver_mbox_error_to_mail_error(r); } static int acquire_write_mbox(struct mailmbox_folder * folder) { int r; int res; r = mailmbox_validate_write_lock(folder); if (r != MAILMBOX_NO_ERROR) { res = mboxdriver_mbox_error_to_mail_error(r); goto err; } if (folder->mb_written_uid < folder->mb_max_uid) { r = mailmbox_expunge_no_lock(folder); if (r != MAILMBOX_NO_ERROR) { res = mboxdriver_mbox_error_to_mail_error(r); goto unlock; } } return MAIL_NO_ERROR; unlock: mailmbox_write_unlock(folder); err: return res; } /* get message list with all valid written UID */ int mbox_get_uid_messages_list(struct mailmbox_folder * folder, mailsession * session, mailmessage_driver * driver, struct mailmessage_list ** result) { return mbox_get_locked_messages_list(folder, session, driver, acquire_write_mbox, release_write_mbox, result); } /* get message list */ int mbox_get_messages_list(struct mailmbox_folder * folder, mailsession * session, mailmessage_driver * driver, struct mailmessage_list ** result) { return mbox_get_locked_messages_list(folder, session, driver, acquire_read_mbox, release_read_mbox, result); } diff --git a/kmicromail/libetpan/generic/mboxstorage.c b/kmicromail/libetpan/generic/mboxstorage.c index 0a7dc93..4b55b2b 100644 --- a/kmicromail/libetpan/generic/mboxstorage.c +++ b/kmicromail/libetpan/generic/mboxstorage.c @@ -1,192 +1,192 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "mboxstorage.h" #include "mail.h" #include "mailmessage.h" #include "mboxdriver.h" #include "mboxdriver_cached.h" #include "maildriver.h" #include <stdlib.h> #include <string.h> /* mbox storage */ static int mbox_mailstorage_connect(struct mailstorage * storage); static int mbox_mailstorage_get_folder_session(struct mailstorage * storage, char * pathname, mailsession ** result); static void mbox_mailstorage_uninitialize(struct mailstorage * storage); static mailstorage_driver mbox_mailstorage_driver = { .sto_name = "mbox", .sto_connect = mbox_mailstorage_connect, .sto_get_folder_session = mbox_mailstorage_get_folder_session, .sto_uninitialize = mbox_mailstorage_uninitialize, }; int mbox_mailstorage_init(struct mailstorage * storage, char * mbox_pathname, int mbox_cached, char * mbox_cache_directory, char * mbox_flags_directory) { struct mbox_mailstorage * mbox_storage; - mbox_storage = malloc(sizeof(struct mbox_mailstorage)); + mbox_storage = malloc(sizeof(* mbox_storage)); if (mbox_storage == NULL) goto err; mbox_storage->mbox_pathname = strdup(mbox_pathname); if (mbox_storage->mbox_pathname == NULL) goto free; mbox_storage->mbox_cached = mbox_cached; if (mbox_cached && (mbox_cache_directory != NULL) && (mbox_flags_directory != NULL)) { mbox_storage->mbox_cache_directory = strdup(mbox_cache_directory); if (mbox_storage->mbox_cache_directory == NULL) goto free_pathname; mbox_storage->mbox_flags_directory = strdup(mbox_flags_directory); if (mbox_storage->mbox_flags_directory == NULL) goto free_cache_directory; } else { mbox_storage->mbox_cached = FALSE; mbox_storage->mbox_cache_directory = NULL; mbox_storage->mbox_flags_directory = NULL; } storage->sto_data = mbox_storage; storage->sto_driver = &mbox_mailstorage_driver; return MAIL_NO_ERROR; free_cache_directory: free(mbox_storage->mbox_cache_directory); free_pathname: free(mbox_storage->mbox_pathname); free: free(mbox_storage); err: return MAIL_ERROR_MEMORY; } static void mbox_mailstorage_uninitialize(struct mailstorage * storage) { struct mbox_mailstorage * mbox_storage; mbox_storage = storage->sto_data; if (mbox_storage->mbox_flags_directory != NULL) free(mbox_storage->mbox_flags_directory); if (mbox_storage->mbox_cache_directory != NULL) free(mbox_storage->mbox_cache_directory); free(mbox_storage->mbox_pathname); free(mbox_storage); storage->sto_data = NULL; } static int mbox_mailstorage_connect(struct mailstorage * storage) { struct mbox_mailstorage * mbox_storage; mailsession_driver * driver; int r; int res; mailsession * session; mbox_storage = storage->sto_data; if (mbox_storage->mbox_cached) driver = mbox_cached_session_driver; else driver = mbox_session_driver; session = mailsession_new(driver); if (session == NULL) { res = MAIL_ERROR_MEMORY; goto err; } if (mbox_storage->mbox_cached) { r = mailsession_parameters(session, MBOXDRIVER_CACHED_SET_CACHE_DIRECTORY, mbox_storage->mbox_cache_directory); if (r != MAIL_NO_ERROR) { res = r; goto free; } r = mailsession_parameters(session, MBOXDRIVER_CACHED_SET_FLAGS_DIRECTORY, mbox_storage->mbox_flags_directory); if (r != MAIL_NO_ERROR) { res = r; goto free; } } r = mailsession_connect_path(session, mbox_storage->mbox_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 mbox_mailstorage_get_folder_session(struct mailstorage * storage, char * pathname, mailsession ** result) { * result = storage->sto_session; return MAIL_NO_ERROR; } diff --git a/kmicromail/libetpan/generic/mhdriver.c b/kmicromail/libetpan/generic/mhdriver.c index af38d27..05a6a4f 100644 --- a/kmicromail/libetpan/generic/mhdriver.c +++ b/kmicromail/libetpan/generic/mhdriver.c @@ -1,866 +1,875 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "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 = 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/kmicromail/libetpan/generic/mhdriver_cached.c b/kmicromail/libetpan/generic/mhdriver_cached.c index 5c35089..04aa523 100644 --- a/kmicromail/libetpan/generic/mhdriver_cached.c +++ b/kmicromail/libetpan/generic/mhdriver_cached.c @@ -1,1232 +1,1315 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "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 mailsession_append_message(get_ancestor(session), message, 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-%u-%u-envelope", - num, (uint32_t) msg_info->msg_mtime, msg_info->msg_size); + 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-%u-%u-envelope", - num, (uint32_t) msg_info->msg_mtime, msg_info->msg_size); + 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/kmicromail/libetpan/generic/mhdriver_cached_message.c b/kmicromail/libetpan/generic/mhdriver_cached_message.c index f716fb9..f69868d 100644 --- a/kmicromail/libetpan/generic/mhdriver_cached_message.c +++ b/kmicromail/libetpan/generic/mhdriver_cached_message.c @@ -1,338 +1,338 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "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-%u", msg_info->msg_index, - mh_msg_info->msg_mtime, mh_msg_info->msg_size); + 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/kmicromail/libetpan/generic/mhdriver_message.c b/kmicromail/libetpan/generic/mhdriver_message.c index 2c023e7..aafd2d9 100644 --- a/kmicromail/libetpan/generic/mhdriver_message.c +++ b/kmicromail/libetpan/generic/mhdriver_message.c @@ -1,212 +1,213 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "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-%u", msg_info->msg_index, - mh_msg_info->msg_mtime, mh_msg_info->msg_size); + 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/kmicromail/libetpan/generic/mhdriver_tools.c b/kmicromail/libetpan/generic/mhdriver_tools.c index cb863fa..c15bb6d 100644 --- a/kmicromail/libetpan/generic/mhdriver_tools.c +++ b/kmicromail/libetpan/generic/mhdriver_tools.c @@ -1,475 +1,476 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "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_NO_ERROR; 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, size) == 0) { cur_token += 5; while (str[cur_token] != '\n') { 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, size) == 0) { cur_token += 5; while (str[cur_token] != '\n') { 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-%u-%u-flags", - num, (uint32_t) msg_info->msg_mtime, msg_info->msg_size); + 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/kmicromail/libetpan/generic/mhstorage.c b/kmicromail/libetpan/generic/mhstorage.c index 32fc26b..715b961 100644 --- a/kmicromail/libetpan/generic/mhstorage.c +++ b/kmicromail/libetpan/generic/mhstorage.c @@ -1,192 +1,192 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "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(struct mh_mailstorage)); + 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/kmicromail/libetpan/generic/nntpdriver.c b/kmicromail/libetpan/generic/nntpdriver.c index fde5f1a..1b65838 100644 --- a/kmicromail/libetpan/generic/nntpdriver.c +++ b/kmicromail/libetpan/generic/nntpdriver.c @@ -1,1170 +1,1180 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "nntpdriver.h" #include <string.h> #include <stdlib.h> #include "mail.h" #include "mailmessage.h" #include "nntpdriver_tools.h" #include "maildriver_tools.h" #include "nntpdriver_message.h" static int nntpdriver_initialize(mailsession * session); static void nntpdriver_uninitialize(mailsession * session); static int nntpdriver_parameters(mailsession * session, int id, void * value); static int nntpdriver_connect_stream(mailsession * session, mailstream * s); static int nntpdriver_login(mailsession * session, char * userid, char * password); static int nntpdriver_logout(mailsession * session); static int nntpdriver_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); static int nntpdriver_messages_number(mailsession * session, char * mb, uint32_t * result); static int nntpdriver_append_message(mailsession * session, char * message, size_t size); +static int nntpdriver_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags); + static int nntpdriver_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list); static int nntpdriver_get_messages_list(mailsession * session, struct mailmessage_list ** result); static int nntpdriver_list_folders(mailsession * session, char * mb, struct mail_list ** result); static int nntpdriver_lsub_folders(mailsession * session, char * mb, struct mail_list ** result); static int nntpdriver_subscribe_folder(mailsession * session, char * mb); static int nntpdriver_unsubscribe_folder(mailsession * session, char * mb); static int nntpdriver_get_message(mailsession * session, uint32_t num, mailmessage ** result); static int nntpdriver_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result); static int nntpdriver_noop(mailsession * session); static mailsession_driver local_nntp_session_driver = { .sess_name = "nntp", .sess_initialize = nntpdriver_initialize, .sess_uninitialize = nntpdriver_uninitialize, .sess_parameters = nntpdriver_parameters, .sess_connect_stream = nntpdriver_connect_stream, .sess_connect_path = NULL, .sess_starttls = NULL, .sess_login = nntpdriver_login, .sess_logout = nntpdriver_logout, .sess_noop = nntpdriver_noop, .sess_build_folder_name = NULL, .sess_create_folder = NULL, .sess_delete_folder = NULL, .sess_rename_folder = NULL, .sess_check_folder = NULL, .sess_examine_folder = NULL, .sess_select_folder = nntpdriver_select_folder, .sess_expunge_folder = NULL, .sess_status_folder = nntpdriver_status_folder, .sess_messages_number = nntpdriver_messages_number, .sess_recent_number = nntpdriver_messages_number, .sess_unseen_number = nntpdriver_messages_number, .sess_list_folders = nntpdriver_list_folders, .sess_lsub_folders = nntpdriver_lsub_folders, .sess_subscribe_folder = nntpdriver_subscribe_folder, .sess_unsubscribe_folder = nntpdriver_unsubscribe_folder, .sess_append_message = nntpdriver_append_message, + .sess_append_message_flags = nntpdriver_append_message_flags, .sess_copy_message = NULL, .sess_move_message = NULL, .sess_get_messages_list = nntpdriver_get_messages_list, .sess_get_envelopes_list = nntpdriver_get_envelopes_list, .sess_remove_message = NULL, #if 0 .sess_search_messages = maildriver_generic_search_messages, #endif .sess_get_message = nntpdriver_get_message, .sess_get_message_by_uid = nntpdriver_get_message_by_uid, }; mailsession_driver * nntp_session_driver = &local_nntp_session_driver; static inline struct nntp_session_state_data * get_data(mailsession * session) { return session->sess_data; } static inline newsnntp * get_nntp_session(mailsession * session) { return get_data(session)->nntp_session; } static int nntpdriver_initialize(mailsession * session) { struct nntp_session_state_data * data; newsnntp * nntp; nntp = newsnntp_new(0, NULL); if (nntp == NULL) goto err; data = malloc(sizeof(* data)); if (data == NULL) goto free; data->nntp_session = nntp; data->nntp_userid = NULL; data->nntp_password = NULL; data->nntp_group_info = NULL; data->nntp_group_name = NULL; data->nntp_subscribed_list = clist_new(); if (data->nntp_subscribed_list == NULL) goto free_data; data->nntp_max_articles = 0; data->nntp_mode_reader = FALSE; session->sess_data = data; return MAIL_NO_ERROR; free_data: free(data); free: newsnntp_free(nntp); err: return MAIL_ERROR_MEMORY; } static void nntpdriver_uninitialize(mailsession * session) { struct nntp_session_state_data * data; data = get_data(session); clist_foreach(data->nntp_subscribed_list, (clist_func) free, NULL); clist_free(data->nntp_subscribed_list); if (data->nntp_group_info != NULL) newsnntp_group_free(data->nntp_group_info); if (data->nntp_group_name != NULL) free(data->nntp_group_name); if (data->nntp_userid != NULL) free(data->nntp_userid); if (data->nntp_password != NULL) free(data->nntp_password); newsnntp_free(data->nntp_session); free(data); session->sess_data = NULL; } static int nntpdriver_parameters(mailsession * session, int id, void * value) { struct nntp_session_state_data * data; data = get_data(session); switch (id) { case NNTPDRIVER_SET_MAX_ARTICLES: { uint32_t * param; param = value; data->nntp_max_articles = * param; return MAIL_NO_ERROR; } } return MAIL_ERROR_INVAL; } static int add_to_list(mailsession * session, char * mb) { char * new_mb; int r; struct nntp_session_state_data * data; data = get_data(session); new_mb = strdup(mb); if (new_mb == NULL) return -1; r = clist_append(data->nntp_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 nntp_session_state_data * data; data = get_data(session); for(cur = clist_begin(data->nntp_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->nntp_subscribed_list, cur); free(cur_name); return 0; } } return -1; } static int nntpdriver_connect_stream(mailsession * session, mailstream * s) { int r; r = newsnntp_connect(get_nntp_session(session), s); switch (r) { case NEWSNNTP_NO_ERROR: return MAIL_NO_ERROR_NON_AUTHENTICATED; default: return nntpdriver_nntp_error_to_mail_error(r); } } static int nntpdriver_login(mailsession * session, char * userid, char * password) { struct nntp_session_state_data * data; char * new_userid; char * new_password; data = get_data(session); if (userid != NULL) { new_userid = strdup(userid); if (new_userid == NULL) goto err; } else new_userid = NULL; if (password != NULL) { new_password = strdup(password); if (new_password == NULL) goto free_uid; } else new_password = NULL; data->nntp_userid = new_userid; data->nntp_password = new_password; return MAIL_NO_ERROR; free_uid: if (new_userid != NULL) free(new_userid); err: return MAIL_ERROR_MEMORY; } static int nntpdriver_logout(mailsession * session) { int r; r = newsnntp_quit(get_nntp_session(session)); return nntpdriver_nntp_error_to_mail_error(r); } static int nntpdriver_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { uint32_t count; int r; r = nntpdriver_select_folder(session, mb); if (r != MAIL_NO_ERROR) return r; r = nntpdriver_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 nntpdriver_messages_number(mailsession * session, char * mb, uint32_t * result) { int r; struct nntp_session_state_data * data; if (mb != NULL) { r = nntpdriver_select_folder(session, mb); if (r != MAIL_NO_ERROR) return r; } data = get_data(session); if (data->nntp_group_info == NULL) return MAIL_ERROR_FOLDER_NOT_FOUND; * result = data->nntp_group_info->grp_last - data->nntp_group_info->grp_first + 1; return MAIL_NO_ERROR; } static int nntpdriver_list_folders(mailsession * session, char * mb, struct mail_list ** result) { int r; clist * group_list; newsnntp * nntp; clistiter * cur; char * new_mb; int done; clist * list; struct mail_list * ml; int res; nntp = get_nntp_session(session); new_mb = NULL; if ((mb != NULL) && (*mb != '\0')) { new_mb = malloc(strlen(mb) + 3); if (new_mb == NULL) { res = MAIL_ERROR_MEMORY; goto err; } strcpy(new_mb, mb); strcat(new_mb, ".*"); } done = FALSE; do { if (new_mb != NULL) r = newsnntp_list_active(nntp, new_mb, &group_list); else r = newsnntp_list(nntp, &group_list); switch (r) { case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME: r = nntpdriver_authenticate_user(session); if (r != MAIL_NO_ERROR) { res = r; goto err; } break; case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD: r = nntpdriver_authenticate_password(session); if (r != MAIL_NO_ERROR) { res = r; goto err; } break; case NEWSNNTP_NO_ERROR: if (new_mb != NULL) free(new_mb); done = TRUE; break; default: if (new_mb != NULL) free(new_mb); return nntpdriver_nntp_error_to_mail_error(r); } } while (!done); list = clist_new(); if (list == NULL) { res = MAIL_ERROR_MEMORY; goto err; } for(cur = clist_begin(group_list) ; cur != NULL ; cur = clist_next(cur)) { struct newsnntp_group_info * info; char * new_name; info = clist_content(cur); new_name = strdup(info->grp_name); if (new_name == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, new_name); if (r < 0) { free(new_name); res = MAIL_ERROR_MEMORY; goto free_list; } } ml = mail_list_new(list); if (ml == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } newsnntp_list_free(group_list); * result = ml; return MAIL_NO_ERROR; free_list: clist_foreach(list, (clist_func) free, NULL); clist_free(list); newsnntp_list_free(group_list); err: return res; } static int nntpdriver_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 res; int r; struct nntp_session_state_data * data; length = strlen(mb); data = get_data(session); subscribed = data->nntp_subscribed_list; lsub_result = clist_new(); if (lsub_result == NULL) { res = MAIL_ERROR_MEMORY; goto err; } 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) { res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(lsub_result, new_mb); if (r < 0) { free(new_mb); res = MAIL_ERROR_MEMORY; goto free_list; } } } lsub = mail_list_new(lsub_result); if (lsub == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } * result = lsub; return MAIL_NO_ERROR; free_list: clist_foreach(lsub_result, (clist_func) free, NULL); clist_free(lsub_result); err: return res; } static int nntpdriver_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 nntpdriver_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 nntpdriver_append_message(mailsession * session, char * message, size_t size) { int r; struct nntp_session_state_data * data; data = get_data(session); do { r = newsnntp_post(get_nntp_session(session), message, size); switch (r) { case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME: r = nntpdriver_authenticate_user(session); if (r != MAIL_NO_ERROR) return r; break; case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD: r = nntpdriver_authenticate_password(session); if (r != MAIL_NO_ERROR) return r; break; default: return nntpdriver_nntp_error_to_mail_error(r); } } while (1); } +static int nntpdriver_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags) +{ + return nntpdriver_append_message(session, message, size); +} + static int xover_resp_to_fields(struct newsnntp_xover_resp_item * item, struct mailimf_fields ** result); static int nntpdriver_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list) { newsnntp * nntp; int r; struct nntp_session_state_data * data; clist * list; int done; clistiter * cur; uint32_t first_seq; unsigned int i; nntp = get_nntp_session(session); data = get_data(session); if (data->nntp_group_info == NULL) return MAIL_ERROR_BAD_STATE; first_seq = data->nntp_group_info->grp_first; if (carray_count(env_list->msg_tab) > 0) { mailmessage * msg; msg = carray_get(env_list->msg_tab, 0); first_seq = msg->msg_index; } if (carray_count(env_list->msg_tab) > 0) { i = carray_count(env_list->msg_tab) - 1; while (1) { mailmessage * msg; msg = carray_get(env_list->msg_tab, i); if (msg->msg_fields != NULL) { first_seq = msg->msg_index + 1; break; } if (i == 0) break; i --; } } if (first_seq > data->nntp_group_info->grp_last) { list = NULL; } else { done = FALSE; do { r = newsnntp_xover_range(nntp, first_seq, data->nntp_group_info->grp_last, &list); switch (r) { case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME: r = nntpdriver_authenticate_user(session); if (r != MAIL_NO_ERROR) return r; break; case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD: r = nntpdriver_authenticate_password(session); if (r != MAIL_NO_ERROR) return r; break; case NEWSNNTP_NO_ERROR: done = TRUE; break; default: return nntpdriver_nntp_error_to_mail_error(r); } } while (!done); } #if 0 i = 0; j = 0; if (list != NULL) { for(cur = clist_begin(list) ; cur != NULL ; cur = clist_next(cur)) { struct newsnntp_xover_resp_item * item; struct mailimf_fields * fields; item = clist_content(cur); while (i < carray_count(env_list->msg_tab)) { mailmessage * info; info = carray_get(env_list->msg_tab, i); if (item->ovr_article == info->msg_index) { if (info->fields == NULL) { r = xover_resp_to_fields(item, &fields); if (r == MAIL_NO_ERROR) { info->fields = fields; } info->size = item->ovr_size; carray_set(env_list->msg_tab, j, info); j ++; i ++; break; } else { carray_set(env_list->msg_tab, j, info); j ++; } } else { if (info->fields != NULL) { carray_set(env_list->msg_tab, j, info); j ++; } else { if (info->flags != NULL) { info->flags->flags &= ~MAIL_FLAG_NEW; info->flags->flags |= MAIL_FLAG_SEEN | MAIL_FLAG_DELETED; mailmessage_check(info); } mailmessage_free(info); carray_set(env_list->msg_tab, i, NULL); } } i ++; } } } while (i < carray_count(env_list->msg_tab)) { mailmessage * info; info = carray_get(env_list->msg_tab, i); if (info->fields != NULL) { carray_set(env_list->msg_tab, j, info); j ++; } else { if (info->flags != NULL) { info->flags->flags &= ~MAIL_FLAG_NEW; info->flags->flags |= MAIL_FLAG_SEEN | MAIL_FLAG_DELETED; mailmessage_check(info); } mailmessage_free(info); carray_set(env_list->msg_tab, i, NULL); } i ++; } r = carray_set_size(env_list->msg_tab, j); if (r < 0) { if (list != NULL) newsnntp_xover_resp_list_free(list); return MAIL_ERROR_MEMORY; } #endif i = 0; if (list != NULL) { for(cur = clist_begin(list) ; cur != NULL ; cur = clist_next(cur)) { struct newsnntp_xover_resp_item * item; struct mailimf_fields * fields; item = clist_content(cur); while (i < carray_count(env_list->msg_tab)) { mailmessage * info; info = carray_get(env_list->msg_tab, i); if (item->ovr_article == info->msg_index) { if (info->msg_fields == NULL) { r = xover_resp_to_fields(item, &fields); if (r == MAIL_NO_ERROR) { info->msg_fields = fields; } info->msg_size = item->ovr_size; i ++; break; } } #if 0 else if ((info->fields == NULL) && (info->flags != NULL)) { info->flags->flags &= ~MAIL_FLAG_NEW; info->flags->flags |= MAIL_FLAG_CANCELLED; mailmessage_check(info); } #endif i ++; } } } #if 0 while (i < env_list->msg_tab->len) { mailmessage * info; info = carray_get(env_list->msg_tab, i); if ((info->fields == NULL) && (info->flags != NULL)) { info->flags->flags &= ~MAIL_FLAG_NEW; info->flags->flags |= MAIL_FLAG_CANCELLED; mailmessage_check(info); } i ++; } #endif if (list != NULL) newsnntp_xover_resp_list_free(list); return MAIL_NO_ERROR; } static int xover_resp_to_fields(struct newsnntp_xover_resp_item * item, struct mailimf_fields ** result) { size_t cur_token; clist * list; int r; struct mailimf_fields * fields; int res; list = clist_new(); if (list == NULL) { res = MAIL_ERROR_MEMORY; goto err; } if (item->ovr_subject != NULL) { char * subject_str; struct mailimf_subject * subject; struct mailimf_field * field; subject_str = strdup(item->ovr_subject); if (subject_str == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } subject = mailimf_subject_new(subject_str); if (subject == NULL) { free(subject_str); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_SUBJECT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, subject, NULL, NULL, NULL); if (field == NULL) { mailimf_subject_free(subject); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r < 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } } if (item->ovr_author != NULL) { struct mailimf_mailbox_list * mb_list; struct mailimf_from * from; struct mailimf_field * field; cur_token = 0; r = mailimf_mailbox_list_parse(item->ovr_author, strlen(item->ovr_author), &cur_token, &mb_list); switch (r) { case MAILIMF_NO_ERROR: from = mailimf_from_new(mb_list); if (from == NULL) { mailimf_mailbox_list_free(mb_list); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_FROM, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, from, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (field == NULL) { mailimf_from_free(from); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r < 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } break; case MAILIMF_ERROR_PARSE: break; default: res = maildriver_imf_error_to_mail_error(r); goto free_list; } } if (item->ovr_date != NULL) { struct mailimf_date_time * date_time; struct mailimf_orig_date * orig_date; struct mailimf_field * field; cur_token = 0; r = mailimf_date_time_parse(item->ovr_date, strlen(item->ovr_date), &cur_token, &date_time); switch (r) { case MAILIMF_NO_ERROR: orig_date = mailimf_orig_date_new(date_time); if (orig_date == NULL) { mailimf_date_time_free(date_time); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_ORIG_DATE, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, orig_date, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (field == NULL) { mailimf_orig_date_free(orig_date); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r < 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } break; case MAILIMF_ERROR_PARSE: break; default: res = maildriver_imf_error_to_mail_error(r); goto free_list; } } if (item->ovr_message_id != NULL) { char * msgid_str; struct mailimf_message_id * msgid; struct mailimf_field * field; cur_token = 0; r = mailimf_msg_id_parse(item->ovr_message_id, strlen(item->ovr_message_id), &cur_token, &msgid_str); switch (r) { case MAILIMF_NO_ERROR: msgid = mailimf_message_id_new(msgid_str); if (msgid == NULL) { mailimf_msg_id_free(msgid_str); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_MESSAGE_ID, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, msgid, NULL, NULL, NULL, NULL, NULL, NULL); r = clist_append(list, field); if (r < 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } break; case MAILIMF_ERROR_PARSE: break; default: res = maildriver_imf_error_to_mail_error(r); goto free_list; } } if (item->ovr_references != NULL) { clist * msgid_list; struct mailimf_references * references; struct mailimf_field * field; cur_token = 0; r = mailimf_msg_id_list_parse(item->ovr_references, strlen(item->ovr_references), &cur_token, &msgid_list); switch (r) { case MAILIMF_NO_ERROR: references = mailimf_references_new(msgid_list); if (references == NULL) { clist_foreach(msgid_list, (clist_func) mailimf_msg_id_free, NULL); clist_free(msgid_list); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_REFERENCES, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, references, NULL, NULL, NULL, NULL); r = clist_append(list, field); if (r < 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } case MAILIMF_ERROR_PARSE: break; default: res = maildriver_imf_error_to_mail_error(r); goto free_list; } } fields = mailimf_fields_new(list); if (fields == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } * result = fields; return MAIL_NO_ERROR; free_list: clist_foreach(list, (clist_func) mailimf_field_free, NULL); clist_free(list); err: return res; } /* get messages list with group info */ static int nntpdriver_get_messages_list(mailsession * session, struct mailmessage_list ** result) { return nntp_get_messages_list(session, session, nntp_message_driver, result); } static int nntpdriver_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, nntp_message_driver, num, 0); if (r != MAIL_NO_ERROR) { mailmessage_free(msg_info); return r; } * result = msg_info; return MAIL_NO_ERROR; } static int nntpdriver_noop(mailsession * session) { newsnntp * nntp; int r; struct tm tm; nntp = get_nntp_session(session); r = newsnntp_date(nntp, &tm); return nntpdriver_nntp_error_to_mail_error(r); } static int nntpdriver_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result) { uint32_t num; char * p; if (uid == NULL) return MAIL_ERROR_INVAL; num = strtoul(uid, &p, 10); if ((p == uid) || (* p != '\0')) return MAIL_ERROR_INVAL; return nntpdriver_get_message(session, num, result); } diff --git a/kmicromail/libetpan/generic/nntpdriver_cached.c b/kmicromail/libetpan/generic/nntpdriver_cached.c index 1f8a8af..0343a65 100644 --- a/kmicromail/libetpan/generic/nntpdriver_cached.c +++ b/kmicromail/libetpan/generic/nntpdriver_cached.c @@ -1,1048 +1,1058 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "nntpdriver_cached.h" #include "libetpan-config.h" #include <string.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include "mail_cache_db.h" #include "mail.h" #include "mailmessage.h" #include "maildriver_tools.h" #include "nntpdriver.h" #include "maildriver.h" #include "newsnntp.h" #include "generic_cache.h" #include "imfcache.h" #include "maillock.h" #include "nntpdriver_cached_message.h" #include "nntpdriver_tools.h" static int nntpdriver_cached_initialize(mailsession * session); static void nntpdriver_cached_uninitialize(mailsession * session); static int nntpdriver_cached_parameters(mailsession * session, int id, void * value); static int nntpdriver_cached_connect_stream(mailsession * session, mailstream * s); static int nntpdriver_cached_login(mailsession * session, char * userid, char * password); static int nntpdriver_cached_logout(mailsession * session); static int nntpdriver_cached_check_folder(mailsession * session); static int nntpdriver_cached_select_folder(mailsession * session, char * mb); static int nntpdriver_cached_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); static int nntpdriver_cached_messages_number(mailsession * session, char * mb, uint32_t * result); static int nntpdriver_cached_recent_number(mailsession * session, char * mb, uint32_t * result); static int nntpdriver_cached_unseen_number(mailsession * session, char * mb, uint32_t * result); static int nntpdriver_cached_append_message(mailsession * session, char * message, size_t size); +static int nntpdriver_cached_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags); + static int nntpdriver_cached_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list); static int nntpdriver_cached_get_messages_list(mailsession * session, struct mailmessage_list ** result); static int nntpdriver_cached_list_folders(mailsession * session, char * mb, struct mail_list ** result); static int nntpdriver_cached_lsub_folders(mailsession * session, char * mb, struct mail_list ** result); static int nntpdriver_cached_subscribe_folder(mailsession * session, char * mb); static int nntpdriver_cached_unsubscribe_folder(mailsession * session, char * mb); static int nntpdriver_cached_get_message(mailsession * session, uint32_t num, mailmessage ** result); static int nntpdriver_cached_noop(mailsession * session); static int nntpdriver_cached_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result); static mailsession_driver local_nntp_cached_session_driver = { .sess_name = "nntp-cached", .sess_initialize = nntpdriver_cached_initialize, .sess_uninitialize = nntpdriver_cached_uninitialize, .sess_parameters = nntpdriver_cached_parameters, .sess_connect_stream = nntpdriver_cached_connect_stream, .sess_connect_path = NULL, .sess_starttls = NULL, .sess_login = nntpdriver_cached_login, .sess_logout = nntpdriver_cached_logout, .sess_noop = nntpdriver_cached_noop, .sess_build_folder_name = NULL, .sess_create_folder = NULL, .sess_delete_folder = NULL, .sess_rename_folder = NULL, .sess_check_folder = nntpdriver_cached_check_folder, .sess_examine_folder = NULL, .sess_select_folder = nntpdriver_cached_select_folder, .sess_expunge_folder = NULL, .sess_status_folder = nntpdriver_cached_status_folder, .sess_messages_number = nntpdriver_cached_messages_number, .sess_recent_number = nntpdriver_cached_recent_number, .sess_unseen_number = nntpdriver_cached_unseen_number, .sess_list_folders = nntpdriver_cached_list_folders, .sess_lsub_folders = nntpdriver_cached_lsub_folders, .sess_subscribe_folder = nntpdriver_cached_subscribe_folder, .sess_unsubscribe_folder = nntpdriver_cached_unsubscribe_folder, .sess_append_message = nntpdriver_cached_append_message, + .sess_append_message_flags = nntpdriver_cached_append_message_flags, .sess_copy_message = NULL, .sess_move_message = NULL, .sess_get_messages_list = nntpdriver_cached_get_messages_list, .sess_get_envelopes_list = nntpdriver_cached_get_envelopes_list, .sess_remove_message = NULL, #if 0 .sess_search_messages = maildriver_generic_search_messages, #endif .sess_get_message = nntpdriver_cached_get_message, .sess_get_message_by_uid = nntpdriver_cached_get_message_by_uid, }; mailsession_driver * nntp_cached_session_driver = &local_nntp_cached_session_driver; #define ENV_NAME "env.db" #define FLAGS_NAME "flags.db" static void read_article_seq(mailsession * session, uint32_t * pfirst, uint32_t * plast); static void write_article_seq(mailsession * session, uint32_t first, uint32_t last); static inline struct nntp_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)->nntp_ancestor; } static inline struct nntp_session_state_data * get_ancestor_data(mailsession * session) { return get_ancestor(session)->sess_data; } static inline newsnntp * get_nntp_session(mailsession * session) { return get_ancestor_data(session)->nntp_session; } static int nntpdriver_cached_initialize(mailsession * session) { struct nntp_cached_session_state_data * data; data = malloc(sizeof(* data)); if (data == NULL) goto err; data->nntp_flags_store = mail_flags_store_new(); if (data->nntp_flags_store == NULL) goto free; data->nntp_ancestor = mailsession_new(nntp_session_driver); if (data->nntp_ancestor == NULL) goto free_store; session->sess_data = data; return MAIL_NO_ERROR; free_store: mail_flags_store_free(data->nntp_flags_store); free: free(data); err: return MAIL_ERROR_MEMORY; } static int nntp_flags_store_process(char * flags_directory, char * group_name, 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 (group_name == NULL) return MAIL_NO_ERROR; snprintf(filename_flags, PATH_MAX, "%s/%s/%s", flags_directory, group_name, 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 = nntpdriver_write_cached_flags(cache_db_flags, mmapstr, msg->msg_index, 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 nntpdriver_cached_uninitialize(mailsession * session) { struct nntp_cached_session_state_data * cached_data; struct nntp_session_state_data * ancestor_data; cached_data = get_cached_data(session); ancestor_data = get_ancestor_data(session); nntp_flags_store_process(cached_data->nntp_flags_directory, ancestor_data->nntp_group_name, cached_data->nntp_flags_store); mail_flags_store_free(cached_data->nntp_flags_store); mailsession_free(cached_data->nntp_ancestor); free(cached_data); session->sess_data = NULL; } static int nntpdriver_cached_parameters(mailsession * session, int id, void * value) { struct nntp_cached_session_state_data * cached_data; int r; cached_data = get_cached_data(session); switch (id) { case NNTPDRIVER_CACHED_SET_CACHE_DIRECTORY: strncpy(cached_data->nntp_cache_directory, value, PATH_MAX); cached_data->nntp_cache_directory[PATH_MAX - 1] = '\0'; r = generic_cache_create_dir(cached_data->nntp_cache_directory); if (r != MAIL_NO_ERROR) return r; return MAIL_NO_ERROR; case NNTPDRIVER_CACHED_SET_FLAGS_DIRECTORY: strncpy(cached_data->nntp_flags_directory, value, PATH_MAX); cached_data->nntp_flags_directory[PATH_MAX - 1] = '\0'; r = generic_cache_create_dir(cached_data->nntp_flags_directory); if (r != MAIL_NO_ERROR) return r; return MAIL_NO_ERROR; default: return mailsession_parameters(get_ancestor(session), id, value); } } static int nntpdriver_cached_connect_stream(mailsession * session, mailstream * s) { return mailsession_connect_stream(get_ancestor(session), s); } static int nntpdriver_cached_login(mailsession * session, char * userid, char * password) { return mailsession_login(get_ancestor(session), userid, password); } static int nntpdriver_cached_logout(mailsession * session) { struct nntp_cached_session_state_data * cached_data; struct nntp_session_state_data * ancestor_data; cached_data = get_cached_data(session); ancestor_data = get_ancestor_data(session); nntp_flags_store_process(cached_data->nntp_flags_directory, ancestor_data->nntp_group_name, cached_data->nntp_flags_store); return mailsession_logout(get_ancestor(session)); } static int nntpdriver_cached_select_folder(mailsession * session, char * mb) { int r; struct nntp_session_state_data * ancestor_data; struct nntp_cached_session_state_data * cached_data; int res; char key[PATH_MAX]; cached_data = get_cached_data(session); ancestor_data = get_ancestor_data(session); nntp_flags_store_process(cached_data->nntp_flags_directory, ancestor_data->nntp_group_name, cached_data->nntp_flags_store); r = mailsession_select_folder(get_ancestor(session), mb); if (r != MAIL_NO_ERROR) return r; if (ancestor_data->nntp_group_name == NULL) return MAIL_ERROR_BAD_STATE; snprintf(key, PATH_MAX, "%s/%s", cached_data->nntp_cache_directory, ancestor_data->nntp_group_name); r = generic_cache_create_dir(key); if (r != MAIL_NO_ERROR) { res = r; goto err; } snprintf(key, PATH_MAX, "%s/%s", cached_data->nntp_flags_directory, ancestor_data->nntp_group_name); r = generic_cache_create_dir(key); if (r != MAIL_NO_ERROR) { res = r; goto err; } return MAIL_NO_ERROR; err: return res; } static int nntpdriver_cached_check_folder(mailsession * session) { struct nntp_session_state_data * ancestor_data; struct nntp_cached_session_state_data * cached_data; cached_data = get_cached_data(session); ancestor_data = get_ancestor_data(session); nntp_flags_store_process(cached_data->nntp_flags_directory, ancestor_data->nntp_group_name, cached_data->nntp_flags_store); return MAIL_NO_ERROR; } static int nntpdriver_cached_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { int res; struct nntp_cached_session_state_data * cached_data; struct nntp_session_state_data * ancestor_data; char filename_flags[PATH_MAX]; struct mail_cache_db * cache_db_flags; MMAPString * mmapstr; uint32_t i; int r; uint32_t recent; uint32_t unseen; uint32_t first; uint32_t last; uint32_t count; uint32_t additionnal; r = nntpdriver_cached_select_folder(session, mb); if (r != MAIL_NO_ERROR) { res = r; goto err; } read_article_seq(session, &first, &last); count = 0; recent = 0; unseen = 0; ancestor_data = get_ancestor_data(session); cached_data = get_cached_data(session); if (ancestor_data->nntp_group_name == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } if (ancestor_data->nntp_group_info->grp_first > first) first = ancestor_data->nntp_group_info->grp_first; if (last < first) last = ancestor_data->nntp_group_info->grp_last; snprintf(filename_flags, PATH_MAX, "%s/%s/%s", cached_data->nntp_flags_directory, ancestor_data->nntp_group_name, 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; } for(i = first ; i <= last ; i++) { struct mail_flags * flags; r = nntpdriver_get_cached_flags(cache_db_flags, mmapstr, i, &flags); if (r == MAIL_NO_ERROR) { if ((flags->fl_flags & MAIL_FLAG_CANCELLED) != 0) { continue; } count ++; if ((flags->fl_flags & MAIL_FLAG_NEW) != 0) { recent ++; } if ((flags->fl_flags & MAIL_FLAG_SEEN) == 0) { unseen ++; } mail_flags_free(flags); } } if ((count == 0) && (first != last)) { count = last - first + 1; recent = count; unseen = count; } additionnal = ancestor_data->nntp_group_info->grp_last - last; recent += additionnal; unseen += additionnal; 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 nntpdriver_cached_messages_number(mailsession * session, char * mb, uint32_t * result) { uint32_t messages; uint32_t recent; uint32_t unseen; int r; r = nntpdriver_cached_status_folder(session, mb, &messages, &recent, &unseen); if (r != MAIL_NO_ERROR) return r; * result = messages; return MAIL_NO_ERROR; } static int nntpdriver_cached_recent_number(mailsession * session, char * mb, uint32_t * result) { uint32_t messages; uint32_t recent; uint32_t unseen; int r; r = nntpdriver_cached_status_folder(session, mb, &messages, &recent, &unseen); if (r != MAIL_NO_ERROR) return r; * result = recent; return MAIL_NO_ERROR; } static int nntpdriver_cached_unseen_number(mailsession * session, char * mb, uint32_t * result) { uint32_t messages; uint32_t recent; uint32_t unseen; int r; r = nntpdriver_cached_status_folder(session, mb, &messages, &recent, &unseen); if (r != MAIL_NO_ERROR) return r; * result = unseen; return MAIL_NO_ERROR; } static int nntpdriver_cached_list_folders(mailsession * session, char * mb, struct mail_list ** result) { return mailsession_list_folders(get_ancestor(session), mb, result); } static int nntpdriver_cached_lsub_folders(mailsession * session, char * mb, struct mail_list ** result) { return mailsession_lsub_folders(get_ancestor(session), mb, result); } static int nntpdriver_cached_subscribe_folder(mailsession * session, char * mb) { return mailsession_subscribe_folder(get_ancestor(session), mb); } static int nntpdriver_cached_unsubscribe_folder(mailsession * session, char * mb) { return mailsession_unsubscribe_folder(get_ancestor(session), mb); } /* messages operations */ static int nntpdriver_cached_append_message(mailsession * session, char * message, size_t size) { return mailsession_append_message(get_ancestor(session), message, size); } +static int nntpdriver_cached_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags) +{ + return nntpdriver_cached_append_message(session, message, size); +} + static int get_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr, mailsession * session, uint32_t num, struct mailimf_fields ** result) { char keyname[PATH_MAX]; int r; struct mailimf_fields * fields; int res; snprintf(keyname, PATH_MAX, "%i-envelope", num); 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; int res; char keyname[PATH_MAX]; snprintf(keyname, PATH_MAX, "%i-envelope", num); 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; } #define SEQ_FILENAME "articles-seq" static void read_article_seq(mailsession * session, uint32_t * pfirst, uint32_t * plast) { FILE * f; struct nntp_session_state_data * ancestor_data; uint32_t first; uint32_t last; char seq_filename[PATH_MAX]; struct nntp_cached_session_state_data * cached_data; int r; first = 0; last = 0; cached_data = get_cached_data(session); ancestor_data = get_ancestor_data(session); if (ancestor_data->nntp_group_name == NULL) return; snprintf(seq_filename, PATH_MAX, "%s/%s/%s", cached_data->nntp_cache_directory, ancestor_data->nntp_group_name, SEQ_FILENAME); f = fopen(seq_filename, "r"); if (f != NULL) { int fd; fd = fileno(f); r = maillock_read_lock(seq_filename, fd); if (r == 0) { MMAPString * mmapstr; size_t cur_token; char buf[sizeof(uint32_t) * 2]; size_t read_size; read_size = fread(buf, 1, sizeof(uint32_t) * 2, f); mmapstr = mmap_string_new_len(buf, read_size); if (mmapstr != NULL) { cur_token = 0; r = mailimf_cache_int_read(mmapstr, &cur_token, &first); r = mailimf_cache_int_read(mmapstr, &cur_token, &last); mmap_string_free(mmapstr); } maillock_read_unlock(seq_filename, fd); } fclose(f); } * pfirst = first; * plast = last; } static void write_article_seq(mailsession * session, uint32_t first, uint32_t last) { FILE * f; struct nntp_session_state_data * ancestor_data; char seq_filename[PATH_MAX]; struct nntp_cached_session_state_data * cached_data; int r; int fd; cached_data = get_cached_data(session); ancestor_data = get_ancestor_data(session); if (ancestor_data->nntp_group_name == NULL) return; snprintf(seq_filename, PATH_MAX, "%s/%s/%s", cached_data->nntp_cache_directory, ancestor_data->nntp_group_name, SEQ_FILENAME); fd = creat(seq_filename, S_IRUSR | S_IWUSR); if (fd < 0) return; f = fdopen(fd, "w"); if (f != NULL) { r = maillock_write_lock(seq_filename, fd); if (r == 0) { MMAPString * mmapstr; size_t cur_token; mmapstr = mmap_string_new(""); if (mmapstr != NULL) { r = mail_serialize_clear(mmapstr, &cur_token); if (r == MAIL_NO_ERROR) { r = mailimf_cache_int_write(mmapstr, &cur_token, first); r = mailimf_cache_int_write(mmapstr, &cur_token, last); fwrite(mmapstr->str, 1, mmapstr->len, f); } mmap_string_free(mmapstr); } maillock_write_unlock(seq_filename, fd); } fclose(f); } else close(fd); } static void get_uid_from_filename(char * filename) { char * p; if (strcmp(filename, SEQ_FILENAME) == 0) * filename = 0; p = strstr(filename, "-header"); if (p != NULL) * p = 0; } static int nntpdriver_cached_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list) { int r; unsigned int i; struct nntp_cached_session_state_data * cached_data; uint32_t first; uint32_t last; struct nntp_session_state_data * ancestor_data; 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; char cache_dir[PATH_MAX]; cached_data = get_cached_data(session); ancestor_data = get_ancestor_data(session); nntp_flags_store_process(cached_data->nntp_flags_directory, ancestor_data->nntp_group_name, cached_data->nntp_flags_store); if (ancestor_data->nntp_group_name == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } /* read articles sequence */ read_article_seq(session, &first, &last); mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto err; } snprintf(filename_env, PATH_MAX, "%s/%s/%s", cached_data->nntp_cache_directory, ancestor_data->nntp_group_name, 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->nntp_flags_directory, ancestor_data->nntp_group_name, FLAGS_NAME); /* fill with cached */ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; struct mailimf_fields * fields; msg = carray_get(env_list->msg_tab, i); if ((msg->msg_index < first) || (msg->msg_index > last)) continue; if (msg->msg_fields == NULL) { r = get_cached_envelope(cache_db_env, mmapstr, session, msg->msg_index, &fields); if (r == MAIL_NO_ERROR) { msg->msg_fields = fields; msg->msg_cached = TRUE; } } } 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_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_mmapstr; } /* 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) { struct mail_flags * flags; r = nntpdriver_get_cached_flags(cache_db_flags, mmapstr, msg->msg_index, &flags); if (r == MAIL_NO_ERROR) { msg->msg_flags = flags; } else { msg->msg_flags = mail_flags_new_empty(); if (msg->msg_fields == NULL) { msg->msg_flags->fl_flags |= MAIL_FLAG_CANCELLED; mailmessage_check(msg); } } } } mail_cache_db_close_unlock(filename_flags, cache_db_flags); 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; } /* 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 = nntpdriver_write_cached_flags(cache_db_flags, mmapstr, msg->msg_index, msg->msg_flags); } } first = 0; last = 0; if (carray_count(env_list->msg_tab) > 0) { mailmessage * msg; msg = carray_get(env_list->msg_tab, 0); first = msg->msg_index; msg = carray_get(env_list->msg_tab, carray_count(env_list->msg_tab) - 1); last = msg->msg_index; } /* write articles sequence */ write_article_seq(session, first, last); /* flush cache */ maildriver_cache_clean_up(cache_db_env, cache_db_flags, env_list); /* remove cache files */ snprintf(cache_dir, PATH_MAX, "%s/%s", cached_data->nntp_cache_directory, ancestor_data->nntp_group_name); mail_cache_db_close_unlock(filename_flags, cache_db_flags); mail_cache_db_close_unlock(filename_env, cache_db_env); mmap_string_free(mmapstr); maildriver_message_cache_clean_up(cache_dir, env_list, get_uid_from_filename); 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 nntpdriver_cached_get_messages_list(mailsession * session, struct mailmessage_list ** result) { return nntp_get_messages_list(get_ancestor(session), session, nntp_cached_message_driver, result); } static int nntpdriver_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, nntp_cached_message_driver, num, 0); if (r != MAIL_NO_ERROR) { mailmessage_free(msg_info); return r; } * result = msg_info; return MAIL_NO_ERROR; } static int nntpdriver_cached_noop(mailsession * session) { return mailsession_noop(get_ancestor(session)); } static int nntpdriver_cached_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result) { uint32_t num; char * p; if (uid == NULL) return MAIL_ERROR_INVAL; num = strtoul(uid, &p, 10); if ((p == uid) || (* p != '\0')) return MAIL_ERROR_INVAL; return nntpdriver_cached_get_message(session, num, result); } diff --git a/kmicromail/libetpan/generic/nntpstorage.c b/kmicromail/libetpan/generic/nntpstorage.c index 5ba333b..89974cd 100644 --- a/kmicromail/libetpan/generic/nntpstorage.c +++ b/kmicromail/libetpan/generic/nntpstorage.c @@ -1,267 +1,267 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "nntpstorage.h" #include <stdlib.h> #include <string.h> #include "maildriver.h" #include "nntpdriver.h" #include "nntpdriver_cached.h" #include "mailstorage_tools.h" #include "mail.h" /* nntp storage */ #define NNTP_DEFAULT_PORT 119 #define NNTPS_DEFAULT_PORT 563 static int nntp_mailstorage_connect(struct mailstorage * storage); static int nntp_mailstorage_get_folder_session(struct mailstorage * storage, char * pathname, mailsession ** result); static void nntp_mailstorage_uninitialize(struct mailstorage * storage); static mailstorage_driver nntp_mailstorage_driver = { .sto_name = "nntp", .sto_connect = nntp_mailstorage_connect, .sto_get_folder_session = nntp_mailstorage_get_folder_session, .sto_uninitialize = nntp_mailstorage_uninitialize, }; int nntp_mailstorage_init(struct mailstorage * storage, char * nn_servername, uint16_t nn_port, char * nn_command, int nn_connection_type, int nn_auth_type, char * nn_login, char * nn_password, int nn_cached, char * nn_cache_directory, char * nn_flags_directory) { struct nntp_mailstorage * nntp_storage; int res; - nntp_storage = malloc(sizeof(struct nntp_mailstorage)); + nntp_storage = malloc(sizeof(* nntp_storage)); if (nntp_storage == NULL) { res = MAIL_ERROR_MEMORY; goto err; } nntp_storage->nntp_servername = strdup(nn_servername); if (nntp_storage->nntp_servername == NULL) { res = MAIL_ERROR_MEMORY; goto free; } nntp_storage->nntp_connection_type = nn_connection_type; if (nn_port == 0) { switch (nn_connection_type) { case CONNECTION_TYPE_PLAIN: case CONNECTION_TYPE_COMMAND: nn_port = NNTP_DEFAULT_PORT; break; case CONNECTION_TYPE_TLS: case CONNECTION_TYPE_COMMAND_TLS: nn_port = NNTPS_DEFAULT_PORT; break; default: res = MAIL_ERROR_INVAL; goto free_servername; } } nntp_storage->nntp_port = nn_port; if (nn_command != NULL) { nntp_storage->nntp_command = strdup(nn_command); if (nntp_storage->nntp_command == NULL) { res = MAIL_ERROR_MEMORY; goto free_servername; } } else nntp_storage->nntp_command = NULL; nntp_storage->nntp_auth_type = nn_auth_type; if (nn_login != NULL) { nntp_storage->nntp_login = strdup(nn_login); if (nntp_storage->nntp_login == NULL) { res = MAIL_ERROR_MEMORY; goto free_command; } } else nntp_storage->nntp_login = NULL; if (nn_password != NULL) { nntp_storage->nntp_password = strdup(nn_password); if (nntp_storage->nntp_password == NULL) { res = MAIL_ERROR_MEMORY; goto free_login; } } else nntp_storage->nntp_password = NULL; nntp_storage->nntp_cached = nn_cached; if (nn_cached && (nn_cache_directory != NULL) && (nn_flags_directory != NULL)) { nntp_storage->nntp_cache_directory = strdup(nn_cache_directory); if (nntp_storage->nntp_cache_directory == NULL) { res = MAIL_ERROR_MEMORY; goto free_password; } nntp_storage->nntp_flags_directory = strdup(nn_flags_directory); if (nntp_storage->nntp_flags_directory == NULL) { res = MAIL_ERROR_MEMORY; goto free_cache_directory; } } else { nntp_storage->nntp_cached = FALSE; nntp_storage->nntp_cache_directory = NULL; nntp_storage->nntp_flags_directory = NULL; } storage->sto_data = nntp_storage; storage->sto_driver = &nntp_mailstorage_driver; return MAIL_NO_ERROR; free_cache_directory: free(nntp_storage->nntp_cache_directory); free_password: free(nntp_storage->nntp_password); free_login: free(nntp_storage->nntp_login); free_command: free(nn_command); free_servername: free(nntp_storage->nntp_servername); free: free(nntp_storage); err: return res; } static void nntp_mailstorage_uninitialize(struct mailstorage * storage) { struct nntp_mailstorage * nntp_storage; nntp_storage = storage->sto_data; if (nntp_storage->nntp_flags_directory != NULL) free(nntp_storage->nntp_flags_directory); if (nntp_storage->nntp_cache_directory != NULL) free(nntp_storage->nntp_cache_directory); if (nntp_storage->nntp_password != NULL) free(nntp_storage->nntp_password); if (nntp_storage->nntp_login != NULL) free(nntp_storage->nntp_login); if (nntp_storage->nntp_command != NULL) free(nntp_storage->nntp_command); free(nntp_storage->nntp_servername); free(nntp_storage); storage->sto_data = NULL; } static int nntp_mailstorage_connect(struct mailstorage * storage) { struct nntp_mailstorage * nntp_storage; mailsession_driver * driver; int r; int res; mailsession * session; nntp_storage = storage->sto_data; if (nntp_storage->nntp_cached) driver = nntp_cached_session_driver; else driver = nntp_session_driver; r = mailstorage_generic_connect(driver, nntp_storage->nntp_servername, nntp_storage->nntp_port, nntp_storage->nntp_command, nntp_storage->nntp_connection_type, NNTPDRIVER_CACHED_SET_CACHE_DIRECTORY, nntp_storage->nntp_cache_directory, NNTPDRIVER_CACHED_SET_FLAGS_DIRECTORY, nntp_storage->nntp_flags_directory, &session); switch (r) { case MAIL_NO_ERROR_NON_AUTHENTICATED: case MAIL_NO_ERROR_AUTHENTICATED: case MAIL_NO_ERROR: break; default: res = r; goto err; } r = mailstorage_generic_auth(session, r, nntp_storage->nntp_connection_type, nntp_storage->nntp_login, nntp_storage->nntp_password); if (r != MAIL_NO_ERROR) { res = r; goto free; } storage->sto_session = session; return MAIL_NO_ERROR; free: mailsession_free(session); err: return res; } static int nntp_mailstorage_get_folder_session(struct mailstorage * storage, char * pathname, mailsession ** result) { int r; r = mailsession_select_folder(storage->sto_session, pathname); * result = storage->sto_session; return MAIL_NO_ERROR; } diff --git a/kmicromail/libetpan/generic/pop3driver.c b/kmicromail/libetpan/generic/pop3driver.c index 20b0fc2..375879e 100644 --- a/kmicromail/libetpan/generic/pop3driver.c +++ b/kmicromail/libetpan/generic/pop3driver.c @@ -1,387 +1,388 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "pop3driver.h" #include <string.h> #include <stdlib.h> #include "pop3driver_message.h" #include "maildriver_tools.h" #include "pop3driver_tools.h" #include "mailmessage.h" static int pop3driver_initialize(mailsession * session); static void pop3driver_uninitialize(mailsession * session); static int pop3driver_parameters(mailsession * session, int id, void * value); static int pop3driver_connect_stream(mailsession * session, mailstream * s); static int pop3driver_starttls(mailsession * session); static int pop3driver_login(mailsession * session, char * userid, char * password); static int pop3driver_logout(mailsession * session); static int pop3driver_noop(mailsession * session); static int pop3driver_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); static int pop3driver_messages_number(mailsession * session, char * mb, uint32_t * result); static int pop3driver_remove_message(mailsession * session, uint32_t num); static int pop3driver_get_messages_list(mailsession * session, struct mailmessage_list ** result); static int pop3driver_get_message(mailsession * session, uint32_t num, mailmessage ** result); static mailsession_driver local_pop3_session_driver = { .sess_name = "pop3", .sess_initialize = pop3driver_initialize, .sess_uninitialize = pop3driver_uninitialize, .sess_parameters = pop3driver_parameters, .sess_connect_stream = pop3driver_connect_stream, .sess_connect_path = NULL, .sess_starttls = pop3driver_starttls, .sess_login = pop3driver_login, .sess_logout = pop3driver_logout, .sess_noop = pop3driver_noop, .sess_build_folder_name = NULL, .sess_create_folder = NULL, .sess_delete_folder = NULL, .sess_rename_folder = NULL, .sess_check_folder = NULL, .sess_examine_folder = NULL, .sess_select_folder = NULL, .sess_expunge_folder = NULL, .sess_status_folder = pop3driver_status_folder, .sess_messages_number = pop3driver_messages_number, .sess_recent_number = pop3driver_messages_number, .sess_unseen_number = pop3driver_messages_number, .sess_list_folders = NULL, .sess_lsub_folders = NULL, .sess_subscribe_folder = NULL, .sess_unsubscribe_folder = NULL, .sess_append_message = NULL, + .sess_append_message_flags = NULL, .sess_copy_message = NULL, .sess_move_message = NULL, .sess_get_messages_list = pop3driver_get_messages_list, .sess_get_envelopes_list = maildriver_generic_get_envelopes_list, .sess_remove_message = pop3driver_remove_message, #if 0 .sess_search_messages = maildriver_generic_search_messages, #endif .sess_get_message = pop3driver_get_message, .sess_get_message_by_uid = NULL, }; mailsession_driver * pop3_session_driver = &local_pop3_session_driver; static inline struct pop3_session_state_data * get_data(mailsession * session) { return session->sess_data; } static mailpop3 * get_pop3_session(mailsession * session) { return get_data(session)->pop3_session; } static int pop3driver_initialize(mailsession * session) { struct pop3_session_state_data * data; mailpop3 * pop3; pop3 = mailpop3_new(0, NULL); if (session == NULL) goto err; data = malloc(sizeof(* data)); if (data == NULL) goto free; data->pop3_session = pop3; data->pop3_auth_type = POP3DRIVER_AUTH_TYPE_PLAIN; session->sess_data = data; return MAIL_NO_ERROR; free: mailpop3_free(pop3); err: return MAIL_ERROR_MEMORY; } static void pop3driver_uninitialize(mailsession * session) { struct pop3_session_state_data * data; data = get_data(session); mailpop3_free(data->pop3_session); free(data); session->sess_data = data; } static int pop3driver_connect_stream(mailsession * session, mailstream * s) { int r; r = mailpop3_connect(get_pop3_session(session), s); switch (r) { case MAILPOP3_NO_ERROR: return MAIL_NO_ERROR_NON_AUTHENTICATED; default: return pop3driver_pop3_error_to_mail_error(r); } } static int pop3driver_starttls(mailsession * session) { int r; int fd; mailstream_low * low; mailstream_low * new_low; mailpop3 * pop3; pop3 = get_pop3_session(session); r = mailpop3_stls(pop3); switch (r) { case MAILPOP3_NO_ERROR: break; default: return pop3driver_pop3_error_to_mail_error(r); } low = mailstream_get_low(pop3->pop3_stream); fd = mailstream_low_get_fd(low); if (fd == -1) return MAIL_ERROR_STREAM; new_low = mailstream_low_ssl_open(fd); if (new_low == NULL) return MAIL_ERROR_STREAM; mailstream_low_free(low); mailstream_set_low(pop3->pop3_stream, new_low); return MAIL_NO_ERROR; } static int pop3driver_parameters(mailsession * session, int id, void * value) { struct pop3_session_state_data * data; data = get_data(session); switch (id) { case POP3DRIVER_SET_AUTH_TYPE: { int * param; param = value; data->pop3_auth_type = * param; return MAIL_NO_ERROR; } } return MAIL_ERROR_INVAL; } static int pop3driver_login(mailsession * session, char * userid, char * password) { int r; carray * msg_tab; struct pop3_session_state_data * data; data = get_data(session); switch (data->pop3_auth_type) { case POP3DRIVER_AUTH_TYPE_TRY_APOP: r = mailpop3_login_apop(get_pop3_session(session), userid, password); if (r != MAILPOP3_NO_ERROR) r = mailpop3_login(get_pop3_session(session), userid, password); break; case POP3DRIVER_AUTH_TYPE_APOP: r = mailpop3_login_apop(get_pop3_session(session), userid, password); break; default: case POP3DRIVER_AUTH_TYPE_PLAIN: r = mailpop3_login(get_pop3_session(session), userid, password); break; } mailpop3_list(get_pop3_session(session), &msg_tab); return pop3driver_pop3_error_to_mail_error(r); } static int pop3driver_logout(mailsession * session) { int r; r = mailpop3_quit(get_pop3_session(session)); return pop3driver_pop3_error_to_mail_error(r); } static int pop3driver_noop(mailsession * session) { int r; r = mailpop3_noop(get_pop3_session(session)); return pop3driver_pop3_error_to_mail_error(r); } static int pop3driver_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { uint32_t count; int r; r = pop3driver_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 pop3driver_messages_number(mailsession * session, char * mb, uint32_t * result) { carray * msg_tab; mailpop3_list(get_pop3_session(session), &msg_tab); * result = carray_count(msg_tab) - get_pop3_session(session)->pop3_deleted_count; return MAIL_NO_ERROR; } /* messages operations */ static int pop3driver_remove_message(mailsession * session, uint32_t num) { mailpop3 * pop3; int r; pop3 = get_pop3_session(session); r = mailpop3_dele(pop3, num); switch (r) { case MAILPOP3_ERROR_BAD_STATE: return MAIL_ERROR_BAD_STATE; case MAILPOP3_ERROR_NO_SUCH_MESSAGE: return MAIL_ERROR_MSG_NOT_FOUND; case MAILPOP3_ERROR_STREAM: return MAIL_ERROR_STREAM; case MAILPOP3_NO_ERROR: return MAIL_NO_ERROR; default: return MAIL_ERROR_REMOVE; } } static int pop3driver_get_messages_list(mailsession * session, struct mailmessage_list ** result) { mailpop3 * pop3; pop3 = get_pop3_session(session); return pop3_get_messages_list(pop3, session, pop3_message_driver, result); } static int pop3driver_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, pop3_message_driver, num, 0); if (r != MAIL_NO_ERROR) { mailmessage_free(msg_info); return r; } * result = msg_info; return MAIL_NO_ERROR; } diff --git a/kmicromail/libetpan/generic/pop3driver_cached.c b/kmicromail/libetpan/generic/pop3driver_cached.c index 6f97303..24f624b 100644 --- a/kmicromail/libetpan/generic/pop3driver_cached.c +++ b/kmicromail/libetpan/generic/pop3driver_cached.c @@ -1,857 +1,899 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "pop3driver_cached.h" #include "libetpan-config.h" #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include "mail.h" #include "mail_cache_db.h" #include "maildriver.h" #include "mailmessage.h" #include "pop3driver.h" #include "mailpop3.h" #include "generic_cache.h" #include "imfcache.h" #include "pop3driver_cached_message.h" #include "pop3driver_tools.h" #include "maildriver_tools.h" static int pop3driver_cached_initialize(mailsession * session); static void pop3driver_cached_uninitialize(mailsession * session); static int pop3driver_cached_parameters(mailsession * session, int id, void * value); static int pop3driver_cached_connect_stream(mailsession * session, mailstream * s); static int pop3driver_cached_starttls(mailsession * session); static int pop3driver_cached_login(mailsession * session, char * userid, char * password); static int pop3driver_cached_logout(mailsession * session); static int pop3driver_cached_check_folder(mailsession * session); static int pop3driver_cached_noop(mailsession * session); static int pop3driver_cached_expunge_folder(mailsession * session); static int pop3driver_cached_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); static int pop3driver_cached_messages_number(mailsession * session, char * mb, uint32_t * result); static int pop3driver_cached_recent_number(mailsession * session, char * mb, uint32_t * result); static int pop3driver_cached_unseen_number(mailsession * session, char * mb, uint32_t * result); static int pop3driver_cached_remove_message(mailsession * session, uint32_t num); static int pop3driver_cached_get_messages_list(mailsession * session, struct mailmessage_list ** result); static int pop3driver_cached_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list); static int pop3driver_cached_get_message(mailsession * session, uint32_t num, mailmessage ** result); +static int pop3driver_cached_get_message_by_uid(mailsession * session, + const char * uid, mailmessage ** result); + static mailsession_driver local_pop3_cached_session_driver = { .sess_name = "pop3-cached", .sess_initialize = pop3driver_cached_initialize, .sess_uninitialize = pop3driver_cached_uninitialize, .sess_parameters = pop3driver_cached_parameters, .sess_connect_stream = pop3driver_cached_connect_stream, .sess_connect_path = NULL, .sess_starttls = pop3driver_cached_starttls, .sess_login = pop3driver_cached_login, .sess_logout = pop3driver_cached_logout, .sess_noop = pop3driver_cached_noop, .sess_build_folder_name = NULL, .sess_create_folder = NULL, .sess_delete_folder = NULL, .sess_rename_folder = NULL, .sess_check_folder = pop3driver_cached_check_folder, .sess_examine_folder = NULL, .sess_select_folder = NULL, .sess_expunge_folder = pop3driver_cached_expunge_folder, .sess_status_folder = pop3driver_cached_status_folder, .sess_messages_number = pop3driver_cached_messages_number, .sess_recent_number = pop3driver_cached_recent_number, .sess_unseen_number = pop3driver_cached_unseen_number, .sess_list_folders = NULL, .sess_lsub_folders = NULL, .sess_subscribe_folder = NULL, .sess_unsubscribe_folder = NULL, .sess_append_message = NULL, + .sess_append_message_flags = NULL, .sess_copy_message = NULL, .sess_move_message = NULL, .sess_get_messages_list = pop3driver_cached_get_messages_list, .sess_get_envelopes_list = pop3driver_cached_get_envelopes_list, .sess_remove_message = pop3driver_cached_remove_message, #if 0 .sess_search_messages = maildriver_generic_search_messages, #endif .sess_get_message = pop3driver_cached_get_message, - .sess_get_message_by_uid = NULL, + .sess_get_message_by_uid = pop3driver_cached_get_message_by_uid, }; mailsession_driver * pop3_cached_session_driver = &local_pop3_cached_session_driver; #define ENV_NAME "env.db" #define FLAGS_NAME "flags.db" static inline struct pop3_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)->pop3_ancestor; } static inline struct pop3_session_state_data * get_ancestor_data(mailsession * session) { return get_ancestor(session)->sess_data; } static inline mailpop3 * get_pop3_session(mailsession * session) { return get_ancestor_data(session)->pop3_session; } static int pop3driver_cached_initialize(mailsession * session) { struct pop3_cached_session_state_data * data; data = malloc(sizeof(* data)); if (data == NULL) goto err; data->pop3_flags_store = mail_flags_store_new(); if (data->pop3_flags_store == NULL) goto free_data; data->pop3_ancestor = mailsession_new(pop3_session_driver); if (data->pop3_ancestor == NULL) goto free_store; data->pop3_flags_hash = chash_new(128, CHASH_COPYNONE); if (data->pop3_flags_hash == NULL) goto free_session; session->sess_data = data; return MAIL_NO_ERROR; free_session: mailsession_free(data->pop3_ancestor); free_store: mail_flags_store_free(data->pop3_flags_store); free_data: free(data); err: return MAIL_ERROR_MEMORY; } static int pop3_flags_store_process(char * flags_directory, 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; snprintf(filename_flags, PATH_MAX, "%s/%s", flags_directory, 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 = pop3driver_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 pop3driver_cached_uninitialize(mailsession * session) { struct pop3_cached_session_state_data * data; data = get_cached_data(session); pop3_flags_store_process(data->pop3_flags_directory, data->pop3_flags_store); mail_flags_store_free(data->pop3_flags_store); chash_free(data->pop3_flags_hash); mailsession_free(data->pop3_ancestor); free(data); session->sess_data = data; } static int pop3driver_cached_check_folder(mailsession * session) { struct pop3_cached_session_state_data * pop3_data; pop3_data = get_cached_data(session); pop3_flags_store_process(pop3_data->pop3_flags_directory, pop3_data->pop3_flags_store); return MAIL_NO_ERROR; } static int pop3driver_cached_parameters(mailsession * session, int id, void * value) { struct pop3_cached_session_state_data * data; int r; data = get_cached_data(session); switch (id) { case POP3DRIVER_CACHED_SET_CACHE_DIRECTORY: strncpy(data->pop3_cache_directory, value, PATH_MAX); data->pop3_cache_directory[PATH_MAX - 1] = '\0'; r = generic_cache_create_dir(data->pop3_cache_directory); if (r != MAIL_NO_ERROR) return r; return MAIL_NO_ERROR; case POP3DRIVER_CACHED_SET_FLAGS_DIRECTORY: strncpy(data->pop3_flags_directory, value, PATH_MAX); data->pop3_flags_directory[PATH_MAX - 1] = '\0'; r = generic_cache_create_dir(data->pop3_flags_directory); if (r != MAIL_NO_ERROR) return r; return MAIL_NO_ERROR; default: return mailsession_parameters(data->pop3_ancestor, id, value); } } static int pop3driver_cached_connect_stream(mailsession * session, mailstream * s) { int r; r = mailsession_connect_stream(get_ancestor(session), s); if (r != MAIL_NO_ERROR) return r; return MAIL_NO_ERROR; } static int pop3driver_cached_starttls(mailsession * session) { return mailsession_starttls(get_ancestor(session)); } static int pop3driver_cached_login(mailsession * session, char * userid, char * password) { return mailsession_login(get_ancestor(session), userid, password); } static int pop3driver_cached_logout(mailsession * session) { struct pop3_cached_session_state_data * cached_data; cached_data = get_cached_data(session); pop3_flags_store_process(cached_data->pop3_flags_directory, cached_data->pop3_flags_store); return mailsession_logout(get_ancestor(session)); } static int pop3driver_cached_noop(mailsession * session) { return mailsession_noop(get_ancestor(session)); } static int pop3driver_cached_expunge_folder(mailsession * session) { int res; struct pop3_cached_session_state_data * cached_data; char filename_flags[PATH_MAX]; struct mail_cache_db * cache_db_flags; MMAPString * mmapstr; unsigned int i; int r; carray * msg_tab; mailpop3 * pop3; pop3 = get_pop3_session(session); cached_data = get_cached_data(session); pop3_flags_store_process(cached_data->pop3_flags_directory, cached_data->pop3_flags_store); snprintf(filename_flags, PATH_MAX, "%s/%s", cached_data->pop3_flags_directory, 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; } mailpop3_list(pop3, &msg_tab); for(i = 0 ; i < carray_count(msg_tab) ; i++) { struct mailpop3_msg_info * pop3_info; struct mail_flags * flags; pop3_info = carray_get(msg_tab, i); if (pop3_info == NULL) continue; if (pop3_info->msg_deleted) continue; r = pop3driver_get_cached_flags(cache_db_flags, mmapstr, session, pop3_info->msg_index, &flags); if (r != MAIL_NO_ERROR) continue; if (flags->fl_flags & MAIL_FLAG_DELETED) { r = mailpop3_dele(pop3, pop3_info->msg_index); } mail_flags_free(flags); } mmap_string_free(mmapstr); mail_cache_db_close_unlock(filename_flags, cache_db_flags); return MAIL_NO_ERROR; close_db_flags: mail_cache_db_close_unlock(filename_flags, cache_db_flags); err: return res; } static int pop3driver_cached_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { int res; struct pop3_cached_session_state_data * cached_data; char filename_flags[PATH_MAX]; struct mail_cache_db * cache_db_flags; MMAPString * mmapstr; unsigned int i; int r; carray * msg_tab; mailpop3 * pop3; uint32_t recent; uint32_t unseen; recent = 0; unseen = 0; pop3 = get_pop3_session(session); cached_data = get_cached_data(session); pop3_flags_store_process(cached_data->pop3_flags_directory, cached_data->pop3_flags_store); snprintf(filename_flags, PATH_MAX, "%s/%s", cached_data->pop3_flags_directory, 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; } mailpop3_list(pop3, &msg_tab); for(i = 0 ; i < carray_count(msg_tab) ; i++) { struct mailpop3_msg_info * pop3_info; struct mail_flags * flags; pop3_info = carray_get(msg_tab, i); if (pop3_info == NULL) continue; if (pop3_info->msg_deleted) continue; r = pop3driver_get_cached_flags(cache_db_flags, mmapstr, session, pop3_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 = carray_count(msg_tab) - pop3->pop3_deleted_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 pop3driver_cached_messages_number(mailsession * session, char * mb, uint32_t * result) { return mailsession_messages_number(get_ancestor(session), mb, result); } static int pop3driver_cached_recent_number(mailsession * session, char * mb, uint32_t * result) { uint32_t messages; uint32_t recent; uint32_t unseen; int r; r = pop3driver_cached_status_folder(session, mb, &messages, &recent, &unseen); if (r != MAIL_NO_ERROR) return r; * result = recent; return MAIL_NO_ERROR; } static int pop3driver_cached_unseen_number(mailsession * session, char * mb, uint32_t * result) { uint32_t messages; uint32_t recent; uint32_t unseen; int r; r = pop3driver_cached_status_folder(session, mb, &messages, &recent, &unseen); if (r != MAIL_NO_ERROR) return r; * result = unseen; return MAIL_NO_ERROR; } /* messages operations */ static int pop3driver_cached_remove_message(mailsession * session, uint32_t num) { return mailsession_remove_message(get_ancestor(session), num); } static int pop3driver_cached_get_messages_list(mailsession * session, struct mailmessage_list ** result) { mailpop3 * pop3; pop3 = get_pop3_session(session); return pop3_get_messages_list(pop3, session, pop3_cached_message_driver, result); } 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 mailpop3_msg_info * info; struct mailimf_fields * fields; int res; mailpop3 * pop3; pop3 = get_pop3_session(session); r = mailpop3_get_msg_info(pop3, num, &info); switch (r) { case MAILPOP3_ERROR_BAD_STATE: return MAIL_ERROR_BAD_STATE; case MAILPOP3_ERROR_NO_SUCH_MESSAGE: return MAIL_ERROR_MSG_NOT_FOUND; case MAILPOP3_NO_ERROR: break; default: return MAIL_ERROR_FETCH; } snprintf(keyname, PATH_MAX, "%s-envelope", info->msg_uidl); 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 mailpop3_msg_info * info; mailpop3 * pop3; pop3 = get_pop3_session(session); r = mailpop3_get_msg_info(pop3, num, &info); switch (r) { case MAILPOP3_ERROR_BAD_STATE: return MAIL_ERROR_BAD_STATE; case MAILPOP3_ERROR_NO_SUCH_MESSAGE: return MAIL_ERROR_MSG_NOT_FOUND; case MAILPOP3_NO_ERROR: break; default: return MAIL_ERROR_FETCH; } snprintf(keyname, PATH_MAX, "%s-envelope", info->msg_uidl); 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 void get_uid_from_filename(char * filename) { char * p; p = strstr(filename, "-header"); if (p != NULL) * p = 0; } static int pop3driver_cached_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list) { int r; unsigned int i; struct pop3_cached_session_state_data * cached_data; 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; cached_data = get_cached_data(session); pop3_flags_store_process(cached_data->pop3_flags_directory, cached_data->pop3_flags_store); snprintf(filename_env, PATH_MAX, "%s/%s", cached_data->pop3_cache_directory, ENV_NAME); mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto err; } 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", cached_data->pop3_flags_directory, 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, session, msg->msg_index, &fields); if (r == MAIL_NO_ERROR) { msg->msg_cached = TRUE; msg->msg_fields = fields; } } if (msg->msg_flags == NULL) { r = pop3driver_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 = maildriver_generic_get_envelopes_list(session, env_list); if (r != MAIL_NO_ERROR) { res = r; goto free_mmapstr; } /* 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(); } 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; } /* 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 = pop3driver_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); /* remove cache files */ maildriver_message_cache_clean_up(cached_data->pop3_cache_directory, env_list, get_uid_from_filename); 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 pop3driver_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, pop3_cached_message_driver, num, 0); if (r != MAIL_NO_ERROR) { mailmessage_free(msg_info); return r; } * result = msg_info; return MAIL_NO_ERROR; } + +static int pop3driver_cached_get_message_by_uid(mailsession * session, + const char * uid, mailmessage ** result) +{ + mailpop3 * pop3; + struct mailpop3_msg_info * msg_info; + int found; + unsigned int i; + + if (uid == NULL) + return MAIL_ERROR_INVAL; + + pop3 = get_pop3_session(session); + + found = 0; + + /* iterate all messages and look for uid */ + for(i = 0 ; i < carray_count(pop3->pop3_msg_tab) ; i++) { + msg_info = carray_get(pop3->pop3_msg_tab, i); + + if (msg_info == NULL) + continue; + + if (msg_info->msg_deleted) + continue; + + /* uid found, stop looking */ + if (strcmp(msg_info->msg_uidl, uid) == 0) { + found = 1; + break; + } + } + + if (!found) + return MAIL_ERROR_MSG_NOT_FOUND; + + return pop3driver_cached_get_message(session, msg_info->msg_index, result); +} diff --git a/kmicromail/libetpan/generic/pop3driver_message.c b/kmicromail/libetpan/generic/pop3driver_message.c index 77bd94c..357bb2e 100644 --- a/kmicromail/libetpan/generic/pop3driver_message.c +++ b/kmicromail/libetpan/generic/pop3driver_message.c @@ -1,159 +1,193 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "pop3driver_message.h" #include "mailmessage_tools.h" #include "pop3driver_tools.h" #include "pop3driver.h" #include "mailpop3.h" +#include <stdlib.h> +#include <string.h> static int pop3_prefetch(mailmessage * msg_info); static void pop3_prefetch_free(struct generic_message_t * msg); static int pop3_initialize(mailmessage * msg_info); static int pop3_fetch_header(mailmessage * msg_info, char ** result, size_t * result_len); static int pop3_fetch_size(mailmessage * msg_info, size_t * result); static mailmessage_driver local_pop3_message_driver = { .msg_name = "pop3", .msg_initialize = pop3_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 = pop3_fetch_header, .msg_fetch_body = mailmessage_generic_fetch_body, .msg_fetch_size = pop3_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 * pop3_message_driver = &local_pop3_message_driver; +static inline struct pop3_session_state_data * +get_data(mailsession * session) +{ + return session->sess_data; +} + + +static mailpop3 * get_pop3_session(mailsession * session) +{ + return get_data(session)->pop3_session; +} + static int pop3_prefetch(mailmessage * msg_info) { char * msg_content; size_t msg_length; struct generic_message_t * msg; int r; r = pop3driver_retr(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 pop3_prefetch_free(struct generic_message_t * msg) { if (msg->msg_message != NULL) { mmap_string_unref(msg->msg_message); msg->msg_message = NULL; } } static int pop3_initialize(mailmessage * msg_info) { struct generic_message_t * msg; int r; + char * uid; + struct mailpop3_msg_info * info; + mailpop3 * pop3; + + pop3 = get_pop3_session(msg_info->msg_session); + + r = mailpop3_get_msg_info(pop3, msg_info->msg_index, &info); + switch (r) { + case MAILPOP3_NO_ERROR: + break; + default: + return pop3driver_pop3_error_to_mail_error(r); + } + + uid = strdup(info->msg_uidl); + if (uid == NULL) + return MAIL_ERROR_MEMORY; r = mailmessage_generic_initialize(msg_info); - if (r != MAIL_NO_ERROR) + if (r != MAIL_NO_ERROR) { + free(uid); return r; + } msg = msg_info->msg_data; msg->msg_prefetch = pop3_prefetch; msg->msg_prefetch_free = pop3_prefetch_free; + msg_info->msg_uid = uid; return MAIL_NO_ERROR; } static int pop3_fetch_header(mailmessage * msg_info, char ** result, size_t * result_len) { struct generic_message_t * msg; char * headers; size_t headers_length; int r; msg = msg_info->msg_data; if (msg->msg_message != NULL) return mailmessage_generic_fetch_header(msg_info, result, result_len); r = pop3driver_header(msg_info->msg_session, msg_info->msg_index, &headers, &headers_length); if (r != MAIL_NO_ERROR) return r; * result = headers; * result_len = headers_length; return MAIL_NO_ERROR; } static int pop3_fetch_size(mailmessage * msg_info, size_t * result) { return pop3driver_size(msg_info->msg_session, msg_info->msg_index, result); } diff --git a/kmicromail/libetpan/generic/pop3storage.c b/kmicromail/libetpan/generic/pop3storage.c index 8e7a94e..375aeaf 100644 --- a/kmicromail/libetpan/generic/pop3storage.c +++ b/kmicromail/libetpan/generic/pop3storage.c @@ -1,284 +1,284 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "pop3storage.h" #include <stdlib.h> #include <string.h> #include "mail.h" #include "mailstorage_tools.h" #include "maildriver.h" /* pop3 storage */ #define POP3_DEFAULT_PORT 110 #define POP3S_DEFAULT_PORT 995 static int pop3_mailstorage_connect(struct mailstorage * storage); static int pop3_mailstorage_get_folder_session(struct mailstorage * storage, char * pathname, mailsession ** result); static void pop3_mailstorage_uninitialize(struct mailstorage * storage); static mailstorage_driver pop3_mailstorage_driver = { .sto_name = "pop3", .sto_connect = pop3_mailstorage_connect, .sto_get_folder_session = pop3_mailstorage_get_folder_session, .sto_uninitialize = pop3_mailstorage_uninitialize, }; int pop3_mailstorage_init(struct mailstorage * storage, char * pop3_servername, uint16_t pop3_port, char * pop3_command, int pop3_connection_type, int pop3_auth_type, char * pop3_login, char * pop3_password, int pop3_cached, char * pop3_cache_directory, char * pop3_flags_directory) { struct pop3_mailstorage * pop3_storage; - pop3_storage = malloc(sizeof(struct pop3_mailstorage)); + pop3_storage = malloc(sizeof(* pop3_storage)); if (pop3_storage == NULL) goto err; pop3_storage->pop3_servername = strdup(pop3_servername); if (pop3_storage->pop3_servername == NULL) goto free; pop3_storage->pop3_connection_type = pop3_connection_type; if (pop3_port == 0) { switch (pop3_connection_type) { case CONNECTION_TYPE_PLAIN: case CONNECTION_TYPE_TRY_STARTTLS: case CONNECTION_TYPE_STARTTLS: case CONNECTION_TYPE_COMMAND: case CONNECTION_TYPE_COMMAND_TRY_STARTTLS: case CONNECTION_TYPE_COMMAND_STARTTLS: pop3_port = POP3_DEFAULT_PORT; break; case CONNECTION_TYPE_TLS: case CONNECTION_TYPE_COMMAND_TLS: pop3_port = POP3S_DEFAULT_PORT; break; } } pop3_storage->pop3_port = pop3_port; if (pop3_command != NULL) { pop3_storage->pop3_command = strdup(pop3_command); if (pop3_storage->pop3_command == NULL) goto free_servername; } else pop3_storage->pop3_command = NULL; pop3_storage->pop3_auth_type = pop3_auth_type; if (pop3_login != NULL) { pop3_storage->pop3_login = strdup(pop3_login); if (pop3_storage->pop3_login == NULL) goto free_command; } else pop3_storage->pop3_login = NULL; if (pop3_password != NULL) { pop3_storage->pop3_password = strdup(pop3_password); if (pop3_storage->pop3_password == NULL) goto free_login; } else pop3_storage->pop3_password = NULL; pop3_storage->pop3_cached = pop3_cached; if (pop3_cached && (pop3_cache_directory != NULL) && (pop3_flags_directory != NULL)) { pop3_storage->pop3_cache_directory = strdup(pop3_cache_directory); if (pop3_storage->pop3_cache_directory == NULL) goto free_password; pop3_storage->pop3_flags_directory = strdup(pop3_flags_directory); if (pop3_storage->pop3_flags_directory == NULL) goto free_cache_directory; } else { pop3_storage->pop3_cached = FALSE; pop3_storage->pop3_cache_directory = NULL; pop3_storage->pop3_flags_directory = NULL; } storage->sto_data = pop3_storage; storage->sto_driver = &pop3_mailstorage_driver; return MAIL_NO_ERROR; free_cache_directory: free(pop3_storage->pop3_cache_directory); free_password: if (pop3_storage->pop3_password != NULL) free(pop3_storage->pop3_password); free_login: if (pop3_storage->pop3_login != NULL) free(pop3_storage->pop3_login); free_command: if (pop3_storage->pop3_command != NULL) free(pop3_storage->pop3_command); free_servername: if (pop3_storage->pop3_servername != NULL) free(pop3_storage->pop3_servername); free: free(pop3_storage); err: return MAIL_ERROR_MEMORY; } static void pop3_mailstorage_uninitialize(struct mailstorage * storage) { struct pop3_mailstorage * pop3_storage; pop3_storage = storage->sto_data; if (pop3_storage->pop3_flags_directory != NULL) free(pop3_storage->pop3_flags_directory); if (pop3_storage->pop3_cache_directory != NULL) free(pop3_storage->pop3_cache_directory); if (pop3_storage->pop3_password != NULL) free(pop3_storage->pop3_password); if (pop3_storage->pop3_login != NULL) free(pop3_storage->pop3_login); if (pop3_storage->pop3_command != NULL) free(pop3_storage->pop3_command); free(pop3_storage->pop3_servername); free(pop3_storage); storage->sto_data = pop3_storage; } static int pop3_mailstorage_connect(struct mailstorage * storage) { struct pop3_mailstorage * pop3_storage; mailsession_driver * driver; int r; int res; mailsession * session; int auth_type; pop3_storage = storage->sto_data; if (pop3_storage->pop3_cached) driver = pop3_cached_session_driver; else driver = pop3_session_driver; r = mailstorage_generic_connect(driver, pop3_storage->pop3_servername, pop3_storage->pop3_port, pop3_storage->pop3_command, pop3_storage->pop3_connection_type, POP3DRIVER_CACHED_SET_CACHE_DIRECTORY, pop3_storage->pop3_cache_directory, POP3DRIVER_CACHED_SET_FLAGS_DIRECTORY, pop3_storage->pop3_flags_directory, &session); switch (r) { case MAIL_NO_ERROR_NON_AUTHENTICATED: case MAIL_NO_ERROR_AUTHENTICATED: case MAIL_NO_ERROR: break; default: res = r; goto err; } auth_type = -1; switch (pop3_storage->pop3_auth_type) { case POP3_AUTH_TYPE_PLAIN: auth_type = POP3DRIVER_AUTH_TYPE_PLAIN; break; case POP3_AUTH_TYPE_APOP: auth_type = POP3DRIVER_AUTH_TYPE_APOP; break; case POP3_AUTH_TYPE_TRY_APOP: auth_type = POP3DRIVER_AUTH_TYPE_TRY_APOP; break; } if (auth_type != -1) { mailsession_parameters(session, POP3DRIVER_SET_AUTH_TYPE, &auth_type); } r = mailstorage_generic_auth(session, r, pop3_storage->pop3_auth_type, pop3_storage->pop3_login, pop3_storage->pop3_password); if (r != MAIL_NO_ERROR) { if (pop3_storage->pop3_auth_type == POP3_AUTH_TYPE_TRY_APOP) { /* try in clear authentication */ mailsession_free(session); pop3_storage->pop3_auth_type = POP3_AUTH_TYPE_PLAIN; r = mailstorage_connect(storage); if (r != MAIL_NO_ERROR) { res = r; return res; } pop3_storage->pop3_auth_type = POP3_AUTH_TYPE_TRY_APOP; return MAIL_NO_ERROR; } res = r; goto free; } storage->sto_session = session; return MAIL_NO_ERROR; free: mailsession_free(session); err: return res; } static int pop3_mailstorage_get_folder_session(struct mailstorage * storage, char * pathname, mailsession ** result) { * result = storage->sto_session; return MAIL_NO_ERROR; } |