From 9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf Mon Sep 17 00:00:00 2001 From: zautrix Date: Fri, 18 Mar 2005 20:17:03 +0000 Subject: Initial revision --- (limited to 'libetpan/src/driver/implementation/imap') diff --git a/libetpan/src/driver/implementation/imap/imapdriver.c b/libetpan/src/driver/implementation/imap/imapdriver.c new file mode 100644 index 0000000..815e077 --- a/dev/null +++ b/libetpan/src/driver/implementation/imap/imapdriver.c @@ -0,0 +1,1226 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "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 +#include + +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); +} + + + +#define IMAP_SET_MAX_COUNT 100 + +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; + clistiter * set_iter; + + 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); + + set_iter = clist_begin(set->set_list); + while (set_iter != NULL) { + struct mailimap_set * subset; + unsigned int count; + + subset = mailimap_set_new_empty(); + if (subset == NULL) { + res = MAIL_ERROR_MEMORY; + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); + res = MAIL_ERROR_MEMORY; + goto err; + } + + count = 0; + while (count < IMAP_SET_MAX_COUNT) { + struct mailimap_set_item * item; + + item = clist_content(set_iter); + set_iter = clist_delete(set->set_list, set_iter); + + r = mailimap_set_add(subset, item); + if (r != MAILIMAP_NO_ERROR) { + mailimap_set_item_free(item); + mailimap_set_free(subset); + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); + res = MAIL_ERROR_MEMORY; + goto err; + } + + count ++; + + if (set_iter == NULL) + break; + } + + r = mailimap_uid_fetch(get_imap_session(session), subset, + fetch_type, &fetch_result); + + mailimap_set_free(subset); + + switch (r) { + case MAILIMAP_NO_ERROR: + break; + default: + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); + 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) { + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); + res = MAIL_ERROR_MEMORY; + goto err; + } + } + +#if 0 + r = mailimap_uid_fetch(get_imap_session(session), set, + fetch_type, &fetch_result); +#endif + + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); +#if 0 + 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; + } +#endif + + 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/libetpan/src/driver/implementation/imap/imapdriver.h b/libetpan/src/driver/implementation/imap/imapdriver.h new file mode 100644 index 0000000..cbc0c51 --- a/dev/null +++ b/libetpan/src/driver/implementation/imap/imapdriver.h @@ -0,0 +1,52 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef IMAPDRIVER_H + +#define IMAPDRIVER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +extern mailsession_driver * imap_session_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/imap/imapdriver_cached.c b/libetpan/src/driver/implementation/imap/imapdriver_cached.c new file mode 100644 index 0000000..806b282 --- a/dev/null +++ b/libetpan/src/driver/implementation/imap/imapdriver_cached.c @@ -0,0 +1,1370 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "imapdriver_cached.h" + +#include "libetpan-config.h" + +#include +#include +#include +#include +#include +#include +#include + +#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) { + mailmessage * msg; + + msg = carray_get(env_list->msg_tab, i); + mailmessage_free(msg); + 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; +} + +#define IMAP_SET_MAX_COUNT 100 + +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; + clistiter * set_iter; + +#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); + + set_iter = clist_begin(set->set_list); + while (set_iter != NULL) { + struct mailimap_set * subset; + unsigned int count; + + subset = mailimap_set_new_empty(); + if (subset == NULL) { + res = MAIL_ERROR_MEMORY; + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); + res = MAIL_ERROR_MEMORY; + goto err; + } + + count = 0; + while (count < IMAP_SET_MAX_COUNT) { + struct mailimap_set_item * item; + + item = clist_content(set_iter); + set_iter = clist_delete(set->set_list, set_iter); + + r = mailimap_set_add(subset, item); + if (r != MAILIMAP_NO_ERROR) { + mailimap_set_item_free(item); + mailimap_set_free(subset); + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); + res = MAIL_ERROR_MEMORY; + goto err; + } + + count ++; + + if (set_iter == NULL) + break; + } + + r = mailimap_uid_fetch(get_imap_session(session), subset, + fetch_type, &fetch_result); + + mailimap_set_free(subset); + + switch (r) { + case MAILIMAP_NO_ERROR: + break; + default: + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); + 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) { + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); + res = MAIL_ERROR_MEMORY; + goto err; + } + } + +#if 0 + r = mailimap_uid_fetch(get_imap_session(session), set, + fetch_type, &fetch_result); +#endif + + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); + +#if 0 + 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; + } +#endif + + /* 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/libetpan/src/driver/implementation/imap/imapdriver_cached.h b/libetpan/src/driver/implementation/imap/imapdriver_cached.h new file mode 100644 index 0000000..c324f5e --- a/dev/null +++ b/libetpan/src/driver/implementation/imap/imapdriver_cached.h @@ -0,0 +1,52 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef IMAPDRIVER_CACHED_H + +#define IMAPDRIVER_CACHED_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailsession_driver * imap_cached_session_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/imap/imapdriver_cached_message.c b/libetpan/src/driver/implementation/imap/imapdriver_cached_message.c new file mode 100644 index 0000000..34e1ca3 --- a/dev/null +++ b/libetpan/src/driver/implementation/imap/imapdriver_cached_message.c @@ -0,0 +1,664 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "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 +#include + +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:; +} + +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/libetpan/src/driver/implementation/imap/imapdriver_cached_message.h b/libetpan/src/driver/implementation/imap/imapdriver_cached_message.h new file mode 100644 index 0000000..bf43311 --- a/dev/null +++ b/libetpan/src/driver/implementation/imap/imapdriver_cached_message.h @@ -0,0 +1,52 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef IMAPDRIVER_CACHED_MESSAGE_H + +#define IMAPDRIVER_CACHED_MESSAGE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailmessage_driver * imap_cached_message_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/imap/imapdriver_message.c b/libetpan/src/driver/implementation/imap/imapdriver_message.c new file mode 100644 index 0000000..42e645d --- a/dev/null +++ b/libetpan/src/driver/implementation/imap/imapdriver_message.c @@ -0,0 +1,1239 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "imapdriver_message.h" + +#include "imapdriver_tools.h" +#include "imapdriver.h" +#include "imapdriver_types.h" +#include "mailimap.h" +#include "maildriver_tools.h" +#include "generic_cache.h" + +#include +#include + +static int imap_initialize(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 void imap_flush(mailmessage * msg_info); + +static void imap_check(mailmessage * msg_info); + +static mailmessage_driver local_imap_message_driver = { + .msg_name = "imap", + + .msg_initialize = imap_initialize, + .msg_uninitialize = NULL, + + .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_message_driver = &local_imap_message_driver; + +static inline struct imap_session_state_data * +get_session_data(mailmessage * msg) +{ + return msg->msg_session->sess_data; +} + +static inline mailimap * get_imap_session(mailmessage * msg) +{ + return get_session_data(msg)->imap_session; +} + + + +static int imap_initialize(mailmessage * msg_info) +{ + char key[PATH_MAX]; + char * uid; + mailimap * imap; + + 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) { + return MAIL_ERROR_MEMORY; + } + + msg_info->msg_uid = uid; + + return MAIL_NO_ERROR; +} + + +static void imap_fetch_result_free(mailmessage * msg_info, + char * msg) +{ + if (msg != NULL) { + if (mmap_string_unref(msg) != 0) + free(msg); + } +} + + +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) +{ + int r; + + if (msg_info->msg_flags != NULL) { + r = mail_flags_store_set(get_session_data(msg_info)->imap_flags_store, + msg_info); + /* ignore errors */ + } +} + +static int imap_fetch(mailmessage * msg_info, + char ** result, + size_t * result_len) +{ + int r; + struct mailimap_set * set; + struct mailimap_fetch_att * fetch_att; + struct mailimap_fetch_type * fetch_type; + clist * fetch_result; + struct mailimap_msg_att * msg_att; + struct mailimap_msg_att_item * msg_att_item; + char * text; + size_t text_length; + int res; + clistiter * cur; + struct mailimap_section * section; + + set = mailimap_set_new_single(msg_info->msg_index); + if (set == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + +#if 0 + fetch_att = mailimap_fetch_att_new_rfc822(); + if (fetch_att == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_set; + } + + fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att); + if (fetch_type == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_att; + } + + r = mailimap_uid_fetch(get_imap_session(msg_info->session), set, + fetch_type, &fetch_result); + + mailimap_fetch_type_free(fetch_type); +#endif + + section = mailimap_section_new(NULL); + if (section == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_set; + } + + fetch_att = mailimap_fetch_att_new_body_peek_section(section); + if (fetch_att == NULL) { + mailimap_section_free(section); + res = MAIL_ERROR_MEMORY; + goto free_set; + } + + fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att); + if (fetch_type == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_att; + } + + r = mailimap_uid_fetch(get_imap_session(msg_info), 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) { + mailimap_fetch_list_free(fetch_result); + return MAIL_ERROR_FETCH; + } + + msg_att = clist_begin(fetch_result)->data; + + text = NULL; + text_length = 0; + + for(cur = clist_begin(msg_att->att_list) ; cur != NULL ; + cur = clist_next(cur)) { + msg_att_item = clist_content(cur); + + if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) { +#if 0 + if (msg_att_item->msg_att_static->type == MAILIMAP_MSG_ATT_RFC822) { + text = msg_att_item->msg_att_static->rfc822; + msg_att_item->msg_att_static->rfc822 = NULL; + text_length = msg_att_item->msg_att_static->length; + } +#endif + if (msg_att_item->att_data.att_static->att_type == + MAILIMAP_MSG_ATT_BODY_SECTION) { + text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part; + /* detach */ + msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL; + text_length = + msg_att_item->att_data.att_static->att_data.att_body_section->sec_length; + } + } + } + + mailimap_fetch_list_free(fetch_result); + + if (text == NULL) + return MAIL_ERROR_FETCH; + + * result = text; + * result_len = text_length; + + return MAIL_NO_ERROR; + + free_fetch_att: + mailimap_fetch_att_free(fetch_att); + free_set: + mailimap_set_free(set); + err: + return res; +} + +static int imap_fetch_header(mailmessage * msg_info, + char ** result, + size_t * result_len) +{ + int r; + struct mailimap_set * set; + struct mailimap_fetch_att * fetch_att; + struct mailimap_fetch_type * fetch_type; + clist * fetch_result; + struct mailimap_msg_att * msg_att; + struct mailimap_msg_att_item * msg_att_item; + char * text; + size_t text_length; + int res; + clistiter * cur; + struct mailimap_section * section; + + set = mailimap_set_new_single(msg_info->msg_index); + if (set == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + +#if 0 + fetch_att = mailimap_fetch_att_new_rfc822_header(); + if (fetch_att == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_set; + } + + fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att); + if (fetch_type == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_att; + } + + r = mailimap_uid_fetch(get_imap_session(msg_info->session), + set, fetch_type, &fetch_result); + + mailimap_fetch_type_free(fetch_type); +#endif + + section = mailimap_section_new_header(); + if (section == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_set; + } + + fetch_att = mailimap_fetch_att_new_body_peek_section(section); + if (fetch_att == NULL) { + mailimap_section_free(section); + res = MAIL_ERROR_MEMORY; + goto free_set; + } + + fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att); + if (fetch_type == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_att; + } + + r = mailimap_uid_fetch(get_imap_session(msg_info), 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) { + mailimap_fetch_list_free(fetch_result); + return MAIL_ERROR_FETCH; + } + + msg_att = clist_begin(fetch_result)->data; + + text = NULL; + text_length = 0; + + for(cur = clist_begin(msg_att->att_list) ; cur != NULL ; + cur = clist_next(cur)) { + msg_att_item = clist_content(cur); + + if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) { +#if 0 + if (msg_att_item->msg_att_static->type == + MAILIMAP_MSG_ATT_RFC822_HEADER) { + text = msg_att_item->msg_att_static->rfc822_header; + msg_att_item->msg_att_static->rfc822_header = NULL; + text_length = msg_att_item->msg_att_static->length; + } +#endif + if (msg_att_item->att_data.att_static->att_type == + MAILIMAP_MSG_ATT_BODY_SECTION) { + text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part; + msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL; + text_length = + msg_att_item->att_data.att_static->att_data.att_body_section->sec_length; + } + } + } + + mailimap_fetch_list_free(fetch_result); + + if (text == NULL) + return MAIL_ERROR_FETCH; + + * result = text; + * result_len = text_length; + + return MAIL_NO_ERROR; + + free_fetch_att: + mailimap_fetch_att_free(fetch_att); + free_set: + mailimap_set_free(set); + err: + return res; +} + +static int imap_fetch_body(mailmessage * msg_info, + char ** result, size_t * result_len) +{ + int r; + struct mailimap_set * set; + struct mailimap_fetch_att * fetch_att; + struct mailimap_fetch_type * fetch_type; + clist * fetch_result; + struct mailimap_msg_att * msg_att; + struct mailimap_msg_att_item * msg_att_item; + char * text; + size_t text_length; + int res; + clistiter * cur; + struct mailimap_section * section; + + set = mailimap_set_new_single(msg_info->msg_index); + if (set == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + +#if 0 + fetch_att = mailimap_fetch_att_new_rfc822_text(); + if (fetch_att == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_set; + } + + fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att); + if (fetch_type == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_att; + } + + r = mailimap_uid_fetch(get_imap_session(msg_info->session), set, + fetch_type, &fetch_result); + + mailimap_fetch_type_free(fetch_type); +#endif + section = mailimap_section_new_text(); + if (section == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_set; + } + + fetch_att = mailimap_fetch_att_new_body_peek_section(section); + if (fetch_att == NULL) { + mailimap_section_free(section); + res = MAIL_ERROR_MEMORY; + goto free_set; + } + + fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att); + if (fetch_type == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_att; + } + + r = mailimap_uid_fetch(get_imap_session(msg_info), 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); + } + + cur = clist_begin(fetch_result); + if (cur == NULL) { + mailimap_fetch_list_free(fetch_result); + return MAIL_ERROR_FETCH; + } + + msg_att = clist_content(cur); + + text = NULL; + text_length = 0; + + for(cur = clist_begin(msg_att->att_list) ; cur != NULL ; + cur = clist_next(cur)) { + msg_att_item = clist_content(cur); + + if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) { +#if 0 + if (msg_att_item->msg_att_static->type == + MAILIMAP_MSG_ATT_RFC822_TEXT) { + text = msg_att_item->msg_att_static->rfc822_text; + msg_att_item->msg_att_static->rfc822_text = NULL; + text_length = msg_att_item->msg_att_static->length; + } +#endif + if (msg_att_item->att_data.att_static->att_type == + MAILIMAP_MSG_ATT_BODY_SECTION) { + text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part; + msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL; + text_length = + msg_att_item->att_data.att_static->att_data.att_body_section->sec_length; + } + } + } + + mailimap_fetch_list_free(fetch_result); + + if (text == NULL) + return MAIL_ERROR_FETCH; + + * result = text; + * result_len = text_length; + + return MAIL_NO_ERROR; + + free_fetch_att: + mailimap_fetch_att_free(fetch_att); + free_set: + mailimap_set_free(set); + err: + return res; +} + +static int imap_fetch_size(mailmessage * msg_info, + size_t * result) +{ + int r; + struct mailimap_set * set; + struct mailimap_fetch_att * fetch_att; + struct mailimap_fetch_type * fetch_type; + clist * fetch_result; + struct mailimap_msg_att * msg_att; + struct mailimap_msg_att_item * msg_att_item; + size_t size; + int res; + clistiter * cur; + + set = mailimap_set_new_single(msg_info->msg_index); + if (set == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + fetch_att = mailimap_fetch_att_new_rfc822_size(); + if (fetch_att == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_set; + } + + fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att); + if (fetch_type == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_att; + } + + r = mailimap_uid_fetch(get_imap_session(msg_info), set, + fetch_type, &fetch_result); + + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); + + switch (r) { + case MAILIMAP_ERROR_BAD_STATE: + return MAIL_ERROR_BAD_STATE; + case MAILIMAP_ERROR_STREAM: + return MAIL_ERROR_STREAM; + case MAILIMAP_NO_ERROR: + break; + default: + return MAIL_ERROR_FETCH; + } + + if (clist_begin(fetch_result) == NULL) { + mailimap_fetch_list_free(fetch_result); + return MAIL_ERROR_FETCH; + } + + msg_att = clist_begin(fetch_result)->data; + + for(cur = clist_begin(msg_att->att_list) ; cur != NULL ; + cur = clist_next(cur)) { + msg_att_item = clist_content(cur); + + if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) { + + if (msg_att_item->att_data.att_static->att_type == + MAILIMAP_MSG_ATT_RFC822_SIZE) { + size = msg_att_item->att_data.att_static->att_data.att_rfc822_size; + + * result = size; + + mailimap_fetch_list_free(fetch_result); + return MAIL_NO_ERROR; + } + } + } + + mailimap_fetch_list_free(fetch_result); + + return MAIL_ERROR_FETCH; + + free_fetch_att: + mailimap_fetch_att_free(fetch_att); + free_set: + mailimap_set_free(set); + err: + return res; +} + +static int imap_get_bodystructure(mailmessage * msg_info, + struct mailmime ** result) +{ + int r; + struct mailimap_set * set; + struct mailimap_fetch_att * fetch_att; + struct mailimap_fetch_type * fetch_type; + clist * fetch_result; + struct mailimap_msg_att * msg_att; + struct mailimap_body * imap_body; + struct mailmime * body; + int res; + struct mailimf_fields * fields; + struct mailmime * new_body; + struct mailmime_content * content_message; + struct mailimap_envelope * envelope; + uint32_t uid; + char * references; + size_t ref_size; + clistiter * cur; + + if (msg_info->msg_mime != NULL) { + * result = msg_info->msg_mime; + + return MAIL_NO_ERROR; + } + + set = mailimap_set_new_single(msg_info->msg_index); + 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_bodystructure(); + 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 = mailimap_uid_fetch(get_imap_session(msg_info), 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); + } + + cur = clist_begin(fetch_result); + if (cur == NULL) { + mailimap_fetch_list_free(fetch_result); + return MAIL_ERROR_FETCH; + } + + msg_att = clist_content(cur); + + uid = 0; + references = NULL; + ref_size = 0; + imap_body = NULL; + envelope = NULL; + + r = imap_get_msg_att_info(msg_att, + &uid, &envelope, &references, &ref_size, NULL, &imap_body); + if (r != MAIL_NO_ERROR) { + mailimap_fetch_list_free(fetch_result); + res = r; + goto err; + } + + if (uid != msg_info->msg_index) { + mailimap_fetch_list_free(fetch_result); + res = MAIL_ERROR_MSG_NOT_FOUND; + goto err; + } + + if (imap_body == NULL) { + mailimap_fetch_list_free(fetch_result); + res = MAIL_ERROR_FETCH; + goto err; + } + + r = imap_body_to_body(imap_body, &body); + if (r != MAIL_NO_ERROR) { + mailimap_fetch_list_free(fetch_result); + res = r; + goto err; + } + + fields = NULL; + if (envelope != NULL) { + r = imap_env_to_fields(envelope, references, ref_size, &fields); + if (r != MAIL_NO_ERROR) { + mailmime_free(body); + mailimap_fetch_list_free(fetch_result); + res = r; + goto err; + } + } + + content_message = mailmime_get_content_message(); + if (content_message == NULL) { + if (fields != NULL) + mailimf_fields_free(fields); + mailmime_free(body); + mailimap_fetch_list_free(fetch_result); + res = MAIL_ERROR_MEMORY; + goto err; + } + + new_body = mailmime_new(MAILMIME_MESSAGE, NULL, + 0, NULL, content_message, + NULL, NULL, NULL, NULL, fields, body); + + if (new_body == NULL) { + mailmime_content_free(content_message); + if (fields != NULL) + mailimf_fields_free(fields); + mailmime_free(body); + mailimap_fetch_list_free(fetch_result); + res = MAIL_ERROR_MEMORY; + goto err; + } + msg_info->msg_mime = new_body; + + mailimap_fetch_list_free(fetch_result); + + * result = new_body; + + return MAIL_NO_ERROR; + + free_fetch_type: + mailimap_fetch_type_free(fetch_type); + free_set: + mailimap_set_free(set); + err: + return res; +} + +static int +fetch_imap(mailmessage * msg, + struct mailimap_fetch_type * fetch_type, + char ** result, size_t * result_len) +{ + int r; + struct mailimap_msg_att * msg_att; + struct mailimap_msg_att_item * msg_att_item; + clist * fetch_result; + struct mailimap_set * set; + char * text; + size_t text_length; + clistiter * cur; + + set = mailimap_set_new_single(msg->msg_index); + if (set == NULL) + return MAIL_ERROR_MEMORY; + + r = mailimap_uid_fetch(get_imap_session(msg), set, + fetch_type, &fetch_result); + + 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) { + mailimap_fetch_list_free(fetch_result); + return MAIL_ERROR_FETCH; + } + + msg_att = clist_begin(fetch_result)->data; + + text = NULL; + text_length = 0; + + for(cur = clist_begin(msg_att->att_list) ; cur != NULL ; + cur = clist_next(cur)) { + msg_att_item = clist_content(cur); + + if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) { + + if (msg_att_item->att_data.att_static->att_type == + MAILIMAP_MSG_ATT_BODY_SECTION) { + text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part; + msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL; + text_length = + msg_att_item->att_data.att_static->att_data.att_body_section->sec_length; + } + } + } + + mailimap_fetch_list_free(fetch_result); + + if (text == NULL) + return MAIL_ERROR_FETCH; + + * result = text; + * result_len = text_length; + + return MAIL_NO_ERROR; +} + + +static int imap_fetch_section(mailmessage * msg_info, + struct mailmime * mime, + char ** result, size_t * result_len) +{ + struct mailimap_section * section; + struct mailimap_fetch_att * fetch_att; + int r; + struct mailimap_fetch_type * fetch_type; + char * text; + size_t text_length; + struct mailmime_section * part; + + if (mime->mm_parent == NULL) + return imap_fetch(msg_info, result, result_len); + + r = mailmime_get_section_id(mime, &part); + if (r != MAILIMF_NO_ERROR) + return maildriver_imf_error_to_mail_error(r); + + r = section_to_imap_section(part, IMAP_SECTION_MESSAGE, §ion); + mailmime_section_free(part); + if (r != MAIL_NO_ERROR) + return r; + + fetch_att = mailimap_fetch_att_new_body_peek_section(section); + if (fetch_att == NULL) { + mailimap_section_free(section); + return MAIL_ERROR_MEMORY; + } + + fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att); + if (fetch_type == NULL) { + mailimap_fetch_att_free(fetch_att); + return MAIL_ERROR_MEMORY; + } + + r = fetch_imap(msg_info, fetch_type, &text, &text_length); + + mailimap_fetch_type_free(fetch_type); + + if (r != MAIL_NO_ERROR) + return r; + + * result = text; + * result_len = text_length; + + return MAIL_NO_ERROR; +} + +static int imap_fetch_section_header(mailmessage * msg_info, + struct mailmime * mime, + char ** result, + size_t * result_len) +{ + struct mailimap_section * section; + struct mailimap_fetch_att * fetch_att; + int r; + struct mailimap_fetch_type * fetch_type; + char * text; + size_t text_length; + struct mailmime_section * part; + + if (mime->mm_parent == NULL) + return imap_fetch_header(msg_info, result, result_len); + + r = mailmime_get_section_id(mime, &part); + if (r != MAILIMF_NO_ERROR) + return maildriver_imf_error_to_mail_error(r); + + r = section_to_imap_section(part, IMAP_SECTION_HEADER, §ion); + mailmime_section_free(part); + if (r != MAIL_NO_ERROR) + return r; + + fetch_att = mailimap_fetch_att_new_body_peek_section(section); + if (fetch_att == NULL) { + mailimap_section_free(section); + return MAIL_ERROR_MEMORY; + } + + fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att); + if (fetch_type == NULL) { + mailimap_fetch_att_free(fetch_att); + return MAIL_ERROR_MEMORY; + } + + r = fetch_imap(msg_info, fetch_type, &text, &text_length); + mailimap_fetch_type_free(fetch_type); + + if (r != MAIL_NO_ERROR) + return r; + + * result = text; + * result_len = text_length; + + return MAIL_NO_ERROR; +} + +static int imap_fetch_section_mime(mailmessage * msg_info, + struct mailmime * mime, + char ** result, + size_t * result_len) +{ + struct mailimap_section * section; + struct mailimap_fetch_att * fetch_att; + int r; + struct mailimap_fetch_type * fetch_type; + char * text; + size_t text_length; + struct mailmime_section * part; + + if (mime->mm_parent == NULL) + return MAIL_ERROR_INVAL; + + if (mime->mm_parent->mm_parent == NULL) + return imap_fetch_header(msg_info, result, result_len); + + r = mailmime_get_section_id(mime, &part); + if (r != MAILIMF_NO_ERROR) + return maildriver_imf_error_to_mail_error(r); + + r = section_to_imap_section(part, IMAP_SECTION_MIME, §ion); + mailmime_section_free(part); + if (r != MAIL_NO_ERROR) + return MAIL_ERROR_MEMORY; + + fetch_att = mailimap_fetch_att_new_body_peek_section(section); + if (fetch_att == NULL) { + mailimap_section_free(section); + return MAIL_ERROR_MEMORY; + } + + fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att); + if (fetch_type == NULL) { + mailimap_fetch_att_free(fetch_att); + return MAIL_ERROR_MEMORY; + } + + r = fetch_imap(msg_info, fetch_type, &text, &text_length); + + mailimap_fetch_type_free(fetch_type); + + if (r != MAIL_NO_ERROR) + return r; + + * result = text; + * result_len = text_length; + + return MAIL_NO_ERROR; +} + +static int imap_fetch_section_body(mailmessage * msg_info, + struct mailmime * mime, + char ** result, + size_t * result_len) +{ + struct mailimap_section * section; + struct mailimap_fetch_att * fetch_att; + int r; + struct mailimap_fetch_type * fetch_type; + char * text; + size_t text_length; + struct mailmime_section * part; + + if (mime->mm_parent == NULL) + return imap_fetch_body(msg_info, result, result_len); + + if (mime->mm_parent->mm_parent == NULL) + return imap_fetch_body(msg_info, result, result_len); + + r = mailmime_get_section_id(mime, &part); + if (r != MAILIMF_NO_ERROR) + return maildriver_imf_error_to_mail_error(r); + + r = section_to_imap_section(part, IMAP_SECTION_BODY, §ion); + mailmime_section_free(part); + if (r != MAIL_NO_ERROR) + return MAIL_ERROR_MEMORY; + + fetch_att = mailimap_fetch_att_new_body_peek_section(section); + if (fetch_att == NULL) { + mailimap_section_free(section); + return MAIL_ERROR_MEMORY; + } + + fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att); + if (fetch_type == NULL) { + mailimap_fetch_att_free(fetch_att); + return MAIL_ERROR_MEMORY; + } + + r = fetch_imap(msg_info, fetch_type, &text, &text_length); + + mailimap_fetch_type_free(fetch_type); + + if (r != MAIL_NO_ERROR) + return r; + + * result = text; + * result_len = text_length; + + return MAIL_NO_ERROR; +} + +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; + } + + flags = mail_flags_store_get(get_session_data(msg_info)->imap_flags_store, + msg_info->msg_index); + + if (flags == NULL) { + r = imap_fetch_flags(get_imap_session(msg_info), + msg_info->msg_index, &flags); + if (r != MAIL_NO_ERROR) + return r; + } + + msg_info->msg_flags = flags; + + * result = flags; + + return MAIL_NO_ERROR; +} + +static int imap_fetch_envelope(mailmessage * msg_info, + struct mailimf_fields ** result) +{ + int r; + struct mailimap_set * set; + struct mailimap_fetch_att * fetch_att; + struct mailimap_fetch_type * fetch_type; + clist * fetch_result; + struct mailimap_msg_att * msg_att; + int res; + struct mailimf_fields * fields; + struct mailimap_envelope * envelope; + uint32_t uid; + char * references; + size_t ref_size; + + set = mailimap_set_new_single(msg_info->msg_index); + 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; + } + + r = imap_add_envelope_fetch_att(fetch_type); + if (r != MAIL_NO_ERROR) { + res = r; + goto free_fetch_type; + } + + r = mailimap_uid_fetch(get_imap_session(msg_info), 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) { + mailimap_fetch_list_free(fetch_result); + return MAIL_ERROR_FETCH; + } + + msg_att = clist_begin(fetch_result)->data; + + uid = 0; + references = NULL; + ref_size = 0; + envelope = NULL; + + r = imap_get_msg_att_info(msg_att, + &uid, + &envelope, + &references, + &ref_size, + NULL, + NULL); + if (r != MAIL_NO_ERROR) { + mailimap_fetch_list_free(fetch_result); + res = r; + goto err; + } + + if (uid != msg_info->msg_index) { + mailimap_fetch_list_free(fetch_result); + res = MAIL_ERROR_MSG_NOT_FOUND; + goto err; + } + + fields = NULL; + if (envelope != NULL) { + r = imap_env_to_fields(envelope, references, ref_size, &fields); + if (r != MAIL_NO_ERROR) { + mailimap_fetch_list_free(fetch_result); + res = r; + goto err; + } + } + + mailimap_fetch_list_free(fetch_result); + + * result = fields; + + return MAIL_NO_ERROR; + + free_fetch_type: + mailimap_fetch_type_free(fetch_type); + free_set: + mailimap_set_free(set); + err: + return res; +} diff --git a/libetpan/src/driver/implementation/imap/imapdriver_message.h b/libetpan/src/driver/implementation/imap/imapdriver_message.h new file mode 100644 index 0000000..74fc2e6 --- a/dev/null +++ b/libetpan/src/driver/implementation/imap/imapdriver_message.h @@ -0,0 +1,52 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef IMAPDRIVER_MESSAGE_H + +#define IMAPDRIVER_MESSAGE_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailmessage_driver * imap_message_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/imap/imapdriver_tools.c b/libetpan/src/driver/implementation/imap/imapdriver_tools.c new file mode 100644 index 0000000..6051281 --- a/dev/null +++ b/libetpan/src/driver/implementation/imap/imapdriver_tools.c @@ -0,0 +1,3623 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "imapdriver_tools.h" + +#include "maildriver.h" + +#include +#include + +#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; +} + +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; + 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/libetpan/src/driver/implementation/imap/imapdriver_tools.h b/libetpan/src/driver/implementation/imap/imapdriver_tools.h new file mode 100644 index 0000000..e15fdda --- a/dev/null +++ b/libetpan/src/driver/implementation/imap/imapdriver_tools.h @@ -0,0 +1,116 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef 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/libetpan/src/driver/implementation/imap/imapdriver_types.h b/libetpan/src/driver/implementation/imap/imapdriver_types.h new file mode 100644 index 0000000..00559dc --- a/dev/null +++ b/libetpan/src/driver/implementation/imap/imapdriver_types.h @@ -0,0 +1,144 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef IMAPDRIVER_TYPES_H + +#define IMAPDRIVER_TYPES_H + +#include + +#include +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* IMAP driver for session */ + +struct imap_session_state_data { + mailimap * imap_session; + char * imap_mailbox; + struct mail_flags_store * imap_flags_store; +}; + +enum { + IMAP_SECTION_MESSAGE, + IMAP_SECTION_HEADER, + IMAP_SECTION_MIME, + IMAP_SECTION_BODY +}; + +/* cached IMAP driver for session */ + +enum { + IMAPDRIVER_CACHED_SET_CACHE_DIRECTORY = 1, +}; + +struct imap_cached_session_state_data { + mailsession * imap_ancestor; + char * imap_quoted_mb; + char imap_cache_directory[PATH_MAX]; + carray * imap_uid_list; +}; + + +/* IMAP storage */ + +/* + imap_mailstorage is the state data specific to the IMAP4rev1 storage. + + - servername this is the name of the IMAP4rev1 server + + - port is the port to connect to, on the server. + you give 0 to use the default port. + + - command, if non-NULL the command used to connect to the + server instead of allowing normal TCP connections to be used. + + - connection_type is the type of socket layer to use. + The value can be CONNECTION_TYPE_PLAIN, CONNECTION_TYPE_STARTTLS, + CONNECTION_TYPE_TRY_STARTTLS, CONNECTION_TYPE_TLS or + CONNECTION_TYPE_COMMAND. + + - auth_type is the authenticate mechanism to use. + The value can be IMAP_AUTH_TYPE_PLAIN. + Other values are not yet implemented. + + - login is the login of the IMAP4rev1 account. + + - password is the password of the IMAP4rev1 account. + + - cached if this value is != 0, a persistant cache will be + stored on local system. + + - cache_directory is the location of the cache +*/ + +struct imap_mailstorage { + 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; +}; + +/* this is the type of IMAP4rev1 authentication */ + +enum { + IMAP_AUTH_TYPE_PLAIN, /* plain text authentication */ + IMAP_AUTH_TYPE_SASL_ANONYMOUS, /* SASL anonymous */ + IMAP_AUTH_TYPE_SASL_CRAM_MD5, /* SASL CRAM MD5 */ + IMAP_AUTH_TYPE_SASL_KERBEROS_V4, /* SASL KERBEROS V4 */ + IMAP_AUTH_TYPE_SASL_PLAIN, /* SASL plain */ + IMAP_AUTH_TYPE_SASL_SCRAM_MD5, /* SASL SCRAM MD5 */ + IMAP_AUTH_TYPE_SASL_GSSAPI, /* SASL GSSAPI */ + IMAP_AUTH_TYPE_SASL_DIGEST_MD5, /* SASL digest MD5 */ +}; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/imap/imapstorage.c b/libetpan/src/driver/implementation/imap/imapstorage.c new file mode 100644 index 0000000..0bf6ec2 --- a/dev/null +++ b/libetpan/src/driver/implementation/imap/imapstorage.c @@ -0,0 +1,297 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "imapstorage.h" + +#include +#include + +#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(* 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/libetpan/src/driver/implementation/imap/imapstorage.h b/libetpan/src/driver/implementation/imap/imapstorage.h new file mode 100644 index 0000000..929a86e --- a/dev/null +++ b/libetpan/src/driver/implementation/imap/imapstorage.h @@ -0,0 +1,90 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef IMAPSTORAGE_H + +#define IMAPSTORAGE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* + imap_mailstorage_init is the constructor for a IMAP4rev1 storage + + @param storage this is the storage to initialize. + + @param servername this is the name of the IMAP4rev1 server + + @param port is the port to connect to, on the server. + you give 0 to use the default port. + + @param command the command used to connect to the server instead of + allowing normal TCP connections to be used. + + @param connection_type is the type of socket layer to use. + The value can be CONNECTION_TYPE_PLAIN, CONNECTION_TYPE_STARTTLS, + CONNECTION_TYPE_TRY_STARTTLS, CONNECTION_TYPE_TLS, + CONNECTION_TYPE_COMMAND, CONNECTION_TYPE_COMMAND_STARTTLS, + CONNECTION_TYPE_COMMAND_TRY_STARTTLS, CONNECTION_TYPE_COMMAND_TLS,. + + @param auth_type is the authenticate mechanism to use. + The value can be IMAP_AUTH_TYPE_PLAIN. + Other values are not yet implemented. + + @param login is the login of the IMAP4rev1 account. + + @param password is the password of the IMAP4rev1 account. + + @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 +*/ + +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); + +#ifdef __cplusplus +} +#endif + +#endif -- cgit v0.9.0.2