author | zautrix <zautrix> | 2004-09-01 10:23:29 (UTC) |
---|---|---|
committer | zautrix <zautrix> | 2004-09-01 10:23:29 (UTC) |
commit | 6cefbdc9c8f3f3001373f10715361e2740c45395 (patch) (side-by-side diff) | |
tree | cb2c36f57620e698913c27ca4ebe59e4a7c9d46e /kmicromail | |
parent | b9257cb225cd29bab5d96fcdaf557926603ee587 (diff) | |
download | kdepimpi-6cefbdc9c8f3f3001373f10715361e2740c45395.zip kdepimpi-6cefbdc9c8f3f3001373f10715361e2740c45395.tar.gz kdepimpi-6cefbdc9c8f3f3001373f10715361e2740c45395.tar.bz2 |
Mail fixes and libetpan updated
68 files changed, 1002 insertions, 89 deletions
diff --git a/kmicromail/libetpan/generic/imapdriver.c b/kmicromail/libetpan/generic/imapdriver.c index 0d63319..b3e5982 100644 --- a/kmicromail/libetpan/generic/imapdriver.c +++ b/kmicromail/libetpan/generic/imapdriver.c @@ -1,1130 +1,1158 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "imapdriver.h" #include "mail.h" #include "imapdriver_tools.h" #include "mailmessage.h" #include "imapdriver_message.h" #include "imapdriver_types.h" #include "maildriver.h" #include "maildriver_tools.h" #include "generic_cache.h" #include <stdlib.h> #include <string.h> static int imapdriver_initialize(mailsession * session); static void imapdriver_uninitialize(mailsession * session); static int imapdriver_connect_stream(mailsession * session, mailstream * s); static int imapdriver_starttls(mailsession * session); static int imapdriver_login(mailsession * session, char * userid, char * password); static int imapdriver_logout(mailsession * session); static int imapdriver_noop(mailsession * session); static int imapdriver_build_folder_name(mailsession * session, char * mb, char * name, char ** result); static int imapdriver_create_folder(mailsession * session, char * mb); static int imapdriver_delete_folder(mailsession * session, char * mb); static int imapdriver_rename_folder(mailsession * session, char * mb, char * new_name); static int imapdriver_check_folder(mailsession * session); static int imapdriver_examine_folder(mailsession * session, char * mb); static int imapdriver_select_folder(mailsession * session, char * mb); static int imapdriver_expunge_folder(mailsession * session); static int imapdriver_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); static int imapdriver_messages_number(mailsession * session, char * mb, uint32_t * result); static int imapdriver_recent_number(mailsession * session, char * mb, uint32_t * result); static int imapdriver_unseen_number(mailsession * session, char * mb, uint32_t * result); static int imapdriver_list_folders(mailsession * session, char * mb, struct mail_list ** result); static int imapdriver_lsub_folders(mailsession * session, char * mb, struct mail_list ** result); static int imapdriver_subscribe_folder(mailsession * session, char * mb); static int imapdriver_unsubscribe_folder(mailsession * session, char * mb); static int imapdriver_append_message(mailsession * session, char * message, size_t size); +static int imapdriver_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags); static int imapdriver_copy_message(mailsession * session, uint32_t num, char * mb); static int imapdriver_get_messages_list(mailsession * session, struct mailmessage_list ** result); static int imapdriver_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list); #if 0 static int imapdriver_search_messages(mailsession * session, char * charset, struct mail_search_key * key, struct mail_search_result ** result); #endif static int imapdriver_get_message(mailsession * session, uint32_t num, mailmessage ** result); static int imapdriver_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result); static mailsession_driver local_imap_session_driver = { .sess_name = "imap", .sess_initialize = imapdriver_initialize, .sess_uninitialize = imapdriver_uninitialize, .sess_parameters = NULL, .sess_connect_stream = imapdriver_connect_stream, .sess_connect_path = NULL, .sess_starttls = imapdriver_starttls, .sess_login = imapdriver_login, .sess_logout = imapdriver_logout, .sess_noop = imapdriver_noop, .sess_build_folder_name = imapdriver_build_folder_name, .sess_create_folder = imapdriver_create_folder, .sess_delete_folder = imapdriver_delete_folder, .sess_rename_folder = imapdriver_rename_folder, .sess_check_folder = imapdriver_check_folder, .sess_examine_folder = imapdriver_examine_folder, .sess_select_folder = imapdriver_select_folder, .sess_expunge_folder = imapdriver_expunge_folder, .sess_status_folder = imapdriver_status_folder, .sess_messages_number = imapdriver_messages_number, .sess_recent_number = imapdriver_recent_number, .sess_unseen_number = imapdriver_unseen_number, .sess_list_folders = imapdriver_list_folders, .sess_lsub_folders = imapdriver_lsub_folders, .sess_subscribe_folder = imapdriver_subscribe_folder, .sess_unsubscribe_folder = imapdriver_unsubscribe_folder, .sess_append_message = imapdriver_append_message, + .sess_append_message_flags = imapdriver_append_message_flags, .sess_copy_message = imapdriver_copy_message, .sess_move_message = NULL, .sess_get_messages_list = imapdriver_get_messages_list, .sess_get_envelopes_list = imapdriver_get_envelopes_list, .sess_remove_message = NULL, #if 0 .sess_search_messages = imapdriver_search_messages, #endif .sess_get_message = imapdriver_get_message, .sess_get_message_by_uid = imapdriver_get_message_by_uid, }; mailsession_driver * imap_session_driver = &local_imap_session_driver; static inline struct imap_session_state_data * get_data(mailsession * session) { return session->sess_data; } static mailimap * get_imap_session(mailsession * session) { return get_data(session)->imap_session; } static int imapdriver_initialize(mailsession * session) { struct imap_session_state_data * data; mailimap * imap; struct mail_flags_store * flags_store; imap = mailimap_new(0, NULL); if (imap == NULL) goto err; flags_store = mail_flags_store_new(); if (flags_store == NULL) goto free_session; data = malloc(sizeof(* data)); if (data == NULL) goto free_flags_store; data->imap_mailbox = NULL; data->imap_session = imap; data->imap_flags_store = flags_store; session->sess_data = data; return MAIL_NO_ERROR; free_flags_store: mail_flags_store_free(flags_store); free_session: mailimap_free(imap); err: return MAIL_ERROR_MEMORY; } static void imap_flags_store_process(mailimap * imap, struct mail_flags_store * flags_store) { unsigned int i; int r; mailmessage * first; mailmessage * last; mail_flags_store_sort(flags_store); if (carray_count(flags_store->fls_tab) == 0) return; first = carray_get(flags_store->fls_tab, 0); last = first; for(i = 1 ; i < carray_count(flags_store->fls_tab) ; i ++) { mailmessage * msg; msg = carray_get(flags_store->fls_tab, i); if (last->msg_index + 1 == msg->msg_index) { r = mail_flags_compare(first->msg_flags, msg->msg_flags); if (r == 0) { last = msg; continue; } } r = imap_store_flags(imap, first->msg_index, last->msg_index, first->msg_flags); first = msg; last = msg; } r = imap_store_flags(imap, first->msg_index, last->msg_index, first->msg_flags); mail_flags_store_clear(flags_store); } static void imapdriver_uninitialize(mailsession * session) { struct imap_session_state_data * data; data = get_data(session); imap_flags_store_process(data->imap_session, data->imap_flags_store); mail_flags_store_free(data->imap_flags_store); mailimap_free(data->imap_session); if (data->imap_mailbox != NULL) free(data->imap_mailbox); free(data); session->sess_data = NULL; } static int imapdriver_connect_stream(mailsession * session, mailstream * s) { int r; r = mailimap_connect(get_imap_session(session), s); return imap_error_to_mail_error(r); } static int imapdriver_login(mailsession * session, char * userid, char * password) { int r; r = mailimap_login(get_imap_session(session), userid, password); return imap_error_to_mail_error(r); } static int imapdriver_logout(mailsession * session) { int r; imap_flags_store_process(get_imap_session(session), get_data(session)->imap_flags_store); r = mailimap_logout(get_imap_session(session)); return imap_error_to_mail_error(r); } static int imapdriver_noop(mailsession * session) { int r; r = mailimap_noop(get_imap_session(session)); return imap_error_to_mail_error(r); } static int imapdriver_build_folder_name(mailsession * session, char * mb, char * name, char ** result) { char delimiter[2] = "X"; char * folder_name; mailimap * imap; struct mailimap_mailbox_list * mb_list; int r; clist * imap_list; imap = get_imap_session(session); r = mailimap_list(imap, mb, "", &imap_list); if (r != MAILIMAP_NO_ERROR) return r; if (clist_begin(imap_list) == NULL) return MAIL_ERROR_LIST; mb_list = clist_begin(imap_list)->data; delimiter[0] = mb_list->mb_delimiter; folder_name = malloc(strlen(mb) + strlen(delimiter) + strlen(name) + 1); if (folder_name == NULL) return MAIL_ERROR_MEMORY; strcpy(folder_name, mb); strcat(folder_name, delimiter); strcat(folder_name, name); * result = folder_name; return MAIL_NO_ERROR; } /* folders operations */ static int imapdriver_create_folder(mailsession * session, char * mb) { int r; r = mailimap_create(get_imap_session(session), mb); return imap_error_to_mail_error(r); } static int imapdriver_delete_folder(mailsession * session, char * mb) { int r; r = mailimap_delete(get_imap_session(session), mb); return imap_error_to_mail_error(r); } static int imapdriver_rename_folder(mailsession * session, char * mb, char * new_name) { int r; r = mailimap_rename(get_imap_session(session), mb, new_name); return imap_error_to_mail_error(r); } static int imapdriver_check_folder(mailsession * session) { int r; imap_flags_store_process(get_imap_session(session), get_data(session)->imap_flags_store); r = mailimap_check(get_imap_session(session)); return imap_error_to_mail_error(r); } static int imapdriver_examine_folder(mailsession * session, char * mb) { int r; r = mailimap_examine(get_imap_session(session), mb); return imap_error_to_mail_error(r); } static int imapdriver_select_folder(mailsession * session, char * mb) { int r; char * new_mb; char * old_mb; old_mb = get_data(session)->imap_mailbox; if (old_mb != NULL) if (strcmp(mb, old_mb) == 0) return MAIL_NO_ERROR; imap_flags_store_process(get_imap_session(session), get_data(session)->imap_flags_store); r = mailimap_select(get_imap_session(session), mb); switch (r) { case MAILIMAP_NO_ERROR: new_mb = strdup(mb); if (new_mb == NULL) { if (old_mb != NULL) free(old_mb); get_data(session)->imap_mailbox = NULL; return MAIL_ERROR_MEMORY; } get_data(session)->imap_mailbox = new_mb; return MAIL_NO_ERROR; default: return imap_error_to_mail_error(r); } } static int imapdriver_expunge_folder(mailsession * session) { int r; imap_flags_store_process(get_imap_session(session), get_data(session)->imap_flags_store); r = mailimap_expunge(get_imap_session(session)); return imap_error_to_mail_error(r); } static int status_selected_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { int r; int res; mailimap * imap; uint32_t exists; uint32_t unseen; uint32_t recent; struct mailimap_search_key * search_key; clist * search_result; imap = get_imap_session(session); exists = imap->imap_selection_info->sel_exists; recent = imap->imap_selection_info->sel_recent; search_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_UNSEEN, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL); if (search_key == NULL) { res = MAIL_ERROR_MEMORY; goto err; } /* default : use the RECENT count if search fails */ unseen = recent; r = mailimap_search(imap, NULL, search_key, &search_result); mailimap_search_key_free(search_key); if (r == MAILIMAP_NO_ERROR) { /* if this succeed, we use the real count */ unseen = clist_count(search_result); mailimap_mailbox_data_search_free(search_result); } * result_messages = exists; * result_unseen = unseen; * result_recent = recent; return MAIL_NO_ERROR; err: return res; } static int status_unselected_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { struct mailimap_status_att_list * att_list; struct mailimap_mailbox_data_status * status; int r; int res; clistiter * cur; mailimap * imap; imap = get_imap_session(session); att_list = mailimap_status_att_list_new_empty(); if (att_list == NULL) { res = MAIL_ERROR_MEMORY; goto err; } r = mailimap_status_att_list_add(att_list, MAILIMAP_STATUS_ATT_MESSAGES); switch (r) { case MAILIMAP_NO_ERROR: break; default: res = MAIL_ERROR_MEMORY; goto free; } r = mailimap_status_att_list_add(att_list, MAILIMAP_STATUS_ATT_RECENT); switch (r) { case MAILIMAP_NO_ERROR: break; default: res = MAIL_ERROR_MEMORY; goto free; } r = mailimap_status_att_list_add(att_list, MAILIMAP_STATUS_ATT_UNSEEN); switch (r) { case MAILIMAP_NO_ERROR: break; default: res = MAIL_ERROR_MEMORY; goto free; } r = mailimap_status(imap, mb, att_list, &status); switch (r) { case MAILIMAP_NO_ERROR: break; default: res = imap_error_to_mail_error(r); goto free; } * result_messages = 0; * result_recent = 0; * result_unseen = 0; for (cur = clist_begin(status->st_info_list); cur != NULL ; cur = clist_next(cur)) { struct mailimap_status_info * status_info; status_info = clist_content(cur); switch (status_info->st_att) { case MAILIMAP_STATUS_ATT_MESSAGES: * result_messages = status_info->st_value; break; case MAILIMAP_STATUS_ATT_RECENT: * result_recent = status_info->st_value; break; case MAILIMAP_STATUS_ATT_UNSEEN: * result_unseen = status_info->st_value; break; } } mailimap_mailbox_data_status_free(status); mailimap_status_att_list_free(att_list); return MAIL_NO_ERROR; free: mailimap_status_att_list_free(att_list); err: return res; } static int imapdriver_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { int res; int current_folder; char * current_mb; if (mb == NULL) { mb = get_data(session)->imap_mailbox; if (mb == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } } current_mb = get_data(session)->imap_mailbox; if (strcmp(mb, current_mb) == 0) current_folder = 1; else current_folder = 0; if (current_folder) return status_selected_folder(session, mb, result_messages, result_recent, result_unseen); else return status_unselected_folder(session, mb, result_messages, result_recent, result_unseen); err: return res; } /* TODO : more efficient functions */ static int imapdriver_messages_number(mailsession * session, char * mb, uint32_t * result) { uint32_t messages; uint32_t recent; uint32_t unseen; int r; r = imapdriver_status_folder(session, mb, &messages, &recent, &unseen); if (r != MAIL_NO_ERROR) return r; * result = messages; return MAIL_NO_ERROR; } static int imapdriver_recent_number(mailsession * session, char * mb, uint32_t * result) { uint32_t messages; uint32_t recent; uint32_t unseen; int r; r = imapdriver_status_folder(session, mb, &messages, &recent, &unseen); if (r != MAIL_NO_ERROR) return r; * result = recent; return MAIL_NO_ERROR; } static int imapdriver_unseen_number(mailsession * session, char * mb, uint32_t * result) { uint32_t messages; uint32_t recent; uint32_t unseen; int r; r = imapdriver_status_folder(session, mb, &messages, &recent, &unseen); if (r != MAIL_NO_ERROR) return r; * result = unseen; return MAIL_NO_ERROR; } enum { IMAP_LIST, IMAP_LSUB }; static int imapdriver_list_lsub_folders(mailsession * session, int type, char * mb, struct mail_list ** result) { clist * imap_list; struct mail_list * resp; int r; int res; switch (type) { case IMAP_LIST: r = mailimap_list(get_imap_session(session), mb, "*", &imap_list); break; case IMAP_LSUB: r = mailimap_lsub(get_imap_session(session), mb, "*", &imap_list); break; default: res = MAIL_ERROR_LIST; goto err; } switch (r) { case MAILIMAP_NO_ERROR: break; default: res = imap_error_to_mail_error(r); goto err; } r = imap_list_to_list(imap_list, &resp); if (r != MAIL_NO_ERROR) { mailimap_list_result_free(imap_list); res = r; goto err; } mailimap_list_result_free(imap_list); * result = resp; return MAIL_NO_ERROR; err: return res; } static int imapdriver_list_folders(mailsession * session, char * mb, struct mail_list ** result) { return imapdriver_list_lsub_folders(session, IMAP_LIST, mb, result); } static int imapdriver_lsub_folders(mailsession * session, char * mb, struct mail_list ** result) { return imapdriver_list_lsub_folders(session, IMAP_LSUB, mb, result); } static int imapdriver_subscribe_folder(mailsession * session, char * mb) { int r; r = mailimap_subscribe(get_imap_session(session), mb); return imap_error_to_mail_error(r); } static int imapdriver_unsubscribe_folder(mailsession * session, char * mb) { int r; r = mailimap_unsubscribe(get_imap_session(session), mb); return imap_error_to_mail_error(r); } /* messages operations */ static int imapdriver_append_message(mailsession * session, char * message, size_t size) { int r; r = mailimap_append_simple(get_imap_session(session), get_data(session)->imap_mailbox, message, size); return imap_error_to_mail_error(r); } +static int imapdriver_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags) +{ + struct mailimap_flag_list * flag_list; + int r; + + if (flags != NULL) { + r = imap_flags_to_imap_flags(flags, &flag_list); + if (r != MAIL_NO_ERROR) + return r; + } + else { + flag_list = NULL; + } + + r = mailimap_append(get_imap_session(session), + get_data(session)->imap_mailbox, + flag_list, NULL, message, size); + + if (flag_list != NULL) + mailimap_flag_list_free(flag_list); + + return imap_error_to_mail_error(r); +} + static int imapdriver_copy_message(mailsession * session, uint32_t num, char * mb) { int r; struct mailimap_set * set; int res; set = mailimap_set_new_single(num); if (set == NULL) { res = MAIL_ERROR_MEMORY; goto err; } r = mailimap_uid_copy(get_imap_session(session), set, mb); mailimap_set_free(set); return imap_error_to_mail_error(r); err: return res; } static int imapdriver_get_messages_list(mailsession * session, struct mailmessage_list ** result) { return imap_get_messages_list(get_imap_session(session), session, imap_message_driver, 1, result); } static int imapdriver_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list) { struct mailimap_set * set; struct mailimap_fetch_att * fetch_att; struct mailimap_fetch_type * fetch_type; int res; clist * fetch_result; int r; uint32_t exists; clist * msg_list; if (get_imap_session(session)->imap_selection_info == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } imap_flags_store_process(get_imap_session(session), get_data(session)->imap_flags_store); exists = get_imap_session(session)->imap_selection_info->sel_exists; if (exists == 0) return MAIL_NO_ERROR; fetch_type = mailimap_fetch_type_new_fetch_att_list_empty(); if (fetch_type == NULL) { res = MAIL_ERROR_MEMORY; goto err; } fetch_att = mailimap_fetch_att_new_uid(); if (fetch_att == NULL) { res = MAIL_ERROR_MEMORY; goto free_fetch_type; } r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); if (r != MAILIMAP_NO_ERROR) { mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto free_fetch_type; } fetch_att = mailimap_fetch_att_new_flags(); if (fetch_att == NULL) { res = MAIL_ERROR_MEMORY; goto free_fetch_type; } r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); if (r != MAILIMAP_NO_ERROR) { mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto free_fetch_type; } r = imap_add_envelope_fetch_att(fetch_type); if (r != MAIL_NO_ERROR) { res = r; goto free_fetch_type; } r = maildriver_env_list_to_msg_list(env_list, &msg_list); if (r != MAIL_NO_ERROR) { res = MAIL_ERROR_MEMORY; goto free_fetch_type; } if (clist_begin(msg_list) == NULL) { /* no need to fetch envelopes */ mailimap_fetch_type_free(fetch_type); clist_free(msg_list); return MAIL_NO_ERROR; } r = msg_list_to_imap_set(msg_list, &set); if (r != MAIL_NO_ERROR) { clist_foreach(msg_list, (clist_func) free, NULL); clist_free(msg_list); res = MAIL_ERROR_MEMORY; goto free_fetch_type; } clist_foreach(msg_list, (clist_func) free, NULL); clist_free(msg_list); r = mailimap_uid_fetch(get_imap_session(session), set, fetch_type, &fetch_result); mailimap_fetch_type_free(fetch_type); mailimap_set_free(set); switch (r) { case MAILIMAP_NO_ERROR: break; default: return imap_error_to_mail_error(r); } if (clist_begin(fetch_result) == NULL) { res = MAIL_ERROR_FETCH; goto err; } r = imap_fetch_result_to_envelop_list(fetch_result, env_list); mailimap_fetch_list_free(fetch_result); if (r != MAIL_NO_ERROR) { res = MAIL_ERROR_MEMORY; goto err; } return MAIL_NO_ERROR; free_fetch_type: mailimap_fetch_type_free(fetch_type); err: return res; } #if 0 static int imapdriver_search_messages(mailsession * session, char * charset, struct mail_search_key * key, struct mail_search_result ** result) { struct mailimap_search_key * imap_key; int r; clist * imap_result; clist * result_list; struct mail_search_result * search_result; clistiter * cur; r = mail_search_to_imap_search(key, &imap_key); if (r != MAIL_NO_ERROR) return MAIL_ERROR_MEMORY; r = mailimap_uid_search(get_imap_session(session), charset, imap_key, &imap_result); mailimap_search_key_free(imap_key); switch (r) { case MAILIMAP_NO_ERROR: break; default: return imap_error_to_mail_error(r); } result_list = clist_new(); if (result_list == NULL) return MAIL_ERROR_MEMORY; for(cur = clist_begin(imap_result) ; cur != NULL ; cur = clist_next(cur)) { uint32_t val = * (uint32_t *) clist_content(cur); uint32_t * new; new = malloc(sizeof(* new)); if (new == NULL) { goto free_imap_result; } * new = val; r = clist_append(result_list, new); if (r != 0) { free(new); goto free_imap_result; } } search_result = mail_search_result_new(result_list); if (search_result == NULL) goto free_imap_result; mailimap_search_result_free(imap_result); * result = search_result; return MAIL_NO_ERROR; free_imap_result: mailimap_search_result_free(imap_result); return MAIL_ERROR_MEMORY; } #endif static int imapdriver_starttls(mailsession * session) { mailimap * imap; int r; struct mailimap_capability_data * cap_data; clistiter * cur; int starttls; int fd; mailstream_low * low; mailstream_low * new_low; int capability_available; imap = get_imap_session(session); capability_available = FALSE; if (imap->imap_connection_info != NULL) if (imap->imap_connection_info->imap_capability != NULL) { capability_available = TRUE; cap_data = imap->imap_connection_info->imap_capability; } if (!capability_available) { r = mailimap_capability(imap, &cap_data); switch (r) { case MAILIMAP_NO_ERROR: break; default: return imap_error_to_mail_error(r); } } starttls = FALSE; for(cur = clist_begin(cap_data->cap_list) ; cur != NULL ; cur = clist_next(cur)) { struct mailimap_capability * cap; cap = clist_content(cur); if (cap->cap_type == MAILIMAP_CAPABILITY_NAME) if (strcasecmp(cap->cap_data.cap_name, "STARTTLS") == 0) { starttls = TRUE; break; } } if (!capability_available) mailimap_capability_data_free(cap_data); if (!starttls) return MAIL_ERROR_NO_TLS; r = mailimap_starttls(imap); switch (r) { case MAILIMAP_NO_ERROR: break; default: return imap_error_to_mail_error(r); } low = mailstream_get_low(imap->imap_stream); fd = mailstream_low_get_fd(low); if (fd == -1) return MAIL_ERROR_STREAM; new_low = mailstream_low_ssl_open(fd); if (new_low == NULL) return MAIL_ERROR_STREAM; mailstream_low_free(low); mailstream_set_low(imap->imap_stream, new_low); return MAIL_NO_ERROR; } static int imapdriver_get_message(mailsession * session, uint32_t num, mailmessage ** result) { mailmessage * msg_info; int r; msg_info = mailmessage_new(); if (msg_info == NULL) return MAIL_ERROR_MEMORY; r = mailmessage_init(msg_info, session, imap_message_driver, num, 0); if (r != MAIL_NO_ERROR) { mailmessage_free(msg_info); return r; } * result = msg_info; return MAIL_NO_ERROR; } /* Retrieve a message by UID libEtPan! uid format for IMAP is "UIDVALIDITY-UID" where UIDVALIDITY and UID are decimal representation of respectively uidvalidity and uid numbers. Return value: MAIL_ERROR_INVAL if uid is NULL or has an incorrect format. MAIL_ERROR_MSG_NOT_FOUND if uidvalidity has changed or uid was not found MAIL_NO_ERROR if message was found. Result is in result */ static int imapdriver_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result) { uint32_t uidvalidity; uint32_t num; char * p1, * p2; mailimap * imap; if (uid == NULL) return MAIL_ERROR_INVAL; uidvalidity = strtoul(uid, &p1, 10); if (p1 == uid || * p1 != '-') return MAIL_ERROR_INVAL; p1++; num = strtoul(p1, &p2, 10); if (p2 == p1 || * p2 != '\0') return MAIL_ERROR_INVAL; imap = get_imap_session(session); if (imap->imap_selection_info->sel_uidvalidity != uidvalidity) return MAIL_ERROR_MSG_NOT_FOUND; return imapdriver_get_message(session, num, result); } diff --git a/kmicromail/libetpan/generic/imapdriver_cached.c b/kmicromail/libetpan/generic/imapdriver_cached.c index e6af8e8..04044ae 100644 --- a/kmicromail/libetpan/generic/imapdriver_cached.c +++ b/kmicromail/libetpan/generic/imapdriver_cached.c @@ -1,1274 +1,1290 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "imapdriver_cached.h" #include "libetpan-config.h" #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include "mail.h" #include "imapdriver_tools.h" #include "mail_cache_db.h" #include "mailmessage.h" #include "imapdriver_cached_message.h" #include "maildriver.h" #include "imapdriver_types.h" #include "generic_cache.h" #include "imfcache.h" #include "maildriver_tools.h" #include "imapdriver.h" static int imapdriver_cached_initialize(mailsession * session); static void imapdriver_cached_uninitialize(mailsession * session); static int imapdriver_cached_parameters(mailsession * session, int id, void * value); static int imapdriver_cached_connect_stream(mailsession * session, mailstream * s); static int imapdriver_cached_starttls(mailsession * session); static int imapdriver_cached_login(mailsession * session, char * userid, char * password); static int imapdriver_cached_logout(mailsession * session); static int imapdriver_cached_noop(mailsession * session); static int imapdriver_cached_build_folder_name(mailsession * session, char * mb, char * name, char ** result); static int imapdriver_cached_create_folder(mailsession * session, char * mb); static int imapdriver_cached_delete_folder(mailsession * session, char * mb); static int imapdriver_cached_rename_folder(mailsession * session, char * mb, char * new_name); static int imapdriver_cached_check_folder(mailsession * session); static int imapdriver_cached_examine_folder(mailsession * session, char * mb); static int imapdriver_cached_select_folder(mailsession * session, char * mb); static int imapdriver_cached_expunge_folder(mailsession * session); static int imapdriver_cached_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); static int imapdriver_cached_messages_number(mailsession * session, char * mb, uint32_t * result); static int imapdriver_cached_recent_number(mailsession * session, char * mb, uint32_t * result); static int imapdriver_cached_unseen_number(mailsession * session, char * mb, uint32_t * result); static int imapdriver_cached_list_folders(mailsession * session, char * mb, struct mail_list ** result); static int imapdriver_cached_lsub_folders(mailsession * session, char * mb, struct mail_list ** result); static int imapdriver_cached_subscribe_folder(mailsession * session, char * mb); static int imapdriver_cached_unsubscribe_folder(mailsession * session, char * mb); static int imapdriver_cached_append_message(mailsession * session, char * message, size_t size); +static int imapdriver_cached_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags); static int imapdriver_cached_copy_message(mailsession * session, uint32_t num, char * mb); static int imapdriver_cached_get_messages_list(mailsession * session, struct mailmessage_list ** result); static int imapdriver_cached_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list); static int imapdriver_cached_remove_message(mailsession * session, uint32_t num); #if 0 static int imapdriver_cached_search_messages(mailsession * session, char * charset, struct mail_search_key * key, struct mail_search_result ** result); #endif static int imapdriver_cached_get_message(mailsession * session, uint32_t num, mailmessage ** result); static int imapdriver_cached_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result); static mailsession_driver local_imap_cached_session_driver = { .sess_name = "imap-cached", .sess_initialize = imapdriver_cached_initialize, .sess_uninitialize = imapdriver_cached_uninitialize, .sess_parameters = imapdriver_cached_parameters, .sess_connect_stream = imapdriver_cached_connect_stream, .sess_connect_path = NULL, .sess_starttls = imapdriver_cached_starttls, .sess_login = imapdriver_cached_login, .sess_logout = imapdriver_cached_logout, .sess_noop = imapdriver_cached_noop, .sess_build_folder_name = imapdriver_cached_build_folder_name, .sess_create_folder = imapdriver_cached_create_folder, .sess_delete_folder = imapdriver_cached_delete_folder, .sess_rename_folder = imapdriver_cached_rename_folder, .sess_check_folder = imapdriver_cached_check_folder, .sess_examine_folder = imapdriver_cached_examine_folder, .sess_select_folder = imapdriver_cached_select_folder, .sess_expunge_folder = imapdriver_cached_expunge_folder, .sess_status_folder = imapdriver_cached_status_folder, .sess_messages_number = imapdriver_cached_messages_number, .sess_recent_number = imapdriver_cached_recent_number, .sess_unseen_number = imapdriver_cached_unseen_number, .sess_list_folders = imapdriver_cached_list_folders, .sess_lsub_folders = imapdriver_cached_lsub_folders, .sess_subscribe_folder = imapdriver_cached_subscribe_folder, .sess_unsubscribe_folder = imapdriver_cached_unsubscribe_folder, .sess_append_message = imapdriver_cached_append_message, + .sess_append_message_flags = imapdriver_cached_append_message_flags, .sess_copy_message = imapdriver_cached_copy_message, .sess_move_message = NULL, .sess_get_messages_list = imapdriver_cached_get_messages_list, .sess_get_envelopes_list = imapdriver_cached_get_envelopes_list, .sess_remove_message = imapdriver_cached_remove_message, #if 0 .sess_search_messages = imapdriver_cached_search_messages, #endif .sess_get_message = imapdriver_cached_get_message, .sess_get_message_by_uid = imapdriver_cached_get_message_by_uid, }; mailsession_driver * imap_cached_session_driver = &local_imap_cached_session_driver; #define CACHE_MESSAGE_LIST static inline struct imap_cached_session_state_data * get_cached_data(mailsession * session) { return session->sess_data; } static inline mailsession * get_ancestor(mailsession * s) { return get_cached_data(s)->imap_ancestor; } static inline struct imap_session_state_data * get_ancestor_data(mailsession * s) { return get_ancestor(s)->sess_data; } static inline mailimap * get_imap_session(mailsession * session) { return get_ancestor_data(session)->imap_session; } static int imapdriver_cached_initialize(mailsession * session) { struct imap_cached_session_state_data * data; data = malloc(sizeof(* data)); if (data == NULL) goto err; data->imap_ancestor = mailsession_new(imap_session_driver); if (data->imap_ancestor == NULL) goto free_data; data->imap_quoted_mb = NULL; data->imap_cache_directory[0] = '\0'; data->imap_uid_list = carray_new(128); if (data->imap_uid_list == NULL) goto free_session; session->sess_data = data; return MAIL_NO_ERROR; free_session: mailsession_free(data->imap_ancestor); free_data: free(data); err: return MAIL_ERROR_MEMORY; } static void free_quoted_mb(struct imap_cached_session_state_data * imap_cached_data) { if (imap_cached_data->imap_quoted_mb != NULL) { free(imap_cached_data->imap_quoted_mb); imap_cached_data->imap_quoted_mb = NULL; } } struct uid_cache_item { uint32_t uid; uint32_t size; }; static int update_uid_cache(mailsession * session, struct mailmessage_list * env_list) { unsigned int i; int r; struct imap_cached_session_state_data * data; int res; data = get_cached_data(session); /* free all UID cache */ for(i = 0 ; i < carray_count(data->imap_uid_list) ; i ++) { struct uid_cache_item * cache_item; cache_item = carray_get(data->imap_uid_list, i); free(cache_item); } /* build UID cache */ r = carray_set_size(data->imap_uid_list, carray_count(env_list->msg_tab)); if (r < 0) { res = MAIL_ERROR_MEMORY; goto err; } for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { struct uid_cache_item * cache_item; mailmessage * msg; cache_item = malloc(sizeof(* cache_item)); if (cache_item == NULL) { res = MAIL_ERROR_MEMORY; goto err; } msg = carray_get(env_list->msg_tab, i); cache_item->uid = msg->msg_index; cache_item->size = msg->msg_size; carray_set(data->imap_uid_list, i, cache_item); } return MAIL_NO_ERROR; err: return res; } static void check_for_uid_cache(mailsession * session) { #if 0 mailsession * imap; #endif mailimap * imap; #if 0 struct imap_session_state_data * imap_data; #endif clist * list; clistiter * cur; struct imap_cached_session_state_data * data; unsigned int i; unsigned dest; data = get_cached_data(session); #if 0 imap = get_ancestor(session); imap_data = imap->data; #endif imap = get_imap_session(session); if (imap->imap_response_info == NULL) return; list = imap->imap_response_info->rsp_expunged; if (list == NULL) return; dest = 0; i = 0; /* remove expunged */ for(cur = clist_begin(list) ; cur != NULL ; cur = clist_next(cur)) { uint32_t expunged; expunged = * (uint32_t *) clist_content(cur); while (i < carray_count(data->imap_uid_list)) { struct uid_cache_item * cache_item; if (dest + 1 == expunged) { cache_item = carray_get(data->imap_uid_list, i); free(cache_item); i ++; break; } else { cache_item = carray_get(data->imap_uid_list, i); carray_set(data->imap_uid_list, dest, cache_item); i ++; dest ++; } } } /* complete list */ while (i < carray_count(data->imap_uid_list)) { struct uid_cache_item * cache_item; cache_item = carray_get(data->imap_uid_list, i); carray_set(data->imap_uid_list, dest, cache_item); i ++; dest ++; } carray_set_size(data->imap_uid_list, dest); } static void imapdriver_cached_uninitialize(mailsession * session) { struct imap_cached_session_state_data * data; unsigned int i; data = get_cached_data(session); for(i = 0 ; i < carray_count(data->imap_uid_list) ; i ++) { struct uid_cache_item * cache_item; cache_item = carray_get(data->imap_uid_list, i); free(cache_item); } carray_free(data->imap_uid_list); free_quoted_mb(data); mailsession_free(data->imap_ancestor); free(data); session->sess_data = NULL; } static int imapdriver_cached_parameters(mailsession * session, int id, void * value) { struct imap_cached_session_state_data * data; int r; data = get_cached_data(session); switch (id) { case IMAPDRIVER_CACHED_SET_CACHE_DIRECTORY: strncpy(data->imap_cache_directory, value, PATH_MAX); data->imap_cache_directory[PATH_MAX - 1] = '\0'; r = generic_cache_create_dir(data->imap_cache_directory); if (r != MAIL_NO_ERROR) return r; return MAIL_NO_ERROR; } return MAIL_ERROR_INVAL; } static int imapdriver_cached_connect_stream(mailsession * session, mailstream * s) { int r; check_for_uid_cache(session); r = mailsession_connect_stream(get_ancestor(session), s); check_for_uid_cache(session); return r; } static int imapdriver_cached_starttls(mailsession * session) { int r; r = mailsession_starttls(get_ancestor(session)); check_for_uid_cache(session); return r; } static int imapdriver_cached_login(mailsession * session, char * userid, char * password) { int r; r = mailsession_login(get_ancestor(session), userid, password); check_for_uid_cache(session); return r; } static int imapdriver_cached_logout(mailsession * session) { int r; r = mailsession_logout(get_ancestor(session)); check_for_uid_cache(session); if (r == MAIL_NO_ERROR) { struct imap_cached_session_state_data * imap_cached_data; imap_cached_data = get_cached_data(session); free_quoted_mb(imap_cached_data); } return r; } static int imapdriver_cached_noop(mailsession * session) { int r; r = mailsession_noop(get_ancestor(session)); check_for_uid_cache(session); return r; } static int imapdriver_cached_build_folder_name(mailsession * session, char * mb, char * name, char ** result) { int r; r = mailsession_build_folder_name(get_ancestor(session), mb, name, result); check_for_uid_cache(session); return r; } static int imapdriver_cached_create_folder(mailsession * session, char * mb) { int r; r = mailsession_create_folder(get_ancestor(session), mb); check_for_uid_cache(session); return r; } static int imapdriver_cached_delete_folder(mailsession * session, char * mb) { int r; r = mailsession_delete_folder(get_ancestor(session), mb); check_for_uid_cache(session); return r; } static int imapdriver_cached_rename_folder(mailsession * session, char * mb, char * new_name) { int r; r = mailsession_rename_folder(get_ancestor(session), mb, new_name); check_for_uid_cache(session); return r; } static int imapdriver_cached_check_folder(mailsession * session) { int r; r = mailsession_check_folder(get_ancestor(session)); check_for_uid_cache(session); return r; } static int imapdriver_cached_examine_folder(mailsession * session, char * mb) { int r; r = mailsession_examine_folder(get_ancestor(session), mb); check_for_uid_cache(session); return r; } static int get_cache_folder(mailsession * session, char ** result) { #if 0 mailsession * imap_session; #endif mailimap * imap; char * mb; char * cache_dir; char * dirname; char * quoted_mb; int res; int r; char key[PATH_MAX]; #if 0 struct imap_session_state_data * imap_data; struct imap_cached_session_state_data * cached_data; #endif #if 0 imap_session = get_ancestor(session); imap_data = imap_session->data; imap = imap_data->session; #endif imap = get_imap_session(session); mb = get_ancestor_data(session)->imap_mailbox; cache_dir = get_cached_data(session)->imap_cache_directory; if (imap->imap_state != MAILIMAP_STATE_SELECTED) return MAIL_ERROR_BAD_STATE; if (imap->imap_selection_info == NULL) return MAIL_ERROR_BAD_STATE; quoted_mb = maildriver_quote_mailbox(mb); if (quoted_mb == NULL) { res = MAIL_ERROR_MEMORY; goto err; } snprintf(key, PATH_MAX, "%s/%s", cache_dir, quoted_mb); dirname = strdup(key); if (dirname == NULL) { res = MAIL_ERROR_MEMORY; goto free_mb; } r = generic_cache_create_dir(dirname); if (r != MAIL_NO_ERROR) { res = r; goto free_dirname; } free(quoted_mb); * result = dirname; return MAIL_NO_ERROR; free_dirname: free(dirname); free_mb: free(quoted_mb); err: return res; } static int imapdriver_cached_select_folder(mailsession * session, char * mb) { int r; char * quoted_mb; struct imap_cached_session_state_data * data; mailsession * imap; char * old_mb; imap = get_ancestor(session); old_mb = get_ancestor_data(session)->imap_mailbox; if (old_mb != NULL) if (strcmp(mb, old_mb) == 0) return MAIL_NO_ERROR; r = mailsession_select_folder(get_ancestor(session), mb); if (r != MAIL_NO_ERROR) return r; check_for_uid_cache(session); r = get_cache_folder(session, "ed_mb); if (r != MAIL_NO_ERROR) return r; data = get_cached_data(session); if (data->imap_quoted_mb != NULL) free(data->imap_quoted_mb); data->imap_quoted_mb = quoted_mb; /* clear UID cache */ carray_set_size(data->imap_uid_list, 0); return MAIL_NO_ERROR; } static int imapdriver_cached_expunge_folder(mailsession * session) { int r; r = mailsession_expunge_folder(get_ancestor(session)); check_for_uid_cache(session); return r; } static int imapdriver_cached_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { int r; r = mailsession_status_folder(get_ancestor(session), mb, result_messages, result_recent, result_unseen); check_for_uid_cache(session); return r; } static int imapdriver_cached_messages_number(mailsession * session, char * mb, uint32_t * result) { int r; r = mailsession_messages_number(get_ancestor(session), mb, result); check_for_uid_cache(session); return r; } static int imapdriver_cached_recent_number(mailsession * session, char * mb, uint32_t * result) { int r; r = mailsession_recent_number(get_ancestor(session), mb, result); check_for_uid_cache(session); return r; } static int imapdriver_cached_unseen_number(mailsession * session, char * mb, uint32_t * result) { int r; r = mailsession_unseen_number(get_ancestor(session), mb, result); check_for_uid_cache(session); return r; } static int imapdriver_cached_list_folders(mailsession * session, char * mb, struct mail_list ** result) { int r; r = mailsession_list_folders(get_ancestor(session), mb, result); check_for_uid_cache(session); return r; } static int imapdriver_cached_lsub_folders(mailsession * session, char * mb, struct mail_list ** result) { int r; r = mailsession_lsub_folders(get_ancestor(session), mb, result); check_for_uid_cache(session); return r; } static int imapdriver_cached_subscribe_folder(mailsession * session, char * mb) { int r; r = mailsession_subscribe_folder(get_ancestor(session), mb); check_for_uid_cache(session); return r; } static int imapdriver_cached_unsubscribe_folder(mailsession * session, char * mb) { int r; r = mailsession_unsubscribe_folder(get_ancestor(session), mb); check_for_uid_cache(session); return r; } static int imapdriver_cached_append_message(mailsession * session, char * message, size_t size) { int r; r = mailsession_append_message(get_ancestor(session), message, size); check_for_uid_cache(session); return r; } +static int imapdriver_cached_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags) +{ + int r; + + r = mailsession_append_message_flags(get_ancestor(session), + message, size, flags); + + check_for_uid_cache(session); + + return r; +} + static int imapdriver_cached_copy_message(mailsession * session, uint32_t num, char * mb) { int r; r = mailsession_copy_message(get_ancestor(session), num, mb); check_for_uid_cache(session); return r; } static int cmp_uid(uint32_t ** pa, uint32_t ** pb) { uint32_t * a; uint32_t * b; a = * pa; b = * pb; return * a - * b; } static int imapdriver_cached_get_messages_list(mailsession * session, struct mailmessage_list ** result) { #if 0 mailsession * imap_session; #endif mailimap * imap; uint32_t uid_max; struct imap_cached_session_state_data * data; struct mailmessage_list * env_list; unsigned i; int r; int res; carray * tab; #if 0 data = session->data; imap_session = get_ancestor(session); imap = ((struct imap_session_state_data *) (imap_session->data))->session; #endif data = get_cached_data(session); imap = get_imap_session(session); uid_max = 0; #ifdef CACHE_MESSAGE_LIST /* get UID max */ uid_max = 0; for(i = 0 ; i < carray_count(data->imap_uid_list) ; i ++) { struct uid_cache_item * cache_item; cache_item = carray_get(data->imap_uid_list, i); if (cache_item->uid > uid_max) uid_max = cache_item->uid; } #endif r = imap_get_messages_list(imap, session, imap_cached_message_driver, uid_max + 1, &env_list); check_for_uid_cache(session); if (r != MAIL_NO_ERROR) { res = r; goto err; } #ifdef CACHE_MESSAGE_LIST /* remove unsollicited message */ i = 0; while (i < carray_count(env_list->msg_tab)) { mailmessage * msg; msg = carray_get(env_list->msg_tab, i); if (msg->msg_index < uid_max + 1) carray_delete(env_list->msg_tab, i); else i ++; } tab = carray_new(carray_count(env_list->msg_tab) + carray_count(data->imap_uid_list)); if (tab == NULL) { res = MAIL_ERROR_MEMORY; goto free; } carray_set_size(tab, carray_count(env_list->msg_tab) + carray_count(data->imap_uid_list)); /* sort cached data before adding them to the list */ qsort(carray_data(data->imap_uid_list), carray_count(data->imap_uid_list), sizeof(* carray_data(data->imap_uid_list)), (int (*)(const void *, const void *)) cmp_uid); /* adds cached UID */ for(i = 0 ; i < carray_count(data->imap_uid_list) ; i ++) { struct uid_cache_item * cache_item; mailmessage * msg; cache_item = carray_get(data->imap_uid_list, i); msg = mailmessage_new(); if (msg == NULL) { res = MAIL_ERROR_MEMORY; goto free; } r = mailmessage_init(msg, session, imap_cached_message_driver, cache_item->uid, cache_item->size); if (r != MAIL_NO_ERROR) { mailmessage_free(msg); res = r; goto free; } carray_set(tab, i, msg); } /* adds new elements */ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; msg = carray_get(env_list->msg_tab, i); carray_set(tab, carray_count(data->imap_uid_list) + i, msg); } /* replace list of messages in env_list */ carray_free(env_list->msg_tab); env_list->msg_tab = tab; r = update_uid_cache(session, env_list); if (r != MAIL_NO_ERROR) { res = r; goto free; } #endif * result = env_list; return MAIL_NO_ERROR; free: mailmessage_list_free(env_list); err: return res; } static int get_flags_list(mailsession * session, struct mailmessage_list * env_list) { struct mailimap_set * set; struct mailimap_fetch_att * fetch_att; struct mailimap_fetch_type * fetch_type; int res; clist * fetch_result; int r; clist * msg_list; #if 0 struct imap_session_state_data * data; #endif unsigned i; unsigned dest; #if 0 data = session->data; #endif fetch_type = mailimap_fetch_type_new_fetch_att_list_empty(); if (fetch_type == NULL) { res = MAIL_ERROR_MEMORY; goto err; } fetch_att = mailimap_fetch_att_new_uid(); if (fetch_att == NULL) { res = MAIL_ERROR_MEMORY; goto free_fetch_type; } r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); if (r != MAILIMAP_NO_ERROR) { mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto free_fetch_type; } fetch_att = mailimap_fetch_att_new_flags(); if (fetch_att == NULL) { res = MAIL_ERROR_MEMORY; goto free_fetch_type; } r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); if (r != MAILIMAP_NO_ERROR) { mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto free_fetch_type; } r = maildriver_env_list_to_msg_list_no_flags(env_list, &msg_list); if (r != MAIL_NO_ERROR) { res = MAIL_ERROR_MEMORY; goto free_fetch_type; } if (clist_begin(msg_list) == NULL) { /* no need to fetch envelopes */ clist_free(msg_list); mailimap_fetch_type_free(fetch_type); return MAIL_NO_ERROR; } r = msg_list_to_imap_set(msg_list, &set); if (r != MAIL_NO_ERROR) { clist_foreach(msg_list, (clist_func) free, NULL); clist_free(msg_list); res = MAIL_ERROR_MEMORY; goto free_fetch_type; } clist_foreach(msg_list, (clist_func) free, NULL); clist_free(msg_list); r = mailimap_uid_fetch(get_imap_session(session), set, fetch_type, &fetch_result); mailimap_fetch_type_free(fetch_type); mailimap_set_free(set); switch (r) { case MAILIMAP_NO_ERROR: break; default: return imap_error_to_mail_error(r); } r = imap_fetch_result_to_envelop_list(fetch_result, env_list); mailimap_fetch_list_free(fetch_result); if (r != MAIL_NO_ERROR) { res = MAIL_ERROR_MEMORY; goto err; } /* remove messages that don't have flags */ i = 0; dest = 0; while (i < carray_count(env_list->msg_tab)) { mailmessage * msg; msg = carray_get(env_list->msg_tab, i); if (msg->msg_flags != NULL) { carray_set(env_list->msg_tab, dest, msg); dest ++; } else { mailmessage_free(msg); } i ++; } carray_set_size(env_list->msg_tab, dest); return MAIL_NO_ERROR; free_fetch_type: mailimap_fetch_type_free(fetch_type); err: return res; } #define ENV_NAME "env.db" static void get_uid_from_filename(char * filename) { char * p; p = strstr(filename, "-part"); if (p != NULL) * p = 0; p = strstr(filename, "-envelope"); if (p != NULL) * p = 0; p = strstr(filename, "-rfc822"); if (p != NULL) * p = 0; } static int imapdriver_cached_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list) { int r; int res; uint32_t i; struct imap_cached_session_state_data * data; MMAPString * mmapstr; struct mail_cache_db * cache_db; char filename[PATH_MAX]; data = get_cached_data(session); if (data->imap_quoted_mb == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto err; } snprintf(filename, PATH_MAX, "%s/%s", data->imap_quoted_mb, ENV_NAME); r = mail_cache_db_open_lock(filename, &cache_db); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_mmapstr; } /* fill with cached */ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; struct mailimf_fields * fields; msg = carray_get(env_list->msg_tab, i); if (msg->msg_fields == NULL) { r = imapdriver_get_cached_envelope(cache_db, mmapstr, session, msg, &fields); if (r == MAIL_NO_ERROR) { msg->msg_cached = TRUE; msg->msg_fields = fields; } } } mail_cache_db_close_unlock(filename, cache_db); r = mailsession_get_envelopes_list(get_ancestor(session), env_list); check_for_uid_cache(session); if (r != MAIL_NO_ERROR) { res = r; goto free_mmapstr; } r = get_flags_list(session, env_list); if (r != MAIL_NO_ERROR) { res = r; goto free_mmapstr; } #ifdef CACHE_MESSAGE_LIST r = update_uid_cache(session, env_list); if (r != MAIL_NO_ERROR) { res = r; goto free_mmapstr; } #endif /* must write cache */ r = mail_cache_db_open_lock(filename, &cache_db); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_mmapstr; } for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; msg = carray_get(env_list->msg_tab, i); if (msg->msg_fields != NULL) { if (!msg->msg_cached) { r = imapdriver_write_cached_envelope(cache_db, mmapstr, session, msg, msg->msg_fields); } } } /* flush cache */ maildriver_cache_clean_up(cache_db, NULL, env_list); mail_cache_db_close_unlock(filename, cache_db); mmap_string_free(mmapstr); /* remove cache files */ maildriver_message_cache_clean_up(data->imap_quoted_mb, env_list, get_uid_from_filename); return MAIL_NO_ERROR; free_mmapstr: mmap_string_free(mmapstr); err: return res; } static int imapdriver_cached_remove_message(mailsession * session, uint32_t num) { int r; r = mailsession_remove_message(get_ancestor(session), num); check_for_uid_cache(session); return r; } #if 0 static int imapdriver_cached_search_messages(mailsession * session, char * charset, struct mail_search_key * key, struct mail_search_result ** result) { int r; r = mailsession_search_messages(get_ancestor(session), charset, key, result); check_for_uid_cache(session); return r; } #endif static int imapdriver_cached_get_message(mailsession * session, uint32_t num, mailmessage ** result) { mailmessage * msg_info; int r; msg_info = mailmessage_new(); if (msg_info == NULL) return MAIL_ERROR_MEMORY; r = mailmessage_init(msg_info, session, imap_cached_message_driver, num, 0); if (r != MAIL_NO_ERROR) { mailmessage_free(msg_info); return r; } * result = msg_info; return MAIL_NO_ERROR; } /* Retrieve a message by UID * libEtPan! uid format for IMAP is "UIDVALIDITY-UID" * where UIDVALIDITY and UID are decimal representation of * respectively uidvalidity and uid numbers. * Return value: * MAIL_ERROR_INVAL if uid is NULL or has an incorrect format. * MAIL_ERROR_MSG_NOT_FOUND if uidvalidity has changed or uid was not found * MAIL_NO_ERROR if message was found. Result is in result */ static int imapdriver_cached_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result) { uint32_t uidvalidity; uint32_t num; char * p1, * p2; mailimap *imap; if (uid == NULL) return MAIL_ERROR_INVAL; uidvalidity = strtoul(uid, &p1, 10); if (p1 == uid || * p1 != '-') return MAIL_ERROR_INVAL; p1++; num = strtoul(p1, &p2, 10); if (p2 == p1 || * p2 != '\0') return MAIL_ERROR_INVAL; imap = get_imap_session(session); if (imap->imap_selection_info->sel_uidvalidity != uidvalidity) return MAIL_ERROR_MSG_NOT_FOUND; return imapdriver_cached_get_message(session, num, result); } diff --git a/kmicromail/libetpan/generic/imapdriver_cached_message.c b/kmicromail/libetpan/generic/imapdriver_cached_message.c index c0542a3..c4357a3 100644 --- a/kmicromail/libetpan/generic/imapdriver_cached_message.c +++ b/kmicromail/libetpan/generic/imapdriver_cached_message.c @@ -1,664 +1,664 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "imapdriver_cached_message.h" #include "imapdriver_tools.h" #include "imapdriver_message.h" #include "imapdriver_cached.h" #include "imapdriver_types.h" #include "imapdriver.h" #include "mailmessage.h" #include "generic_cache.h" #include "mail_cache_db.h" #include <string.h> #include <stdlib.h> static int imap_initialize(mailmessage * msg_info); static void imap_uninitialize(mailmessage * msg_info); static void imap_flush(mailmessage * msg_info); static void imap_check(mailmessage * msg_info); static void imap_fetch_result_free(mailmessage * msg_info, char * msg); static int imap_fetch(mailmessage * msg_info, char ** result, size_t * result_len); static int imap_fetch_header(mailmessage * msg_info, char ** result, size_t * result_len); static int imap_fetch_body(mailmessage * msg_info, char ** result, size_t * result_len); static int imap_fetch_size(mailmessage * msg_info, size_t * result); static int imap_get_bodystructure(mailmessage * msg_info, struct mailmime ** result); static int imap_fetch_section(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len); static int imap_fetch_section_header(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len); static int imap_fetch_section_mime(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len); static int imap_fetch_section_body(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len); static int imap_fetch_envelope(mailmessage * msg_info, struct mailimf_fields ** result); static int imap_get_flags(mailmessage * msg_info, struct mail_flags ** result); static mailmessage_driver local_imap_cached_message_driver = { .msg_name = "imap-cached", .msg_initialize = imap_initialize, .msg_uninitialize = imap_uninitialize, .msg_flush = imap_flush, .msg_check = imap_check, .msg_fetch_result_free = imap_fetch_result_free, .msg_fetch = imap_fetch, .msg_fetch_header = imap_fetch_header, .msg_fetch_body = imap_fetch_body, .msg_fetch_size = imap_fetch_size, .msg_get_bodystructure = imap_get_bodystructure, .msg_fetch_section = imap_fetch_section, .msg_fetch_section_header = imap_fetch_section_header, .msg_fetch_section_mime = imap_fetch_section_mime, .msg_fetch_section_body = imap_fetch_section_body, .msg_fetch_envelope = imap_fetch_envelope, .msg_get_flags = imap_get_flags, }; mailmessage_driver * imap_cached_message_driver = &local_imap_cached_message_driver; static inline struct imap_cached_session_state_data * get_cached_session_data(mailmessage * msg) { return msg->msg_session->sess_data; } static inline mailmessage * get_ancestor(mailmessage * msg_info) { return msg_info->msg_data; } static inline struct imap_cached_session_state_data * cached_session_get_data(mailsession * s) { return s->sess_data; } static inline mailsession * cached_session_get_ancestor(mailsession * s) { return cached_session_get_data(s)->imap_ancestor; } static inline struct imap_session_state_data * cached_session_get_ancestor_data(mailsession * s) { return cached_session_get_ancestor(s)->sess_data; } static inline mailimap * cached_session_get_imap_session(mailsession * session) { return cached_session_get_ancestor_data(session)->imap_session; } static inline mailimap * get_imap_session(mailmessage * msg) { return cached_session_get_imap_session(msg->msg_session); } static inline mailsession * get_ancestor_session(mailmessage * msg_info) { return cached_session_get_ancestor(msg_info->msg_session); } static void generate_key_from_mime_section(char * key, size_t size, struct mailmime * mime) { clistiter * cur; MMAPString * gstr; struct mailmime_section * part; int r; snprintf(key, size, "unvalid"); r = mailmime_get_section_id(mime, &part); if (r != MAILIMF_NO_ERROR) goto err; gstr = mmap_string_new("part"); if (gstr == NULL) goto free_section; for(cur = clist_begin(part->sec_list) ; cur != NULL ; cur = clist_next(cur)) { char s[20]; snprintf(s, 20, ".%u", * (uint32_t *) clist_content(cur)); if (mmap_string_append(gstr, s) == NULL) goto free_str; } snprintf(key, size, "%s", gstr->str); mmap_string_free(gstr); mailmime_section_free(part); return; free_str: mmap_string_free(gstr); free_section: mailmime_section_free(part); - err: + err:; } static void generate_key_from_section(char * key, size_t size, mailmessage * msg_info, struct mailmime * mime, int type) { char section_str[PATH_MAX]; generate_key_from_mime_section(section_str, PATH_MAX, mime); switch (type) { case IMAP_SECTION_MESSAGE: snprintf(key, size, "%s-%s", msg_info->msg_uid, section_str); break; case IMAP_SECTION_HEADER: snprintf(key, size, "%s-%s-header", msg_info->msg_uid, section_str); break; case IMAP_SECTION_MIME: snprintf(key, size, "%s-%s-mime", msg_info->msg_uid, section_str); break; case IMAP_SECTION_BODY: snprintf(key, size, "%s-%s-text", msg_info->msg_uid, section_str); break; } } static void generate_key_from_message(char * key, size_t size, mailmessage * msg_info, int type) { switch (type) { case MAILIMAP_MSG_ATT_RFC822: snprintf(key, size, "%s-rfc822", msg_info->msg_uid); break; case MAILIMAP_MSG_ATT_RFC822_HEADER: snprintf(key, size, "%s-rfc822-header", msg_info->msg_uid); break; case MAILIMAP_MSG_ATT_RFC822_TEXT: snprintf(key, size, "%s-rfc822-text", msg_info->msg_uid); break; case MAILIMAP_MSG_ATT_ENVELOPE: snprintf(key, size, "%s-envelope", msg_info->msg_uid); break; } } static void build_cache_name(char * filename, size_t size, mailmessage * msg, char * key) { char * quoted_mb; quoted_mb = get_cached_session_data(msg)->imap_quoted_mb; snprintf(filename, size, "%s/%s", quoted_mb, key); } static int imap_initialize(mailmessage * msg_info) { mailmessage * ancestor; int r; char key[PATH_MAX]; char * uid; mailimap * imap; ancestor = mailmessage_new(); if (ancestor == NULL) return MAIL_ERROR_MEMORY; r = mailmessage_init(ancestor, get_ancestor_session(msg_info), imap_message_driver, msg_info->msg_index, 0); if (r != MAIL_NO_ERROR) { mailmessage_free(ancestor); return r; } imap = get_imap_session(msg_info); snprintf(key, PATH_MAX, "%u-%u", imap->imap_selection_info->sel_uidvalidity, msg_info->msg_index); uid = strdup(key); if (uid == NULL) { mailmessage_free(ancestor); return MAIL_ERROR_MEMORY; } msg_info->msg_data = ancestor; msg_info->msg_uid = uid; return MAIL_NO_ERROR; } static void imap_uninitialize(mailmessage * msg_info) { mailmessage_free(get_ancestor(msg_info)); msg_info->msg_data = NULL; } static void imap_flush(mailmessage * msg_info) { if (msg_info->msg_mime != NULL) { mailmime_free(msg_info->msg_mime); msg_info->msg_mime = NULL; } } static void imap_check(mailmessage * msg_info) { get_ancestor(msg_info)->msg_flags = msg_info->msg_flags; mailmessage_check(get_ancestor(msg_info)); get_ancestor(msg_info)->msg_flags = NULL; } static void imap_fetch_result_free(mailmessage * msg_info, char * msg) { mailmessage_fetch_result_free(get_ancestor(msg_info), msg); } static int imap_fetch(mailmessage * msg_info, char ** result, size_t * result_len) { char key[PATH_MAX]; char filename[PATH_MAX]; int r; char * str; size_t len; generate_key_from_message(key, PATH_MAX, msg_info, MAILIMAP_MSG_ATT_RFC822); build_cache_name(filename, PATH_MAX, msg_info, key); r = generic_cache_read(filename, &str, &len); if (r == MAIL_NO_ERROR) { * result = str; * result_len = len; return MAIL_NO_ERROR; } r = mailmessage_fetch(get_ancestor(msg_info), result, result_len); if (r == MAIL_NO_ERROR) generic_cache_store(filename, * result, strlen(* result)); return r; } static int imap_fetch_header(mailmessage * msg_info, char ** result, size_t * result_len) { char key[PATH_MAX]; char filename[PATH_MAX]; int r; char * str; size_t len; generate_key_from_message(key, PATH_MAX, msg_info, MAILIMAP_MSG_ATT_RFC822_HEADER); build_cache_name(filename, PATH_MAX, msg_info, key); r = generic_cache_read(filename, &str, &len); if (r == MAIL_NO_ERROR) { * result = str; * result_len = len; return MAIL_NO_ERROR; } r = mailmessage_fetch_header(get_ancestor(msg_info), result, result_len); if (r == MAIL_NO_ERROR) generic_cache_store(filename, * result, * result_len); return r; } static int imap_fetch_body(mailmessage * msg_info, char ** result, size_t * result_len) { char key[PATH_MAX]; char filename[PATH_MAX]; int r; char * str; size_t len; generate_key_from_message(key, PATH_MAX, msg_info, MAILIMAP_MSG_ATT_RFC822_TEXT); build_cache_name(filename, PATH_MAX, msg_info, key); r = generic_cache_read(filename, &str, &len); if (r == MAIL_NO_ERROR) { * result = str; * result_len = len; return MAIL_NO_ERROR; } r = mailmessage_fetch_body(get_ancestor(msg_info), result, result_len); if (r == MAIL_NO_ERROR) generic_cache_store(filename, * result, * result_len); return r; } static int imap_fetch_size(mailmessage * msg_info, size_t * result) { return mailmessage_fetch_size(get_ancestor(msg_info), result); } static int imap_get_bodystructure(mailmessage * msg_info, struct mailmime ** result) { int r; if (msg_info->msg_mime != NULL) { * result = msg_info->msg_mime; return MAIL_NO_ERROR; } r = mailmessage_get_bodystructure(get_ancestor(msg_info), result); if (r == MAIL_NO_ERROR) { msg_info->msg_mime = get_ancestor(msg_info)->msg_mime; get_ancestor(msg_info)->msg_mime = NULL; } return r; } static int imap_fetch_section(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len) { char key[PATH_MAX]; char filename[PATH_MAX]; int r; char * str; size_t len; generate_key_from_section(key, PATH_MAX, msg_info, mime, IMAP_SECTION_MESSAGE); build_cache_name(filename, PATH_MAX, msg_info, key); r = generic_cache_read(filename, &str, &len); if (r == MAIL_NO_ERROR) { * result = str; * result_len = len; return MAIL_NO_ERROR; } r = mailmessage_fetch_section(get_ancestor(msg_info), mime, result, result_len); if (r == MAIL_NO_ERROR) generic_cache_store(filename, * result, * result_len); return r; } static int imap_fetch_section_header(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len) { char key[PATH_MAX]; char filename[PATH_MAX]; int r; char * str; size_t len; generate_key_from_section(key, PATH_MAX, msg_info, mime, IMAP_SECTION_HEADER); build_cache_name(filename, PATH_MAX, msg_info, key); r = generic_cache_read(filename, &str, &len); if (r == MAIL_NO_ERROR) { * result = str; * result_len = len; return MAIL_NO_ERROR; } r = mailmessage_fetch_section_header(get_ancestor(msg_info), mime, result, result_len); if (r == MAIL_NO_ERROR) generic_cache_store(filename, * result, * result_len); return r; } static int imap_fetch_section_mime(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len) { char key[PATH_MAX]; char filename[PATH_MAX]; int r; char * str; size_t len; generate_key_from_section(key, PATH_MAX, msg_info, mime, IMAP_SECTION_MIME); build_cache_name(filename, PATH_MAX, msg_info, key); r = generic_cache_read(filename, &str, &len); if (r == MAIL_NO_ERROR) { * result = str; * result_len = len; return MAIL_NO_ERROR; } r = mailmessage_fetch_section_mime(get_ancestor(msg_info), mime, result, result_len); if (r == MAIL_NO_ERROR) generic_cache_store(filename, * result, * result_len); return r; } static int imap_fetch_section_body(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len) { char key[PATH_MAX]; char filename[PATH_MAX]; int r; char * str; size_t len; generate_key_from_section(key, PATH_MAX, msg_info, mime, IMAP_SECTION_BODY); build_cache_name(filename, PATH_MAX, msg_info, key); r = generic_cache_read(filename, &str, &len); if (r == MAIL_NO_ERROR) { * result = str; * result_len = len; return MAIL_NO_ERROR; } r = mailmessage_fetch_section_body(get_ancestor(msg_info), mime, result, result_len); if (r == MAIL_NO_ERROR) generic_cache_store(filename, * result, * result_len); return r; } static int imap_get_flags(mailmessage * msg_info, struct mail_flags ** result) { int r; struct mail_flags * flags; if (msg_info->msg_flags != NULL) { * result = msg_info->msg_flags; return MAIL_NO_ERROR; } r = mailmessage_get_flags(get_ancestor(msg_info), &flags); if (r != MAIL_NO_ERROR) return r; get_ancestor(msg_info)->msg_flags = NULL; msg_info->msg_flags = flags; * result = flags; return MAIL_NO_ERROR; } #define ENV_NAME "env.db" static int imap_fetch_envelope(mailmessage * msg_info, struct mailimf_fields ** result) { struct mailimf_fields * fields; int r; struct mail_cache_db * cache_db; MMAPString * mmapstr; char filename[PATH_MAX]; struct imap_cached_session_state_data * data; int res; data = get_cached_session_data(msg_info); if (data->imap_quoted_mb == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } snprintf(filename, PATH_MAX, "%s/%s", data->imap_quoted_mb, ENV_NAME); r = mail_cache_db_open_lock(filename, &cache_db); if (r < 0) { res = MAIL_ERROR_MEMORY; goto err; } mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto close_db; } r = imapdriver_get_cached_envelope(cache_db, mmapstr, msg_info->msg_session, msg_info, &fields); if ((r != MAIL_ERROR_CACHE_MISS) && (r != MAIL_NO_ERROR)) { res = r; goto close_db; } r = mailmessage_fetch_envelope(get_ancestor(msg_info), &fields); if (r != MAIL_NO_ERROR) { res = r; goto close_db; } r = imapdriver_write_cached_envelope(cache_db, mmapstr, msg_info->msg_session, msg_info, fields); * result = fields; mmap_string_free(mmapstr); mail_cache_db_close_unlock(filename, cache_db); return MAIL_NO_ERROR; close_db: mail_cache_db_close_unlock(filename, cache_db); err: return res; } diff --git a/kmicromail/libetpan/generic/imapdriver_tools.c b/kmicromail/libetpan/generic/imapdriver_tools.c index 3d737f3..de4008f 100644 --- a/kmicromail/libetpan/generic/imapdriver_tools.c +++ b/kmicromail/libetpan/generic/imapdriver_tools.c @@ -1,3599 +1,3623 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "imapdriver_tools.h" #include "maildriver.h" #include <stdlib.h> #include <string.h> #include "mail.h" #include "imapdriver_types.h" #include "maildriver_tools.h" #include "generic_cache.h" #include "mailmessage.h" #include "mail_cache_db.h" static inline struct imap_session_state_data * session_get_data(mailsession * session) { return session->sess_data; } static inline struct imap_cached_session_state_data * cached_session_get_data(mailsession * session) { return session->sess_data; } static inline mailsession * cached_session_get_ancestor(mailsession * session) { return cached_session_get_data(session)->imap_ancestor; } static inline struct imap_session_state_data * cached_session_get_ancestor_data(mailsession * session) { return session_get_data(cached_session_get_ancestor(session)); } static inline mailimap * cached_session_get_imap_session(mailsession * session) { return cached_session_get_ancestor_data(session)->imap_session; } static int imap_flags_to_flags(struct mailimap_msg_att_dynamic * att_dyn, struct mail_flags ** result); int imap_error_to_mail_error(int error) { switch (error) { case MAILIMAP_NO_ERROR: return MAIL_NO_ERROR; case MAILIMAP_NO_ERROR_AUTHENTICATED: return MAIL_NO_ERROR_AUTHENTICATED; case MAILIMAP_NO_ERROR_NON_AUTHENTICATED: return MAIL_NO_ERROR_NON_AUTHENTICATED; case MAILIMAP_ERROR_BAD_STATE: return MAIL_ERROR_BAD_STATE; case MAILIMAP_ERROR_STREAM: return MAIL_ERROR_STREAM; case MAILIMAP_ERROR_PARSE: return MAIL_ERROR_PARSE; case MAILIMAP_ERROR_CONNECTION_REFUSED: return MAIL_ERROR_CONNECT; case MAILIMAP_ERROR_MEMORY: return MAIL_ERROR_MEMORY; case MAILIMAP_ERROR_FATAL: return MAIL_ERROR_FATAL; case MAILIMAP_ERROR_PROTOCOL: return MAIL_ERROR_PROTOCOL; case MAILIMAP_ERROR_DONT_ACCEPT_CONNECTION: return MAIL_ERROR_CONNECT; case MAILIMAP_ERROR_APPEND: return MAIL_ERROR_APPEND; case MAILIMAP_ERROR_NOOP: return MAIL_ERROR_NOOP; case MAILIMAP_ERROR_LOGOUT: return MAIL_ERROR_LOGOUT; case MAILIMAP_ERROR_CAPABILITY: return MAIL_ERROR_CAPABILITY; case MAILIMAP_ERROR_CHECK: return MAIL_ERROR_CHECK; case MAILIMAP_ERROR_CLOSE: return MAIL_ERROR_CLOSE; case MAILIMAP_ERROR_EXPUNGE: return MAIL_ERROR_EXPUNGE; case MAILIMAP_ERROR_COPY: case MAILIMAP_ERROR_UID_COPY: return MAIL_ERROR_COPY; case MAILIMAP_ERROR_CREATE: return MAIL_ERROR_CREATE; case MAILIMAP_ERROR_DELETE: return MAIL_ERROR_DELETE; case MAILIMAP_ERROR_EXAMINE: return MAIL_ERROR_EXAMINE; case MAILIMAP_ERROR_FETCH: case MAILIMAP_ERROR_UID_FETCH: return MAIL_ERROR_FETCH; case MAILIMAP_ERROR_LIST: return MAIL_ERROR_LIST; case MAILIMAP_ERROR_LOGIN: return MAIL_ERROR_LOGIN; case MAILIMAP_ERROR_LSUB: return MAIL_ERROR_LSUB; case MAILIMAP_ERROR_RENAME: return MAIL_ERROR_RENAME; case MAILIMAP_ERROR_SEARCH: case MAILIMAP_ERROR_UID_SEARCH: return MAIL_ERROR_SEARCH; case MAILIMAP_ERROR_SELECT: return MAIL_ERROR_SELECT; case MAILIMAP_ERROR_STATUS: return MAIL_ERROR_STATUS; case MAILIMAP_ERROR_STORE: case MAILIMAP_ERROR_UID_STORE: return MAIL_ERROR_STORE; case MAILIMAP_ERROR_SUBSCRIBE: return MAIL_ERROR_SUBSCRIBE; case MAILIMAP_ERROR_UNSUBSCRIBE: return MAIL_ERROR_UNSUBSCRIBE; case MAILIMAP_ERROR_STARTTLS: return MAIL_ERROR_STARTTLS; case MAILIMAP_ERROR_INVAL: return MAIL_ERROR_INVAL; default: return MAIL_ERROR_INVAL; } } static int imap_body_parameter_to_content(struct mailimap_body_fld_param * body_parameter, char * subtype, struct mailmime_type * mime_type, struct mailmime_content ** result); static int imap_body_type_text_to_content_type(char * subtype, struct mailimap_body_fld_param * body_parameter, struct mailmime_content ** result); int imap_list_to_list(clist * imap_list, struct mail_list ** result) { clistiter * cur; clist * list; struct mail_list * resp; int r; int res; list = clist_new(); if (list == NULL) { res = MAIL_ERROR_MEMORY; goto err; } for(cur = clist_begin(imap_list) ; cur != NULL ; cur = clist_next(cur)) { struct mailimap_mailbox_list * mb_list; char * new_mb; mb_list = clist_content(cur); new_mb = strdup(mb_list->mb_name); if (new_mb == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, new_mb); if (r != 0) { free(new_mb); res = MAIL_ERROR_MEMORY; goto free_list; } } resp = mail_list_new(list); if (resp == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } * result = resp; return MAIL_NO_ERROR; free_list: clist_foreach(list, (clist_func) free, NULL); clist_free(list); err: return res; } int section_to_imap_section(struct mailmime_section * section, int type, struct mailimap_section ** result) { struct mailimap_section_part * section_part; struct mailimap_section * imap_section; clist * list; clistiter * cur; int r; int res; list = clist_new(); if (list == NULL) { res = MAIL_ERROR_MEMORY; goto err; } for(cur = clist_begin(section->sec_list) ; cur != NULL ; cur = clist_next(cur)) { uint32_t value; uint32_t * id; value = * (uint32_t *) clist_content(cur); id = malloc(sizeof(* id)); if (id == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } * id = value; r = clist_append(list, id); if (r != 0) { res = MAIL_ERROR_MEMORY; free(id); goto free_list; } } section_part = mailimap_section_part_new(list); if (section_part == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } imap_section = NULL; switch (type) { case IMAP_SECTION_MESSAGE: imap_section = mailimap_section_new_part(section_part); break; case IMAP_SECTION_HEADER: imap_section = mailimap_section_new_part_header(section_part); break; case IMAP_SECTION_MIME: imap_section = mailimap_section_new_part_mime(section_part); break; case IMAP_SECTION_BODY: imap_section = mailimap_section_new_part_text(section_part); break; } if (imap_section == NULL) { res = MAIL_ERROR_MEMORY; goto free_part; } * result = imap_section; return MAIL_NO_ERROR; free_part: mailimap_section_part_free(section_part); free_list: if (list != NULL) { clist_foreach(list, (clist_func) free, NULL); clist_free(list); } err: return res; } static int imap_body_media_basic_to_content_type(struct mailimap_media_basic * media_basic, struct mailimap_body_fld_param * body_parameter, struct mailmime_content ** result) { struct mailmime_content * content; struct mailmime_type * mime_type; struct mailmime_discrete_type * discrete_type; struct mailmime_composite_type * composite_type; char * discrete_type_extension; int discrete_type_type; int composite_type_type; int mime_type_type; char * subtype; int r; int res; discrete_type = NULL; composite_type = NULL; discrete_type_extension = NULL; subtype = NULL; discrete_type_type = 0; composite_type_type = 0; mime_type_type = 0; switch (media_basic->med_type) { case MAILIMAP_MEDIA_BASIC_APPLICATION: mime_type_type = MAILMIME_TYPE_DISCRETE_TYPE; discrete_type_type = MAILMIME_DISCRETE_TYPE_APPLICATION; break; case MAILIMAP_MEDIA_BASIC_AUDIO: mime_type_type = MAILMIME_TYPE_DISCRETE_TYPE; discrete_type_type = MAILMIME_DISCRETE_TYPE_APPLICATION; break; case MAILIMAP_MEDIA_BASIC_IMAGE: mime_type_type = MAILMIME_TYPE_DISCRETE_TYPE; discrete_type_type = MAILMIME_DISCRETE_TYPE_IMAGE; break; case MAILIMAP_MEDIA_BASIC_MESSAGE: mime_type_type = MAILMIME_TYPE_COMPOSITE_TYPE; composite_type_type = MAILMIME_COMPOSITE_TYPE_MESSAGE; break; case MAILIMAP_MEDIA_BASIC_VIDEO: mime_type_type = MAILMIME_TYPE_DISCRETE_TYPE; discrete_type_type = MAILMIME_DISCRETE_TYPE_VIDEO; break; case MAILIMAP_MEDIA_BASIC_OTHER: mime_type_type = MAILMIME_TYPE_DISCRETE_TYPE; discrete_type_type = MAILMIME_DISCRETE_TYPE_EXTENSION; discrete_type_extension = media_basic->med_basic_type; if (discrete_type_extension == NULL) { res = MAIL_ERROR_INVAL; goto err; } break; default: res = MAIL_ERROR_INVAL; goto err; } switch (mime_type_type) { case MAILMIME_TYPE_DISCRETE_TYPE: if (discrete_type_extension != NULL) { discrete_type_extension = strdup(discrete_type_extension); if (discrete_type_extension == NULL) { res = MAIL_ERROR_MEMORY; goto err; } } discrete_type = mailmime_discrete_type_new(discrete_type_type, discrete_type_extension); if (discrete_type == NULL) { if (discrete_type_extension != NULL) free(discrete_type_extension); res = MAIL_ERROR_MEMORY; goto err; } break; case MAILMIME_TYPE_COMPOSITE_TYPE: composite_type = mailmime_composite_type_new(composite_type_type, NULL); if (composite_type == NULL) { res = MAIL_ERROR_MEMORY; goto err; } break; default: res = MAIL_ERROR_INVAL; goto err; } mime_type = mailmime_type_new(mime_type_type, discrete_type, composite_type); if (mime_type == NULL) { res = MAIL_ERROR_MEMORY; goto free; } r = imap_body_parameter_to_content(body_parameter, media_basic->med_subtype, mime_type, &content); if (r != MAIL_NO_ERROR) { res = r; goto free_type; } * result = content; return MAIL_NO_ERROR; free_type: mailmime_type_free(mime_type); free: if (discrete_type != NULL) mailmime_discrete_type_free(discrete_type); if (composite_type != NULL) mailmime_composite_type_free(composite_type); err: return res; } static int imap_disposition_to_mime_disposition(struct mailimap_body_fld_dsp * imap_dsp, struct mailmime_disposition ** result) { size_t cur_token; int r; struct mailmime_disposition_type * dsp_type; struct mailmime_disposition * dsp; clist * parameters; int res; cur_token = 0; r = mailmime_disposition_type_parse(imap_dsp->dsp_type, strlen(imap_dsp->dsp_type), &cur_token, &dsp_type); if (r != MAILIMF_NO_ERROR) { res = MAILIMF_ERROR_PARSE; goto err; } parameters = clist_new(); if (parameters == NULL) { res = MAIL_ERROR_MEMORY; goto err; } if (imap_dsp->dsp_attributes != NULL) { clistiter * cur; for(cur = clist_begin(imap_dsp->dsp_attributes->pa_list) ; cur != NULL ; cur = clist_next(cur)) { struct mailimap_single_body_fld_param * imap_param; struct mailmime_disposition_parm * dsp_param; struct mailmime_parameter * param; char * filename; char * creation_date; char * modification_date; char * read_date; size_t size; int type; imap_param = clist_content(cur); filename = NULL; creation_date = NULL; modification_date = NULL; read_date = NULL; size = 0; param = NULL; type = mailmime_disposition_guess_type(imap_param->pa_name, strlen(imap_param->pa_name), 0); switch (type) { case MAILMIME_DISPOSITION_PARM_FILENAME: if (strcasecmp(imap_param->pa_name, "filename") != 0) { type = MAILMIME_DISPOSITION_PARM_PARAMETER; break; } filename = strdup(imap_param->pa_value); if (filename == NULL) { res = MAIL_ERROR_MEMORY; goto free_dsp_type; } break; case MAILMIME_DISPOSITION_PARM_CREATION_DATE: if (strcasecmp(imap_param->pa_name, "creation-date") != 0) { type = MAILMIME_DISPOSITION_PARM_PARAMETER; break; } creation_date = strdup(imap_param->pa_value); if (creation_date == NULL) { res = MAIL_ERROR_MEMORY; goto free_dsp_type; } break; case MAILMIME_DISPOSITION_PARM_MODIFICATION_DATE: if (strcasecmp(imap_param->pa_name, "modification-date") != 0) { type = MAILMIME_DISPOSITION_PARM_PARAMETER; break; } modification_date = strdup(imap_param->pa_value); if (modification_date == NULL) { res = MAIL_ERROR_MEMORY; goto free_dsp_type; } break; case MAILMIME_DISPOSITION_PARM_READ_DATE: if (strcasecmp(imap_param->pa_name, "read-date") != 0) { type = MAILMIME_DISPOSITION_PARM_PARAMETER; break; } read_date = strdup(imap_param->pa_value); if (read_date == NULL) { res = MAIL_ERROR_MEMORY; goto free_dsp_type; } break; case MAILMIME_DISPOSITION_PARM_SIZE: if (strcasecmp(imap_param->pa_name, "size") != 0) { type = MAILMIME_DISPOSITION_PARM_PARAMETER; break; } size = strtoul(imap_param->pa_value, NULL, 10); break; } if (type == MAILMIME_DISPOSITION_PARM_PARAMETER) { char * name; char * value; name = strdup(imap_param->pa_name); if (name == NULL) { res = MAIL_ERROR_MEMORY; goto free_dsp_type; } value = strdup(imap_param->pa_value); if (value == NULL) { res = MAIL_ERROR_MEMORY; free(name); goto free_dsp_type; } param = mailmime_parameter_new(name, value); if (param == NULL) { free(value); free(name); res = MAIL_ERROR_MEMORY; goto free_dsp_type; } } dsp_param = mailmime_disposition_parm_new(type, filename, creation_date, modification_date, read_date, size, param); if (dsp_param == NULL) { if (filename != NULL) free(filename); if (creation_date != NULL) free(creation_date); if (modification_date != NULL) free(modification_date); if (read_date != NULL) free(read_date); if (param != NULL) mailmime_parameter_free(param); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(parameters, dsp_param); if (r != 0) { mailmime_disposition_parm_free(dsp_param); res = MAIL_ERROR_MEMORY; goto free_list; } } } dsp = mailmime_disposition_new(dsp_type, parameters); if (dsp == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } * result = dsp; return MAIL_NO_ERROR; free_list: clist_foreach(parameters, (clist_func) mailmime_disposition_parm_free, NULL); clist_free(parameters); free_dsp_type: mailmime_disposition_type_free(dsp_type); err: return res; } static int imap_language_to_mime_language(struct mailimap_body_fld_lang * imap_lang, struct mailmime_language ** result) { clist * list; clistiter * cur; int res; char * single; int r; struct mailmime_language * lang; list = clist_new(); if (list == NULL) { res = MAIL_ERROR_MEMORY; goto err; } switch (imap_lang->lg_type) { case MAILIMAP_BODY_FLD_LANG_SINGLE: if (imap_lang->lg_data.lg_single != NULL) { single = strdup(imap_lang->lg_data.lg_single); if (single == NULL) { res = MAIL_ERROR_MEMORY; goto free; } r = clist_append(list, single); if (r < 0) { free(single); res = MAIL_ERROR_MEMORY; goto free; } } break; case MAILIMAP_BODY_FLD_LANG_LIST: for(cur = clist_begin(imap_lang->lg_data.lg_list) ; cur != NULL ; cur = clist_next(cur)) { single = strdup(clist_content(cur)); if (single == NULL) { res = MAIL_ERROR_MEMORY; goto free; } r = clist_append(list, single); if (r < 0) { free(single); res = MAIL_ERROR_MEMORY; goto free; } } } lang = mailmime_language_new(list); if (lang == NULL) { res = MAIL_ERROR_MEMORY; goto free; } * result = lang; return MAIL_NO_ERROR; free: clist_foreach(list, (clist_func) free, NULL); clist_free(list); err: return res; } static int imap_body_fields_to_mime_fields(struct mailimap_body_fields * body_fields, struct mailimap_body_fld_dsp * imap_dsp, struct mailimap_body_fld_lang * imap_lang, struct mailmime_fields ** result, uint32_t * pbody_size) { struct mailmime_field * mime_field; struct mailmime_fields * mime_fields; clist * list; char * id; struct mailmime_mechanism * encoding; char * description; struct mailmime_disposition * dsp; struct mailmime_language * lang; int type; int r; int res; list = clist_new(); if (list == NULL) { res = MAIL_ERROR_MEMORY; goto err; } if (body_fields != NULL) { if (pbody_size != NULL) * pbody_size = body_fields->bd_size; if (body_fields->bd_id != NULL) { type = MAILMIME_FIELD_ID; id = strdup(body_fields->bd_id); if (id == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } mime_field = mailmime_field_new(type, NULL, NULL, id, NULL, 0, NULL, NULL); if (mime_field == NULL) { free(id); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, mime_field); if (r != 0) { mailmime_field_free(mime_field); res = MAIL_ERROR_MEMORY; goto free_list; } } if (body_fields->bd_description != NULL) { type = MAILMIME_FIELD_DESCRIPTION; description = strdup(body_fields->bd_description); if (description == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } mime_field = mailmime_field_new(type, NULL, NULL, NULL, description, 0, NULL, NULL); if (mime_field == NULL) { free(description); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, mime_field); if (r != 0) { mailmime_field_free(mime_field); res = MAIL_ERROR_MEMORY; goto free_list; } } if (body_fields->bd_encoding != NULL) { char * encoding_value; int encoding_type; type = MAILMIME_FIELD_TRANSFER_ENCODING; encoding_value = NULL; switch (body_fields->bd_encoding->enc_type) { case MAILIMAP_BODY_FLD_ENC_7BIT: encoding_type = MAILMIME_MECHANISM_7BIT; break; case MAILIMAP_BODY_FLD_ENC_8BIT: encoding_type = MAILMIME_MECHANISM_8BIT; break; case MAILIMAP_BODY_FLD_ENC_BINARY: encoding_type = MAILMIME_MECHANISM_BINARY; break; case MAILIMAP_BODY_FLD_ENC_BASE64: encoding_type = MAILMIME_MECHANISM_BASE64; break; case MAILIMAP_BODY_FLD_ENC_QUOTED_PRINTABLE: encoding_type = MAILMIME_MECHANISM_QUOTED_PRINTABLE; break; case MAILIMAP_BODY_FLD_ENC_OTHER: encoding_type = MAILMIME_MECHANISM_TOKEN; encoding_value = strdup(body_fields->bd_encoding->enc_value); if (encoding_value == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } break; default: res = MAIL_ERROR_INVAL; goto free_list; } encoding = mailmime_mechanism_new(encoding_type, encoding_value); if (encoding == NULL) { if (encoding_value != NULL) free(encoding_value); res = MAIL_ERROR_MEMORY; goto free_list; } mime_field = mailmime_field_new(type, NULL, encoding, NULL, NULL, 0, NULL, NULL); if (mime_field == NULL) { mailmime_mechanism_free(encoding); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, mime_field); if (r != 0) { mailmime_field_free(mime_field); res = MAIL_ERROR_MEMORY; goto free_list; } } } if (imap_dsp != NULL) { r = imap_disposition_to_mime_disposition(imap_dsp, &dsp); if (r != MAIL_ERROR_PARSE) { if (r != MAIL_NO_ERROR) { res = MAIL_ERROR_MEMORY; goto free_list; } type = MAILMIME_FIELD_DISPOSITION; mime_field = mailmime_field_new(type, NULL, NULL, NULL, NULL, 0, dsp, NULL); if (mime_field == NULL) { mailmime_disposition_free(dsp); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, mime_field); if (r != 0) { mailmime_field_free(mime_field); res = MAIL_ERROR_MEMORY; goto free_list; } } } if (imap_lang != NULL) { r = imap_language_to_mime_language(imap_lang, &lang); if (r != MAIL_NO_ERROR) { res = MAIL_ERROR_MEMORY; goto free_list; } type = MAILMIME_FIELD_LANGUAGE; mime_field = mailmime_field_new(type, NULL, NULL, NULL, NULL, 0, NULL, lang); if (mime_field == NULL) { mailmime_language_free(lang); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, mime_field); if (r != 0) { mailmime_field_free(mime_field); res = MAIL_ERROR_MEMORY; goto free_list; } } mime_fields = mailmime_fields_new(list); if (mime_fields == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } * result = mime_fields; return MAIL_NO_ERROR; free_list: clist_foreach(list, (clist_func) mailmime_fields_free, NULL); clist_free(list); err: return res; } static int imap_body_type_basic_to_body(struct mailimap_body_type_basic * imap_type_basic, struct mailimap_body_ext_1part * body_ext_1part, struct mailmime ** result) { struct mailmime_content * content; struct mailmime_fields * mime_fields; struct mailmime * body; int r; int res; uint32_t mime_size; r = imap_body_media_basic_to_content_type(imap_type_basic->bd_media_basic, imap_type_basic->bd_fields->bd_parameter, &content); if (r != MAIL_NO_ERROR) { res = r; goto err; } if (body_ext_1part != NULL) r = imap_body_fields_to_mime_fields(imap_type_basic->bd_fields, body_ext_1part->bd_disposition, body_ext_1part->bd_language, &mime_fields, &mime_size); else r = imap_body_fields_to_mime_fields(imap_type_basic->bd_fields, NULL, NULL, &mime_fields, &mime_size); if (r != MAIL_NO_ERROR) { res = r; goto free_content; } body = mailmime_new(MAILMIME_SINGLE, NULL, mime_size, mime_fields, content, NULL, NULL, NULL, NULL, NULL, NULL); if (body == NULL) { res = MAIL_ERROR_MEMORY; goto free_fields; } * result = body; return MAIL_NO_ERROR; free_fields: mailmime_fields_free(mime_fields); free_content: mailmime_content_free(content); err: return res; } static int imap_body_type_text_to_body(struct mailimap_body_type_text * imap_type_text, struct mailimap_body_ext_1part * body_ext_1part, struct mailmime ** result) { struct mailmime_content * content; struct mailmime_fields * mime_fields; struct mailmime * body; int r; int res; uint32_t mime_size; r = imap_body_type_text_to_content_type(imap_type_text->bd_media_text, imap_type_text->bd_fields->bd_parameter, &content); if (r != MAIL_NO_ERROR) { res = r; goto err; } if (body_ext_1part == NULL) { r = imap_body_fields_to_mime_fields(imap_type_text->bd_fields, NULL, NULL, &mime_fields, &mime_size); } else { r = imap_body_fields_to_mime_fields(imap_type_text->bd_fields, body_ext_1part->bd_disposition, body_ext_1part->bd_language, &mime_fields, &mime_size); } if (r != MAIL_NO_ERROR) { res = r; goto free_content; } body = mailmime_new(MAILMIME_SINGLE, NULL, mime_size, mime_fields, content, NULL, NULL, NULL, NULL, NULL, NULL); if (body == NULL) { res = MAIL_ERROR_MEMORY; goto free_fields; } * result = body; return MAIL_NO_ERROR; free_fields: mailmime_fields_free(mime_fields); free_content: mailmime_content_free(content); err: return res; } static int imap_body_parameter_to_content(struct mailimap_body_fld_param * body_parameter, char * subtype, struct mailmime_type * mime_type, struct mailmime_content ** result) { clist * parameters; char * new_subtype; struct mailmime_content * content; int r; int res; new_subtype = strdup(subtype); if (new_subtype == NULL) { res = MAIL_ERROR_MEMORY; goto err; } parameters = clist_new(); if (parameters == NULL) { res = MAIL_ERROR_MEMORY; goto free_subtype; } if (body_parameter != NULL) { clistiter * cur; for(cur = clist_begin(body_parameter->pa_list) ; cur != NULL ; cur = clist_next(cur)) { struct mailimap_single_body_fld_param * imap_param; struct mailmime_parameter * param; char * name; char * value; imap_param = clist_content(cur); name = strdup(imap_param->pa_name); if (name == NULL) { res = MAIL_ERROR_MEMORY; goto free_parameters; } value = strdup(imap_param->pa_value); if (value == NULL) { free(name); res = MAIL_ERROR_MEMORY; goto free_parameters; } param = mailmime_parameter_new(name, value); if (param == NULL) { free(value); free(name); res = MAIL_ERROR_MEMORY; goto free_parameters; } r = clist_append(parameters, param); if (r != 0) { mailmime_parameter_free(param); res = MAIL_ERROR_MEMORY; goto free_parameters; } } } content = mailmime_content_new(mime_type, new_subtype, parameters); if (content == NULL) { res = MAIL_ERROR_MEMORY; goto free_parameters; } * result = content; return MAIL_NO_ERROR; free_parameters: clist_foreach(parameters, (clist_func) mailmime_parameter_free, NULL); clist_free(parameters); free_subtype: free(new_subtype); err: return res; } static int imap_body_type_text_to_content_type(char * subtype, struct mailimap_body_fld_param * body_parameter, struct mailmime_content ** result) { struct mailmime_content * content; struct mailmime_type * mime_type; struct mailmime_discrete_type * discrete_type; int r; int res; discrete_type = NULL; discrete_type = mailmime_discrete_type_new(MAILMIME_DISCRETE_TYPE_TEXT, NULL); if (discrete_type == NULL) { res = MAIL_ERROR_MEMORY; goto err; } mime_type = mailmime_type_new(MAILMIME_TYPE_DISCRETE_TYPE, discrete_type, NULL); if (mime_type == NULL) { mailmime_discrete_type_free(discrete_type); res = MAIL_ERROR_MEMORY; goto err; } r = imap_body_parameter_to_content(body_parameter, subtype, mime_type, &content); if (r != MAIL_NO_ERROR) { res = r; goto free_type; } * result = content; return MAIL_NO_ERROR; free_type: mailmime_type_free(mime_type); err: return res; } static int imap_body_type_msg_to_body(struct mailimap_body_type_msg * imap_type_msg, struct mailimap_body_ext_1part * body_ext_1part, struct mailmime ** result) { struct mailmime * body; struct mailmime * msg_body; struct mailmime_fields * mime_fields; struct mailmime_composite_type * composite_type; struct mailmime_type * mime_type; struct mailmime_content * content_type; struct mailimf_fields * fields; int r; int res; uint32_t mime_size; r = imap_body_fields_to_mime_fields(imap_type_msg->bd_fields, body_ext_1part->bd_disposition, body_ext_1part->bd_language, &mime_fields, &mime_size); if (r != MAIL_NO_ERROR) { res = r; goto err; } r = imap_env_to_fields(imap_type_msg->bd_envelope, NULL, 0, &fields); if (r != MAIL_NO_ERROR) { res = r; goto free_mime_fields; } r = imap_body_to_body(imap_type_msg->bd_body, &msg_body); if (r != MAIL_NO_ERROR) { res = r; goto free_fields; } composite_type = mailmime_composite_type_new(MAILMIME_COMPOSITE_TYPE_MESSAGE, NULL); if (composite_type == NULL) { res = MAIL_ERROR_MEMORY; goto free_fields; } mime_type = mailmime_type_new(MAILMIME_TYPE_COMPOSITE_TYPE, NULL, composite_type); if (mime_type == NULL) { mailmime_composite_type_free(composite_type); res = MAIL_ERROR_MEMORY; goto free_fields; } r = imap_body_parameter_to_content(imap_type_msg->bd_fields->bd_parameter, "rfc822", mime_type, &content_type); if (r != MAIL_NO_ERROR) { mailmime_type_free(mime_type); res = MAIL_ERROR_MEMORY; goto free_fields; } body = mailmime_new(MAILMIME_MESSAGE, NULL, mime_size, mime_fields, content_type, NULL, NULL, NULL, NULL, fields, msg_body); if (body == NULL) { res = MAIL_ERROR_MEMORY; goto free_content; } * result = body; return MAIL_NO_ERROR; free_content: mailmime_content_free(content_type); free_fields: mailimf_fields_free(fields); free_mime_fields: mailmime_fields_free(mime_fields); err: return res; } static int imap_body_type_1part_to_body(struct mailimap_body_type_1part * type_1part, struct mailmime ** result) { struct mailmime * body; int r; int res; switch (type_1part->bd_type) { case MAILIMAP_BODY_TYPE_1PART_BASIC: r = imap_body_type_basic_to_body(type_1part->bd_data.bd_type_basic, type_1part->bd_ext_1part, &body); if (r != MAIL_NO_ERROR) { res = r; goto err; } break; case MAILIMAP_BODY_TYPE_1PART_MSG: r = imap_body_type_msg_to_body(type_1part->bd_data.bd_type_msg, type_1part->bd_ext_1part, &body); if (r != MAIL_NO_ERROR) { res = r; goto err; } break; case MAILIMAP_BODY_TYPE_1PART_TEXT: r = imap_body_type_text_to_body(type_1part->bd_data.bd_type_text, type_1part->bd_ext_1part, &body); if (r != MAIL_NO_ERROR) { res = r; goto err; } break; } * result = body; return MAIL_NO_ERROR; err: return res; } static int imap_body_type_mpart_to_body(struct mailimap_body_type_mpart * type_mpart, struct mailmime ** result) { struct mailmime_fields * mime_fields; struct mailmime_composite_type * composite_type; struct mailmime_type * mime_type; struct mailmime_content * content_type; struct mailmime * body; clistiter * cur; clist * list; int r; int res; uint32_t mime_size; r = imap_body_fields_to_mime_fields(NULL, type_mpart->bd_ext_mpart->bd_disposition, type_mpart->bd_ext_mpart->bd_language, &mime_fields, &mime_size); if (r != MAIL_NO_ERROR) { res = r; goto err; } composite_type = mailmime_composite_type_new(MAILMIME_COMPOSITE_TYPE_MULTIPART, NULL); if (composite_type == NULL) { res = MAIL_ERROR_MEMORY; goto free_fields; } mime_type = mailmime_type_new(MAILMIME_TYPE_COMPOSITE_TYPE, NULL, composite_type); if (mime_type == NULL) { mailmime_composite_type_free(composite_type); res = MAIL_ERROR_MEMORY; goto free_fields; } r = imap_body_parameter_to_content(type_mpart->bd_ext_mpart->bd_parameter, type_mpart->bd_media_subtype, mime_type, &content_type); if (r != MAIL_NO_ERROR) { mailmime_type_free(mime_type); res = r; goto free_fields; } list = clist_new(); if (list == NULL) { res = MAIL_ERROR_MEMORY; goto free_content; } for(cur = clist_begin(type_mpart->bd_list) ; cur != NULL ; cur = clist_next(cur)) { struct mailimap_body * imap_body; struct mailmime * sub_body; imap_body = clist_content(cur); r = imap_body_to_body(imap_body, &sub_body); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } r = clist_append(list, sub_body); if (r != 0) { mailmime_free(sub_body); res = r; goto free_list; } } body = mailmime_new(MAILMIME_MULTIPLE, NULL, mime_size, mime_fields, content_type, NULL, NULL, NULL, list, NULL, NULL); if (body == NULL) { res = MAIL_ERROR_MEMORY; goto err; } * result = body; return MAIL_NO_ERROR; free_list: clist_foreach(list, (clist_func) mailmime_free, NULL); clist_free(list); free_content: mailmime_content_free(content_type); free_fields: mailmime_fields_free(mime_fields); err: return res; } int imap_body_to_body(struct mailimap_body * imap_body, struct mailmime ** result) { struct mailmime * body; int r; int res; switch (imap_body->bd_type) { case MAILIMAP_BODY_1PART: r = imap_body_type_1part_to_body(imap_body->bd_data.bd_body_1part, &body); if (r != MAIL_NO_ERROR) { res = r; goto err; } break; case MAILIMAP_BODY_MPART: r = imap_body_type_mpart_to_body(imap_body->bd_data.bd_body_mpart, &body); if (r != MAIL_NO_ERROR) { res = r; goto err; } break; default: return MAIL_ERROR_INVAL; } * result = body; return MAIL_NO_ERROR; err: return res; } int imap_address_to_mailbox(struct mailimap_address * imap_addr, struct mailimf_mailbox ** result) { char * dsp_name; char * addr; struct mailimf_mailbox * mb; int res; if (imap_addr->ad_personal_name == NULL) dsp_name = NULL; else { dsp_name = strdup(imap_addr->ad_personal_name); if (dsp_name == NULL) { res = MAIL_ERROR_MEMORY; goto err; } } if (imap_addr->ad_host_name == NULL) { addr = strdup(imap_addr->ad_mailbox_name); if (addr == NULL) { res = MAIL_ERROR_MEMORY; goto free_name; } } else { addr = malloc(strlen(imap_addr->ad_mailbox_name) + strlen(imap_addr->ad_host_name) + 2); if (addr == NULL) { res = MAIL_ERROR_MEMORY; goto free_name; } strcpy(addr, imap_addr->ad_mailbox_name); strcat(addr, "@"); strcat(addr, imap_addr->ad_host_name); } mb = mailimf_mailbox_new(dsp_name, addr); if (mb == NULL) { res = MAIL_ERROR_MEMORY; goto free_addr; } * result = mb; return MAIL_NO_ERROR; free_addr: free(addr); free_name: free(dsp_name); err: return res; } int imap_address_to_address(struct mailimap_address * imap_addr, struct mailimf_address ** result) { struct mailimf_address * addr; struct mailimf_mailbox * mb; int r; int res; r = imap_address_to_mailbox(imap_addr, &mb); if (r != MAIL_NO_ERROR) { res = r; goto err; } addr = mailimf_address_new(MAILIMF_ADDRESS_MAILBOX, mb, NULL); if (addr == NULL) { res = MAIL_ERROR_MEMORY; goto free_mb; } * result = addr; return MAIL_NO_ERROR; free_mb: mailimf_mailbox_free(mb); err: return res; } int imap_mailbox_list_to_mailbox_list(clist * imap_mailbox_list, struct mailimf_mailbox_list ** result) { clistiter * cur; clist * list; struct mailimf_mailbox_list * mb_list; int r; int res; list = clist_new(); if (list == NULL) { res = MAIL_ERROR_MEMORY; goto err; } for(cur = clist_begin(imap_mailbox_list) ; cur != NULL ; cur = clist_next(cur)) { struct mailimap_address * imap_addr; struct mailimf_mailbox * mb; imap_addr = clist_content(cur); if (imap_addr->ad_mailbox_name == NULL) continue; r = imap_address_to_mailbox(imap_addr, &mb); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } r = clist_append(list, mb); if (r != 0) { mailimf_mailbox_free(mb); res = MAIL_ERROR_MEMORY; goto free_list; } } mb_list = mailimf_mailbox_list_new(list); if (mb_list == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } * result = mb_list; return MAIL_NO_ERROR; free_list: clist_foreach(list, (clist_func) mailimf_mailbox_free, NULL); clist_free(list); err: return MAIL_ERROR_MEMORY; } /* at exit, imap_mb_list will fall on the last element of the group, where mailbox name will be NIL, so that imap_mailbox_list_to_address_list can continue */ static int imap_mailbox_list_to_group(clist * imap_mb_list, clistiter ** iter, struct mailimf_group ** result) { clistiter * imap_mailbox_listiter; clist * list; struct mailimf_group * group; struct mailimap_address * imap_addr; char * group_name; clistiter * cur; struct mailimf_mailbox_list * mb_list; int r; int res; imap_mailbox_listiter = * iter; imap_addr = clist_content(imap_mailbox_listiter); if (imap_addr->ad_mailbox_name == NULL) { res = MAIL_ERROR_INVAL; goto err; } group_name = strdup(imap_addr->ad_mailbox_name); if (group_name == NULL) { res = MAIL_ERROR_MEMORY; goto err; } list = clist_new(); if (list == NULL) { res = MAIL_ERROR_MEMORY; goto free_group_name; } for(cur = clist_next(imap_mailbox_listiter) ; cur != NULL ; cur = clist_next(cur)) { struct mailimf_mailbox * mb; imap_addr = clist_content(cur); if (imap_addr->ad_mailbox_name == NULL) { break; } r = imap_address_to_mailbox(imap_addr, &mb); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } r = clist_append(list, mb); if (r != 0) { mailimf_mailbox_free(mb); res = MAIL_ERROR_MEMORY; goto free_list; } } mb_list = mailimf_mailbox_list_new(list); if (mb_list == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } group = mailimf_group_new(group_name, mb_list); if (group == NULL) { mailimf_mailbox_list_free(mb_list); res = MAIL_ERROR_MEMORY; goto free_group_name; } * result = group; * iter = cur; return MAIL_NO_ERROR; free_list: clist_foreach(list, (clist_func) mailimf_mailbox_free, NULL); clist_free(list); free_group_name: free(group_name); err: return res; } int imap_mailbox_list_to_address_list(clist * imap_mailbox_list, struct mailimf_address_list ** result) { clistiter * cur; clist * list; struct mailimf_address_list * addr_list; int r; int res; list = clist_new(); if (list == NULL) { res = MAIL_ERROR_MEMORY; goto err; } for(cur = clist_begin(imap_mailbox_list) ; cur != NULL ; cur = clist_next(cur)) { struct mailimap_address * imap_addr; struct mailimf_address * addr; imap_addr = clist_content(cur); if (imap_addr->ad_mailbox_name == NULL) continue; if ((imap_addr->ad_host_name == NULL) && (imap_addr->ad_mailbox_name != NULL)) { struct mailimf_group * group; r = imap_mailbox_list_to_group(imap_mailbox_list, &cur, &group); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } addr = mailimf_address_new(MAILIMF_ADDRESS_GROUP, NULL, group); if (addr == NULL) { mailimf_group_free(group); res = MAIL_ERROR_MEMORY; goto free_list; } } else { r = imap_address_to_address(imap_addr, &addr); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } } r = clist_append(list, addr); if (r != 0) { mailimf_address_free(addr); res = MAIL_ERROR_MEMORY; goto free_list; } } addr_list = mailimf_address_list_new(list); if (addr_list == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } * result = addr_list; return MAIL_NO_ERROR; free_list: clist_foreach(list, (clist_func) mailimf_address_free, NULL); clist_free(list); err: return res; } int imap_add_envelope_fetch_att(struct mailimap_fetch_type * fetch_type) { struct mailimap_fetch_att * fetch_att; int res; int r; char * header; clist * hdrlist; struct mailimap_header_list * imap_hdrlist; struct mailimap_section * section; fetch_att = mailimap_fetch_att_new_envelope(); if (fetch_att == NULL) { res = MAIL_ERROR_MEMORY; goto err; } r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); if (r != MAILIMAP_NO_ERROR) { mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto err; } header = strdup("References"); if (header == NULL) { mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto err; } hdrlist = clist_new(); if (hdrlist == NULL) { free(header); mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto err; } r = clist_append(hdrlist, header); if (r < 0) { free(header); clist_foreach(hdrlist, (clist_func) free, NULL); clist_free(hdrlist); mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto err; } imap_hdrlist = mailimap_header_list_new(hdrlist); if (imap_hdrlist == 0) { clist_foreach(hdrlist, (clist_func) free, NULL); clist_free(hdrlist); mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto err; } section = mailimap_section_new_header_fields(imap_hdrlist); if (section == NULL) { mailimap_header_list_free(imap_hdrlist); mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto err; } fetch_att = mailimap_fetch_att_new_body_peek_section(section); if (fetch_att == NULL) { mailimap_section_free(section); res = MAIL_ERROR_MEMORY; goto err; } r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); if (r != MAILIMAP_NO_ERROR) { mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto err; } return MAIL_NO_ERROR; err: return res; } int imap_env_to_fields(struct mailimap_envelope * env, char * ref_str, size_t ref_size, struct mailimf_fields ** result) { clist * list; struct mailimf_field * field; int r; struct mailimf_fields * fields; int res; list = clist_new(); if (list == NULL) { res = MAIL_ERROR_MEMORY; goto err; } if (env->env_date != NULL) { size_t cur_token; struct mailimf_date_time * date_time; cur_token = 0; r = mailimf_date_time_parse(env->env_date, strlen(env->env_date), &cur_token, &date_time); if (r == MAILIMF_NO_ERROR) { struct mailimf_orig_date * orig; orig = mailimf_orig_date_new(date_time); if (orig == NULL) { mailimf_date_time_free(date_time); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_ORIG_DATE, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, orig, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (field == NULL) { mailimf_orig_date_free(orig); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r != 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } } } if (env->env_subject != NULL) { char * subject; struct mailimf_subject * subject_field; subject = strdup(env->env_subject); if (subject == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } subject_field = mailimf_subject_new(subject); if (subject_field == NULL) { free(subject); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_SUBJECT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, subject_field, NULL, NULL, NULL); if (field == NULL) { mailimf_subject_free(subject_field); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r != 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } } if (env->env_from != NULL) { if (env->env_from->frm_list != NULL) { struct mailimf_mailbox_list * mb_list; struct mailimf_from * from; r = imap_mailbox_list_to_mailbox_list(env->env_from->frm_list, &mb_list); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } from = mailimf_from_new(mb_list); if (from == NULL) { mailimf_mailbox_list_free(mb_list); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_FROM, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, from, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (field == NULL) { mailimf_from_free(from); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r != 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } } } if (env->env_sender != NULL) { if (env->env_sender->snd_list != NULL) { struct mailimf_sender * sender; struct mailimf_mailbox * mb; r = imap_address_to_mailbox(clist_begin(env->env_sender->snd_list)->data, &mb); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } sender = mailimf_sender_new(mb); if (sender == NULL) { mailimf_mailbox_free(mb); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_SENDER, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, sender, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (field == NULL) { mailimf_sender_free(sender); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r != 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } } } if (env->env_reply_to != NULL) { if (env->env_reply_to->rt_list != NULL) { struct mailimf_address_list * addr_list; struct mailimf_reply_to * reply_to; r = imap_mailbox_list_to_address_list(env->env_reply_to->rt_list, &addr_list); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } reply_to = mailimf_reply_to_new(addr_list); if (reply_to == NULL) { mailimf_address_list_free(addr_list); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_REPLY_TO, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, reply_to, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (field == NULL) { mailimf_reply_to_free(reply_to); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r != 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } } } if (env->env_to != NULL) { if (env->env_to->to_list != NULL) { struct mailimf_address_list * addr_list; struct mailimf_to * to; r = imap_mailbox_list_to_address_list(env->env_to->to_list, &addr_list); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } to = mailimf_to_new(addr_list); if (to == NULL) { mailimf_address_list_free(addr_list); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_TO, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, to, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (field == NULL) { mailimf_to_free(to); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r != 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } } } if (env->env_cc != NULL) { if (env->env_cc->cc_list != NULL) { struct mailimf_address_list * addr_list; struct mailimf_cc * cc; r = imap_mailbox_list_to_address_list(env->env_cc->cc_list, &addr_list); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } cc = mailimf_cc_new(addr_list); if (cc == NULL) { mailimf_address_list_free(addr_list); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_CC, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, cc, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (field == NULL) { mailimf_cc_free(cc); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r != 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } } } if (env->env_bcc != NULL) { if (env->env_bcc->bcc_list != NULL) { struct mailimf_address_list * addr_list; struct mailimf_bcc * bcc; r = imap_mailbox_list_to_address_list(env->env_bcc->bcc_list, &addr_list); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } bcc = mailimf_bcc_new(addr_list); if (bcc == NULL) { mailimf_address_list_free(addr_list); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_BCC, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, bcc, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (field == NULL) { mailimf_bcc_free(bcc); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r != 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } } } if (env->env_in_reply_to != NULL) { struct mailimf_in_reply_to * in_reply_to; size_t cur_token; clist * msg_id_list; cur_token = 0; r = mailimf_msg_id_list_parse(env->env_in_reply_to, strlen(env->env_in_reply_to), &cur_token, &msg_id_list); switch (r) { case MAILIMF_NO_ERROR: in_reply_to = mailimf_in_reply_to_new(msg_id_list); if (in_reply_to == NULL) { clist_foreach(msg_id_list, (clist_func) mailimf_msg_id_free, NULL); clist_free(msg_id_list); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_IN_REPLY_TO, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, in_reply_to, NULL, NULL, NULL, NULL, NULL); if (field == NULL) { mailimf_in_reply_to_free(in_reply_to); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r != 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } break; case MAILIMF_ERROR_PARSE: break; default: res = maildriver_imf_error_to_mail_error(r); goto free_list; } } if (env->env_message_id != NULL) { char * id; struct mailimf_message_id * msg_id; size_t cur_token; cur_token = 0; r = mailimf_msg_id_parse(env->env_message_id, strlen(env->env_message_id), &cur_token, &id); switch (r) { case MAILIMF_NO_ERROR: msg_id = mailimf_message_id_new(id); if (msg_id == NULL) { mailimf_msg_id_free(id); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_MESSAGE_ID, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, msg_id, NULL, NULL, NULL, NULL, NULL, NULL); if (field == NULL) { mailimf_message_id_free(msg_id); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r != 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } break; case MAILIMF_ERROR_PARSE: break; default: res = maildriver_imf_error_to_mail_error(r); goto free_list; } } if (ref_str != NULL) { struct mailimf_references * references; size_t cur_token; cur_token = 0; r = mailimf_references_parse(ref_str, ref_size, &cur_token, &references); switch (r) { case MAILIMF_NO_ERROR: field = mailimf_field_new(MAILIMF_FIELD_REFERENCES, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, references, NULL, NULL, NULL, NULL); if (field == NULL) { mailimf_references_free(references); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r < 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } break; case MAILIMF_ERROR_PARSE: break; default: res = maildriver_imf_error_to_mail_error(r); goto free_list; } } fields = mailimf_fields_new(list); if (fields == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } * result = fields; return MAIL_NO_ERROR; free_list: clist_foreach(list, (clist_func) mailimf_field_free, NULL); clist_free(list); err: return res; } int imap_get_msg_att_info(struct mailimap_msg_att * msg_att, uint32_t * puid, struct mailimap_envelope ** pimap_envelope, char ** preferences, size_t * pref_size, struct mailimap_msg_att_dynamic ** patt_dyn, struct mailimap_body ** pimap_body) { clistiter * item_cur; uint32_t uid; struct mailimap_envelope * imap_envelope; char * references; size_t ref_size; struct mailimap_msg_att_dynamic * att_dyn; struct mailimap_body * imap_body; uid = 0; imap_envelope = NULL; references = NULL; ref_size = 0; att_dyn = NULL; imap_body = NULL; for(item_cur = clist_begin(msg_att->att_list) ; item_cur != NULL ; item_cur = clist_next(item_cur)) { struct mailimap_msg_att_item * item; item = clist_content(item_cur); switch (item->att_type) { case MAILIMAP_MSG_ATT_ITEM_STATIC: switch (item->att_data.att_static->att_type) { case MAILIMAP_MSG_ATT_BODYSTRUCTURE: if (imap_body == NULL) imap_body = item->att_data.att_static->att_data.att_bodystructure; break; case MAILIMAP_MSG_ATT_ENVELOPE: if (imap_envelope == NULL) { imap_envelope = item->att_data.att_static->att_data.att_env; } break; case MAILIMAP_MSG_ATT_UID: uid = item->att_data.att_static->att_data.att_uid; break; case MAILIMAP_MSG_ATT_BODY_SECTION: if (references == NULL) { references = item->att_data.att_static->att_data.att_body_section->sec_body_part; ref_size = item->att_data.att_static->att_data.att_body_section->sec_length; } break; } break; case MAILIMAP_MSG_ATT_ITEM_DYNAMIC: if (att_dyn == NULL) { att_dyn = item->att_data.att_dyn; } break; } } if (puid != NULL) * puid = uid; if (pimap_envelope != NULL) * pimap_envelope = imap_envelope; if (preferences != NULL) * preferences = references; if (pref_size != NULL) * pref_size = ref_size; if (patt_dyn != NULL) * patt_dyn = att_dyn; if (pimap_body != NULL) * pimap_body = imap_body; return MAIL_NO_ERROR; } int imap_fetch_result_to_envelop_list(clist * fetch_result, struct mailmessage_list * env_list) { clistiter * cur; int r; unsigned int i; i = 0; for(cur = clist_begin(fetch_result) ; cur != NULL ; cur = clist_next(cur)) { struct mailimap_msg_att * msg_att; uint32_t uid; struct mailimap_envelope * imap_envelope; struct mailimap_msg_att_dynamic * att_dyn; char * references; size_t ref_size; msg_att = clist_content(cur); r = imap_get_msg_att_info(msg_att, &uid, &imap_envelope, &references, &ref_size, &att_dyn, NULL); if (r == MAIL_NO_ERROR) { if (uid != 0) { while (i < carray_count(env_list->msg_tab)) { mailmessage * msg; msg = carray_get(env_list->msg_tab, i); if (uid == msg->msg_index) { struct mailimf_fields * fields; struct mail_flags * flags; if (imap_envelope != NULL) { r = imap_env_to_fields(imap_envelope, references, ref_size, &fields); if (r == MAIL_NO_ERROR) { msg->msg_fields = fields; } } if (att_dyn != NULL) { r = imap_flags_to_flags(att_dyn, &flags); if (r == MAIL_NO_ERROR) { msg->msg_flags = flags; } } i ++; break; } i ++; } } } } return MAIL_NO_ERROR; } int mailimf_date_time_to_imap_date(struct mailimf_date_time * date, struct mailimap_date ** result) { struct mailimap_date * imap_date; imap_date = mailimap_date_new(date->dt_day, date->dt_month, date->dt_year); if (imap_date == NULL) return MAIL_ERROR_MEMORY; * result = imap_date; return MAIL_NO_ERROR; } #if 0 int mail_search_to_imap_search(struct mail_search_key * key, struct mailimap_search_key ** result) { struct mailimap_search_key * imap_key; char * bcc; struct mailimap_date * before; char * body; char * cc; char * from; struct mailimap_date * on; struct mailimap_date * since; char * subject; char * text; char * to; char * header_name; char * header_value; size_t larger; struct mailimap_search_key * not; struct mailimap_search_key * or1; struct mailimap_search_key * or2; size_t smaller; clist * multiple; int type; clistiter * cur; int r; int res; bcc = NULL; before = NULL; body = NULL; cc = NULL; from = NULL; on = NULL; since = NULL; subject = NULL; text = NULL; to = NULL; header_name = NULL; header_value = NULL; not = NULL; or1 = NULL; or2 = NULL; multiple = NULL; larger = 0; smaller = 0; switch (key->sk_type) { case MAIL_SEARCH_KEY_ALL: type = MAILIMAP_SEARCH_KEY_ALL; break; case MAIL_SEARCH_KEY_ANSWERED: type = MAILIMAP_SEARCH_KEY_ANSWERED; break; case MAIL_SEARCH_KEY_BCC: type = MAILIMAP_SEARCH_KEY_BCC; bcc = strdup(key->sk_bcc); if (bcc == NULL) { res = MAIL_ERROR_MEMORY; goto err; } break; case MAIL_SEARCH_KEY_BEFORE: type = MAILIMAP_SEARCH_KEY_BEFORE; r = mailimf_date_time_to_imap_date(key->sk_before, &before); if (r != MAIL_NO_ERROR) { res = r; goto err; } break; case MAIL_SEARCH_KEY_BODY: type = MAILIMAP_SEARCH_KEY_BODY; body = strdup(key->sk_body); if (body == NULL) { res = MAIL_ERROR_MEMORY; goto err; } break; case MAIL_SEARCH_KEY_CC: type = MAILIMAP_SEARCH_KEY_CC; cc = strdup(key->sk_cc); if (cc == NULL) { res = MAIL_ERROR_MEMORY; goto err; } break; case MAIL_SEARCH_KEY_DELETED: type = MAILIMAP_SEARCH_KEY_DELETED; break; case MAIL_SEARCH_KEY_FLAGGED: type = MAILIMAP_SEARCH_KEY_FLAGGED; break; case MAIL_SEARCH_KEY_FROM: type = MAILIMAP_SEARCH_KEY_FROM; from = strdup(key->sk_from); if (from == NULL) { res = MAIL_ERROR_MEMORY; goto err; } break; case MAIL_SEARCH_KEY_NEW: type = MAILIMAP_SEARCH_KEY_NEW; break; case MAIL_SEARCH_KEY_OLD: type = MAILIMAP_SEARCH_KEY_OLD; break; case MAIL_SEARCH_KEY_ON: type = MAILIMAP_SEARCH_KEY_ON; r = mailimf_date_time_to_imap_date(key->sk_on, &on); if (r != MAIL_NO_ERROR) { res = r; goto err; } break; case MAIL_SEARCH_KEY_RECENT: type = MAILIMAP_SEARCH_KEY_RECENT; break; case MAIL_SEARCH_KEY_SEEN: type = MAILIMAP_SEARCH_KEY_SEEN; break; case MAIL_SEARCH_KEY_SINCE: type = MAILIMAP_SEARCH_KEY_SINCE; r = mailimf_date_time_to_imap_date(key->sk_since, &since); if (r != MAIL_NO_ERROR) { res = r; goto err; } break; case MAIL_SEARCH_KEY_SUBJECT: type = MAILIMAP_SEARCH_KEY_SUBJECT; subject = strdup(key->sk_subject); if (subject == NULL) { res = MAIL_ERROR_MEMORY; goto err; } break; case MAIL_SEARCH_KEY_TEXT: type = MAILIMAP_SEARCH_KEY_TEXT; text = strdup(key->sk_text); if (text == NULL) { res = MAIL_ERROR_MEMORY; goto err; } break; case MAIL_SEARCH_KEY_TO: type = MAILIMAP_SEARCH_KEY_TO; to = strdup(key->sk_to); if (to == NULL) { return MAIL_ERROR_MEMORY; goto err; } break; case MAIL_SEARCH_KEY_UNANSWERED: type = MAILIMAP_SEARCH_KEY_UNANSWERED; break; case MAIL_SEARCH_KEY_UNDELETED: type = MAILIMAP_SEARCH_KEY_UNFLAGGED; break; case MAIL_SEARCH_KEY_UNFLAGGED: type = MAILIMAP_SEARCH_KEY_UNANSWERED; break; case MAIL_SEARCH_KEY_UNSEEN: type = MAILIMAP_SEARCH_KEY_UNSEEN; break; case MAIL_SEARCH_KEY_HEADER: type = MAILIMAP_SEARCH_KEY_HEADER; header_name = strdup(key->sk_header_name); if (header_name == NULL) { res = MAIL_ERROR_MEMORY; goto err; } header_value = strdup(key->sk_header_value); if (header_value == NULL) { free(header_name); res = MAIL_ERROR_MEMORY; goto err; } break; case MAIL_SEARCH_KEY_LARGER: type = MAILIMAP_SEARCH_KEY_LARGER; larger = key->sk_larger; break; case MAIL_SEARCH_KEY_NOT: type = MAILIMAP_SEARCH_KEY_NOT; r = mail_search_to_imap_search(key->sk_not, ¬); if (r != MAIL_NO_ERROR) { res = r; goto err; } break; case MAIL_SEARCH_KEY_OR: type = MAILIMAP_SEARCH_KEY_OR; r = mail_search_to_imap_search(key->sk_or1, &or1); if (r != MAIL_NO_ERROR) { res = r; goto err; } r = mail_search_to_imap_search(key->sk_or2, &or2); if (r != MAIL_NO_ERROR) { mailimap_search_key_free(or1); res = r; goto err; } break; case MAIL_SEARCH_KEY_SMALLER: type = MAILIMAP_SEARCH_KEY_SMALLER; smaller = key->sk_smaller; break; case MAIL_SEARCH_KEY_MULTIPLE: multiple = clist_new(); if (multiple == NULL) { res = MAIL_ERROR_MEMORY; goto err; } type = MAILIMAP_SEARCH_KEY_MULTIPLE; for(cur = clist_begin(key->sk_multiple) ; cur != NULL ; cur = clist_next(cur)) { struct mail_search_key * key_elt; struct mailimap_search_key * imap_key_elt; key_elt = clist_content(cur); r = mail_search_to_imap_search(key_elt, &imap_key_elt); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } r = clist_append(multiple, imap_key_elt); if (r != 0) { mailimap_search_key_free(imap_key_elt); res = MAIL_ERROR_MEMORY; goto free_list; } } break; free_list: clist_foreach(multiple, (clist_func) mailimap_search_key_free, NULL); clist_free(multiple); goto err; default: return MAIL_ERROR_INVAL; } imap_key = mailimap_search_key_new(type, bcc, before, body, cc, from, NULL, on, since, subject, text, to, NULL, header_name, header_value, larger, not, or1, or2, NULL, NULL, NULL, smaller, NULL, NULL, multiple); if (imap_key == NULL) { res = MAIL_ERROR_MEMORY; goto free; } * result = imap_key; return MAIL_NO_ERROR; free: if (bcc != NULL) free(bcc); if (before != NULL) mailimap_date_free(before); if (body != NULL) free(body); if (cc != NULL) free(cc); if (from != NULL) free(from); if (on != NULL) mailimap_date_free(on); if (since != NULL) mailimap_date_free(since); if (subject != NULL) free(subject); if (text != NULL) free(text); if (to != NULL) free(to); if (header_name != NULL) free(header_name); if (header_value != NULL) free(header_value); if (not != NULL) mailimap_search_key_free(not); if (or1 != NULL) mailimap_search_key_free(or1); if (or2 != NULL) mailimap_search_key_free(or2); clist_foreach(multiple, (clist_func) mailimap_search_key_free, NULL); clist_free(multiple); err: return res; } #endif int msg_list_to_imap_set(clist * msg_list, struct mailimap_set ** result) { struct mailimap_set * imap_set; clistiter * cur; int previous_valid; uint32_t first_seq; uint32_t previous; int r; int res; imap_set = mailimap_set_new_empty(); if (imap_set == NULL) { res = MAIL_ERROR_MEMORY; goto err; } cur = clist_begin(msg_list); previous_valid = FALSE; first_seq = 0; previous = 0; while (1) { uint32_t * pindex; if ((cur == NULL) && (previous_valid)) { if (first_seq == previous) { r = mailimap_set_add_single(imap_set, first_seq); if (r != MAILIMAP_NO_ERROR) { res = r; goto free; } } else { r = mailimap_set_add_interval(imap_set, first_seq, previous); if (r != MAILIMAP_NO_ERROR) { res = r; goto free; } } break; } pindex = clist_content(cur); if (!previous_valid) { first_seq = * pindex; previous_valid = TRUE; previous = * pindex; cur = clist_next(cur); } else { if (* pindex != previous + 1) { if (first_seq == previous) { r = mailimap_set_add_single(imap_set, first_seq); if (r != MAILIMAP_NO_ERROR) { res = r; goto free; } } else { r = mailimap_set_add_interval(imap_set, first_seq, previous); if (r != MAILIMAP_NO_ERROR) { res = r; goto free; } } previous_valid = FALSE; } else { previous = * pindex; cur = clist_next(cur); } } } * result = imap_set; return MAIL_NO_ERROR; free: mailimap_set_free(imap_set); err: return res; } static int uid_list_to_env_list(clist * fetch_result, struct mailmessage_list ** result, mailsession * session, mailmessage_driver * driver) { clistiter * cur; struct mailmessage_list * env_list; int r; int res; carray * tab; unsigned int i; mailmessage * msg; tab = carray_new(128); if (tab == NULL) { res = MAIL_ERROR_MEMORY; goto err; } for(cur = clist_begin(fetch_result) ; cur != NULL ; cur = clist_next(cur)) { struct mailimap_msg_att * msg_att; clistiter * item_cur; uint32_t uid; size_t size; msg_att = clist_content(cur); uid = 0; size = 0; for(item_cur = clist_begin(msg_att->att_list) ; item_cur != NULL ; item_cur = clist_next(item_cur)) { struct mailimap_msg_att_item * item; item = clist_content(item_cur); switch (item->att_type) { case MAILIMAP_MSG_ATT_ITEM_STATIC: switch (item->att_data.att_static->att_type) { case MAILIMAP_MSG_ATT_UID: uid = item->att_data.att_static->att_data.att_uid; break; case MAILIMAP_MSG_ATT_RFC822_SIZE: size = item->att_data.att_static->att_data.att_rfc822_size; break; } break; } } msg = mailmessage_new(); if (msg == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } r = mailmessage_init(msg, session, driver, uid, size); if (r != MAIL_NO_ERROR) { res = r; goto free_msg; } r = carray_add(tab, msg, NULL); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_msg; } } env_list = mailmessage_list_new(tab); if (env_list == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } * result = env_list; return MAIL_NO_ERROR; free_msg: mailmessage_free(msg); free_list: for(i = 0 ; i < carray_count(tab) ; i++) mailmessage_free(carray_get(tab, i)); err: return res; } /* MAILIMAP_FLAG_FETCH_RECENT, MAILIMAP_FLAG_FETCH_OTHER MAILIMAP_FLAG_ANSWERED, MAILIMAP_FLAG_FLAGGED, MAILIMAP_FLAG_DELETED, MAILIMAP_FLAG_SEEN, MAILIMAP_FLAG_DRAFT, MAILIMAP_FLAG_KEYWORD, MAILIMAP_FLAG_EXTENSION */ static int imap_flags_to_flags(struct mailimap_msg_att_dynamic * att_dyn, struct mail_flags ** result) { struct mail_flags * flags; clist * flag_list; clistiter * cur; flags = mail_flags_new_empty(); if (flags == NULL) goto err; flags->fl_flags = 0; flag_list = att_dyn->att_list; if (flag_list != NULL) { for(cur = clist_begin(flag_list) ; cur != NULL ; cur = clist_next(cur)) { struct mailimap_flag_fetch * flag_fetch; flag_fetch = clist_content(cur); if (flag_fetch->fl_type == MAILIMAP_FLAG_FETCH_RECENT) flags->fl_flags |= MAIL_FLAG_NEW; else { char * keyword; int r; switch (flag_fetch->fl_flag->fl_type) { case MAILIMAP_FLAG_ANSWERED: flags->fl_flags |= MAIL_FLAG_ANSWERED; break; case MAILIMAP_FLAG_FLAGGED: flags->fl_flags |= MAIL_FLAG_FLAGGED; break; case MAILIMAP_FLAG_DELETED: flags->fl_flags |= MAIL_FLAG_DELETED; break; case MAILIMAP_FLAG_SEEN: flags->fl_flags |= MAIL_FLAG_SEEN; break; case MAILIMAP_FLAG_DRAFT: keyword = strdup("Draft"); if (keyword == NULL) goto free; r = clist_append(flags->fl_extension, keyword); if (r < 0) { free(keyword); goto free; } break; case MAILIMAP_FLAG_KEYWORD: if (strcasecmp(flag_fetch->fl_flag->fl_data.fl_keyword, "$Forwarded") == 0) { flags->fl_flags |= MAIL_FLAG_FORWARDED; } else { keyword = strdup(flag_fetch->fl_flag->fl_data.fl_keyword); if (keyword == NULL) goto free; r = clist_append(flags->fl_extension, keyword); if (r < 0) { free(keyword); goto free; } } break; case MAILIMAP_FLAG_EXTENSION: /* do nothing */ break; } } } /* MAIL_FLAG_NEW was set for \Recent messages. Correct this flag for \Seen messages by unsetting it. */ if ((flags->fl_flags & MAIL_FLAG_SEEN) && (flags->fl_flags & MAIL_FLAG_NEW)) { flags->fl_flags &= ~MAIL_FLAG_NEW; } } * result = flags; return MAIL_NO_ERROR; free: mail_flags_free(flags); err: return MAIL_ERROR_MEMORY; } -static int flags_to_imap_flags(struct mail_flags * flags, - struct mailimap_store_att_flags ** result) +int imap_flags_to_imap_flags(struct mail_flags * flags, + struct mailimap_flag_list ** result) { struct mailimap_flag * flag; struct mailimap_flag_list * flag_list; - struct mailimap_store_att_flags * att_flags; int res; clistiter * cur; int r; flag_list = mailimap_flag_list_new_empty(); if (flag_list == NULL) { res = MAIL_ERROR_MEMORY; goto err; } if ((flags->fl_flags & MAIL_FLAG_DELETED) != 0) { flag = mailimap_flag_new_deleted(); if (flag == NULL) { res = MAIL_ERROR_MEMORY; goto free_flag_list; } r = mailimap_flag_list_add(flag_list, flag); if (r != MAILIMAP_NO_ERROR) { mailimap_flag_free(flag); res = MAIL_ERROR_MEMORY; goto free_flag_list; } } if ((flags->fl_flags & MAIL_FLAG_FLAGGED) != 0) { flag = mailimap_flag_new_flagged(); if (flag == NULL) { res = MAIL_ERROR_MEMORY; goto free_flag_list; } r = mailimap_flag_list_add(flag_list, flag); if (r != MAILIMAP_NO_ERROR) { mailimap_flag_free(flag); res = MAIL_ERROR_MEMORY; goto free_flag_list; } } if ((flags->fl_flags & MAIL_FLAG_SEEN) != 0) { flag = mailimap_flag_new_seen(); if (flag == NULL) { res = MAIL_ERROR_MEMORY; goto free_flag_list; } r = mailimap_flag_list_add(flag_list, flag); if (r != MAILIMAP_NO_ERROR) { res = MAIL_ERROR_MEMORY; goto free_flag_list; } } if ((flags->fl_flags & MAIL_FLAG_ANSWERED) != 0) { flag = mailimap_flag_new_answered(); if (flag == NULL) { res = MAIL_ERROR_MEMORY; goto free_flag_list; } r = mailimap_flag_list_add(flag_list, flag); if (r != MAILIMAP_NO_ERROR) { mailimap_flag_free(flag); res = MAIL_ERROR_MEMORY; goto free_flag_list; } } if ((flags->fl_flags & MAIL_FLAG_FORWARDED) != 0) { char * flag_str; flag_str = strdup("$Forwarded"); if (flag_str == NULL) { res = MAIL_ERROR_MEMORY; goto free_flag_list; } flag = mailimap_flag_new_flag_keyword(flag_str); if (flag == NULL) { free(flag_str); res = MAIL_ERROR_MEMORY; goto free_flag_list; } r = mailimap_flag_list_add(flag_list, flag); if (r != MAILIMAP_NO_ERROR) { mailimap_flag_free(flag); res = MAIL_ERROR_MEMORY; goto free_flag_list; } } for(cur = clist_begin(flags->fl_extension) ; cur != NULL ; cur = clist_next(cur)) { char * flag_str; flag_str = clist_content(cur); if (strcasecmp(flag_str, "Draft") == 0) { flag = mailimap_flag_new_draft(); if (flag == NULL) { res = MAIL_ERROR_MEMORY; goto free_flag_list; } r = mailimap_flag_list_add(flag_list, flag); if (r != MAILIMAP_NO_ERROR) { mailimap_flag_free(flag); res = MAIL_ERROR_MEMORY; goto free_flag_list; } } else { flag_str = strdup(flag_str); if (flag_str == NULL) { res = MAIL_ERROR_MEMORY; goto free_flag_list; } flag = mailimap_flag_new_flag_keyword(flag_str); if (flag == NULL) { free(flag_str); res = MAIL_ERROR_MEMORY; goto free_flag_list; } r = mailimap_flag_list_add(flag_list, flag); if (r != MAILIMAP_NO_ERROR) { mailimap_flag_free(flag); res = MAIL_ERROR_MEMORY; goto free_flag_list; } } } + * result = flag_list; + + return MAIL_NO_ERROR; + + free_flag_list: + mailimap_flag_list_free(flag_list); + err: + return res; +} + +static int flags_to_imap_flags(struct mail_flags * flags, + struct mailimap_store_att_flags ** result) +{ + struct mailimap_flag_list * flag_list; + struct mailimap_store_att_flags * att_flags; + int res; + int r; + + r = imap_flags_to_imap_flags(flags, + &flag_list); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + att_flags = mailimap_store_att_flags_new_set_flags_silent(flag_list); if (att_flags == NULL) { res = MAIL_ERROR_MEMORY; goto free_flag_list; } * result = att_flags; return MAIL_NO_ERROR; free_flag_list: mailimap_flag_list_free(flag_list); err: return res; } static int imap_fetch_result_to_flags(clist * fetch_result, uint32_t index, struct mail_flags ** result) { clistiter * cur; int r; for(cur = clist_begin(fetch_result) ; cur != NULL ; cur = clist_next(cur)) { struct mailimap_msg_att * msg_att; clistiter * item_cur; uint32_t uid; struct mailimap_msg_att_dynamic * att_dyn; msg_att = clist_content(cur); uid = 0; att_dyn = NULL; for(item_cur = clist_begin(msg_att->att_list) ; item_cur != NULL ; item_cur = clist_next(item_cur)) { struct mailimap_msg_att_item * item; item = clist_content(item_cur); if (item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) { switch (item->att_data.att_static->att_type) { case MAILIMAP_MSG_ATT_UID: uid = item->att_data.att_static->att_data.att_uid; break; } } else if (item->att_type == MAILIMAP_MSG_ATT_ITEM_DYNAMIC) { if (att_dyn == NULL) { att_dyn = item->att_data.att_dyn; } } } if (uid != 0) { if (uid == index) { struct mail_flags * flags; if (att_dyn != NULL) { r = imap_flags_to_flags(att_dyn, &flags); if (r == MAIL_NO_ERROR) { * result = flags; return MAIL_NO_ERROR; } } } } } return MAIL_ERROR_MSG_NOT_FOUND; } int imap_fetch_flags(mailimap * imap, uint32_t index, struct mail_flags ** result) { struct mailimap_fetch_att * fetch_att; struct mailimap_fetch_type * fetch_type; struct mailimap_set * set; int r; int res; clist * fetch_result; struct mail_flags * flags; fetch_type = mailimap_fetch_type_new_fetch_att_list_empty(); if (fetch_type == NULL) { res = MAIL_ERROR_MEMORY; goto err; } fetch_att = mailimap_fetch_att_new_uid(); if (fetch_att == NULL) { res = MAIL_ERROR_MEMORY; goto free_fetch_type; } r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); if (r != MAILIMAP_NO_ERROR) { mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto free_fetch_type; } fetch_att = mailimap_fetch_att_new_flags(); if (fetch_att == NULL) { res = MAIL_ERROR_MEMORY; goto free_fetch_type; } r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); if (r != MAILIMAP_NO_ERROR) { mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto free_fetch_type; } set = mailimap_set_new_single(index); if (set == NULL) { res = MAIL_ERROR_MEMORY; goto free_fetch_type; } r = mailimap_uid_fetch(imap, set, fetch_type, &fetch_result); mailimap_fetch_type_free(fetch_type); mailimap_set_free(set); switch (r) { case MAILIMAP_NO_ERROR: break; default: return imap_error_to_mail_error(r); } r = imap_fetch_result_to_flags(fetch_result, index, &flags); mailimap_fetch_list_free(fetch_result); if (r != MAIL_NO_ERROR) { res = r; goto err; } * result = flags; return MAIL_NO_ERROR; free_fetch_type: mailimap_fetch_type_free(fetch_type); err: return res; } int imap_store_flags(mailimap * imap, uint32_t first, uint32_t last, struct mail_flags * flags) { struct mailimap_store_att_flags * att_flags; struct mailimap_set * set; int r; int res; set = mailimap_set_new_interval(first, last); if (set == NULL) { res = MAIL_ERROR_MEMORY; goto err; } r = flags_to_imap_flags(flags, &att_flags); if (r != MAIL_NO_ERROR) { res = r; goto free_set; } r = mailimap_uid_store(imap, set, att_flags); if (r != MAILIMAP_NO_ERROR) { res = imap_error_to_mail_error(r); goto free_flag; } mailimap_store_att_flags_free(att_flags); mailimap_set_free(set); return MAIL_NO_ERROR; free_flag: mailimap_store_att_flags_free(att_flags); free_set: mailimap_set_free(set); err: return res; } int imap_get_messages_list(mailimap * imap, mailsession * session, mailmessage_driver * driver, uint32_t first_index, struct mailmessage_list ** result) { struct mailmessage_list * env_list; int r; struct mailimap_fetch_att * fetch_att; struct mailimap_fetch_type * fetch_type; struct mailimap_set * set; clist * fetch_result; int res; set = mailimap_set_new_interval(first_index, 0); if (set == NULL) { res = MAIL_ERROR_MEMORY; goto err; } fetch_type = mailimap_fetch_type_new_fetch_att_list_empty(); if (fetch_type == NULL) { res = MAIL_ERROR_MEMORY; goto free_set; } fetch_att = mailimap_fetch_att_new_uid(); if (fetch_att == NULL) { res = MAIL_ERROR_MEMORY; goto free_fetch_type; } r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); if (r != MAILIMAP_NO_ERROR) { mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto free_fetch_type; } fetch_att = mailimap_fetch_att_new_rfc822_size(); if (fetch_att == NULL) { res = MAIL_ERROR_MEMORY; goto free_fetch_type; } r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); if (r != MAILIMAP_NO_ERROR) { mailimap_fetch_att_free(fetch_att); res = MAIL_ERROR_MEMORY; goto free_fetch_type; } r = mailimap_uid_fetch(imap, set, fetch_type, &fetch_result); mailimap_fetch_type_free(fetch_type); mailimap_set_free(set); if (r != MAILIMAP_NO_ERROR) { res = imap_error_to_mail_error(r); goto err; } r = uid_list_to_env_list(fetch_result, &env_list, session, driver); mailimap_fetch_list_free(fetch_result); * result = env_list; return MAIL_NO_ERROR; free_fetch_type: mailimap_fetch_type_free(fetch_type); free_set: mailimap_set_free(set); err: return res; } static void generate_key_from_message(char * key, size_t size, mailmessage * msg_info, int type) { switch (type) { case MAILIMAP_MSG_ATT_RFC822: snprintf(key, size, "%s-rfc822", msg_info->msg_uid); break; case MAILIMAP_MSG_ATT_RFC822_HEADER: snprintf(key, size, "%s-rfc822-header", msg_info->msg_uid); break; case MAILIMAP_MSG_ATT_RFC822_TEXT: snprintf(key, size, "%s-rfc822-text", msg_info->msg_uid); break; case MAILIMAP_MSG_ATT_ENVELOPE: snprintf(key, size, "%s-envelope", msg_info->msg_uid); break; } } int imapdriver_get_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr, mailsession * session, mailmessage * msg, struct mailimf_fields ** result) { #if 0 mailsession * imap_session; #endif mailimap * imap; int r; struct mailimf_fields * fields; int res; char keyname[PATH_MAX]; #if 0 imap_session = cached_session_get_ancestor(session); imap = ((struct imap_session_state_data *) (imap_session->data))->session; #endif imap = cached_session_get_imap_session(session); generate_key_from_message(keyname, PATH_MAX, msg, MAILIMAP_MSG_ATT_ENVELOPE); r = generic_cache_fields_read(cache_db, mmapstr, keyname, &fields); if (r != MAIL_NO_ERROR) { res = r; goto err; } * result = fields; return MAIL_NO_ERROR; err: return res; } int imapdriver_write_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr, mailsession * session, mailmessage * msg, struct mailimf_fields * fields) { char keyname[PATH_MAX]; int r; int res; generate_key_from_message(keyname, PATH_MAX, msg, MAILIMAP_MSG_ATT_ENVELOPE); r = generic_cache_fields_write(cache_db, mmapstr, keyname, fields); if (r != MAIL_NO_ERROR) { res = r; goto err; } return MAIL_NO_ERROR; err: return res; } diff --git a/kmicromail/libetpan/generic/imapdriver_tools.h b/kmicromail/libetpan/generic/imapdriver_tools.h index 6582a31..59c993e 100644 --- a/kmicromail/libetpan/generic/imapdriver_tools.h +++ b/kmicromail/libetpan/generic/imapdriver_tools.h @@ -1,113 +1,116 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #ifndef IMAPDRIVER_TOOLS_H #define IMAPDRIVER_TOOLS_H #include "mailimap.h" #include "mailmime.h" #include "imapdriver_types.h" #include "mail_cache_db.h" #ifdef __cplusplus extern "C" { #endif int imap_list_to_list(clist * imap_list, struct mail_list ** result); int section_to_imap_section(struct mailmime_section * section, int type, struct mailimap_section ** result); int imap_get_msg_att_info(struct mailimap_msg_att * msg_att, uint32_t * puid, struct mailimap_envelope ** pimap_envelope, char ** preferences, size_t * pref_size, struct mailimap_msg_att_dynamic ** patt_dyn, struct mailimap_body ** pimap_body); int imap_add_envelope_fetch_att(struct mailimap_fetch_type * fetch_type); int imap_env_to_fields(struct mailimap_envelope * env, char * ref_str, size_t ref_size, struct mailimf_fields ** result); int imap_fetch_result_to_envelop_list(clist * fetch_result, struct mailmessage_list * env_list); int imap_body_to_body(struct mailimap_body * imap_body, struct mailmime ** result); #if 0 int mail_search_to_imap_search(struct mail_search_key * key, struct mailimap_search_key ** result); #endif int msg_list_to_imap_set(clist * msg_list, struct mailimap_set ** result); int imap_error_to_mail_error(int error); int imap_store_flags(mailimap * imap, uint32_t first, uint32_t last, struct mail_flags * flags); int imap_fetch_flags(mailimap * imap, uint32_t index, struct mail_flags ** result); int imap_get_messages_list(mailimap * imap, mailsession * session, mailmessage_driver * driver, uint32_t first_index, struct mailmessage_list ** result); int imapdriver_get_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr, mailsession * session, mailmessage * msg, struct mailimf_fields ** result); int imapdriver_write_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr, mailsession * session, mailmessage * msg, struct mailimf_fields * fields); +int imap_flags_to_imap_flags(struct mail_flags * flags, + struct mailimap_flag_list ** result); + #ifdef __cplusplus } #endif #endif diff --git a/kmicromail/libetpan/generic/imapstorage.c b/kmicromail/libetpan/generic/imapstorage.c index e8683d8..972b6dd 100644 --- a/kmicromail/libetpan/generic/imapstorage.c +++ b/kmicromail/libetpan/generic/imapstorage.c @@ -1,297 +1,297 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "imapstorage.h" #include <stdlib.h> #include <string.h> #include "mail.h" #include "imapdriver.h" #include "imapdriver_cached.h" #include "mailstorage_tools.h" #include "maildriver.h" /* imap storage */ #define IMAP_DEFAULT_PORT 143 #define IMAPS_DEFAULT_PORT 993 static int imap_mailstorage_connect(struct mailstorage * storage); static int imap_mailstorage_get_folder_session(struct mailstorage * storage, char * pathname, mailsession ** result); static void imap_mailstorage_uninitialize(struct mailstorage * storage); static mailstorage_driver imap_mailstorage_driver = { .sto_name = "imap", .sto_connect = imap_mailstorage_connect, .sto_get_folder_session = imap_mailstorage_get_folder_session, .sto_uninitialize = imap_mailstorage_uninitialize, }; int imap_mailstorage_init(struct mailstorage * storage, char * imap_servername, uint16_t imap_port, char * imap_command, int imap_connection_type, int imap_auth_type, char * imap_login, char * imap_password, int imap_cached, char * imap_cache_directory) { struct imap_mailstorage * imap_storage; - imap_storage = malloc(sizeof(struct imap_mailstorage)); + imap_storage = malloc(sizeof(* imap_storage)); if (imap_storage == NULL) goto err; imap_storage->imap_servername = strdup(imap_servername); if (imap_storage->imap_servername == NULL) goto free; imap_storage->imap_connection_type = imap_connection_type; if (imap_port == 0) { switch (imap_connection_type) { case CONNECTION_TYPE_PLAIN: case CONNECTION_TYPE_TRY_STARTTLS: case CONNECTION_TYPE_STARTTLS: case CONNECTION_TYPE_COMMAND: case CONNECTION_TYPE_COMMAND_TRY_STARTTLS: case CONNECTION_TYPE_COMMAND_STARTTLS: imap_port = IMAP_DEFAULT_PORT; break; case CONNECTION_TYPE_TLS: case CONNECTION_TYPE_COMMAND_TLS: imap_port = IMAPS_DEFAULT_PORT; break; } } imap_storage->imap_port = imap_port; if (imap_command != NULL) { imap_storage->imap_command = strdup(imap_command); if (imap_storage->imap_command == NULL) goto free_servername; } else imap_storage->imap_command = NULL; imap_storage->imap_auth_type = imap_auth_type; if (imap_login != NULL) { imap_storage->imap_login = strdup(imap_login); if (imap_storage->imap_login == NULL) goto free_command; } else imap_storage->imap_login = NULL; if (imap_password != NULL) { imap_storage->imap_password = strdup(imap_password); if (imap_storage->imap_password == NULL) goto free_login; } else imap_storage->imap_password = NULL; imap_storage->imap_cached = imap_cached; if (imap_cached && (imap_cache_directory != NULL)) { imap_storage->imap_cache_directory = strdup(imap_cache_directory); if (imap_storage->imap_cache_directory == NULL) goto free_password; } else { imap_storage->imap_cached = FALSE; imap_storage->imap_cache_directory = NULL; } storage->sto_data = imap_storage; storage->sto_driver = &imap_mailstorage_driver; return MAIL_NO_ERROR; free_password: free(imap_storage->imap_password); free_login: free(imap_storage->imap_login); free_command: free(imap_storage->imap_command); free_servername: free(imap_storage->imap_servername); free: free(imap_storage); err: return MAIL_ERROR_MEMORY; } static void imap_mailstorage_uninitialize(struct mailstorage * storage) { struct imap_mailstorage * imap_storage; imap_storage = storage->sto_data; if (imap_storage->imap_cache_directory != NULL) free(imap_storage->imap_cache_directory); if (imap_storage->imap_password != NULL) free(imap_storage->imap_password); if (imap_storage->imap_login != NULL) free(imap_storage->imap_login); if (imap_storage->imap_command != NULL) free(imap_storage->imap_command); free(imap_storage->imap_servername); free(imap_storage); storage->sto_data = NULL; } static int imap_connect(struct mailstorage * storage, mailsession ** result) { struct imap_mailstorage * imap_storage; mailsession_driver * driver; int r; int res; mailsession * session; imap_storage = storage->sto_data; if (imap_storage->imap_cached) driver = imap_cached_session_driver; else driver = imap_session_driver; r = mailstorage_generic_connect(driver, imap_storage->imap_servername, imap_storage->imap_port, imap_storage->imap_command, imap_storage->imap_connection_type, IMAPDRIVER_CACHED_SET_CACHE_DIRECTORY, imap_storage->imap_cache_directory, 0, NULL, &session); switch (r) { case MAIL_NO_ERROR_NON_AUTHENTICATED: case MAIL_NO_ERROR_AUTHENTICATED: case MAIL_NO_ERROR: break; default: res = r; goto err; } r = mailstorage_generic_auth(session, r, imap_storage->imap_connection_type, imap_storage->imap_login, imap_storage->imap_password); if (r != MAIL_NO_ERROR) { res = r; goto free; } * result = session; return MAIL_NO_ERROR; free: mailsession_free(session); err: return res; } static int imap_mailstorage_connect(struct mailstorage * storage) { mailsession * session; int r; int res; r = imap_connect(storage, &session); if (r != MAIL_NO_ERROR) { res = r; goto err; } r = mailsession_select_folder(session, "INBOX"); if (r != MAIL_NO_ERROR) { mailsession_logout(session); res = r; goto err; } storage->sto_session = session; storage->sto_driver = &imap_mailstorage_driver; return MAIL_NO_ERROR; err: return res; } static int imap_mailstorage_get_folder_session(struct mailstorage * storage, char * pathname, mailsession ** result) { mailsession * session; int r; int res; if (strcasecmp(pathname, "INBOX") == 0) { session = storage->sto_session; } else { r = imap_connect(storage, &session); if (r != MAIL_NO_ERROR) { res = r; goto err; } r = mailsession_select_folder(session, pathname); if (r != MAIL_NO_ERROR) { mailsession_logout(session); res = r; goto free; } } * result = session; return MAIL_NO_ERROR; free: mailsession_free(session); err: return res; } diff --git a/kmicromail/libetpan/generic/maildirdriver.c b/kmicromail/libetpan/generic/maildirdriver.c index 7830ceb..5f21422 100644 --- a/kmicromail/libetpan/generic/maildirdriver.c +++ b/kmicromail/libetpan/generic/maildirdriver.c @@ -1,625 +1,676 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ /* flags directory MUST be kept so that we can have other flags than standards */ #include "maildirdriver.h" #include <stdio.h> #include <sys/types.h> #include <dirent.h> #include <unistd.h> #include <sys/stat.h> #include <ctype.h> #include <fcntl.h> #include <sys/mman.h> #include <stdlib.h> #include <string.h> #include "maildir.h" #include "maildriver_tools.h" #include "maildirdriver_message.h" #include "maildirdriver_tools.h" #include "mailmessage.h" #include "generic_cache.h" static int initialize(mailsession * session); static void uninitialize(mailsession * session); static int connect_path(mailsession * session, char * path); static int logout(mailsession * session); static int expunge_folder(mailsession * session); static int status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); static int recent_number(mailsession * session, char * mb, uint32_t * result); static int unseen_number(mailsession * session, char * mb, uint32_t * result); static int messages_number(mailsession * session, char * mb, uint32_t * result); static int append_message(mailsession * session, char * message, size_t size); +static int append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags); + static int get_messages_list(mailsession * session, struct mailmessage_list ** result); static int get_envelopes_list(mailsession * session, struct mailmessage_list * env_list); static int check_folder(mailsession * session); static int get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result); static mailsession_driver local_maildir_session_driver = { .sess_name = "maildir", .sess_initialize = initialize, .sess_uninitialize = uninitialize, .sess_parameters = NULL, .sess_connect_stream = NULL, .sess_connect_path = connect_path, .sess_starttls = NULL, .sess_login = NULL, .sess_logout = logout, .sess_noop = NULL, .sess_build_folder_name = NULL, .sess_create_folder = NULL, .sess_delete_folder = NULL, .sess_rename_folder = NULL, .sess_check_folder = check_folder, .sess_examine_folder = NULL, .sess_select_folder = NULL, .sess_expunge_folder = expunge_folder, .sess_status_folder = status_folder, .sess_messages_number = messages_number, .sess_recent_number = recent_number, .sess_unseen_number = unseen_number, .sess_list_folders = NULL, .sess_lsub_folders = NULL, .sess_subscribe_folder = NULL, .sess_unsubscribe_folder = NULL, .sess_append_message = append_message, + .sess_append_message_flags = append_message_flags, .sess_copy_message = NULL, .sess_move_message = NULL, .sess_get_messages_list = get_messages_list, .sess_get_envelopes_list = get_envelopes_list, .sess_remove_message = NULL, #if 0 .sess_search_messages = maildriver_generic_search_messages, #endif .sess_get_message = NULL, .sess_get_message_by_uid = get_message_by_uid, }; mailsession_driver * maildir_session_driver = &local_maildir_session_driver; static int flags_store_process(struct maildir * md, struct mail_flags_store * flags_store); static inline struct maildir_session_state_data * get_data(mailsession * session) { return session->sess_data; } static struct maildir * get_maildir_session(mailsession * session) { return get_data(session)->md_session; } static int initialize(mailsession * session) { struct maildir_session_state_data * data; data = malloc(sizeof(* data)); if (data == NULL) goto err; data->md_session = NULL; data->md_flags_store = mail_flags_store_new(); if (data->md_flags_store == NULL) goto free; session->sess_data = data; return MAIL_NO_ERROR; free: free(data); err: return MAIL_ERROR_MEMORY; } static void uninitialize(mailsession * session) { struct maildir_session_state_data * data; data = get_data(session); if (data->md_session != NULL) flags_store_process(data->md_session, data->md_flags_store); mail_flags_store_free(data->md_flags_store); if (data->md_session != NULL) maildir_free(data->md_session); free(data); session->sess_data = NULL; } static int connect_path(mailsession * session, char * path) { struct maildir * md; int res; int r; if (get_maildir_session(session) != NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } md = maildir_new(path); if (md == NULL) { res = MAIL_ERROR_MEMORY; goto err; } r = maildir_update(md); if (r != MAILDIR_NO_ERROR) { res = maildirdriver_maildir_error_to_mail_error(r); goto free; } get_data(session)->md_session = md; return MAIL_NO_ERROR; free: maildir_free(md); err: return res; } static int logout(mailsession * session) { struct maildir * md; check_folder(session); md = get_maildir_session(session); if (md == NULL) return MAIL_ERROR_BAD_STATE; maildir_free(md); get_data(session)->md_session = NULL; return MAIL_NO_ERROR; } /* folders operations */ static int status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { int r; struct maildir * md; unsigned int i; uint32_t messages; uint32_t recent; uint32_t unseen; check_folder(session); md = get_maildir_session(session); if (md == NULL) return MAIL_ERROR_BAD_STATE; r = maildir_update(md); if (r != MAILDIR_NO_ERROR) return maildirdriver_maildir_error_to_mail_error(r); messages = 0; recent = 0; unseen = 0; for(i = 0 ; i < carray_count(md->mdir_msg_list) ; i ++) { struct maildir_msg * msg; msg = carray_get(md->mdir_msg_list, i); if ((msg->msg_flags & MAILDIR_FLAG_NEW) != 0) recent ++; if ((msg->msg_flags & MAILDIR_FLAG_SEEN) == 0) unseen ++; messages ++; } * result_messages = messages; * result_recent = recent; * result_unseen = unseen; return MAIL_NO_ERROR; } static int messages_number(mailsession * session, char * mb, uint32_t * result) { struct maildir * md; int r; md = get_maildir_session(session); if (md == NULL) return MAIL_ERROR_BAD_STATE; r = maildir_update(md); if (r != MAILDIR_NO_ERROR) return maildirdriver_maildir_error_to_mail_error(r); * result = carray_count(md->mdir_msg_list); return MAIL_NO_ERROR; } static int unseen_number(mailsession * session, char * mb, uint32_t * result) { uint32_t messages; uint32_t recent; uint32_t unseen; int r; r = status_folder(session, mb, &messages, &recent, &unseen); if (r != MAIL_NO_ERROR) return r; * result = unseen; return MAIL_NO_ERROR; } static int recent_number(mailsession * session, char * mb, uint32_t * result) { uint32_t messages; uint32_t recent; uint32_t unseen; int r; r = status_folder(session, mb, &messages, &recent, &unseen); if (r != MAIL_NO_ERROR) return r; * result = recent; return MAIL_NO_ERROR; } /* messages operations */ static int append_message(mailsession * session, char * message, size_t size) { +#if 0 struct maildir * md; int r; md = get_maildir_session(session); if (md == NULL) return MAIL_ERROR_BAD_STATE; r = maildir_message_add(md, message, size); if (r != MAILDIR_NO_ERROR) return maildirdriver_maildir_error_to_mail_error(r); return MAIL_NO_ERROR; +#endif + + return append_message_flags(session, message, size, NULL); +} + +static int append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags) +{ + struct maildir * md; + int r; + char uid[PATH_MAX]; + struct maildir_msg * md_msg; + chashdatum key; + chashdatum value; + uint32_t md_flags; + + md = get_maildir_session(session); + if (md == NULL) + return MAIL_ERROR_BAD_STATE; + + r = maildir_message_add_uid(md, message, size, + uid, sizeof(uid)); + if (r != MAILDIR_NO_ERROR) + return maildirdriver_maildir_error_to_mail_error(r); + + if (flags == NULL) + goto exit; + + key.data = uid; + key.len = strlen(uid); + r = chash_get(md->mdir_msg_hash, &key, &value); + if (r < 0) + goto exit; + + md_msg = value.data; + + md_flags = maildirdriver_flags_to_maildir_flags(flags->fl_flags); + + r = maildir_message_change_flags(md, uid, md_flags); + if (r != MAILDIR_NO_ERROR) + goto exit; + + return MAIL_NO_ERROR; + + exit: + return MAIL_NO_ERROR; } static int get_messages_list(mailsession * session, struct mailmessage_list ** result) { struct maildir * md; int r; struct mailmessage_list * env_list; int res; md = get_maildir_session(session); if (md == NULL) return MAIL_ERROR_BAD_STATE; r = maildir_update(md); if (r != MAILDIR_NO_ERROR) { res = maildirdriver_maildir_error_to_mail_error(r); goto err; } r = maildir_get_messages_list(session, md, maildir_message_driver, &env_list); if (r != MAILDIR_NO_ERROR) { res = r; goto free_list; } * result = env_list; return MAIL_NO_ERROR; free_list: mailmessage_list_free(env_list); err: return res; } static int get_envelopes_list(mailsession * session, struct mailmessage_list * env_list) { int r; struct maildir * md; unsigned int i; int res; check_folder(session); md = get_maildir_session(session); if (md == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } r = maildir_update(md); if (r != MAILDIR_NO_ERROR) { res = maildirdriver_maildir_error_to_mail_error(r); goto err; } r = maildriver_generic_get_envelopes_list(session, env_list); if (r != MAIL_NO_ERROR) { res = r; goto err; } for(i = 0 ; i < carray_count(env_list->msg_tab) ; i++) { struct maildir_msg * md_msg; mailmessage * msg; uint32_t driver_flags; clist * ext; chashdatum key; chashdatum value; msg = carray_get(env_list->msg_tab, i); key.data = msg->msg_uid; key.len = strlen(msg->msg_uid); r = chash_get(md->mdir_msg_hash, &key, &value); if (r < 0) continue; md_msg = value.data; driver_flags = maildirdriver_maildir_flags_to_flags(md_msg->msg_flags); if (msg->msg_flags == NULL) { ext = clist_new(); if (ext == NULL) { res = MAIL_ERROR_MEMORY; continue; } msg->msg_flags = mail_flags_new(driver_flags, ext); if (msg->msg_flags == NULL) { clist_free(ext); res = MAIL_ERROR_MEMORY; continue; } if ((md_msg->msg_flags & MAILDIR_FLAG_NEW) != 0) { mail_flags_store_set(get_data(session)->md_flags_store, msg); } } else { msg->msg_flags->fl_flags &= MAIL_FLAG_FORWARDED; msg->msg_flags->fl_flags |= driver_flags; } } return MAIL_NO_ERROR; err: return res; } static int expunge_folder(mailsession * session) { unsigned int i; int r; int res; struct maildir * md; check_folder(session); md = get_maildir_session(session); if (md == NULL) return MAIL_ERROR_BAD_STATE; r = maildir_update(md); if (r != MAILDIR_NO_ERROR) { res = maildirdriver_maildir_error_to_mail_error(r); goto err; } for(i = 0 ; i < carray_count(md->mdir_msg_list) ; i++) { struct maildir_msg * md_msg; md_msg = carray_get(md->mdir_msg_list, i); if ((md_msg->msg_flags & MAILDIR_FLAG_TRASHED) != 0) maildir_message_remove(md, md_msg->msg_uid); } return MAIL_NO_ERROR; err: return res; } static int flags_store_process(struct maildir * md, struct mail_flags_store * flags_store) { unsigned int i; if (carray_count(flags_store->fls_tab) == 0) return MAIL_NO_ERROR; for(i = 0 ; i < carray_count(flags_store->fls_tab) ; i ++) { mailmessage * msg; uint32_t md_flags; msg = carray_get(flags_store->fls_tab, i); md_flags = maildirdriver_flags_to_maildir_flags(msg->msg_flags->fl_flags); md_flags &= ~MAILDIR_FLAG_NEW; maildir_message_change_flags(md, msg->msg_uid, md_flags); } mail_flags_store_clear(flags_store); return MAIL_NO_ERROR; } static int check_folder(mailsession * session) { struct mail_flags_store * flags_store; struct maildir_session_state_data * data; struct maildir * md; md = get_maildir_session(session); if (md == NULL) return MAIL_ERROR_BAD_STATE; data = get_data(session); flags_store = data->md_flags_store; return flags_store_process(md, flags_store); } static int get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result) { int r; struct maildir * md; int res; mailmessage * msg; char * msg_filename; struct stat stat_info; md = get_maildir_session(session); /* update maildir data */ r = maildir_update(md); if (r != MAILDIR_NO_ERROR) { res = maildirdriver_maildir_error_to_mail_error(r); goto err; } msg_filename = maildir_message_get(md, uid); if (msg_filename == NULL) { res = MAIL_ERROR_INVAL; goto err; } r = stat(msg_filename, &stat_info); free(msg_filename); if (r < 0) { res = MAIL_ERROR_INVAL; goto err; } /* create message */ msg = mailmessage_new(); if (msg == NULL) { res = MAIL_ERROR_MEMORY; goto err; } r = mailmessage_init(msg, session, maildir_message_driver, 0, stat_info.st_size); if (r != MAIL_NO_ERROR) { mailmessage_free(msg); res = r; goto err; } msg->msg_uid = strdup(uid); if (msg->msg_uid == NULL) { mailmessage_free(msg); res = r; goto err; } * result = msg; return MAIL_NO_ERROR; err: return res; } diff --git a/kmicromail/libetpan/generic/maildirdriver_cached.c b/kmicromail/libetpan/generic/maildirdriver_cached.c index 503d1c9..8a5e206 100644 --- a/kmicromail/libetpan/generic/maildirdriver_cached.c +++ b/kmicromail/libetpan/generic/maildirdriver_cached.c @@ -1,1080 +1,1158 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "maildirdriver.h" #include <stdio.h> #include <sys/types.h> #include <dirent.h> #include <unistd.h> #include <sys/stat.h> #include <ctype.h> #include <fcntl.h> #include <sys/mman.h> #include <stdlib.h> #include <string.h> #include "mail.h" #include "maildir.h" #include "maildriver_tools.h" #include "maildirdriver_tools.h" #include "maildirdriver_cached_message.h" #include "mailmessage.h" #include "generic_cache.h" #include "imfcache.h" #include "mail_cache_db.h" #include "libetpan-config.h" static int initialize(mailsession * session); static void uninitialize(mailsession * session); static int parameters(mailsession * session, int id, void * value); static int connect_path(mailsession * session, char * path); static int logout(mailsession * session); static int expunge_folder(mailsession * session); static int status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); static int recent_number(mailsession * session, char * mb, uint32_t * result); static int unseen_number(mailsession * session, char * mb, uint32_t * result); static int messages_number(mailsession * session, char * mb, uint32_t * result); static int append_message(mailsession * session, char * message, size_t size); +static int append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags); + static int get_messages_list(mailsession * session, struct mailmessage_list ** result); static int get_envelopes_list(mailsession * session, struct mailmessage_list * env_list); static int check_folder(mailsession * session); static int get_message(mailsession * session, uint32_t num, mailmessage ** result); static int get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result); static mailsession_driver local_maildir_cached_session_driver = { .sess_name = "maildir-cached", .sess_initialize = initialize, .sess_uninitialize = uninitialize, .sess_parameters = parameters, .sess_connect_stream = NULL, .sess_connect_path = connect_path, .sess_starttls = NULL, .sess_login = NULL, .sess_logout = logout, .sess_noop = NULL, .sess_build_folder_name = NULL, .sess_create_folder = NULL, .sess_delete_folder = NULL, .sess_rename_folder = NULL, .sess_check_folder = check_folder, .sess_examine_folder = NULL, .sess_select_folder = NULL, .sess_expunge_folder = expunge_folder, .sess_status_folder = status_folder, .sess_messages_number = messages_number, .sess_recent_number = recent_number, .sess_unseen_number = unseen_number, .sess_list_folders = NULL, .sess_lsub_folders = NULL, .sess_subscribe_folder = NULL, .sess_unsubscribe_folder = NULL, .sess_append_message = append_message, + .sess_append_message_flags = append_message_flags, .sess_copy_message = NULL, .sess_move_message = NULL, .sess_get_messages_list = get_messages_list, .sess_get_envelopes_list = get_envelopes_list, .sess_remove_message = NULL, #if 0 .sess_search_messages = maildriver_generic_search_messages, #endif .sess_get_message = get_message, .sess_get_message_by_uid = get_message_by_uid, }; mailsession_driver * maildir_cached_session_driver = &local_maildir_cached_session_driver; static inline struct maildir_cached_session_state_data * get_cached_data(mailsession * session) { return session->sess_data; } static inline mailsession * get_ancestor(mailsession * session) { return get_cached_data(session)->md_ancestor; } static inline struct maildir_session_state_data * get_ancestor_data(mailsession * session) { return get_ancestor(session)->sess_data; } static struct maildir * get_maildir_session(mailsession * session) { return get_ancestor_data(session)->md_session; } static int initialize(mailsession * session) { struct maildir_cached_session_state_data * data; data = malloc(sizeof(* data)); if (data == NULL) goto err; data->md_ancestor = mailsession_new(maildir_session_driver); if (data->md_ancestor == NULL) goto free; data->md_flags_store = mail_flags_store_new(); if (data->md_flags_store == NULL) goto free_session; data->md_quoted_mb = NULL; data->md_cache_directory[0] = '\0'; data->md_flags_directory[0] = '\0'; session->sess_data = data; return MAIL_NO_ERROR; free_session: mailsession_free(data->md_ancestor); free: free(data); err: return MAIL_ERROR_MEMORY; } static void free_quoted_mb(struct maildir_cached_session_state_data * maildir_cached_data) { if (maildir_cached_data->md_quoted_mb != NULL) { free(maildir_cached_data->md_quoted_mb); maildir_cached_data->md_quoted_mb = NULL; } } static int write_cached_flags(struct mail_cache_db * cache_db, MMAPString * mmapstr, char * uid, struct mail_flags * flags); #define ENV_NAME "env.db" #define FLAGS_NAME "flags.db" static int flags_store_process(char * flags_directory, char * quoted_mb, struct mail_flags_store * flags_store) { char filename_flags[PATH_MAX]; struct mail_cache_db * cache_db_flags; MMAPString * mmapstr; unsigned int i; int r; int res; if (carray_count(flags_store->fls_tab) == 0) return MAIL_NO_ERROR; if (quoted_mb == NULL) return MAIL_NO_ERROR; snprintf(filename_flags, PATH_MAX, "%s%c%s%c%s", flags_directory, MAIL_DIR_SEPARATOR, quoted_mb, MAIL_DIR_SEPARATOR, FLAGS_NAME); r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_FILE; goto err; } mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto close_db_flags; } for(i = 0 ; i < carray_count(flags_store->fls_tab) ; i ++) { mailmessage * msg; msg = carray_get(flags_store->fls_tab, i); r = write_cached_flags(cache_db_flags, mmapstr, msg->msg_uid, msg->msg_flags); if (r != MAIL_NO_ERROR) { /* ignore errors */ } } mmap_string_free(mmapstr); mail_cache_db_close_unlock(filename_flags, cache_db_flags); mail_flags_store_clear(flags_store); return MAIL_NO_ERROR; close_db_flags: mail_cache_db_close_unlock(filename_flags, cache_db_flags); err: return res; } static void uninitialize(mailsession * session) { struct maildir_cached_session_state_data * data; data = get_cached_data(session); flags_store_process(data->md_flags_directory, data->md_quoted_mb, data->md_flags_store); mail_flags_store_free(data->md_flags_store); mailsession_free(data->md_ancestor); free_quoted_mb(data); free(data); session->sess_data = data; } static int parameters(mailsession * session, int id, void * value) { struct maildir_cached_session_state_data * data; int r; data = get_cached_data(session); switch (id) { case MAILDIRDRIVER_CACHED_SET_CACHE_DIRECTORY: strncpy(data->md_cache_directory, value, PATH_MAX); data->md_cache_directory[PATH_MAX - 1] = '\0'; r = generic_cache_create_dir(data->md_cache_directory); if (r != MAIL_NO_ERROR) return r; return MAIL_NO_ERROR; case MAILDIRDRIVER_CACHED_SET_FLAGS_DIRECTORY: strncpy(data->md_flags_directory, value, PATH_MAX); data->md_flags_directory[PATH_MAX - 1] = '\0'; r = generic_cache_create_dir(data->md_flags_directory); if (r != MAIL_NO_ERROR) return r; return MAIL_NO_ERROR; default: return mailsession_parameters(data->md_ancestor, id, value); } } static int get_cache_folder(mailsession * session, char ** result) { struct maildir * md; char * quoted_mb; int res; int r; char key[PATH_MAX]; struct maildir_cached_session_state_data * data; md = get_maildir_session(session); data = get_cached_data(session); quoted_mb = maildriver_quote_mailbox(md->mdir_path); if (quoted_mb == NULL) { res = MAIL_ERROR_MEMORY; goto err; } snprintf(key, PATH_MAX, "%s/%s", data->md_cache_directory, quoted_mb); r = generic_cache_create_dir(key); if (r != MAIL_NO_ERROR) { res = r; goto free_quoted_mb; } snprintf(key, PATH_MAX, "%s/%s", data->md_flags_directory, quoted_mb); r = generic_cache_create_dir(key); if (r != MAIL_NO_ERROR) { res = r; goto free_quoted_mb; } * result = quoted_mb; return MAIL_NO_ERROR; free_quoted_mb: free(quoted_mb); err: return res; } static int connect_path(mailsession * session, char * path) { int r; int res; char * quoted_mb; r = mailsession_connect_path(get_ancestor(session), path); if (r != MAIL_NO_ERROR) { res = r; goto err; } r = get_cache_folder(session, "ed_mb); if (r != MAIL_NO_ERROR) { res = r; goto logout; } get_cached_data(session)->md_quoted_mb = quoted_mb; return MAILDIR_NO_ERROR; logout: mailsession_logout(get_ancestor(session)); err: return res; } static int logout(mailsession * session) { struct maildir_cached_session_state_data * data; int r; data = get_cached_data(session); flags_store_process(data->md_flags_directory, data->md_quoted_mb, data->md_flags_store); r = mailsession_logout(get_ancestor(session)); if (r != MAIL_NO_ERROR) return r; free_quoted_mb(get_cached_data(session)); return MAIL_NO_ERROR; } static int status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { return mailsession_status_folder(get_ancestor(session), mb, result_messages, result_recent, result_unseen); } static int messages_number(mailsession * session, char * mb, uint32_t * result) { return mailsession_messages_number(get_ancestor(session), mb, result); } static int unseen_number(mailsession * session, char * mb, uint32_t * result) { return mailsession_unseen_number(get_ancestor(session), mb, result); } static int recent_number(mailsession * session, char * mb, uint32_t * result) { return mailsession_recent_number(get_ancestor(session), mb, result); } static int append_message(mailsession * session, char * message, size_t size) { +#if 0 return mailsession_append_message(get_ancestor(session), message, size); +#endif + return append_message_flags(session, message, size, NULL); } +static int append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags) +{ + struct maildir * md; + int r; + char uid[PATH_MAX]; + struct maildir_msg * md_msg; + chashdatum key; + chashdatum value; + uint32_t md_flags; + struct mail_cache_db * cache_db_flags; + char filename_flags[PATH_MAX]; + MMAPString * mmapstr; + struct maildir_cached_session_state_data * data; + + md = get_maildir_session(session); + if (md == NULL) + return MAIL_ERROR_BAD_STATE; + + r = maildir_message_add_uid(md, message, size, + uid, sizeof(uid)); + if (r != MAILDIR_NO_ERROR) + return maildirdriver_maildir_error_to_mail_error(r); + + if (flags == NULL) + goto exit; + + data = get_cached_data(session); + + snprintf(filename_flags, PATH_MAX, "%s%c%s%c%s", + data->md_flags_directory, MAIL_DIR_SEPARATOR, data->md_quoted_mb, + MAIL_DIR_SEPARATOR, FLAGS_NAME); + + r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); + if (r < 0) + goto exit; + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) + goto close_db_flags; + + r = write_cached_flags(cache_db_flags, mmapstr, + uid, flags); + + mmap_string_free(mmapstr); + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + + if (r != MAIL_NO_ERROR) + goto exit; + + key.data = uid; + key.len = strlen(uid); + r = chash_get(md->mdir_msg_hash, &key, &value); + if (r < 0) + goto exit; + + md_msg = value.data; + + md_flags = maildirdriver_flags_to_maildir_flags(flags->fl_flags); + + r = maildir_message_change_flags(md, uid, md_flags); + if (r != MAILDIR_NO_ERROR) + goto exit; + + return MAIL_NO_ERROR; + + close_db_flags: + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + exit: + return MAIL_NO_ERROR; +} #define UID_NAME "uid.db" static int uid_clean_up(struct mail_cache_db * uid_db, struct mailmessage_list * env_list) { chash * hash_exist; int res; int r; unsigned int i; chashdatum key; chashdatum value; char key_str[PATH_MAX]; /* flush cache */ hash_exist = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYALL); if (hash_exist == NULL) { res = MAIL_ERROR_MEMORY; goto err; } value.data = NULL; value.len = 0; key.data = "max-uid"; key.len = strlen("max-uid"); r = chash_set(hash_exist, &key, &value, NULL); for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; msg = carray_get(env_list->msg_tab, i); value.data = NULL; value.len = 0; key.data = msg->msg_uid; key.len = strlen(msg->msg_uid); r = chash_set(hash_exist, &key, &value, NULL); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free; } snprintf(key_str, sizeof(key_str), "uid-%lu", (unsigned long) msg->msg_index); key.data = key_str; key.len = strlen(key_str); r = chash_set(hash_exist, &key, &value, NULL); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free; } } mail_cache_db_clean_up(uid_db, hash_exist); chash_free(hash_exist); return MAIL_NO_ERROR; free: chash_free(hash_exist); err: return res; } static int get_messages_list(mailsession * session, struct mailmessage_list ** result) { struct maildir * md; int r; struct mailmessage_list * env_list; int res; uint32_t max_uid; char filename[PATH_MAX]; struct mail_cache_db * uid_db; void * value; size_t value_len; unsigned long i; struct maildir_cached_session_state_data * data; char key[PATH_MAX]; data = get_cached_data(session); md = get_maildir_session(session); if (md == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } check_folder(session); r = maildir_update(md); if (r != MAILDIR_NO_ERROR) { res = maildirdriver_maildir_error_to_mail_error(r); goto err; } r = maildir_get_messages_list(session, md, maildir_cached_message_driver, &env_list); if (r != MAILDIR_NO_ERROR) { res = r; goto err; } /* read/write DB */ snprintf(filename, sizeof(filename), "%s%c%s%c%s", data->md_flags_directory, MAIL_DIR_SEPARATOR, data->md_quoted_mb, MAIL_DIR_SEPARATOR, UID_NAME); r = mail_cache_db_open_lock(filename, &uid_db); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_list; } max_uid = 0; r = mail_cache_db_get(uid_db, "max-uid", sizeof("max-uid") - 1, &value, &value_len); if (r == 0) { memcpy(&max_uid, value, sizeof(max_uid)); } for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; uint32_t index; msg = carray_get(env_list->msg_tab, i); r = mail_cache_db_get(uid_db, msg->msg_uid, strlen(msg->msg_uid), &value, &value_len); if (r < 0) { max_uid ++; msg->msg_index = max_uid; mail_cache_db_put(uid_db, msg->msg_uid, strlen(msg->msg_uid), &msg->msg_index, sizeof(msg->msg_index)); snprintf(key, sizeof(key), "uid-%lu", (unsigned long) msg->msg_index); mail_cache_db_put(uid_db, key, strlen(key), msg->msg_uid, strlen(msg->msg_uid)); } else { memcpy(&index, value, sizeof(index)); msg->msg_index = index; } } mail_cache_db_put(uid_db, "max-uid", sizeof("max-uid") - 1, &max_uid, sizeof(max_uid)); uid_clean_up(uid_db, env_list); mail_cache_db_close_unlock(filename, uid_db); * result = env_list; return MAIL_NO_ERROR; free_list: mailmessage_list_free(env_list); err: return res; } static int get_cached_flags(struct mail_cache_db * cache_db, MMAPString * mmapstr, mailsession * session, char * uid, struct mail_flags ** result) { int r; char keyname[PATH_MAX]; struct mail_flags * flags; int res; snprintf(keyname, PATH_MAX, "%s-flags", uid); r = generic_cache_flags_read(cache_db, mmapstr, keyname, &flags); if (r != MAIL_NO_ERROR) { res = r; goto err; } * result = flags; return MAIL_NO_ERROR; err: return res; } static int get_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr, mailsession * session, char * uid, struct mailimf_fields ** result) { int r; char keyname[PATH_MAX]; struct mailimf_fields * fields; int res; snprintf(keyname, PATH_MAX, "%s-envelope", uid); r = generic_cache_fields_read(cache_db, mmapstr, keyname, &fields); if (r != MAIL_NO_ERROR) { res = r; goto err; } * result = fields; return MAIL_NO_ERROR; err: return res; } static int write_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr, mailsession * session, char * uid, struct mailimf_fields * fields) { int r; char keyname[PATH_MAX]; int res; snprintf(keyname, PATH_MAX, "%s-envelope", uid); r = generic_cache_fields_write(cache_db, mmapstr, keyname, fields); if (r != MAIL_NO_ERROR) { res = r; goto err; } return MAIL_NO_ERROR; err: return res; } static int write_cached_flags(struct mail_cache_db * cache_db, MMAPString * mmapstr, char * uid, struct mail_flags * flags) { int r; char keyname[PATH_MAX]; int res; snprintf(keyname, PATH_MAX, "%s-flags", uid); r = generic_cache_flags_write(cache_db, mmapstr, keyname, flags); if (r != MAIL_NO_ERROR) { res = r; goto err; } return MAIL_NO_ERROR; err: return res; } static int get_envelopes_list(mailsession * session, struct mailmessage_list * env_list) { int r; unsigned int i; int res; struct maildir_cached_session_state_data * data; char filename_env[PATH_MAX]; char filename_flags[PATH_MAX]; struct mail_cache_db * cache_db_env; struct mail_cache_db * cache_db_flags; MMAPString * mmapstr; data = get_cached_data(session); flags_store_process(data->md_flags_directory, data->md_quoted_mb, data->md_flags_store); mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto err; } snprintf(filename_env, PATH_MAX, "%s%c%s%c%s", data->md_cache_directory, MAIL_DIR_SEPARATOR, data->md_quoted_mb, MAIL_DIR_SEPARATOR, ENV_NAME); r = mail_cache_db_open_lock(filename_env, &cache_db_env); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_mmapstr; } snprintf(filename_flags, PATH_MAX, "%s%c%s%c%s", data->md_flags_directory, MAIL_DIR_SEPARATOR, data->md_quoted_mb, MAIL_DIR_SEPARATOR, FLAGS_NAME); r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_FILE; goto close_db_env; } for(i = 0 ; i < carray_count(env_list->msg_tab) ; i++) { mailmessage * msg; struct mailimf_fields * fields; struct mail_flags * flags; msg = carray_get(env_list->msg_tab, i); if (msg->msg_fields == NULL) { r = get_cached_envelope(cache_db_env, mmapstr, session, msg->msg_uid, &fields); if (r == MAIL_NO_ERROR) { msg->msg_cached = TRUE; msg->msg_fields = fields; } } if (msg->msg_flags == NULL) { r = get_cached_flags(cache_db_flags, mmapstr, session, msg->msg_uid, &flags); if (r == MAIL_NO_ERROR) { msg->msg_flags = flags; } } } mail_cache_db_close_unlock(filename_flags, cache_db_flags); mail_cache_db_close_unlock(filename_env, cache_db_env); r = mailsession_get_envelopes_list(get_ancestor(session), env_list); if (r != MAIL_NO_ERROR) { res = r; goto free_mmapstr; } r = mail_cache_db_open_lock(filename_env, &cache_db_env); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_mmapstr; } r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_FILE; goto close_db_env; } /* must write cache */ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; msg = carray_get(env_list->msg_tab, i); if (msg->msg_fields != NULL) { if (!msg->msg_cached) { /* msg->index is the numerical UID of the message */ r = write_cached_envelope(cache_db_env, mmapstr, session, msg->msg_uid, msg->msg_fields); } } if (msg->msg_flags != NULL) { r = write_cached_flags(cache_db_flags, mmapstr, msg->msg_uid, msg->msg_flags); } } /* flush cache */ maildriver_cache_clean_up(cache_db_env, cache_db_flags, env_list); mail_cache_db_close_unlock(filename_flags, cache_db_flags); mail_cache_db_close_unlock(filename_env, cache_db_env); mmap_string_free(mmapstr); return MAIL_NO_ERROR; close_db_env: mail_cache_db_close_unlock(filename_env, cache_db_env); free_mmapstr: mmap_string_free(mmapstr); err: return res; } static int expunge_folder(mailsession * session) { return mailsession_expunge_folder(get_ancestor(session)); } static int check_folder(mailsession * session) { struct maildir_cached_session_state_data * data; data = get_cached_data(session); flags_store_process(data->md_flags_directory, data->md_quoted_mb, data->md_flags_store); return mailsession_check_folder(get_ancestor(session)); } static int get_message(mailsession * session, uint32_t num, mailmessage ** result) { struct maildir * md; int res; mailmessage * msg; char filename[PATH_MAX]; struct mail_cache_db * uid_db; char * msg_filename; struct stat stat_info; char key_str[PATH_MAX]; void * value; size_t value_len; char uid[PATH_MAX]; struct maildir_cached_session_state_data * data; int r; data = get_cached_data(session); md = get_maildir_session(session); /* a get_messages_list() should have been done once before */ /* read DB */ snprintf(filename, sizeof(filename), "%s%c%s%c%s", data->md_flags_directory, MAIL_DIR_SEPARATOR, data->md_quoted_mb, MAIL_DIR_SEPARATOR, UID_NAME); r = mail_cache_db_open_lock(filename, &uid_db); if (r < 0) { res = MAIL_ERROR_MEMORY; goto err; } snprintf(key_str, sizeof(key_str), "uid-%lu", (unsigned long) num); r = mail_cache_db_get(uid_db, key_str, strlen(key_str), &value, &value_len); if (r < 0) { res = MAIL_ERROR_INVAL; goto close_db; } if (value_len >= PATH_MAX) { res = MAIL_ERROR_INVAL; goto close_db; } memcpy(uid, value, value_len); uid[value_len] = '\0'; mail_cache_db_close_unlock(filename, uid_db); /* update maildir data */ r = maildir_update(md); if (r != MAILDIR_NO_ERROR) { res = maildirdriver_maildir_error_to_mail_error(r); goto err; } msg_filename = maildir_message_get(md, uid); if (msg_filename == NULL) { res = MAIL_ERROR_INVAL; goto err; } r = stat(msg_filename, &stat_info); free(msg_filename); if (r < 0) { res = MAIL_ERROR_INVAL; goto err; } /* create message */ msg = mailmessage_new(); if (msg == NULL) { res = MAIL_ERROR_MEMORY; goto err; } r = mailmessage_init(msg, session, maildir_cached_message_driver, num, stat_info.st_size); if (r != MAIL_NO_ERROR) { mailmessage_free(msg); res = r; goto err; } msg->msg_uid = strdup(uid); if (msg->msg_uid == NULL) { mailmessage_free(msg); res = r; goto err; } * result = msg; return MAIL_NO_ERROR; close_db: mail_cache_db_close_unlock(filename, uid_db); err: return res; } static int get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result) { int r; struct maildir * md; int res; mailmessage * msg; char filename[PATH_MAX]; struct mail_cache_db * uid_db; char * msg_filename; struct stat stat_info; void * value; size_t value_len; struct maildir_cached_session_state_data * data; uint32_t index; data = get_cached_data(session); md = get_maildir_session(session); /* a get_messages_list() should have been done once before */ /* read DB */ snprintf(filename, sizeof(filename), "%s%c%s%c%s", data->md_flags_directory, MAIL_DIR_SEPARATOR, data->md_quoted_mb, MAIL_DIR_SEPARATOR, UID_NAME); r = mail_cache_db_open_lock(filename, &uid_db); if (r < 0) { res = MAIL_ERROR_MEMORY; goto err; } r = mail_cache_db_get(uid_db, uid, strlen(uid), &value, &value_len); if (r < 0) { res = MAIL_ERROR_INVAL; goto close_db; } memcpy(&index, value, sizeof(index)); mail_cache_db_close_unlock(filename, uid_db); /* update maildir data */ r = maildir_update(md); if (r != MAILDIR_NO_ERROR) { res = maildirdriver_maildir_error_to_mail_error(r); goto err; } msg_filename = maildir_message_get(md, uid); if (msg_filename == NULL) { res = MAIL_ERROR_INVAL; goto err; } r = stat(msg_filename, &stat_info); free(msg_filename); if (r < 0) { res = MAIL_ERROR_INVAL; goto err; } /* create message */ msg = mailmessage_new(); if (msg == NULL) { res = MAIL_ERROR_MEMORY; goto err; } r = mailmessage_init(msg, session, maildir_cached_message_driver, index, stat_info.st_size); if (r != MAIL_NO_ERROR) { mailmessage_free(msg); res = r; goto err; } msg->msg_uid = strdup(uid); if (msg->msg_uid == NULL) { mailmessage_free(msg); res = r; goto err; } * result = msg; return MAIL_NO_ERROR; close_db: mail_cache_db_close_unlock(filename, uid_db); err: return res; } diff --git a/kmicromail/libetpan/generic/maildirdriver_cached_message.c b/kmicromail/libetpan/generic/maildirdriver_cached_message.c index 51866aa..34de351 100644 --- a/kmicromail/libetpan/generic/maildirdriver_cached_message.c +++ b/kmicromail/libetpan/generic/maildirdriver_cached_message.c @@ -1,248 +1,334 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "maildirdriver_message.h" #include "mailmessage_tools.h" #include "maildirdriver.h" #include "maildir.h" #include "generic_cache.h" +#include "mail_cache_db.h" +#include "maildirdriver_tools.h" #include <unistd.h> #include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <stdlib.h> +static int get_flags(mailmessage * msg_info, + struct mail_flags ** result); + static int prefetch(mailmessage * msg_info); static void prefetch_free(struct generic_message_t * msg); static int initialize(mailmessage * msg_info); static void check(mailmessage * msg_info); static mailmessage_driver local_maildir_cached_message_driver = { .msg_name = "maildir-cached", .msg_initialize = initialize, .msg_uninitialize = mailmessage_generic_uninitialize, .msg_flush = mailmessage_generic_flush, .msg_check = check, .msg_fetch_result_free = mailmessage_generic_fetch_result_free, .msg_fetch = mailmessage_generic_fetch, .msg_fetch_header = mailmessage_generic_fetch_header, .msg_fetch_body = mailmessage_generic_fetch_header, .msg_fetch_size = NULL, .msg_get_bodystructure = mailmessage_generic_get_bodystructure, .msg_fetch_section = mailmessage_generic_fetch_section, .msg_fetch_section_header = mailmessage_generic_fetch_section_header, .msg_fetch_section_mime = mailmessage_generic_fetch_section_mime, .msg_fetch_section_body = mailmessage_generic_fetch_section_body, .msg_fetch_envelope = mailmessage_generic_fetch_envelope, - .msg_get_flags = NULL, + .msg_get_flags = get_flags, }; mailmessage_driver * maildir_cached_message_driver = &local_maildir_cached_message_driver; struct maildir_msg_data { int fd; }; #if 0 static inline struct maildir_cached_session_state_data * get_cached_session_data(mailmessage * msg) { return msg->session->data; } static inline mailsession * cached_session_get_ancestor(mailsession * session) { return get_data(session)->session; } static inline struct maildir_session_state_data * cached_session_get_ancestor_data(mailsession * session) { return get_ancestor(session)->data; } static struct maildir * get_maildir_session(mailmessage * msg) { return cached_session_get_ancestor_data(msg->session)->session; } #endif static inline struct maildir_cached_session_state_data * get_cached_session_data(mailmessage * msg) { return msg->msg_session->sess_data; } static inline struct maildir_cached_session_state_data * cached_session_get_data(mailsession * s) { return s->sess_data; } static inline mailsession * cached_session_get_ancestor(mailsession * s) { return cached_session_get_data(s)->md_ancestor; } static inline struct maildir_session_state_data * cached_session_get_ancestor_data(mailsession * s) { return cached_session_get_ancestor(s)->sess_data; } static inline struct maildir_session_state_data * get_session_ancestor_data(mailmessage * msg) { return cached_session_get_ancestor_data(msg->msg_session); } static inline struct maildir * cached_session_get_maildir_session(mailsession * session) { return cached_session_get_ancestor_data(session)->md_session; } static inline struct maildir * get_maildir_session(mailmessage * msg) { return cached_session_get_maildir_session(msg->msg_session); } static int prefetch(mailmessage * msg_info) { struct generic_message_t * msg; int res; struct maildir_msg_data * data; char * filename; int fd; char * mapping; struct maildir * md; md = get_maildir_session(msg_info); filename = maildir_message_get(md, msg_info->msg_uid); if (filename == NULL) { res = MAIL_ERROR_MEMORY; goto err; } fd = open(filename, O_RDONLY); free(filename); if (fd == -1) { res = MAIL_ERROR_FILE; goto err; } mapping = mmap(NULL, msg_info->msg_size, PROT_READ, MAP_PRIVATE, fd, 0); if (mapping == MAP_FAILED) { res = MAIL_ERROR_FILE; goto close; } data = malloc(sizeof(* data)); if (data == NULL) { res = MAIL_ERROR_MEMORY; goto unmap; } data->fd = fd; msg = msg_info->msg_data; msg->msg_data = data; msg->msg_message = mapping; msg->msg_length = msg_info->msg_size; return MAIL_NO_ERROR; unmap: munmap(mapping, msg_info->msg_size); close: close(fd); err: return res; } static void prefetch_free(struct generic_message_t * msg) { if (msg->msg_message != NULL) { struct maildir_msg_data * data; munmap(msg->msg_message, msg->msg_length); msg->msg_message = NULL; data = msg->msg_data; close(data->fd); free(data); } } static int initialize(mailmessage * msg_info) { struct generic_message_t * msg; int r; r = mailmessage_generic_initialize(msg_info); if (r != MAIL_NO_ERROR) return r; msg = msg_info->msg_data; msg->msg_prefetch = prefetch; msg->msg_prefetch_free = prefetch_free; return MAIL_NO_ERROR; } static void check(mailmessage * msg_info) { int r; if (msg_info->msg_flags != NULL) { r = mail_flags_store_set(get_session_ancestor_data(msg_info)->md_flags_store, msg_info); r = mail_flags_store_set(get_cached_session_data(msg_info)->md_flags_store, msg_info); /* ignore errors */ } } + +#define FLAGS_NAME "flags.db" + +static int get_flags(mailmessage * msg_info, + struct mail_flags ** result) +{ + struct mail_cache_db * cache_db_flags; + chashdatum key; + chashdatum value; + struct maildir * md; + struct mail_flags * flags; + struct maildir_cached_session_state_data * data; + struct maildir_msg * md_msg; + int r; + uint32_t driver_flags; + char filename_flags[PATH_MAX]; + char keyname[PATH_MAX]; + MMAPString * mmapstr; + + if (msg_info->msg_flags != NULL) { + * result = msg_info->msg_flags; + return MAIL_NO_ERROR; + } + + data = get_cached_session_data(msg_info); + flags = mail_flags_store_get(data->md_flags_store, + msg_info->msg_index); + if (flags != NULL) { + msg_info->msg_flags = flags; + * result = msg_info->msg_flags; + return MAIL_NO_ERROR; + } + + snprintf(filename_flags, PATH_MAX, "%s%c%s%c%s", + data->md_flags_directory, MAIL_DIR_SEPARATOR, data->md_quoted_mb, + MAIL_DIR_SEPARATOR, FLAGS_NAME); + + r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); + if (r < 0) + return MAIL_ERROR_FILE; + + snprintf(keyname, PATH_MAX, "%s-flags", msg_info->msg_uid); + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) { + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + return MAIL_ERROR_MEMORY; + } + + r = generic_cache_flags_read(cache_db_flags, mmapstr, keyname, &flags); + mmap_string_free(mmapstr); + + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + + if (r != MAIL_NO_ERROR) { + flags = mail_flags_new_empty(); + if (flags == NULL) + return MAIL_ERROR_MEMORY; + } + + md = get_maildir_session(msg_info); + if (md == NULL) + return MAIL_ERROR_BAD_STATE; + + key.data = msg_info->msg_uid; + key.len = strlen(msg_info->msg_uid); + r = chash_get(md->mdir_msg_hash, &key, &value); + if (r < 0) + return MAIL_ERROR_MSG_NOT_FOUND; + + md_msg = value.data; + + driver_flags = maildirdriver_maildir_flags_to_flags(md_msg->msg_flags); + + flags->fl_flags = driver_flags; + msg_info->msg_flags = flags; + + * result = msg_info->msg_flags; + + return MAIL_NO_ERROR; +} diff --git a/kmicromail/libetpan/generic/maildirdriver_message.c b/kmicromail/libetpan/generic/maildirdriver_message.c index 7cf9dd1..613fc39 100644 --- a/kmicromail/libetpan/generic/maildirdriver_message.c +++ b/kmicromail/libetpan/generic/maildirdriver_message.c @@ -1,199 +1,255 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "maildirdriver_message.h" +#include "maildirdriver_tools.h" #include "mailmessage_tools.h" #include "maildirdriver.h" #include "maildir.h" #include "generic_cache.h" #include <unistd.h> #include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <stdlib.h> +static int get_flags(mailmessage * msg_info, + struct mail_flags ** result); + static int prefetch(mailmessage * msg_info); static void prefetch_free(struct generic_message_t * msg); static int initialize(mailmessage * msg_info); static void check(mailmessage * msg_info); static mailmessage_driver local_maildir_message_driver = { .msg_name = "maildir", .msg_initialize = initialize, .msg_uninitialize = mailmessage_generic_uninitialize, .msg_flush = mailmessage_generic_flush, .msg_check = check, .msg_fetch_result_free = mailmessage_generic_fetch_result_free, .msg_fetch = mailmessage_generic_fetch, .msg_fetch_header = mailmessage_generic_fetch_header, .msg_fetch_body = mailmessage_generic_fetch_header, .msg_fetch_size = NULL, .msg_get_bodystructure = mailmessage_generic_get_bodystructure, .msg_fetch_section = mailmessage_generic_fetch_section, .msg_fetch_section_header = mailmessage_generic_fetch_section_header, .msg_fetch_section_mime = mailmessage_generic_fetch_section_mime, .msg_fetch_section_body = mailmessage_generic_fetch_section_body, .msg_fetch_envelope = mailmessage_generic_fetch_envelope, - .msg_get_flags = NULL, + .msg_get_flags = get_flags, }; mailmessage_driver * maildir_message_driver = &local_maildir_message_driver; struct maildir_msg_data { int fd; }; static inline struct maildir_session_state_data * get_session_data(mailmessage * msg) { return msg->msg_session->sess_data; } static struct maildir * get_maildir_session(mailmessage * msg) { return get_session_data(msg)->md_session; } static int prefetch(mailmessage * msg_info) { struct generic_message_t * msg; int res; struct maildir_msg_data * data; char * filename; int fd; char * mapping; struct maildir * md; md = get_maildir_session(msg_info); if (msg_info->msg_uid == NULL) { res = MAIL_ERROR_INVAL; goto err; } filename = maildir_message_get(md, msg_info->msg_uid); if (filename == NULL) { res = MAIL_ERROR_MEMORY; goto err; } fd = open(filename, O_RDONLY); free(filename); if (fd == -1) { res = MAIL_ERROR_FILE; goto err; } mapping = mmap(NULL, msg_info->msg_size, PROT_READ, MAP_PRIVATE, fd, 0); if (mapping == MAP_FAILED) { res = MAIL_ERROR_FILE; goto close; } data = malloc(sizeof(* data)); if (data == NULL) { res = MAIL_ERROR_MEMORY; goto unmap; } data->fd = fd; msg = msg_info->msg_data; msg->msg_data = data; msg->msg_message = mapping; msg->msg_length = msg_info->msg_size; return MAIL_NO_ERROR; unmap: munmap(mapping, msg_info->msg_size); close: close(fd); err: return res; } static void prefetch_free(struct generic_message_t * msg) { if (msg->msg_message != NULL) { struct maildir_msg_data * data; munmap(msg->msg_message, msg->msg_length); msg->msg_message = NULL; data = msg->msg_data; close(data->fd); free(data); } } static int initialize(mailmessage * msg_info) { struct generic_message_t * msg; int r; r = mailmessage_generic_initialize(msg_info); if (r != MAIL_NO_ERROR) return r; msg = msg_info->msg_data; msg->msg_prefetch = prefetch; msg->msg_prefetch_free = prefetch_free; return MAIL_NO_ERROR; } static void check(mailmessage * msg_info) { int r; if (msg_info->msg_flags != NULL) { r = mail_flags_store_set(get_session_data(msg_info)->md_flags_store, msg_info); /* ignore errors */ } } + +static int get_flags(mailmessage * msg_info, + struct mail_flags ** result) +{ + chashdatum key; + chashdatum value; + struct maildir * md; + struct mail_flags * flags; + struct maildir_session_state_data * data; + struct maildir_msg * md_msg; + int r; + uint32_t driver_flags; + clist * ext; + + if (msg_info->msg_flags != NULL) { + * result = msg_info->msg_flags; + return MAIL_NO_ERROR; + } + + data = get_session_data(msg_info); + flags = mail_flags_store_get(data->md_flags_store, + msg_info->msg_index); + if (flags != NULL) { + msg_info->msg_flags = flags; + * result = msg_info->msg_flags; + return MAIL_NO_ERROR; + } + + md = get_maildir_session(msg_info); + if (md == NULL) + return MAIL_ERROR_BAD_STATE; + + key.data = msg_info->msg_uid; + key.len = strlen(msg_info->msg_uid); + r = chash_get(md->mdir_msg_hash, &key, &value); + if (r < 0) + return MAIL_ERROR_MSG_NOT_FOUND; + + md_msg = value.data; + + driver_flags = maildirdriver_maildir_flags_to_flags(md_msg->msg_flags); + + ext = clist_new(); + if (ext == NULL) + return MAIL_ERROR_MEMORY; + + msg_info->msg_flags = mail_flags_new(driver_flags, ext); + + * result = msg_info->msg_flags; + + return MAIL_NO_ERROR; +} diff --git a/kmicromail/libetpan/generic/maildirstorage.c b/kmicromail/libetpan/generic/maildirstorage.c index 7e6b461..e37f591 100644 --- a/kmicromail/libetpan/generic/maildirstorage.c +++ b/kmicromail/libetpan/generic/maildirstorage.c @@ -1,192 +1,193 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ +#include "maildirstorage.h" #include "mailstorage.h" #include "mail.h" #include "mailmessage.h" #include "maildirdriver.h" #include "maildirdriver_cached.h" #include "maildriver.h" #include <stdlib.h> #include <string.h> /* maildir storage */ static int maildir_mailstorage_connect(struct mailstorage * storage); static int maildir_mailstorage_get_folder_session(struct mailstorage * storage, char * pathname, mailsession ** result); static void maildir_mailstorage_uninitialize(struct mailstorage * storage); static mailstorage_driver maildir_mailstorage_driver = { .sto_name = "maildir", .sto_connect = maildir_mailstorage_connect, .sto_get_folder_session = maildir_mailstorage_get_folder_session, .sto_uninitialize = maildir_mailstorage_uninitialize, }; int maildir_mailstorage_init(struct mailstorage * storage, char * md_pathname, int md_cached, char * md_cache_directory, char * md_flags_directory) { struct maildir_mailstorage * maildir_storage; - maildir_storage = malloc(sizeof(struct maildir_mailstorage)); + maildir_storage = malloc(sizeof(* maildir_storage)); if (maildir_storage == NULL) goto err; maildir_storage->md_pathname = strdup(md_pathname); if (maildir_storage->md_pathname == NULL) goto free; maildir_storage->md_cached = md_cached; if (md_cached && (md_cache_directory != NULL) && (md_flags_directory != NULL)) { maildir_storage->md_cache_directory = strdup(md_cache_directory); if (maildir_storage->md_cache_directory == NULL) goto free_pathname; maildir_storage->md_flags_directory = strdup(md_flags_directory); if (maildir_storage->md_flags_directory == NULL) goto free_cache_directory; } else { maildir_storage->md_cached = FALSE; maildir_storage->md_cache_directory = NULL; maildir_storage->md_flags_directory = NULL; } storage->sto_data = maildir_storage; storage->sto_driver = &maildir_mailstorage_driver; return MAIL_NO_ERROR; free_cache_directory: free(maildir_storage->md_cache_directory); free_pathname: free(maildir_storage->md_pathname); free: free(maildir_storage); err: return MAIL_ERROR_MEMORY; } static void maildir_mailstorage_uninitialize(struct mailstorage * storage) { struct maildir_mailstorage * maildir_storage; maildir_storage = storage->sto_data; if (maildir_storage->md_flags_directory != NULL) free(maildir_storage->md_flags_directory); if (maildir_storage->md_cache_directory != NULL) free(maildir_storage->md_cache_directory); free(maildir_storage->md_pathname); free(maildir_storage); storage->sto_data = NULL; } static int maildir_mailstorage_connect(struct mailstorage * storage) { struct maildir_mailstorage * maildir_storage; mailsession_driver * driver; int r; int res; mailsession * session; maildir_storage = storage->sto_data; if (maildir_storage->md_cached) driver = maildir_cached_session_driver; else driver = maildir_session_driver; session = mailsession_new(driver); if (session == NULL) { res = MAIL_ERROR_MEMORY; goto err; } if (maildir_storage->md_cached) { r = mailsession_parameters(session, MAILDIRDRIVER_CACHED_SET_CACHE_DIRECTORY, maildir_storage->md_cache_directory); if (r != MAIL_NO_ERROR) { res = r; goto free; } r = mailsession_parameters(session, MAILDIRDRIVER_CACHED_SET_FLAGS_DIRECTORY, maildir_storage->md_flags_directory); if (r != MAIL_NO_ERROR) { res = r; goto free; } } r = mailsession_connect_path(session, maildir_storage->md_pathname); switch (r) { case MAIL_NO_ERROR_NON_AUTHENTICATED: case MAIL_NO_ERROR_AUTHENTICATED: case MAIL_NO_ERROR: break; default: res = r; goto free; } storage->sto_session = session; return MAIL_NO_ERROR; free: mailsession_free(session); err: return res; } static int maildir_mailstorage_get_folder_session(struct mailstorage * storage, char * pathname, mailsession ** result) { * result = storage->sto_session; return MAIL_NO_ERROR; } diff --git a/kmicromail/libetpan/generic/maildirstorage.h b/kmicromail/libetpan/generic/maildirstorage.h index d17ea2c..73d7b20 100644 --- a/kmicromail/libetpan/generic/maildirstorage.h +++ b/kmicromail/libetpan/generic/maildirstorage.h @@ -1,69 +1,69 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #ifndef MAILDIRSTORAGE_H #define MAILDIRSTORAGE_H #include <libetpan/maildirdriver_types.h> #ifdef __cplusplus extern "C" { #endif /* - maildir_mailstorage_init is the constructor for a mbox storage. + maildir_mailstorage_init is the constructor for a maildir storage. @param storage this is the storage to initialize. @param pathname is the directory that contains the mailbox. @param cached if this value is != 0, a persistant cache will be stored on local system. @param cache_directory is the location of the cache @param flags_directory is the location of the flags */ int maildir_mailstorage_init(struct mailstorage * storage, char * md_pathname, int md_cached, char * md_cache_directory, char * md_flags_directory); #ifdef __cplusplus } #endif #endif diff --git a/kmicromail/libetpan/generic/maildriver.c b/kmicromail/libetpan/generic/maildriver.c index 01e3e34..1fc478a 100644 --- a/kmicromail/libetpan/generic/maildriver.c +++ b/kmicromail/libetpan/generic/maildriver.c @@ -1,373 +1,383 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "maildriver.h" #include <ctype.h> #include <string.h> #include <stdlib.h> /* *********************************************************************** */ /* mail session */ mailsession * mailsession_new(mailsession_driver * sess_driver) { mailsession * session; int r; session = malloc(sizeof(* session)); session->sess_data = NULL; if (sess_driver->sess_initialize != NULL) { r = sess_driver->sess_initialize(session); if (r != MAIL_NO_ERROR) goto free; } session->sess_driver = sess_driver; return session; free: free(session); return NULL; } void mailsession_free(mailsession * session) { if (session->sess_driver->sess_uninitialize != NULL) session->sess_driver->sess_uninitialize(session); free(session); } int mailsession_parameters(mailsession * session, int id, void * value) { if (session->sess_driver->sess_parameters == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_parameters(session, id, value); } int mailsession_connect_stream(mailsession * session, mailstream * s) { if (session->sess_driver->sess_connect_stream == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_connect_stream(session, s); } int mailsession_connect_path(mailsession * session, char * path) { if (session->sess_driver->sess_connect_path == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_connect_path(session, path); } int mailsession_starttls(mailsession * session) { if (session->sess_driver->sess_starttls == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_starttls(session); } int mailsession_login(mailsession * session, char * userid, char * password) { if (session->sess_driver->sess_login == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_login(session, userid, password); } int mailsession_logout(mailsession * session) { if (session->sess_driver->sess_logout == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_logout(session); } int mailsession_noop(mailsession * session) { if (session->sess_driver->sess_noop == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_noop(session); } /* folders operations */ int mailsession_build_folder_name(mailsession * session, char * mb, char * name, char ** result) { if (session->sess_driver->sess_build_folder_name == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_build_folder_name(session, mb, name, result); } int mailsession_create_folder(mailsession * session, char * mb) { if (session->sess_driver->sess_create_folder == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_create_folder(session, mb); } int mailsession_delete_folder(mailsession * session, char * mb) { if (session->sess_driver->sess_delete_folder == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_delete_folder(session, mb); } int mailsession_rename_folder(mailsession * session, char * mb, char * new_name) { if (session->sess_driver->sess_rename_folder == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_rename_folder(session, mb, new_name); } int mailsession_check_folder(mailsession * session) { if (session->sess_driver->sess_check_folder == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_check_folder(session); } int mailsession_examine_folder(mailsession * session, char * mb) { if (session->sess_driver->sess_examine_folder == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_examine_folder(session, mb); } int mailsession_select_folder(mailsession * session, char * mb) { if (session->sess_driver->sess_select_folder == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_select_folder(session, mb); } int mailsession_expunge_folder(mailsession * session) { if (session->sess_driver->sess_expunge_folder == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_expunge_folder(session); } int mailsession_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { if (session->sess_driver->sess_status_folder == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_status_folder(session, mb, result_messages, result_recent, result_unseen); } int mailsession_messages_number(mailsession * session, char * mb, uint32_t * result) { if (session->sess_driver->sess_messages_number == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_messages_number(session, mb, result); } int mailsession_recent_number(mailsession * session, char * mb, uint32_t * result) { if (session->sess_driver->sess_recent_number == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_recent_number(session, mb, result); } int mailsession_unseen_number(mailsession * session, char * mb, uint32_t * result) { if (session->sess_driver->sess_unseen_number == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_recent_number(session, mb, result); } int mailsession_list_folders(mailsession * session, char * mb, struct mail_list ** result) { if (session->sess_driver->sess_list_folders == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_list_folders(session, mb, result); } int mailsession_lsub_folders(mailsession * session, char * mb, struct mail_list ** result) { if (session->sess_driver->sess_lsub_folders == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_lsub_folders(session, mb, result); } int mailsession_subscribe_folder(mailsession * session, char * mb) { if (session->sess_driver->sess_subscribe_folder == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_subscribe_folder(session, mb); } int mailsession_unsubscribe_folder(mailsession * session, char * mb) { if (session->sess_driver->sess_unsubscribe_folder == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_unsubscribe_folder(session, mb); } /* message */ int mailsession_append_message(mailsession * session, char * message, size_t size) { if (session->sess_driver->sess_append_message == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_append_message(session, message, size); } +int mailsession_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags) +{ + if (session->sess_driver->sess_append_message_flags == NULL) + return MAIL_ERROR_NOT_IMPLEMENTED; + + return session->sess_driver->sess_append_message_flags(session, + message, size, flags); +} + int mailsession_copy_message(mailsession * session, uint32_t num, char * mb) { if (session->sess_driver->sess_copy_message == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_copy_message(session, num, mb); } int mailsession_move_message(mailsession * session, uint32_t num, char * mb) { if (session->sess_driver->sess_move_message == NULL) { int r; if ((session->sess_driver->sess_copy_message == NULL) && (session->sess_driver->sess_remove_message == NULL)) return MAIL_ERROR_NOT_IMPLEMENTED; r = mailsession_copy_message(session, num, mb); if (r != MAIL_NO_ERROR) return r; r = mailsession_remove_message(session, num); if (r != MAIL_NO_ERROR) return r; return MAIL_NO_ERROR; } return session->sess_driver->sess_move_message(session, num, mb); } int mailsession_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list) { if (session->sess_driver->sess_get_envelopes_list == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_get_envelopes_list(session, env_list); } int mailsession_get_messages_list(mailsession * session, struct mailmessage_list ** result) { if (session->sess_driver->sess_get_messages_list == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_get_messages_list(session, result); } int mailsession_remove_message(mailsession * session, uint32_t num) { if (session->sess_driver->sess_remove_message == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_remove_message(session, num); } #if 0 int mailsession_search_messages(mailsession * session, char * charset, struct mail_search_key * key, struct mail_search_result ** result) { if (session->sess_driver->sess_search_messages == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_search_messages(session, charset, key, result); } #endif int mailsession_get_message(mailsession * session, uint32_t num, mailmessage ** result) { if (session->sess_driver->sess_get_message == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_get_message(session, num, result); } int mailsession_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result) { if (session->sess_driver->sess_get_message_by_uid == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return session->sess_driver->sess_get_message_by_uid(session, uid, result); } diff --git a/kmicromail/libetpan/generic/maildriver.h b/kmicromail/libetpan/generic/maildriver.h index 7da9aea..c773190 100644 --- a/kmicromail/libetpan/generic/maildriver.h +++ b/kmicromail/libetpan/generic/maildriver.h @@ -1,543 +1,546 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #ifndef MAILDRIVER_H #define MAILDRIVER_H #include <libetpan/maildriver_types.h> #include <libetpan/maildriver_types_helper.h> #ifdef __cplusplus extern "C" { #endif /* mailsession */ /* mailsession_new creates a new session, using the given driver @return the created session is returned */ mailsession * mailsession_new(mailsession_driver * sess_driver); /* mailsession_free release the memory used by the session */ void mailsession_free(mailsession * session); /* mailsession_parameters is used to make calls specific to the driver @param id is the command to send to the driver, usually, commands can be found in the header of the driver @param value is the parameter of the specific call @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_parameters(mailsession * session, int id, void * value); /* There are drivers of two kinds : stream drivers (driver that connects to servers through TCP or other means of connection) and file drivers (driver that are based on filesystem) The following function can only be used by stream drivers. mailsession_connect_stream connects a stream to the session @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_connect_stream(mailsession * session, mailstream * s); /* The following function can only be used by file drivers. mailsession_connect_path selects the main path of the session @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_connect_path(mailsession * session, char * path); /* NOTE: works only on stream drivers mailsession_starttls switches the current connection to TLS (secure layer) @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_starttls(mailsession * session); /* mailsession_login notifies the login and the password to authenticate to the session @param userid the given string is only needed at this function call (it will be duplicated if necessary) @param password the given string is only needed at this function call (it will be duplicated if necessary) @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_login(mailsession * session, char * userid, char * password); /* NOTE: this function doesn't often work on filsystem drivers mailsession_logout deconnects the session and closes the stream. @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_logout(mailsession * session); /* mailsession_noop does no operation on the session, but it can be used to poll for the status of the connection. @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_noop(mailsession * session); /* NOTE: driver's specific should be used mailsession_build_folder_name will return an allocated string with that contains the complete path of the folder to create @param session the sesion @param mb is the parent mailbox @param name is the name of the folder to create @param result the complete path of the folder to create will be stored in (* result), this name have to be freed with free() @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_build_folder_name(mailsession * session, char * mb, char * name, char ** result); /* NOTE: driver's specific should be used mailsession_create_folder creates the folder that corresponds to the given name @param session the session @param mb is the name of the mailbox @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_create_folder(mailsession * session, char * mb); /* NOTE: driver's specific should be used mailsession_delete_folder deletes the folder that corresponds to the given name @param session the session @param mb is the name of the mailbox @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_delete_folder(mailsession * session, char * mb); /* mailsession_rename_folder changes the name of the folder @param session the session @param mb is the name of the mailbox whose name has to be changed @param new_name is the destination name (the parent of the new folder folder can be other) @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_rename_folder(mailsession * session, char * mb, char * new_name); /* mailsession_check_folder makes a checkpoint of the session @param session the session @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_check_folder(mailsession * session); /* NOTE: this function is not implemented in most drivers mailsession_examine_folder selects a mailbox as readonly @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_examine_folder(mailsession * session, char * mb); /* mailsession_select_folder selects a mailbox @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_select_folder(mailsession * session, char * mb); /* mailsession_expunge_folder deletes all messages marked \Deleted @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_expunge_folder(mailsession * session); /* mailsession_status_folder queries the status of the folder (number of messages, number of recent messages, number of unseen messages) @param session the session @param mb mailbox to query @param result_messages the number of messages is stored in (* result_messages) @param result_recent the number of messages is stored in (* result_recent) @param result_unseen the number of messages is stored in (* result_unseen) @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); /* mailsession_messages_number queries the number of messages in the folder @param session the session @param mb mailbox to query @param result the number of messages is stored in (* result) @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_messages_number(mailsession * session, char * mb, uint32_t * result); /* mailsession_recent_number queries the number of recent messages in the folder @param session the session @param mb mailbox to query @param result the number of recent messages is stored in (* result) @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_recent_number(mailsession * session, char * mb, uint32_t * result); /* mailsession_unseen_number queries the number of unseen messages in the folder @param session the session @param mb mailbox to query @param result the number of unseen messages is stored in (* result) @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_unseen_number(mailsession * session, char * mb, uint32_t * result); /* NOTE: driver's specific should be used mailsession_list_folders returns the list of all sub-mailboxes of the given mailbox @param session the session @param mb the mailbox @param result list of mailboxes if stored in (* result), this structure have to be freed with mail_list_free() @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_list_folders(mailsession * session, char * mb, struct mail_list ** result); /* NOTE: driver's specific should be used mailsession_lsub_folders returns the list of subscribed sub-mailboxes of the given mailbox @param session the session @param mb the mailbox @param result list of mailboxes if stored in (* result), this structure have to be freed with mail_list_free() @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_lsub_folders(mailsession * session, char * mb, struct mail_list ** result); /* NOTE: driver's specific should be used mailsession_subscribe_folder subscribes to the given mailbox @param session the session @param mb the mailbox @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_subscribe_folder(mailsession * session, char * mb); /* NOTE: driver's specific should be used mailsession_unsubscribe_folder unsubscribes to the given mailbox @param session the session @param mb the mailbox @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_unsubscribe_folder(mailsession * session, char * mb); /* mailsession_append_message adds a RFC 2822 message to the current given mailbox @param session the session @param message is a string that contains the RFC 2822 message @param size this is the size of the message @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_append_message(mailsession * session, char * message, size_t size); +int mailsession_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags); + /* NOTE: some drivers does not implement this mailsession_copy_message copies a message whose number is given to a given mailbox. The mailbox must be accessible from the same session. @param session the session @param num the message number @param mb the destination mailbox @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_copy_message(mailsession * session, uint32_t num, char * mb); /* NOTE: some drivers does not implement this mailsession_move_message copies a message whose number is given to a given mailbox. The mailbox must be accessible from the same session. @param session the session @param num the message number @param mb the destination mailbox @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_move_message(mailsession * session, uint32_t num, char * mb); /* mailsession_get_messages_list returns the list of message numbers of the current mailbox. @param session the session @param result the list of message numbers will be stored in (* result), this structure have to be freed with mailmessage_list_free() @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_get_messages_list(mailsession * session, struct mailmessage_list ** result); /* mailsession_get_envelopes_list fills the parsed fields in the mailmessage structures of the mailmessage_list. @param session the session @param result this is the list of mailmessage structures @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_get_envelopes_list(mailsession * session, struct mailmessage_list * result); /* NOTE: some drivers does not implement this mailsession_remove_message removes the given message from the mailbox. The message is permanently deleted. @param session the session @param num is the message number @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_remove_message(mailsession * session, uint32_t num); /* NOTE: this function is not implemented in most drivers mailsession_search_message returns a list of message numbers that corresponds to the given criteria. @param session the session @param charset is the charset to use (it can be NULL) @param key is the list of criteria @param result the search result is stored in (* result), this structure have to be freed with mail_search_result_free() @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ #if 0 int mailsession_search_messages(mailsession * session, char * charset, struct mail_search_key * key, struct mail_search_result ** result); #endif /* mailsession_get_message returns a mailmessage structure that corresponds to the given message number. * WARNING * mailsession_get_message_by_uid() should be used instead. @param session the session @param num the message number @param result the allocated mailmessage structure will be stored in (* result), this structure have to be freed with mailmessage_free() @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_get_message(mailsession * session, uint32_t num, mailmessage ** result); /* mailsession_get_message_by_uid returns a mailmessage structure that corresponds to the given message unique identifier. This is currently implemented only for cached drivers. * WARNING * That will deprecates the use of mailsession_get_message() @param session the session @param uid the message unique identifier @param result the allocated mailmessage structure will be stored in (* result), this structure have to be freed with mailmessage_free() @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result); #ifdef __cplusplus } #endif #endif diff --git a/kmicromail/libetpan/generic/maildriver_types.h b/kmicromail/libetpan/generic/maildriver_types.h index 3ff9440..9eab4d6 100644 --- a/kmicromail/libetpan/generic/maildriver_types.h +++ b/kmicromail/libetpan/generic/maildriver_types.h @@ -1,793 +1,795 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #ifndef MAILDRIVER_TYPES_H #define MAILDRIVER_TYPES_H #include <inttypes.h> #include <sys/types.h> #include <libetpan/mailstream.h> #include <libetpan/mailimf.h> #include <libetpan/mailmime.h> #include <libetpan/carray.h> #include <libetpan/mailthread_types.h> #include <libetpan/maildriver_errors.h> #ifdef __cplusplus extern "C" { #endif typedef struct mailsession_driver mailsession_driver; typedef struct mailsession mailsession; typedef struct mailmessage_driver mailmessage_driver; typedef struct mailmessage mailmessage; /* mailmessage_list is a list of mailmessage - tab is an array of mailmessage structures */ struct mailmessage_list { carray * msg_tab; /* elements are (mailmessage *) */ }; struct mailmessage_list * mailmessage_list_new(carray * msg_tab); void mailmessage_list_free(struct mailmessage_list * env_list); /* mail_list is a list of mailbox names - list is a list of mailbox names */ struct mail_list { clist * mb_list; /* elements are (char *) */ }; struct mail_list * mail_list_new(clist * mb_list); void mail_list_free(struct mail_list * resp); /* This is a flag value. Flags can be combined with OR operation */ enum { MAIL_FLAG_NEW = 1 << 0, MAIL_FLAG_SEEN = 1 << 1, MAIL_FLAG_FLAGGED = 1 << 2, MAIL_FLAG_DELETED = 1 << 3, MAIL_FLAG_ANSWERED = 1 << 4, MAIL_FLAG_FORWARDED = 1 << 5, MAIL_FLAG_CANCELLED = 1 << 6, }; /* mail_flags is the value of a flag related to a message. - flags is the standard flags value - extension is a list of unknown flags for libEtPan! */ struct mail_flags { uint32_t fl_flags; clist * fl_extension; /* elements are (char *) */ }; struct mail_flags * mail_flags_new(uint32_t fl_flags, clist * fl_ext); void mail_flags_free(struct mail_flags * flags); /* This function creates a flag for a new message */ struct mail_flags * mail_flags_new_empty(void); /* mailimf_date_time_comp compares two dates */ int32_t mailimf_date_time_comp(struct mailimf_date_time * date1, struct mailimf_date_time * date2); /* this is type type of the search criteria */ enum { MAIL_SEARCH_KEY_ALL, /* all messages correspond */ MAIL_SEARCH_KEY_ANSWERED, /* messages with flag \Answered */ MAIL_SEARCH_KEY_BCC, /* messages which Bcc field contains a given string */ MAIL_SEARCH_KEY_BEFORE, /* messages which internal date is earlier than the specified date */ MAIL_SEARCH_KEY_BODY, /* message that contains the given string (in header and text parts) */ MAIL_SEARCH_KEY_CC, /* messages whose Cc field contains the given string */ MAIL_SEARCH_KEY_DELETED, /* messages with the flag \Deleted */ MAIL_SEARCH_KEY_FLAGGED, /* messages with the flag \Flagged */ MAIL_SEARCH_KEY_FROM, /* messages whose From field contains the given string */ MAIL_SEARCH_KEY_NEW, /* messages with the flag \Recent and not the \Seen flag */ MAIL_SEARCH_KEY_OLD, /* messages that do not have the \Recent flag set */ MAIL_SEARCH_KEY_ON, /* messages whose internal date is the specified date */ MAIL_SEARCH_KEY_RECENT, /* messages with the flag \Recent */ MAIL_SEARCH_KEY_SEEN, /* messages with the flag \Seen */ MAIL_SEARCH_KEY_SINCE, /* messages whose internal date is later than specified date */ MAIL_SEARCH_KEY_SUBJECT, /* messages whose Subject field contains the given string */ MAIL_SEARCH_KEY_TEXT, /* messages whose text part contains the given string */ MAIL_SEARCH_KEY_TO, /* messages whose To field contains the given string */ MAIL_SEARCH_KEY_UNANSWERED, /* messages with no flag \Answered */ MAIL_SEARCH_KEY_UNDELETED, /* messages with no flag \Deleted */ MAIL_SEARCH_KEY_UNFLAGGED, /* messages with no flag \Flagged */ MAIL_SEARCH_KEY_UNSEEN, /* messages with no flag \Seen */ MAIL_SEARCH_KEY_HEADER, /* messages whose given field contains the given string */ MAIL_SEARCH_KEY_LARGER, /* messages whose size is larger then the given size */ MAIL_SEARCH_KEY_NOT, /* not operation of the condition */ MAIL_SEARCH_KEY_OR, /* or operation between two conditions */ MAIL_SEARCH_KEY_SMALLER, /* messages whose size is smaller than the given size */ MAIL_SEARCH_KEY_MULTIPLE /* the boolean operator between the conditions is AND */ }; /* mail_search_key is the condition on the messages to return - type is the type of the condition - bcc is the text to search in the Bcc field when type is MAIL_SEARCH_KEY_BCC, should be allocated with malloc() - before is a date when type is MAIL_SEARCH_KEY_BEFORE - body is the text to search in the message when type is MAIL_SEARCH_KEY_BODY, should be allocated with malloc() - cc is the text to search in the Cc field when type is MAIL_SEARCH_KEY_CC, should be allocated with malloc() - from is the text to search in the From field when type is MAIL_SEARCH_KEY_FROM, should be allocated with malloc() - on is a date when type is MAIL_SEARCH_KEY_ON - since is a date when type is MAIL_SEARCH_KEY_SINCE - subject is the text to search in the Subject field when type is MAILIMAP_SEARCH_KEY_SUBJECT, should be allocated with malloc() - text is the text to search in the text part of the message when type is MAILIMAP_SEARCH_KEY_TEXT, should be allocated with malloc() - to is the text to search in the To field when type is MAILIMAP_SEARCH_KEY_TO, should be allocated with malloc() - header_name is the header name when type is MAILIMAP_SEARCH_KEY_HEADER, should be allocated with malloc() - header_value is the text to search in the given header when type is MAILIMAP_SEARCH_KEY_HEADER, should be allocated with malloc() - larger is a size when type is MAILIMAP_SEARCH_KEY_LARGER - not is a condition when type is MAILIMAP_SEARCH_KEY_NOT - or1 is a condition when type is MAILIMAP_SEARCH_KEY_OR - or2 is a condition when type is MAILIMAP_SEARCH_KEY_OR - sentbefore is a date when type is MAILIMAP_SEARCH_KEY_SENTBEFORE - senton is a date when type is MAILIMAP_SEARCH_KEY_SENTON - sentsince is a date when type is MAILIMAP_SEARCH_KEY_SENTSINCE - smaller is a size when type is MAILIMAP_SEARCH_KEY_SMALLER - multiple is a set of message when type is MAILIMAP_SEARCH_KEY_MULTIPLE */ #if 0 struct mail_search_key { int sk_type; union { char * sk_bcc; struct mailimf_date_time * sk_before; char * sk_body; char * sk_cc; char * sk_from; struct mailimf_date_time * sk_on; struct mailimf_date_time * sk_since; char * sk_subject; char * sk_text; char * sk_to; char * sk_header_name; char * sk_header_value; size_t sk_larger; struct mail_search_key * sk_not; struct mail_search_key * sk_or1; struct mail_search_key * sk_or2; size_t sk_smaller; clist * sk_multiple; /* list of (struct mailimap_search_key *) */ } sk_data; }; struct mail_search_key * mail_search_key_new(int sk_type, char * sk_bcc, struct mailimf_date_time * sk_before, char * sk_body, char * sk_cc, char * sk_from, struct mailimf_date_time * sk_on, struct mailimf_date_time * sk_since, char * sk_subject, char * sk_text, char * sk_to, char * sk_header_name, char * sk_header_value, size_t sk_larger, struct mail_search_key * sk_not, struct mail_search_key * sk_or1, struct mail_search_key * sk_or2, size_t sk_smaller, clist * sk_multiple); void mail_search_key_free(struct mail_search_key * key); #endif /* mail_search_result is a list of message numbers that is returned by the mailsession_search_messages function() */ #if 0 struct mail_search_result { clist * sr_list; /* list of (uint32_t *) */ }; struct mail_search_result * mail_search_result_new(clist * sr_list); void mail_search_result_free(struct mail_search_result * search_result); #endif /* There is three kinds of identities : - storage - folders - session A storage (struct mailstorage) represents whether a server or a main path, A storage can be an IMAP server, the root path of a MH or a mbox file. Folders (struct mailfolder) are the mailboxes we can choose in the server or as sub-folder of the main path. Folders for IMAP are the IMAP mailboxes, for MH this is one of the folder of the MH storage, for mbox, there is only one folder, the mbox file content; A mail session (struct mailsession) is whether a connection to a server or a path that is open. It is the abstraction lower folders and storage. It allow us to send commands. We have a session driver for mail session for each kind of storage. From a session, we can get a message (struct mailmessage) to read. We have a message driver for each kind of storage. */ /* maildriver is the driver structure for mail sessions - name is the name of the driver - initialize() is the function that will initializes a data structure specific to the driver, it returns a value that will be stored in the field data of the session. The field data of the session is the state of the session, the internal data structure used by the driver. It is called when creating the mailsession structure with mailsession_new(). - uninitialize() frees the structure created with initialize() - parameters() implements functions specific to the given mail access - connect_stream() connects a stream to the session - connect_path() notify a main path to the session - starttls() changes the current stream to a TLS stream - login() notifies the user and the password to authenticate to the session - logout() exits the session and closes the stream - noop() does no operation on the session, but it can be used to poll for the status of the connection. - build_folder_name() will return an allocated string with that contains the complete path of the folder to create - create_folder() creates the folder that corresponds to the given name - delete_folder() deletes the folder that corresponds to the given name - rename_folder() change the name of the folder - check_folder() makes a checkpoint of the session - examine_folder() selects a mailbox as readonly - select_folder() selects a mailbox - expunge_folder() deletes all messages marked \Deleted - status_folder() queries the status of the folder (number of messages, number of recent messages, number of unseen messages) - messages_number() queries the number of messages in the folder - recent_number() queries the number of recent messages in the folder - unseen_number() queries the number of unseen messages in the folder - list_folders() returns the list of all sub-mailboxes of the given mailbox - lsub_folders() returns the list of subscribed sub-mailboxes of the given mailbox - subscribe_folder() subscribes to the given mailbox - unsubscribe_folder() unsubscribes to the given mailbox - append_message() adds a RFC 2822 message to the current given mailbox - copy_message() copies a message whose number is given to a given mailbox. The mailbox must be accessible from the same session. - move_message() copies a message whose number is given to a given mailbox. The mailbox must be accessible from the same session. - get_messages_list() returns the list of message numbers of the current mailbox. - get_envelopes_list() fills the parsed fields in the mailmessage structures of the mailmessage_list. - remove_message() removes the given message from the mailbox. The message is permanently deleted. - search_message() returns a list of message numbers that corresponds to the given criteria. - get_message returns a mailmessage structure that corresponds to the given message number. - get_message_by_uid returns a mailmessage structure that corresponds to the given message unique identifier. * mandatory functions are the following : - connect_stream() of connect_path() - logout() - get_messages_list() - get_envelopes_list() * we advise you to implement these functions : - select_folder() (in case a session can access several folders) - noop() (to check if the server is responding) - check_folder() (to make a checkpoint of the session) - status_folder(), messages_number(), recent_number(), unseen_number() (to get stat of the folder) - append_message() (but can't be done in the case of POP3 at least) - login() in a case of an authenticated driver. - starttls() in a case of a stream driver, if the procotol supports STARTTLS. - get_message_by_uid() so that the application can remember the message by UID and build its own list of messages. * drivers' specific : Everything that is specific to the driver will be implemented in this function : - parameters() */ struct mailsession_driver { char * sess_name; int (* sess_initialize)(mailsession * session); void (* sess_uninitialize)(mailsession * session); int (* sess_parameters)(mailsession * session, int id, void * value); int (* sess_connect_stream)(mailsession * session, mailstream * s); int (* sess_connect_path)(mailsession * session, char * path); int (* sess_starttls)(mailsession * session); int (* sess_login)(mailsession * session, char * userid, char * password); int (* sess_logout)(mailsession * session); int (* sess_noop)(mailsession * session); /* folders operations */ int (* sess_build_folder_name)(mailsession * session, char * mb, char * name, char ** result); int (* sess_create_folder)(mailsession * session, char * mb); int (* sess_delete_folder)(mailsession * session, char * mb); int (* sess_rename_folder)(mailsession * session, char * mb, char * new_name); int (* sess_check_folder)(mailsession * session); int (* sess_examine_folder)(mailsession * session, char * mb); int (* sess_select_folder)(mailsession * session, char * mb); int (* sess_expunge_folder)(mailsession * session); int (* sess_status_folder)(mailsession * session, char * mb, uint32_t * result_num, uint32_t * result_recent, uint32_t * result_unseen); int (* sess_messages_number)(mailsession * session, char * mb, uint32_t * result); int (* sess_recent_number)(mailsession * session, char * mb, uint32_t * result); int (* sess_unseen_number)(mailsession * session, char * mb, uint32_t * result); int (* sess_list_folders)(mailsession * session, char * mb, struct mail_list ** result); int (* sess_lsub_folders)(mailsession * session, char * mb, struct mail_list ** result); int (* sess_subscribe_folder)(mailsession * session, char * mb); int (* sess_unsubscribe_folder)(mailsession * session, char * mb); /* messages operations */ int (* sess_append_message)(mailsession * session, char * message, size_t size); + int (* sess_append_message_flags)(mailsession * session, + char * message, size_t size, struct mail_flags * flags); int (* sess_copy_message)(mailsession * session, uint32_t num, char * mb); int (* sess_move_message)(mailsession * session, uint32_t num, char * mb); int (* sess_get_message)(mailsession * session, uint32_t num, mailmessage ** result); int (* sess_get_message_by_uid)(mailsession * session, const char * uid, mailmessage ** result); int (* sess_get_messages_list)(mailsession * session, struct mailmessage_list ** result); int (* sess_get_envelopes_list)(mailsession * session, struct mailmessage_list * env_list); int (* sess_remove_message)(mailsession * session, uint32_t num); #if 0 int (* sess_search_messages)(mailsession * session, char * charset, struct mail_search_key * key, struct mail_search_result ** result); #endif }; /* session is the data structure for a mail session. - data is the internal data structure used by the driver It is called when initializing the mailsession structure. - driver is the driver used for the session */ struct mailsession { void * sess_data; mailsession_driver * sess_driver; }; /* mailmessage_driver is the driver structure to get information from messages. - name is the name of the driver - initialize() is the function that will initializes a data structure specific to the driver, it returns a value that will be stored in the field data of the mailsession. The field data of the session is the state of the session, the internal data structure used by the driver. It is called when initializing the mailmessage structure with mailmessage_init(). - uninitialize() frees the structure created with initialize(). It will be called by mailmessage_free(). - flush() will free from memory all temporary structures of the message (for example, the MIME structure of the message). - fetch_result_free() will free all strings resulted by fetch() or any fetch_xxx() functions that returns a string. - fetch() returns the content of the message (headers and text). - fetch_header() returns the content of the headers. - fetch_body() returns the message text (message content without headers) - fetch_size() returns the size of the message content. - get_bodystructure() returns the MIME structure of the message. - fetch_section() returns the content of a given MIME part - fetch_section_header() returns the header of the message contained by the given MIME part. - fetch_section_mime() returns the MIME headers of the given MIME part. - fetch_section_body() returns the text (if this is a message, this is the message content without headers) of the given MIME part. - fetch_envelope() returns a mailimf_fields structure, with a list of fields chosen by the driver. - get_flags() returns a the flags related to the message. When you want to get flags of a message, you have to make sure to call get_flags() at least once before using directly message->flags. */ #define LIBETPAN_MAIL_MESSAGE_CHECK struct mailmessage_driver { char * msg_name; int (* msg_initialize)(mailmessage * msg_info); void (* msg_uninitialize)(mailmessage * msg_info); void (* msg_flush)(mailmessage * msg_info); void (* msg_check)(mailmessage * msg_info); void (* msg_fetch_result_free)(mailmessage * msg_info, char * msg); int (* msg_fetch)(mailmessage * msg_info, char ** result, size_t * result_len); int (* msg_fetch_header)(mailmessage * msg_info, char ** result, size_t * result_len); int (* msg_fetch_body)(mailmessage * msg_info, char ** result, size_t * result_len); int (* msg_fetch_size)(mailmessage * msg_info, size_t * result); int (* msg_get_bodystructure)(mailmessage * msg_info, struct mailmime ** result); int (* msg_fetch_section)(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len); int (* msg_fetch_section_header)(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len); int (* msg_fetch_section_mime)(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len); int (* msg_fetch_section_body)(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len); int (* msg_fetch_envelope)(mailmessage * msg_info, struct mailimf_fields ** result); int (* msg_get_flags)(mailmessage * msg_info, struct mail_flags ** result); }; /* mailmessage is a data structure to get information from messages - session is the session linked to the given message, it can be NULL - driver is the message driver - index is the message number - uid, when it is not NULL, it means that the folder the folder has persistant message numbers, the string is the unique message number in the folder. uid should be implemented if possible. for drivers where we cannot generate real uid, a suggestion is "AAAA-IIII" where AAAA is some random session number and IIII the content of index field. - size, when it is not 0, is the size of the message content. - fields, when it is not NULL, are the header fields of the message. - flags, when it is not NULL, are the flags related to the message. - single_fields, when resolved != 0, is filled with the data of fields. - mime, when it is not NULL - cached is != 0 when the header fields were read from the cache. - data is data specific to the driver, this is internal data structure, some state of the message. */ struct mailmessage { mailsession * msg_session; mailmessage_driver * msg_driver; uint32_t msg_index; char * msg_uid; size_t msg_size; struct mailimf_fields * msg_fields; struct mail_flags * msg_flags; int msg_resolved; struct mailimf_single_fields msg_single_fields; struct mailmime * msg_mime; /* internal data */ int msg_cached; void * msg_data; /* msg_folder field : used to reference the mailfolder, this is a workaround due to the problem with initial conception, where folder notion did not exist. */ void * msg_folder; /* user data */ void * msg_user_data; }; /* mailmessage_tree is a node in the messages tree (thread) - parent is the parent of the message, it is NULL if the message is the root of the message tree. - date is the date of the message in number of second elapsed since 00:00:00 on January 1, 1970, Coordinated Universal Time (UTC). - msg is the message structure that is stored referenced by the node. is msg is NULL, this is a dummy node. - children is an array that contains all the children of the node. children are mailmessage_tree structures. - is_reply is != 0 when the message is a reply or a forward - base_subject is the extracted subject of the message. - index is the message number. */ struct mailmessage_tree { struct mailmessage_tree * node_parent; char * node_msgid; time_t node_date; mailmessage * node_msg; carray * node_children; /* array of (struct mailmessage_tree *) */ /* private, used for threading */ int node_is_reply; char * node_base_subject; }; struct mailmessage_tree * mailmessage_tree_new(char * node_msgid, time_t node_date, mailmessage * node_msg); void mailmessage_tree_free(struct mailmessage_tree * tree); /* mailmessage_tree_free_recursive if you want to release memory of the given tree and all the sub-trees, you can use this function. */ void mailmessage_tree_free_recursive(struct mailmessage_tree * tree); struct generic_message_t { int (* msg_prefetch)(mailmessage * msg_info); void (* msg_prefetch_free)(struct generic_message_t * msg); int msg_fetched; char * msg_message; size_t msg_length; void * msg_data; }; const char * maildriver_strerror(int err); #ifdef __cplusplus } #endif #endif diff --git a/kmicromail/libetpan/generic/mailfolder.c b/kmicromail/libetpan/generic/mailfolder.c index 2ddc37d..89ba891 100644 --- a/kmicromail/libetpan/generic/mailfolder.c +++ b/kmicromail/libetpan/generic/mailfolder.c @@ -1,96 +1,103 @@ #include "mailfolder.h" #include "maildriver.h" int mailfolder_noop(struct mailfolder * folder) { return mailsession_noop(folder->fld_session); } int mailfolder_check(struct mailfolder * folder) { return mailsession_check_folder(folder->fld_session); } int mailfolder_expunge(struct mailfolder * folder) { return mailsession_expunge_folder(folder->fld_session); } int mailfolder_status(struct mailfolder * folder, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { return mailsession_status_folder(folder->fld_session, folder->fld_pathname, result_messages, result_recent, result_unseen); } int mailfolder_append_message(struct mailfolder * folder, char * message, size_t size) { return mailsession_append_message(folder->fld_session, message, size); } +int mailfolder_append_message_flags(struct mailfolder * folder, + char * message, size_t size, struct mail_flags * flags) +{ + return mailsession_append_message_flags(folder->fld_session, message, + size, flags); +} + int mailfolder_get_messages_list(struct mailfolder * folder, struct mailmessage_list ** result) { int r; struct mailmessage_list * msg_list; unsigned int i; r = mailsession_get_messages_list(folder->fld_session, &msg_list); if (r != MAIL_NO_ERROR) return r; for(i = 0 ; i < carray_count(msg_list->msg_tab) ; i ++) { mailmessage * msg; msg = carray_get(msg_list->msg_tab, i); msg->msg_folder = folder; } * result = msg_list; return MAIL_NO_ERROR; } int mailfolder_get_envelopes_list(struct mailfolder * folder, struct mailmessage_list * result) { return mailsession_get_envelopes_list(folder->fld_session, result); } int mailfolder_get_message(struct mailfolder * folder, uint32_t num, mailmessage ** result) { mailmessage * msg; int r; r = mailsession_get_message(folder->fld_session, num, &msg); if (r != MAIL_NO_ERROR) return r; msg->msg_folder = folder; * result = msg; return MAIL_NO_ERROR; } int mailfolder_get_message_by_uid(struct mailfolder * folder, const char * uid, mailmessage ** result) { mailmessage * msg; int r; r = mailsession_get_message_by_uid(folder->fld_session, uid, &msg); if (r != MAIL_NO_ERROR) return r; msg->msg_folder = folder; * result = msg; return MAIL_NO_ERROR; } diff --git a/kmicromail/libetpan/generic/mailfolder.h b/kmicromail/libetpan/generic/mailfolder.h index 3ecad23..ff53470 100644 --- a/kmicromail/libetpan/generic/mailfolder.h +++ b/kmicromail/libetpan/generic/mailfolder.h @@ -1,32 +1,35 @@ #ifndef MAILFOLDER_H #define MAILFOLDER_H #include "mailstorage_types.h" int mailfolder_noop(struct mailfolder * folder); int mailfolder_check(struct mailfolder * folder); int mailfolder_expunge(struct mailfolder * folder); int mailfolder_status(struct mailfolder * folder, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); int mailfolder_append_message(struct mailfolder * folder, char * message, size_t size); +int mailfolder_append_message_flags(struct mailfolder * folder, + char * message, size_t size, struct mail_flags * flags); + int mailfolder_get_messages_list(struct mailfolder * folder, struct mailmessage_list ** result); int mailfolder_get_envelopes_list(struct mailfolder * folder, struct mailmessage_list * result); int mailfolder_get_message(struct mailfolder * folder, uint32_t num, mailmessage ** result); int mailfolder_get_message_by_uid(struct mailfolder * folder, const char * uid, mailmessage ** result); #endif diff --git a/kmicromail/libetpan/generic/mailstorage.c b/kmicromail/libetpan/generic/mailstorage.c index 25e561e..dc91744 100644 --- a/kmicromail/libetpan/generic/mailstorage.c +++ b/kmicromail/libetpan/generic/mailstorage.c @@ -1,334 +1,341 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "mailstorage.h" #include "maildriver.h" #include <stdlib.h> #include <string.h> static int mailstorage_get_folder(struct mailstorage * storage, char * pathname, mailsession ** result); struct mailfolder * mailfolder_new(struct mailstorage * storage, char * pathname, char * virtual_name) { struct mailfolder * folder; folder = malloc(sizeof(struct mailfolder)); if (folder == NULL) goto err; if (pathname != NULL) { folder->fld_pathname = strdup(pathname); if (folder->fld_pathname == NULL) goto free; } else folder->fld_pathname = NULL; if (virtual_name != NULL) { folder->fld_virtual_name = strdup(virtual_name); if (folder->fld_virtual_name == NULL) goto free_pathname; } else folder->fld_virtual_name = NULL; folder->fld_storage = storage; folder->fld_session = NULL; folder->fld_shared_session = 0; folder->fld_pos = NULL; folder->fld_parent = NULL; folder->fld_sibling_index = 0; folder->fld_children = carray_new(128); if (folder->fld_children == NULL) goto free_virtualname; return folder; free_virtualname: if (folder->fld_virtual_name != NULL) free(folder->fld_virtual_name); free_pathname: if (folder->fld_pathname != NULL) free(folder->fld_pathname); free: free(folder); err: return NULL; } void mailfolder_free(struct mailfolder * folder) { if (folder->fld_parent != NULL) mailfolder_detach_parent(folder); while (carray_count(folder->fld_children) > 0) { struct mailfolder * child; child = carray_get(folder->fld_children, 0); mailfolder_detach_parent(child); } carray_free(folder->fld_children); if (folder->fld_session != NULL) mailfolder_disconnect(folder); if (folder->fld_virtual_name != NULL) free(folder->fld_virtual_name); if (folder->fld_pathname != NULL) free(folder->fld_pathname); free(folder); } int mailfolder_connect(struct mailfolder * folder) { mailsession * session; int res; int r; if (folder->fld_storage == NULL) { res = MAIL_ERROR_INVAL; goto err; } if (folder->fld_storage->sto_session == NULL) { r = mailstorage_connect(folder->fld_storage); if (r != MAIL_NO_ERROR) { res = r; goto err; } } if (folder->fld_session != NULL) { if ((folder->fld_pathname != NULL) && (folder->fld_shared_session)) { if (folder->fld_session->sess_driver->sess_select_folder != NULL) { r = mailsession_select_folder(folder->fld_session, folder->fld_pathname); if (r != MAIL_NO_ERROR) { res = r; goto err; } } } return MAIL_NO_ERROR; } r = mailstorage_get_folder(folder->fld_storage, folder->fld_pathname, &session); if (r != MAIL_NO_ERROR) { res = r; goto err; } folder->fld_session = session; folder->fld_shared_session = (session == folder->fld_storage->sto_session); if (folder->fld_shared_session) { r = clist_append(folder->fld_storage->sto_shared_folders, folder); if (r < 0) { folder->fld_session = NULL; res = MAIL_ERROR_MEMORY; goto err; } folder->fld_pos = clist_end(folder->fld_storage->sto_shared_folders); } return MAIL_NO_ERROR; err: return res; } void mailfolder_disconnect(struct mailfolder * folder) { if (folder->fld_session == NULL) return; if (folder->fld_shared_session) { clist_delete(folder->fld_storage->sto_shared_folders, folder->fld_pos); folder->fld_pos = NULL; } else { mailsession_logout(folder->fld_session); mailsession_free(folder->fld_session); } folder->fld_session = NULL; } int mailfolder_add_child(struct mailfolder * parent, struct mailfolder * child) { unsigned int index; int r; r = carray_add(parent->fld_children, child, &index); if (r < 0) return MAIL_ERROR_MEMORY; child->fld_sibling_index = index; child->fld_parent = parent; return MAIL_NO_ERROR; } int mailfolder_detach_parent(struct mailfolder * folder) { unsigned int i; int r; if (folder->fld_parent == NULL) return MAIL_ERROR_INVAL; r = carray_delete_slow(folder->fld_parent->fld_children, folder->fld_sibling_index); if (r < 0) return MAIL_ERROR_INVAL; for(i = 0 ; i < carray_count(folder->fld_parent->fld_children) ; i ++) { struct mailfolder * child; child = carray_get(folder->fld_parent->fld_children, i); child->fld_sibling_index = i; } folder->fld_parent = NULL; folder->fld_sibling_index = 0; return MAIL_NO_ERROR; } struct mailstorage * mailstorage_new(char * sto_id) { struct mailstorage * storage; storage = malloc(sizeof(struct mailstorage)); if (storage == NULL) goto err; if (sto_id != NULL) { storage->sto_id = strdup(sto_id); if (storage->sto_id == NULL) goto free; } else storage->sto_id = NULL; storage->sto_data = NULL; storage->sto_session = NULL; storage->sto_driver = NULL; storage->sto_shared_folders = clist_new(); if (storage->sto_shared_folders == NULL) goto free_id; return storage; free_id: if (storage->sto_id != NULL) free(storage->sto_id); free: free(storage); err: return NULL; } void mailstorage_free(struct mailstorage * storage) { if (storage->sto_session != NULL) mailstorage_disconnect(storage); if (storage->sto_driver != NULL) { if (storage->sto_driver->sto_uninitialize != NULL) storage->sto_driver->sto_uninitialize(storage); } clist_free(storage->sto_shared_folders); if (storage->sto_id != NULL) free(storage->sto_id); free(storage); } int mailstorage_connect(struct mailstorage * storage) { if (storage->sto_session != NULL) return MAIL_NO_ERROR; if (!clist_isempty(storage->sto_shared_folders)) return MAIL_ERROR_BAD_STATE; if (storage->sto_driver->sto_connect == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return storage->sto_driver->sto_connect(storage); } void mailstorage_disconnect(struct mailstorage * storage) { int r; clistiter * cur; while ((cur = clist_begin(storage->sto_shared_folders)) != NULL) { struct mailfolder * folder; folder = cur->data; mailfolder_disconnect(folder); } if (storage->sto_session == NULL) return; r = mailsession_logout(storage->sto_session); mailsession_free(storage->sto_session); storage->sto_session = NULL; } + +int mailstorage_noop(struct mailstorage * storage) +{ + return mailsession_noop(storage->sto_session); +} + + static int mailstorage_get_folder(struct mailstorage * storage, char * pathname, mailsession ** result) { if (storage->sto_driver->sto_get_folder_session == NULL) return MAIL_ERROR_NOT_IMPLEMENTED; return storage->sto_driver->sto_get_folder_session(storage, pathname, result); } diff --git a/kmicromail/libetpan/generic/mailstorage.h b/kmicromail/libetpan/generic/mailstorage.h index d56aef1..4c57883 100644 --- a/kmicromail/libetpan/generic/mailstorage.h +++ b/kmicromail/libetpan/generic/mailstorage.h @@ -1,98 +1,99 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #ifndef MAIL_STORAGE_H #define MAIL_STORAGE_H #include <libetpan/maildriver_types.h> #include <libetpan/mailstorage_types.h> #ifdef __cplusplus extern "C" { #endif /* storage */ /* mailstorage_new This function creates an empty storage. This storage have to be initialized. The "driver" and "data" fields should be initialized. @param id is the name of the storage. It can be NULL. The given parameter is no more needed when the creation is finished. The given string is duplicated. @return The mail storage is returned. */ struct mailstorage * mailstorage_new(char * sto_id); void mailstorage_free(struct mailstorage * storage); /* session will be initialized on success. */ int mailstorage_connect(struct mailstorage * storage); void mailstorage_disconnect(struct mailstorage * storage); +int mailstorage_noop(struct mailstorage * storage); + /* folder */ struct mailfolder * mailfolder_new(struct mailstorage * fld_storage, char * fld_pathname, char * fld_virtual_name); void mailfolder_free(struct mailfolder * folder); int mailfolder_add_child(struct mailfolder * parent, struct mailfolder * child); int mailfolder_detach_parent(struct mailfolder * folder); int mailfolder_connect(struct mailfolder * folder); void mailfolder_disconnect(struct mailfolder * folder); - #ifdef __cplusplus } #endif #endif diff --git a/kmicromail/libetpan/generic/mboxdriver.c b/kmicromail/libetpan/generic/mboxdriver.c index fa3e2ea..c19a668 100644 --- a/kmicromail/libetpan/generic/mboxdriver.c +++ b/kmicromail/libetpan/generic/mboxdriver.c @@ -1,505 +1,515 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "mboxdriver.h" #include <stdio.h> #include <string.h> #include <sys/types.h> #include <dirent.h> #include <unistd.h> #include <sys/stat.h> #include <ctype.h> #include <stdlib.h> #include <sys/times.h> #include "mail.h" #include "maildriver_tools.h" #include "mailmbox.h" #include "mboxdriver_tools.h" #include "maildriver.h" #include "carray.h" #include "mboxdriver_message.h" #include "mailmessage.h" static int mboxdriver_initialize(mailsession * session); static void mboxdriver_uninitialize(mailsession * session); static int mboxdriver_parameters(mailsession * session, int id, void * value); static int mboxdriver_connect_path(mailsession * session, char * path); static int mboxdriver_logout(mailsession * session); static int mboxdriver_expunge_folder(mailsession * session); static int mboxdriver_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); static int mboxdriver_messages_number(mailsession * session, char * mb, uint32_t * result); static int mboxdriver_append_message(mailsession * session, char * message, size_t size); +static int mboxdriver_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags); + static int mboxdriver_get_messages_list(mailsession * session, struct mailmessage_list ** result); static int mboxdriver_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list); static int mboxdriver_remove_message(mailsession * session, uint32_t num); static int mboxdriver_get_message(mailsession * session, uint32_t num, mailmessage ** result); static int mboxdriver_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result); static mailsession_driver local_mbox_session_driver = { .sess_name = "mbox", .sess_initialize = mboxdriver_initialize, .sess_uninitialize = mboxdriver_uninitialize, .sess_parameters = mboxdriver_parameters, .sess_connect_path = mboxdriver_connect_path, .sess_connect_stream = NULL, .sess_starttls = NULL, .sess_login = NULL, .sess_logout = mboxdriver_logout, .sess_noop = NULL, .sess_build_folder_name = NULL, .sess_create_folder = NULL, .sess_delete_folder = NULL, .sess_rename_folder = NULL, .sess_check_folder = NULL, .sess_examine_folder = NULL, .sess_select_folder = NULL, .sess_expunge_folder = mboxdriver_expunge_folder, .sess_status_folder = mboxdriver_status_folder, .sess_messages_number = mboxdriver_messages_number, .sess_recent_number = mboxdriver_messages_number, .sess_unseen_number = mboxdriver_messages_number, .sess_list_folders = NULL, .sess_lsub_folders = NULL, .sess_subscribe_folder = NULL, .sess_unsubscribe_folder = NULL, .sess_append_message = mboxdriver_append_message, + .sess_append_message_flags = mboxdriver_append_message_flags, .sess_copy_message = NULL, .sess_move_message = NULL, .sess_get_messages_list = mboxdriver_get_messages_list, .sess_get_envelopes_list = mboxdriver_get_envelopes_list, .sess_remove_message = mboxdriver_remove_message, #if 0 .sess_search_messages = maildriver_generic_search_messages, #endif .sess_get_message = mboxdriver_get_message, .sess_get_message_by_uid = mboxdriver_get_message_by_uid, }; mailsession_driver * mbox_session_driver = &local_mbox_session_driver; static inline struct mbox_session_state_data * get_data(mailsession * session) { return session->sess_data; } static inline struct mailmbox_folder * get_mbox_session(mailsession * session) { return get_data(session)->mbox_folder; } static int mboxdriver_initialize(mailsession * session) { struct mbox_session_state_data * data; data = malloc(sizeof(* data)); if (data == NULL) goto err; data->mbox_folder = NULL; data->mbox_force_read_only = FALSE; data->mbox_force_no_uid = TRUE; session->sess_data = data; return MAIL_NO_ERROR; err: return MAIL_ERROR_MEMORY; } static void free_state(struct mbox_session_state_data * mbox_data) { if (mbox_data->mbox_folder != NULL) { mailmbox_done(mbox_data->mbox_folder); mbox_data->mbox_folder = NULL; } } static void mboxdriver_uninitialize(mailsession * session) { struct mbox_session_state_data * data; data = get_data(session); free_state(data); free(data); } static int mboxdriver_parameters(mailsession * session, int id, void * value) { struct mbox_session_state_data * data; data = get_data(session); switch (id) { case MBOXDRIVER_SET_READ_ONLY: { int * param; param = value; data->mbox_force_read_only = * param; return MAIL_NO_ERROR; } case MBOXDRIVER_SET_NO_UID: { int * param; param = value; data->mbox_force_no_uid = * param; return MAIL_NO_ERROR; } } return MAIL_ERROR_INVAL; } static int mboxdriver_connect_path(mailsession * session, char * path) { struct mbox_session_state_data * mbox_data; struct mailmbox_folder * folder; int r; mbox_data = get_data(session); if (mbox_data->mbox_folder != NULL) return MAIL_ERROR_BAD_STATE; r = mailmbox_init(path, mbox_data->mbox_force_read_only, mbox_data->mbox_force_no_uid, 0, &folder); if (r != MAILMBOX_NO_ERROR) return mboxdriver_mbox_error_to_mail_error(r); mbox_data->mbox_folder = folder; return MAIL_NO_ERROR; } static int mboxdriver_logout(mailsession * session) { struct mbox_session_state_data * mbox_data; mbox_data = get_data(session); if (mbox_data->mbox_folder == NULL) return MAIL_ERROR_BAD_STATE; free_state(mbox_data); mbox_data->mbox_folder = NULL; return MAIL_NO_ERROR; } static int mboxdriver_expunge_folder(mailsession * session) { int r; struct mbox_session_state_data * mbox_data; mbox_data = get_data(session); if (mbox_data->mbox_folder == NULL) return MAIL_ERROR_BAD_STATE; r = mailmbox_expunge(mbox_data->mbox_folder); if (r != MAILMBOX_NO_ERROR) return mboxdriver_mbox_error_to_mail_error(r); return MAIL_NO_ERROR; } static int mboxdriver_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { uint32_t count; int r; r = mboxdriver_messages_number(session, mb, &count); if (r != MAIL_NO_ERROR) return r; * result_messages = count; * result_recent = count; * result_unseen = count; return MAIL_NO_ERROR; } static int mboxdriver_messages_number(mailsession * session, char * mb, uint32_t * result) { struct mailmbox_folder * folder; int r; folder = get_mbox_session(session); if (folder == NULL) return MAIL_ERROR_STATUS; r = mailmbox_validate_read_lock(folder); if (r != MAIL_NO_ERROR) return r; mailmbox_read_unlock(folder); * result = carray_count(folder->mb_tab) - folder->mb_deleted_count; return MAILMBOX_NO_ERROR; } /* messages operations */ static int mboxdriver_append_message(mailsession * session, char * message, size_t size) { int r; struct mailmbox_folder * folder; folder = get_mbox_session(session); if (folder == NULL) return MAIL_ERROR_APPEND; r = mailmbox_append_message(folder, message, size); switch (r) { case MAILMBOX_ERROR_FILE: return MAIL_ERROR_DISKSPACE; default: return mboxdriver_mbox_error_to_mail_error(r); } } +static int mboxdriver_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags) +{ + return mboxdriver_append_message(session, message, size); +} + static int mboxdriver_get_messages_list(mailsession * session, struct mailmessage_list ** result) { struct mailmbox_folder * folder; int res; folder = get_mbox_session(session); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } return mbox_get_messages_list(folder, session, mbox_message_driver, result); err: return res; } static int mboxdriver_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list) { struct mailmbox_folder * folder; unsigned int i; int r; int res; folder = get_mbox_session(session); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } r = mailmbox_validate_read_lock(folder); if (r != MAILMBOX_NO_ERROR) { res = mboxdriver_mbox_error_to_mail_error(r); goto err; } for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; struct mailimf_fields * fields; char * headers; size_t headers_len; size_t cur_token; msg = carray_get(env_list->msg_tab, i); if (msg == NULL) continue; if (msg->msg_fields != NULL) continue; r = mailmbox_fetch_msg_headers_no_lock(folder, msg->msg_index, &headers, &headers_len); if (r != MAILMBOX_NO_ERROR) { res = mboxdriver_mbox_error_to_mail_error(r); goto unlock; } cur_token = 0; r = mailimf_envelope_fields_parse(headers, headers_len, &cur_token, &fields); if (r != MAILIMF_NO_ERROR) continue; msg->msg_fields = fields; } mailmbox_read_unlock(folder); return MAIL_NO_ERROR; unlock: mailmbox_read_unlock(folder); err: return res; } static int mboxdriver_remove_message(mailsession * session, uint32_t num) { int r; struct mailmbox_folder * folder; folder = get_mbox_session(session); if (folder == NULL) return MAIL_ERROR_DELETE; r = mailmbox_delete_msg(folder, num); return mboxdriver_mbox_error_to_mail_error(r); } static int mboxdriver_get_message(mailsession * session, uint32_t num, mailmessage ** result) { mailmessage * msg_info; int r; msg_info = mailmessage_new(); if (msg_info == NULL) return MAIL_ERROR_MEMORY; r = mailmessage_init(msg_info, session, mbox_message_driver, num, 0); if (r != MAIL_NO_ERROR) { mailmessage_free(msg_info); return r; } * result = msg_info; return MAIL_NO_ERROR; } static int mboxdriver_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result) { uint32_t num; char * p; chashdatum key; chashdatum data; struct mailmbox_msg_info * info; struct mailmbox_folder * folder; int r; if (uid == NULL) return MAIL_ERROR_INVAL; num = strtoul(uid, &p, 10); if (p == uid || * p != '-') return MAIL_ERROR_INVAL; folder = get_mbox_session(session); if (folder == NULL) return MAIL_ERROR_BAD_STATE; key.data = # key.len = sizeof(num); r = chash_get(folder->mb_hash, &key, &data); if (r == 0) { char * body_len_p = p + 1; size_t body_len; info = data.data; /* Check if the cached message has the same UID */ body_len = strtoul(body_len_p, &p, 10); if (p == body_len_p || * p != '\0') return MAIL_ERROR_INVAL; if (body_len == info->msg_body_len) return mboxdriver_get_message(session, num, result); } return MAIL_ERROR_MSG_NOT_FOUND; } diff --git a/kmicromail/libetpan/generic/mboxdriver_cached.c b/kmicromail/libetpan/generic/mboxdriver_cached.c index 07871fa..3af7fb9 100644 --- a/kmicromail/libetpan/generic/mboxdriver_cached.c +++ b/kmicromail/libetpan/generic/mboxdriver_cached.c @@ -1,1253 +1,1337 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "mboxdriver_cached.h" #include <stdio.h> #include <string.h> #include <dirent.h> #include <unistd.h> #include <ctype.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include "mail.h" #include "mail_cache_db.h" #include "mboxdriver.h" #include "mboxdriver_tools.h" #include "maildriver_tools.h" #include "mailmbox.h" #include "maildriver.h" #include "carray.h" #include "generic_cache.h" #include "imfcache.h" #include "mboxdriver_cached_message.h" #include "libetpan-config.h" static int mboxdriver_cached_initialize(mailsession * session); static void mboxdriver_cached_uninitialize(mailsession * session); static int mboxdriver_cached_parameters(mailsession * session, int id, void * value); static int mboxdriver_cached_connect_path(mailsession * session, char * path); static int mboxdriver_cached_logout(mailsession * session); static int mboxdriver_cached_check_folder(mailsession * session); static int mboxdriver_cached_expunge_folder(mailsession * session); static int mboxdriver_cached_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); static int mboxdriver_cached_messages_number(mailsession * session, char * mb, uint32_t * result); static int mboxdriver_cached_recent_number(mailsession * session, char * mb, uint32_t * result); static int mboxdriver_cached_unseen_number(mailsession * session, char * mb, uint32_t * result); static int mboxdriver_cached_append_message(mailsession * session, char * message, size_t size); +static int mboxdriver_cached_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags); + static int mboxdriver_cached_get_messages_list(mailsession * session, struct mailmessage_list ** result); static int mboxdriver_cached_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list); static int mboxdriver_cached_remove_message(mailsession * session, uint32_t num); static int mboxdriver_cached_get_message(mailsession * session, uint32_t num, mailmessage ** result); static int mboxdriver_cached_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result); static mailsession_driver local_mbox_cached_session_driver = { .sess_name = "mbox-cached", .sess_initialize = mboxdriver_cached_initialize, .sess_uninitialize = mboxdriver_cached_uninitialize, .sess_parameters = mboxdriver_cached_parameters, .sess_connect_path = mboxdriver_cached_connect_path, .sess_connect_stream = NULL, .sess_starttls = NULL, .sess_login = NULL, .sess_logout = mboxdriver_cached_logout, .sess_noop = NULL, .sess_build_folder_name = NULL, .sess_create_folder = NULL, .sess_delete_folder = NULL, .sess_rename_folder = NULL, .sess_check_folder = mboxdriver_cached_check_folder, .sess_examine_folder = NULL, .sess_select_folder = NULL, .sess_expunge_folder = mboxdriver_cached_expunge_folder, .sess_status_folder = mboxdriver_cached_status_folder, .sess_messages_number = mboxdriver_cached_messages_number, .sess_recent_number = mboxdriver_cached_recent_number, .sess_unseen_number = mboxdriver_cached_unseen_number, .sess_list_folders = NULL, .sess_lsub_folders = NULL, .sess_subscribe_folder = NULL, .sess_unsubscribe_folder = NULL, .sess_append_message = mboxdriver_cached_append_message, + .sess_append_message_flags = mboxdriver_cached_append_message_flags, + .sess_copy_message = NULL, .sess_move_message = NULL, .sess_get_messages_list = mboxdriver_cached_get_messages_list, .sess_get_envelopes_list = mboxdriver_cached_get_envelopes_list, .sess_remove_message = mboxdriver_cached_remove_message, #if 0 .sess_search_messages = maildriver_generic_search_messages, #endif .sess_get_message = mboxdriver_cached_get_message, .sess_get_message_by_uid = mboxdriver_cached_get_message_by_uid, }; mailsession_driver * mbox_cached_session_driver = &local_mbox_cached_session_driver; #define ENV_NAME "env.db" #define FLAGS_NAME "flags.db" static int mbox_error_to_mail_error(int error) { switch (error) { case MAILMBOX_NO_ERROR: return MAIL_NO_ERROR; case MAILMBOX_ERROR_PARSE: return MAIL_ERROR_PARSE; case MAILMBOX_ERROR_INVAL: return MAIL_ERROR_INVAL; case MAILMBOX_ERROR_FILE_NOT_FOUND: return MAIL_ERROR_PARSE; case MAILMBOX_ERROR_MEMORY: return MAIL_ERROR_MEMORY; case MAILMBOX_ERROR_TEMPORARY_FILE: return MAIL_ERROR_PARSE; case MAILMBOX_ERROR_FILE: return MAIL_ERROR_FILE; case MAILMBOX_ERROR_MSG_NOT_FOUND: return MAIL_ERROR_MSG_NOT_FOUND; case MAILMBOX_ERROR_READONLY: return MAIL_ERROR_READONLY; default: return MAIL_ERROR_INVAL; } } static inline struct mbox_cached_session_state_data * get_cached_data(mailsession * session) { return session->sess_data; } static inline mailsession * get_ancestor(mailsession * session) { return get_cached_data(session)->mbox_ancestor; } static inline struct mbox_session_state_data * get_ancestor_data(mailsession * session) { return get_ancestor(session)->sess_data; } static inline struct mailmbox_folder * get_mbox_session(mailsession * session) { return get_ancestor_data(session)->mbox_folder; } static int mboxdriver_cached_initialize(mailsession * session) { struct mbox_cached_session_state_data * cached_data; struct mbox_session_state_data * mbox_data; cached_data = malloc(sizeof(* cached_data)); if (cached_data == NULL) goto err; cached_data->mbox_flags_store = mail_flags_store_new(); if (cached_data->mbox_flags_store == NULL) goto free; cached_data->mbox_ancestor = mailsession_new(mbox_session_driver); if (cached_data->mbox_ancestor == NULL) goto free_store; cached_data->mbox_quoted_mb = NULL; /* UID must be enabled to take advantage of the cache */ mbox_data = cached_data->mbox_ancestor->sess_data; mbox_data->mbox_force_no_uid = FALSE; session->sess_data = cached_data; return MAIL_NO_ERROR; free_store: mail_flags_store_free(cached_data->mbox_flags_store); free: free(cached_data); err: return MAIL_ERROR_MEMORY; } static void free_state(struct mbox_cached_session_state_data * mbox_data) { if (mbox_data->mbox_quoted_mb) { free(mbox_data->mbox_quoted_mb); mbox_data->mbox_quoted_mb = NULL; } } static int mbox_flags_store_process(char * flags_directory, char * quoted_mb, struct mail_flags_store * flags_store) { char filename_flags[PATH_MAX]; struct mail_cache_db * cache_db_flags; MMAPString * mmapstr; unsigned int i; int r; int res; if (carray_count(flags_store->fls_tab) == 0) return MAIL_NO_ERROR; if (quoted_mb == NULL) return MAIL_NO_ERROR; snprintf(filename_flags, PATH_MAX, "%s%c%s%c%s", flags_directory, MAIL_DIR_SEPARATOR, quoted_mb, MAIL_DIR_SEPARATOR, FLAGS_NAME); r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_FILE; goto err; } mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto close_db_flags; } for(i = 0 ; i < carray_count(flags_store->fls_tab) ; i ++) { mailmessage * msg; msg = carray_get(flags_store->fls_tab, i); r = mboxdriver_write_cached_flags(cache_db_flags, mmapstr, msg->msg_uid, msg->msg_flags); if (r != MAIL_NO_ERROR) { /* ignore errors */ } } mmap_string_free(mmapstr); mail_cache_db_close_unlock(filename_flags, cache_db_flags); mail_flags_store_clear(flags_store); return MAIL_NO_ERROR; close_db_flags: mail_cache_db_close_unlock(filename_flags, cache_db_flags); err: return res; } static void mboxdriver_cached_uninitialize(mailsession * session) { struct mbox_cached_session_state_data * data; data = get_cached_data(session); mbox_flags_store_process(data->mbox_flags_directory, data->mbox_quoted_mb, data->mbox_flags_store); mail_flags_store_free(data->mbox_flags_store); free_state(data); mailsession_free(data->mbox_ancestor); free(data); session->sess_data = NULL; } static int mboxdriver_cached_parameters(mailsession * session, int id, void * value) { struct mbox_cached_session_state_data * data; int r; data = get_cached_data(session); switch (id) { case MBOXDRIVER_CACHED_SET_CACHE_DIRECTORY: strncpy(data->mbox_cache_directory, value, PATH_MAX); data->mbox_cache_directory[PATH_MAX - 1] = '\0'; r = generic_cache_create_dir(data->mbox_cache_directory); if (r != MAIL_NO_ERROR) return r; return MAIL_NO_ERROR; case MBOXDRIVER_CACHED_SET_FLAGS_DIRECTORY: strncpy(data->mbox_flags_directory, value, PATH_MAX); data->mbox_flags_directory[PATH_MAX - 1] = '\0'; r = generic_cache_create_dir(data->mbox_flags_directory); if (r != MAIL_NO_ERROR) return r; return MAIL_NO_ERROR; case MBOXDRIVER_SET_NO_UID: return MAIL_ERROR_INVAL; default: return mailsession_parameters(data->mbox_ancestor, id, value); } } static int get_cache_directory(mailsession * session, char * path, char ** result) { char * quoted_mb; char dirname[PATH_MAX]; int res; int r; struct mbox_cached_session_state_data * cached_data; cached_data = get_cached_data(session); quoted_mb = maildriver_quote_mailbox(path); if (quoted_mb == NULL) { res = MAIL_ERROR_MEMORY; goto err; } snprintf(dirname, PATH_MAX, "%s%c%s", cached_data->mbox_cache_directory, MAIL_DIR_SEPARATOR, quoted_mb); r = generic_cache_create_dir(dirname); if (r != MAIL_NO_ERROR) { res = r; goto free; } snprintf(dirname, PATH_MAX, "%s%c%s", cached_data->mbox_flags_directory, MAIL_DIR_SEPARATOR, quoted_mb); r = generic_cache_create_dir(dirname); if (r != MAIL_NO_ERROR) { res = r; goto free; } * result = quoted_mb; return MAIL_NO_ERROR; free: free(quoted_mb); err: return res; } #define FILENAME_MAX_UID "max-uid" /* write max uid current value */ static int write_max_uid_value(mailsession * session) { int r; char filename[PATH_MAX]; FILE * f; int res; #if 0 struct mbox_session_state_data * mbox_data; #endif struct mbox_cached_session_state_data * cached_data; int fd; MMAPString * mmapstr; size_t cur_token; struct mailmbox_folder * folder; /* expunge the mailbox */ #if 0 mbox_data = get_ancestor(session)->data; #endif folder = get_mbox_session(session); r = mailmbox_validate_write_lock(folder); if (r != MAILMBOX_NO_ERROR) { res = mbox_error_to_mail_error(r); goto err; } r = mailmbox_expunge_no_lock(folder); if (r != MAILMBOX_NO_ERROR) { res = r; goto unlock; } cached_data = get_cached_data(session); snprintf(filename, PATH_MAX, "%s%c%s%c%s", cached_data->mbox_flags_directory, MAIL_DIR_SEPARATOR, cached_data->mbox_quoted_mb, MAIL_DIR_SEPARATOR, FILENAME_MAX_UID); fd = creat(filename, S_IRUSR | S_IWUSR); if (fd < 0) { res = MAIL_ERROR_FILE; goto err; } f = fdopen(fd, "w"); if (f == NULL) { close(fd); res = MAIL_ERROR_FILE; goto unlock; } mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto close; } r = mail_serialize_clear(mmapstr, &cur_token); if (r != MAIL_NO_ERROR) { res = r; goto free_mmapstr; } r = mailimf_cache_int_write(mmapstr, &cur_token, folder->mb_written_uid); if (r != MAIL_NO_ERROR) { res = r; goto free_mmapstr; } fwrite(mmapstr->str, 1, mmapstr->len, f); mmap_string_free(mmapstr); fclose(f); mailmbox_write_unlock(folder); return MAIL_NO_ERROR; free_mmapstr: mmap_string_free(mmapstr); close: fclose(f); unlock: mailmbox_read_unlock(folder); err: return res; } static int read_max_uid_value(mailsession * session, uint32_t * result) { int r; char filename[PATH_MAX]; FILE * f; uint32_t written_uid; int res; struct mbox_cached_session_state_data * cached_data; MMAPString * mmapstr; size_t cur_token; char buf[sizeof(uint32_t)]; size_t read_size; cached_data = get_cached_data(session); snprintf(filename, PATH_MAX, "%s%c%s%c%s", cached_data->mbox_flags_directory, MAIL_DIR_SEPARATOR, cached_data->mbox_quoted_mb, MAIL_DIR_SEPARATOR, FILENAME_MAX_UID); f = fopen(filename, "r"); if (f == NULL) { res = MAIL_ERROR_FILE; goto err; } read_size = fread(buf, 1, sizeof(uint32_t), f); mmapstr = mmap_string_new_len(buf, read_size); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto close; } cur_token = 0; r = mailimf_cache_int_read(mmapstr, &cur_token, &written_uid); if (r != MAIL_NO_ERROR) { fclose(f); res = r; goto free_mmapstr; } mmap_string_free(mmapstr); fclose(f); * result = written_uid; return MAIL_NO_ERROR; free_mmapstr: mmap_string_free(mmapstr); close: fclose(f); err: return res; } static int mboxdriver_cached_connect_path(mailsession * session, char * path) { int r; int res; char * quoted_mb; struct mbox_cached_session_state_data * cached_data; struct mbox_session_state_data * ancestor_data; struct mailmbox_folder * folder; uint32_t written_uid; folder = get_mbox_session(session); if (folder != NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } r = get_cache_directory(session, path, "ed_mb); if (r != MAIL_NO_ERROR) { res = r; goto err; } cached_data = get_cached_data(session); free_state(cached_data); cached_data->mbox_quoted_mb = quoted_mb; written_uid = 0; r = read_max_uid_value(session, &written_uid); /* ignore errors */ ancestor_data = get_ancestor_data(session); r = mailmbox_init(path, ancestor_data->mbox_force_read_only, ancestor_data->mbox_force_no_uid, written_uid, &folder); if (r != MAILMBOX_NO_ERROR) { cached_data->mbox_quoted_mb = NULL; res = mboxdriver_mbox_error_to_mail_error(r); goto free; } ancestor_data->mbox_folder = folder; return MAIL_NO_ERROR; free: free(quoted_mb); err: return res; } static int mboxdriver_cached_logout(mailsession * session) { struct mbox_cached_session_state_data * cached_data; int r; r = write_max_uid_value(session); cached_data = get_cached_data(session); mbox_flags_store_process(cached_data->mbox_flags_directory, cached_data->mbox_quoted_mb, cached_data->mbox_flags_store); r = mailsession_logout(get_ancestor(session)); if (r != MAIL_NO_ERROR) return r; free_state(cached_data); return MAIL_NO_ERROR; } static int mboxdriver_cached_check_folder(mailsession * session) { struct mbox_cached_session_state_data * cached_data; cached_data = get_cached_data(session); mbox_flags_store_process(cached_data->mbox_flags_directory, cached_data->mbox_quoted_mb, cached_data->mbox_flags_store); return MAIL_NO_ERROR; } static int mboxdriver_cached_expunge_folder(mailsession * session) { struct mailmbox_folder * folder; int res; char filename_flags[PATH_MAX]; struct mail_cache_db * cache_db_flags; MMAPString * mmapstr; struct mbox_cached_session_state_data * data; int r; unsigned int i; folder = get_mbox_session(session); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } data = get_cached_data(session); if (data->mbox_quoted_mb == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } mbox_flags_store_process(data->mbox_flags_directory, data->mbox_quoted_mb, data->mbox_flags_store); snprintf(filename_flags, PATH_MAX, "%s%c%s%c%s", data->mbox_flags_directory, MAIL_DIR_SEPARATOR, data->mbox_quoted_mb, MAIL_DIR_SEPARATOR, FLAGS_NAME); r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_FILE; goto err; } mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto close_db_flags; } for(i = 0 ; i < carray_count(folder->mb_tab) ; i ++) { struct mailmbox_msg_info * msg_info; struct mail_flags * flags; msg_info = carray_get(folder->mb_tab, i); if (msg_info == NULL) continue; if (msg_info->msg_deleted) continue; r = mboxdriver_get_cached_flags(cache_db_flags, mmapstr, session, msg_info->msg_uid, &flags); if (r != MAIL_NO_ERROR) continue; if (flags->fl_flags & MAIL_FLAG_DELETED) { r = mailmbox_delete_msg(folder, msg_info->msg_uid); } mail_flags_free(flags); } mmap_string_free(mmapstr); mail_cache_db_close_unlock(filename_flags, cache_db_flags); r = mailmbox_expunge(folder); return MAIL_NO_ERROR; close_db_flags: mail_cache_db_close_unlock(filename_flags, cache_db_flags); err: return res; } static int mboxdriver_cached_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { struct mailmbox_folder * folder; int res; char filename_flags[PATH_MAX]; struct mail_cache_db * cache_db_flags; MMAPString * mmapstr; struct mbox_cached_session_state_data * data; int r; unsigned int i; uint32_t recent; uint32_t unseen; uint32_t num; num = 0; recent = 0; unseen = 0; folder = get_mbox_session(session); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } data = get_cached_data(session); if (data->mbox_quoted_mb == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } r = mailmbox_validate_read_lock(folder); if (r != MAIL_NO_ERROR) { res = MAIL_ERROR_BAD_STATE; goto err; } mailmbox_read_unlock(folder); mbox_flags_store_process(data->mbox_flags_directory, data->mbox_quoted_mb, data->mbox_flags_store); snprintf(filename_flags, PATH_MAX, "%s%c%s%c%s", data->mbox_flags_directory, MAIL_DIR_SEPARATOR, data->mbox_quoted_mb, MAIL_DIR_SEPARATOR, FLAGS_NAME); r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_FILE; goto err; } mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto close_db_flags; } for(i = 0 ; i < carray_count(folder->mb_tab) ; i ++) { struct mailmbox_msg_info * msg_info; struct mail_flags * flags; msg_info = carray_get(folder->mb_tab, i); if (msg_info == NULL) continue; if (msg_info->msg_deleted) continue; r = mboxdriver_get_cached_flags(cache_db_flags, mmapstr, session, msg_info->msg_uid, &flags); if (r != MAIL_NO_ERROR) { recent ++; unseen ++; num ++; continue; } if ((flags->fl_flags & MAIL_FLAG_NEW) != 0) { recent ++; } if ((flags->fl_flags & MAIL_FLAG_SEEN) == 0) { unseen ++; } num ++; mail_flags_free(flags); } mmap_string_free(mmapstr); mail_cache_db_close_unlock(filename_flags, cache_db_flags); * result_messages = num; * result_recent = recent; * result_unseen = unseen; return MAIL_NO_ERROR; close_db_flags: mail_cache_db_close_unlock(filename_flags, cache_db_flags); err: return res; } static int mboxdriver_cached_messages_number(mailsession * session, char * mb, uint32_t * result) { return mailsession_messages_number(get_ancestor(session), mb, result); } static int mboxdriver_cached_recent_number(mailsession * session, char * mb, uint32_t * result) { uint32_t messages; uint32_t recent; uint32_t unseen; int r; r = mboxdriver_cached_status_folder(session, mb, &messages, &recent, &unseen); if (r != MAIL_NO_ERROR) return r; * result = recent; return MAIL_NO_ERROR; } static int mboxdriver_cached_unseen_number(mailsession * session, char * mb, uint32_t * result) { uint32_t messages; uint32_t recent; uint32_t unseen; int r; r = mboxdriver_cached_status_folder(session, mb, &messages, &recent, &unseen); if (r != MAIL_NO_ERROR) return r; * result = unseen; return MAIL_NO_ERROR; } /* messages operations */ static int mboxdriver_cached_append_message(mailsession * session, char * message, size_t size) { - return mailsession_append_message(get_ancestor(session), message, size); + return mboxdriver_cached_append_message_flags(session, + message, size, NULL); +} + +static int mboxdriver_cached_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags) +{ + int r; + struct mailmbox_folder * folder; + struct mbox_cached_session_state_data * data; + unsigned int uid; + struct mailmbox_msg_info * msg_info; + chashdatum key; + chashdatum value; + struct mail_cache_db * cache_db_flags; + char filename_flags[PATH_MAX]; + MMAPString * mmapstr; + char keyname[PATH_MAX]; + + folder = get_mbox_session(session); + if (folder == NULL) + return MAIL_ERROR_APPEND; + + r = mailmbox_append_message_uid(folder, message, size, &uid); + + switch (r) { + case MAILMBOX_ERROR_FILE: + return MAIL_ERROR_DISKSPACE; + case MAILMBOX_NO_ERROR: + break; + default: + return mboxdriver_mbox_error_to_mail_error(r); + } + + /* could store in flags store instead */ + + if (flags == NULL) + goto exit; + + key.data = &uid; + key.len = sizeof(uid); + r = chash_get(folder->mb_hash, &key, &value); + if (r < 0) + goto exit; + + msg_info = value.data; + + data = get_cached_data(session); + + snprintf(filename_flags, PATH_MAX, "%s%c%s%c%s", + data->mbox_flags_directory, MAIL_DIR_SEPARATOR, data->mbox_quoted_mb, + MAIL_DIR_SEPARATOR, FLAGS_NAME); + + r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); + if (r < 0) + goto exit; + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) + goto close_db_flags; + + snprintf(keyname, PATH_MAX, "%u-%lu", uid, + (unsigned long) msg_info->msg_body_len); + + r = mboxdriver_write_cached_flags(cache_db_flags, mmapstr, keyname, flags); + + mmap_string_free(mmapstr); + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + + if (r != MAIL_NO_ERROR) + goto exit; + + return MAIL_NO_ERROR; + + close_db_flags: + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + exit: + return MAIL_NO_ERROR; } static int mboxdriver_cached_get_messages_list(mailsession * session, struct mailmessage_list ** result) { struct mailmbox_folder * folder; int res; folder = get_mbox_session(session); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } return mbox_get_uid_messages_list(folder, session, mbox_cached_message_driver, result); err: return res; } static int get_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr, mailsession * session, uint32_t num, struct mailimf_fields ** result) { int r; char keyname[PATH_MAX]; struct mailimf_fields * fields; int res; struct mailmbox_msg_info * info; struct mailmbox_folder * folder; chashdatum key; chashdatum data; folder = get_mbox_session(session); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } key.data = # key.len = sizeof(num); r = chash_get(folder->mb_hash, &key, &data); if (r < 0) { res = MAIL_ERROR_MSG_NOT_FOUND; goto err; } info = data.data; - snprintf(keyname, PATH_MAX, "%u-%u-envelope", num, info->msg_body_len); + snprintf(keyname, PATH_MAX, "%u-%lu-envelope", num, + (unsigned long) info->msg_body_len); r = generic_cache_fields_read(cache_db, mmapstr, keyname, &fields); if (r != MAIL_NO_ERROR) { res = r; goto err; } * result = fields; return MAIL_NO_ERROR; err: return res; } static int write_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr, mailsession * session, uint32_t num, struct mailimf_fields * fields) { int r; char keyname[PATH_MAX]; int res; struct mailmbox_msg_info * info; struct mailmbox_folder * folder; chashdatum key; chashdatum data; folder = get_mbox_session(session); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } key.data = # key.len = sizeof(num); r = chash_get(folder->mb_hash, &key, &data); if (r < 0) { res = MAIL_ERROR_MSG_NOT_FOUND; goto err; } info = data.data; - snprintf(keyname, PATH_MAX, "%u-%u-envelope", num, info->msg_body_len); + snprintf(keyname, PATH_MAX, "%u-%lu-envelope", num, + (unsigned long) info->msg_body_len); r = generic_cache_fields_write(cache_db, mmapstr, keyname, fields); if (r != MAIL_NO_ERROR) { res = r; goto err; } return MAIL_NO_ERROR; err: return res; } static int mboxdriver_cached_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list) { int r; unsigned int i; struct mbox_cached_session_state_data * cached_data; char filename_env[PATH_MAX]; char filename_flags[PATH_MAX]; struct mail_cache_db * cache_db_env; struct mail_cache_db * cache_db_flags; MMAPString * mmapstr; int res; struct mailmbox_folder * folder; folder = get_mbox_session(session); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } cached_data = get_cached_data(session); if (cached_data->mbox_quoted_mb == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } mbox_flags_store_process(cached_data->mbox_flags_directory, cached_data->mbox_quoted_mb, cached_data->mbox_flags_store); mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto err; } snprintf(filename_env, PATH_MAX, "%s%c%s%c%s", cached_data->mbox_cache_directory, MAIL_DIR_SEPARATOR, cached_data->mbox_quoted_mb, MAIL_DIR_SEPARATOR, ENV_NAME); r = mail_cache_db_open_lock(filename_env, &cache_db_env); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_mmapstr; } snprintf(filename_flags, PATH_MAX, "%s%c%s%c%s", cached_data->mbox_flags_directory, MAIL_DIR_SEPARATOR, cached_data->mbox_quoted_mb, MAIL_DIR_SEPARATOR, FLAGS_NAME); r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_FILE; goto close_db_env; } /* fill with cached */ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; struct mailimf_fields * fields; struct mail_flags * flags; msg = carray_get(env_list->msg_tab, i); if (msg->msg_fields == NULL) { r = get_cached_envelope(cache_db_env, mmapstr, session, msg->msg_index, &fields); if (r == MAIL_NO_ERROR) { msg->msg_cached = TRUE; msg->msg_fields = fields; } } if (msg->msg_flags == NULL) { r = mboxdriver_get_cached_flags(cache_db_flags, mmapstr, session, msg->msg_index, &flags); if (r == MAIL_NO_ERROR) { msg->msg_flags = flags; } } } mail_cache_db_close_unlock(filename_flags, cache_db_flags); mail_cache_db_close_unlock(filename_env, cache_db_env); r = mailsession_get_envelopes_list(get_ancestor(session), env_list); if (r != MAIL_NO_ERROR) { res = r; goto free_mmapstr; } /* add flags */ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; msg = carray_get(env_list->msg_tab, i); if (msg->msg_flags == NULL) msg->msg_flags = mail_flags_new_empty(); } r = mail_cache_db_open_lock(filename_env, &cache_db_env); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_mmapstr; } r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_FILE; goto close_db_env; } /* must write cache */ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; msg = carray_get(env_list->msg_tab, i); if (msg->msg_fields != NULL) { if (!msg->msg_cached) { /* msg->msg_index is the numerical UID of the message */ r = write_cached_envelope(cache_db_env, mmapstr, session, msg->msg_index, msg->msg_fields); } } if (msg->msg_flags != NULL) { r = mboxdriver_write_cached_flags(cache_db_flags, mmapstr, msg->msg_uid, msg->msg_flags); } } /* flush cache */ maildriver_cache_clean_up(cache_db_env, cache_db_flags, env_list); mail_cache_db_close_unlock(filename_flags, cache_db_flags); mail_cache_db_close_unlock(filename_env, cache_db_env); mmap_string_free(mmapstr); return MAIL_NO_ERROR; close_db_env: mail_cache_db_close_unlock(filename_env, cache_db_env); free_mmapstr: mmap_string_free(mmapstr); err: return res; } static int mboxdriver_cached_remove_message(mailsession * session, uint32_t num) { return mailsession_remove_message(get_ancestor(session), num); } static int mboxdriver_cached_get_message(mailsession * session, uint32_t num, mailmessage ** result) { mailmessage * msg_info; int r; msg_info = mailmessage_new(); if (msg_info == NULL) return MAIL_ERROR_MEMORY; r = mailmessage_init(msg_info, session, mbox_cached_message_driver, num, 0); if (r != MAIL_NO_ERROR) { mailmessage_free(msg_info); return r; } * result = msg_info; return MAIL_NO_ERROR; } static int mboxdriver_cached_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result) { uint32_t num; char * p; chashdatum key; chashdatum data; struct mailmbox_msg_info * info; struct mailmbox_folder * folder; int r; if (uid == NULL) return MAIL_ERROR_INVAL; num = strtoul(uid, &p, 10); if (p == uid || * p != '-') return MAIL_ERROR_INVAL; folder = get_mbox_session(session); if (folder == NULL) return MAIL_ERROR_BAD_STATE; key.data = # key.len = sizeof(num); r = chash_get(folder->mb_hash, &key, &data); if (r == 0) { char * body_len_p = p + 1; size_t body_len; info = data.data; /* Check if the cached message has the same UID */ body_len = strtoul(body_len_p, &p, 10); if (p == body_len_p || * p != '\0') return MAIL_ERROR_INVAL; if (body_len == info->msg_body_len) return mboxdriver_cached_get_message(session, num, result); } return MAIL_ERROR_MSG_NOT_FOUND; } diff --git a/kmicromail/libetpan/generic/mboxdriver_cached_message.c b/kmicromail/libetpan/generic/mboxdriver_cached_message.c index 6d92b22..828396b 100644 --- a/kmicromail/libetpan/generic/mboxdriver_cached_message.c +++ b/kmicromail/libetpan/generic/mboxdriver_cached_message.c @@ -1,360 +1,361 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "mboxdriver_cached_message.h" #include "mailmessage_tools.h" #include "mboxdriver_tools.h" #include "mboxdriver_cached.h" #include "mboxdriver.h" #include "mailmbox.h" #include "mail_cache_db.h" #include "generic_cache.h" #include <unistd.h> #include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <stdlib.h> static int mbox_prefetch(mailmessage * msg_info); static void mbox_prefetch_free(struct generic_message_t * msg); static int mbox_initialize(mailmessage * msg_info); static void mbox_uninitialize(mailmessage * msg_info); static void mbox_flush(mailmessage * msg_info); static void mbox_check(mailmessage * msg_info); static int mbox_fetch_size(mailmessage * msg_info, size_t * result); static int mbox_get_flags(mailmessage * msg_info, struct mail_flags ** result); static int mbox_fetch_header(mailmessage * msg_info, char ** result, size_t * result_len); static mailmessage_driver local_mbox_cached_message_driver = { .msg_name = "mbox-cached", .msg_initialize = mbox_initialize, .msg_uninitialize = mbox_uninitialize, .msg_flush = mbox_flush, .msg_check = mbox_check, .msg_fetch_result_free = mailmessage_generic_fetch_result_free, .msg_fetch = mailmessage_generic_fetch, .msg_fetch_header = mbox_fetch_header, .msg_fetch_body = mailmessage_generic_fetch_body, .msg_fetch_size = mbox_fetch_size, .msg_get_bodystructure = mailmessage_generic_get_bodystructure, .msg_fetch_section = mailmessage_generic_fetch_section, .msg_fetch_section_header = mailmessage_generic_fetch_section_header, .msg_fetch_section_mime = mailmessage_generic_fetch_section_mime, .msg_fetch_section_body = mailmessage_generic_fetch_section_body, .msg_fetch_envelope = mailmessage_generic_fetch_envelope, .msg_get_flags = mbox_get_flags, }; mailmessage_driver * mbox_cached_message_driver = &local_mbox_cached_message_driver; static inline struct mbox_cached_session_state_data * get_cached_session_data(mailmessage * msg) { return msg->msg_session->sess_data; } static inline mailsession * get_ancestor_session(mailmessage * msg) { return get_cached_session_data(msg)->mbox_ancestor; } static inline struct mbox_session_state_data * get_ancestor_session_data(mailmessage * msg) { return get_ancestor_session(msg)->sess_data; } static inline struct mailmbox_folder * get_mbox_session(mailmessage * msg) { return get_ancestor_session_data(msg)->mbox_folder; } static int mbox_prefetch(mailmessage * msg_info) { struct generic_message_t * msg; int r; char * msg_content; size_t msg_length; r = mboxdriver_fetch_msg(get_ancestor_session(msg_info), msg_info->msg_index, &msg_content, &msg_length); if (r != MAIL_NO_ERROR) return r; msg = msg_info->msg_data; msg->msg_message = msg_content; msg->msg_length = msg_length; return MAIL_NO_ERROR; } static void mbox_prefetch_free(struct generic_message_t * msg) { if (msg->msg_message != NULL) { mmap_string_unref(msg->msg_message); msg->msg_message = NULL; } } static int mbox_initialize(mailmessage * msg_info) { struct generic_message_t * msg; int r; char * uid; char static_uid[PATH_MAX]; struct mailmbox_msg_info * info; struct mailmbox_folder * folder; int res; chashdatum key; chashdatum data; folder = get_mbox_session(msg_info); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } key.data = (char *) &msg_info->msg_index; key.len = sizeof(msg_info->msg_index); r = chash_get(folder->mb_hash, &key, &data); if (r < 0) { res = MAIL_ERROR_MSG_NOT_FOUND; goto err; } info = (struct mailmbox_msg_info *) data.data; - snprintf(static_uid, PATH_MAX, "%u-%u", msg_info->msg_index, info->msg_body_len); + snprintf(static_uid, PATH_MAX, "%u-%lu", + msg_info->msg_index, (unsigned long) info->msg_body_len); uid = strdup(static_uid); if (uid == NULL) { res = MAIL_ERROR_MEMORY; goto err; } r = mailmessage_generic_initialize(msg_info); if (r != MAIL_NO_ERROR) { free(uid); res = r; goto err; } msg = msg_info->msg_data; msg->msg_prefetch = mbox_prefetch; msg->msg_prefetch_free = mbox_prefetch_free; msg_info->msg_uid = uid; return MAIL_NO_ERROR; err: return res; } static void mbox_uninitialize(mailmessage * msg_info) { mailmessage_generic_uninitialize(msg_info); } #define FLAGS_NAME "flags.db" static void mbox_flush(mailmessage * msg_info) { mailmessage_generic_flush(msg_info); } static void mbox_check(mailmessage * msg_info) { int r; if (msg_info->msg_flags != NULL) { r = mail_flags_store_set(get_cached_session_data(msg_info)->mbox_flags_store, msg_info); /* ignore errors */ } } static int mbox_fetch_size(mailmessage * msg_info, size_t * result) { int r; size_t size; r = mboxdriver_fetch_size(get_ancestor_session(msg_info), msg_info->msg_index, &size); if (r != MAIL_NO_ERROR) return r; * result = size; return MAIL_NO_ERROR; } static int mbox_get_flags(mailmessage * msg_info, struct mail_flags ** result) { int r; struct mail_flags * flags; struct mail_cache_db * cache_db_flags; char filename_flags[PATH_MAX]; int res; struct mbox_cached_session_state_data * cached_data; MMAPString * mmapstr; struct mailmbox_folder * folder; if (msg_info->msg_flags != NULL) { * result = msg_info->msg_flags; return MAIL_NO_ERROR; } flags = mail_flags_store_get(get_cached_session_data(msg_info)->mbox_flags_store, msg_info->msg_index); if (flags == NULL) { folder = get_mbox_session(msg_info); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } cached_data = get_cached_session_data(msg_info); if (cached_data->mbox_quoted_mb == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } snprintf(filename_flags, PATH_MAX, "%s/%s/%s", cached_data->mbox_flags_directory, cached_data->mbox_quoted_mb, FLAGS_NAME); r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_MEMORY; goto err; } mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto close_db_flags; } if (msg_info->msg_index > folder->mb_written_uid) { flags = mail_flags_new_empty(); } else { r = mboxdriver_get_cached_flags(cache_db_flags, mmapstr, msg_info->msg_session, msg_info->msg_index, &flags); if (r != MAIL_NO_ERROR) { flags = mail_flags_new_empty(); if (flags == NULL) { res = MAIL_ERROR_MEMORY; goto free_mmapstr; } } } mmap_string_free(mmapstr); mail_cache_db_close_unlock(filename_flags, cache_db_flags); } msg_info->msg_flags = flags; * result = flags; return MAIL_NO_ERROR; free_mmapstr: mmap_string_free(mmapstr); close_db_flags: mail_cache_db_close_unlock(filename_flags, cache_db_flags); err: return res; } static int mbox_fetch_header(mailmessage * msg_info, char ** result, size_t * result_len) { struct generic_message_t * msg; int r; char * msg_content; size_t msg_length; msg = msg_info->msg_data; if (msg->msg_message != NULL) { return mailmessage_generic_fetch_header(msg_info, result, result_len); } else { r = mboxdriver_fetch_header(get_ancestor_session(msg_info), msg_info->msg_index, &msg_content, &msg_length); if (r != MAIL_NO_ERROR) return r; * result = msg_content; * result_len = msg_length; return MAIL_NO_ERROR; } } diff --git a/kmicromail/libetpan/generic/mboxdriver_message.c b/kmicromail/libetpan/generic/mboxdriver_message.c index da9a65d..6922625 100644 --- a/kmicromail/libetpan/generic/mboxdriver_message.c +++ b/kmicromail/libetpan/generic/mboxdriver_message.c @@ -1,225 +1,225 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ -#include "mhdriver_message.h" +#include "mboxdriver_message.h" #include "mailmessage_tools.h" #include "mboxdriver_tools.h" #include "mboxdriver.h" #include "mailmbox.h" #include <unistd.h> #include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <stdlib.h> static int mbox_prefetch(mailmessage * msg_info); static void mbox_prefetch_free(struct generic_message_t * msg); static int mbox_initialize(mailmessage * msg_info); static int mbox_fetch_size(mailmessage * msg_info, size_t * result); static int mbox_fetch_header(mailmessage * msg_info, char ** result, size_t * result_len); static mailmessage_driver local_mbox_message_driver = { .msg_name = "mbox", .msg_initialize = mbox_initialize, .msg_uninitialize = mailmessage_generic_uninitialize, .msg_flush = mailmessage_generic_flush, .msg_check = NULL, .msg_fetch_result_free = mailmessage_generic_fetch_result_free, .msg_fetch = mailmessage_generic_fetch, .msg_fetch_header = mbox_fetch_header, .msg_fetch_body = mailmessage_generic_fetch_body, .msg_fetch_size = mbox_fetch_size, .msg_get_bodystructure = mailmessage_generic_get_bodystructure, .msg_fetch_section = mailmessage_generic_fetch_section, .msg_fetch_section_header = mailmessage_generic_fetch_section_header, .msg_fetch_section_mime = mailmessage_generic_fetch_section_mime, .msg_fetch_section_body = mailmessage_generic_fetch_section_body, .msg_fetch_envelope = mailmessage_generic_fetch_envelope, .msg_get_flags = NULL, }; mailmessage_driver * mbox_message_driver = &local_mbox_message_driver; static inline struct mbox_session_state_data * get_data(mailmessage * msg) { return msg->msg_session->sess_data; } static inline struct mailmbox_folder * get_mbox_session(mailmessage * msg) { return get_data(msg)->mbox_folder; } static int mbox_prefetch(mailmessage * msg_info) { struct generic_message_t * msg; int r; char * msg_content; size_t msg_length; r = mboxdriver_fetch_msg(msg_info->msg_session, msg_info->msg_index, &msg_content, &msg_length); if (r != MAIL_NO_ERROR) return r; msg = msg_info->msg_data; msg->msg_message = msg_content; msg->msg_length = msg_length; return MAIL_NO_ERROR; } static void mbox_prefetch_free(struct generic_message_t * msg) { if (msg->msg_message != NULL) { mmap_string_unref(msg->msg_message); msg->msg_message = NULL; } } static int mbox_initialize(mailmessage * msg_info) { struct generic_message_t * msg; int r; char * uid; char static_uid[PATH_MAX]; struct mailmbox_msg_info * info; struct mailmbox_folder * folder; int res; chashdatum key; chashdatum data; folder = get_mbox_session(msg_info); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } key.data = &msg_info->msg_index; key.len = sizeof(msg_info->msg_index); r = chash_get(folder->mb_hash, &key, &data); if (r < 0) { res = MAIL_ERROR_MSG_NOT_FOUND; goto err; } info = data.data; - snprintf(static_uid, PATH_MAX, "%u-%u", - msg_info->msg_index, info->msg_body_len); + snprintf(static_uid, PATH_MAX, "%u-%lu", + msg_info->msg_index, (unsigned long) info->msg_body_len); uid = strdup(static_uid); if (uid == NULL) { res = MAIL_ERROR_MEMORY; goto err; } r = mailmessage_generic_initialize(msg_info); if (r != MAIL_NO_ERROR) { free(uid); res = r; goto err; } msg = msg_info->msg_data; msg->msg_prefetch = mbox_prefetch; msg->msg_prefetch_free = mbox_prefetch_free; msg_info->msg_uid = uid; return MAIL_NO_ERROR; err: return res; } static int mbox_fetch_size(mailmessage * msg_info, size_t * result) { int r; size_t size; r = mboxdriver_fetch_size(msg_info->msg_session, msg_info->msg_index, &size); if (r != MAIL_NO_ERROR) return r; * result = size; return MAIL_NO_ERROR; } static int mbox_fetch_header(mailmessage * msg_info, char ** result, size_t * result_len) { struct generic_message_t * msg; int r; char * msg_content; size_t msg_length; msg = msg_info->msg_data; if (msg->msg_message != NULL) { return mailmessage_generic_fetch_header(msg_info, result, result_len); } else { r = mboxdriver_fetch_header(msg_info->msg_session, msg_info->msg_index, &msg_content, &msg_length); if (r != MAIL_NO_ERROR) return r; * result = msg_content; * result_len = msg_length; return MAIL_NO_ERROR; } } diff --git a/kmicromail/libetpan/generic/mboxdriver_tools.c b/kmicromail/libetpan/generic/mboxdriver_tools.c index 1e27798..252a20b 100644 --- a/kmicromail/libetpan/generic/mboxdriver_tools.c +++ b/kmicromail/libetpan/generic/mboxdriver_tools.c @@ -1,434 +1,435 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "mboxdriver_tools.h" #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include "maildriver_types.h" #include "mailmbox.h" #include "mboxdriver_cached.h" #include "mboxdriver.h" #include "generic_cache.h" #include "mailmessage.h" #include "imfcache.h" #include "mail_cache_db.h" static inline struct mbox_session_state_data * session_get_data(mailsession * session) { return session->sess_data; } static inline struct mailmbox_folder * session_get_mbox_session(mailsession * session) { return session_get_data(session)->mbox_folder; } static inline struct mbox_cached_session_state_data * cached_session_get_data(mailsession * session) { return session->sess_data; } static inline mailsession * cached_session_get_ancestor(mailsession * session) { return cached_session_get_data(session)->mbox_ancestor; } static inline struct mbox_session_state_data * cached_session_get_ancestor_data(mailsession * session) { return cached_session_get_ancestor(session)->sess_data; } static inline struct mailmbox_folder * cached_session_get_mbox_session(mailsession * session) { return session_get_mbox_session(cached_session_get_ancestor(session)); } int mboxdriver_mbox_error_to_mail_error(int error) { switch (error) { case MAILMBOX_NO_ERROR: return MAIL_NO_ERROR; case MAILMBOX_ERROR_PARSE: return MAIL_ERROR_PARSE; case MAILMBOX_ERROR_INVAL: return MAIL_ERROR_INVAL; case MAILMBOX_ERROR_FILE_NOT_FOUND: return MAIL_ERROR_PARSE; case MAILMBOX_ERROR_MEMORY: return MAIL_ERROR_MEMORY; case MAILMBOX_ERROR_TEMPORARY_FILE: return MAIL_ERROR_PARSE; case MAILMBOX_ERROR_FILE: return MAIL_ERROR_FILE; case MAILMBOX_ERROR_MSG_NOT_FOUND: return MAIL_ERROR_MSG_NOT_FOUND; case MAILMBOX_ERROR_READONLY: return MAIL_ERROR_READONLY; default: return MAIL_ERROR_INVAL; } } int mboxdriver_fetch_msg(mailsession * session, uint32_t index, char ** result, size_t * result_len) { int r; char * msg_content; size_t msg_length; struct mailmbox_folder * folder; folder = session_get_mbox_session(session); if (folder == NULL) return MAIL_ERROR_BAD_STATE; r = mailmbox_fetch_msg(folder, index, &msg_content, &msg_length); if (r != MAILMBOX_NO_ERROR) return mboxdriver_mbox_error_to_mail_error(r); * result = msg_content; * result_len = msg_length; return MAIL_NO_ERROR; } int mboxdriver_fetch_size(mailsession * session, uint32_t index, size_t * result) { struct mailmbox_folder * folder; int r; char * data; size_t len; int res; folder = session_get_mbox_session(session); if (folder == NULL) { res = MAIL_ERROR_FETCH; goto err; } r = mailmbox_validate_read_lock(folder); if (r != MAILMBOX_NO_ERROR) { res = mboxdriver_mbox_error_to_mail_error(r); goto err; } r = mailmbox_fetch_msg_no_lock(folder, index, &data, &len); if (r != MAILMBOX_NO_ERROR) { res = mboxdriver_mbox_error_to_mail_error(r); goto unlock; } mailmbox_read_unlock(folder); * result = len; return MAIL_NO_ERROR; unlock: mailmbox_read_unlock(folder); err: return res; } int mboxdriver_get_cached_flags(struct mail_cache_db * cache_db, MMAPString * mmapstr, mailsession * session, uint32_t num, struct mail_flags ** result) { int r; char keyname[PATH_MAX]; struct mail_flags * flags; int res; struct mailmbox_msg_info * info; struct mailmbox_folder * folder; chashdatum key; chashdatum data; folder = cached_session_get_mbox_session(session); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } key.data = # key.len = sizeof(num); r = chash_get(folder->mb_hash, &key, &data); if (r < 0) { res = MAIL_ERROR_MSG_NOT_FOUND; goto err; } info = data.data; - snprintf(keyname, PATH_MAX, "%u-%u-flags", num, info->msg_body_len); + snprintf(keyname, PATH_MAX, "%u-%lu-flags", num, + (unsigned long) info->msg_body_len); r = generic_cache_flags_read(cache_db, mmapstr, keyname, &flags); if (r != MAIL_NO_ERROR) { res = r; goto err; } * result = flags; return MAIL_NO_ERROR; err: return res; } int mboxdriver_write_cached_flags(struct mail_cache_db * cache_db, MMAPString * mmapstr, char * uid, struct mail_flags * flags) { int r; char keyname[PATH_MAX]; int res; snprintf(keyname, PATH_MAX, "%s-flags", uid); r = generic_cache_flags_write(cache_db, mmapstr, keyname, flags); if (r != MAIL_NO_ERROR) { res = r; goto err; } return MAIL_NO_ERROR; err: return res; } int mboxdriver_fetch_header(mailsession * session, uint32_t index, char ** result, size_t * result_len) { int r; char * msg_content; size_t msg_length; struct mailmbox_folder * folder; folder = session_get_mbox_session(session); if (folder == NULL) return MAIL_ERROR_BAD_STATE; r = mailmbox_fetch_msg_headers(folder, index, &msg_content, &msg_length); if (r != MAILMBOX_NO_ERROR) return mboxdriver_mbox_error_to_mail_error(r); * result = msg_content; * result_len = msg_length; return MAIL_NO_ERROR; } int mbox_get_locked_messages_list(struct mailmbox_folder * folder, mailsession * session, mailmessage_driver * driver, int (* lock)(struct mailmbox_folder *), int (* unlock)(struct mailmbox_folder *), struct mailmessage_list ** result) { struct mailmessage_list * env_list; unsigned int i; int r; int res; carray * tab; tab = carray_new(128); if (tab == NULL) { res = MAIL_ERROR_MEMORY; goto err; } r = lock(folder); if (r != MAIL_NO_ERROR) { res = r; goto free; } for(i = 0 ; i < carray_count(folder->mb_tab) ; i ++) { struct mailmbox_msg_info * msg_info; mailmessage * msg; msg_info = carray_get(folder->mb_tab, i); if (msg_info == NULL) continue; if (msg_info->msg_deleted) continue; msg = mailmessage_new(); if (msg == NULL) { res = MAIL_ERROR_MEMORY; goto unlock; } r = mailmessage_init(msg, session, driver, msg_info->msg_uid, msg_info->msg_size - msg_info->msg_start_len); if (r != MAIL_NO_ERROR) { res = r; goto unlock; } r = carray_add(tab, msg, NULL); if (r < 0) { mailmessage_free(msg); res = MAIL_ERROR_MEMORY; goto unlock; } } env_list = mailmessage_list_new(tab); if (env_list == NULL) { res = MAIL_ERROR_MEMORY; goto unlock; } unlock(folder); * result = env_list; return MAIL_NO_ERROR; unlock: unlock(folder); free: for(i = 0 ; i < carray_count(tab) ; i ++) mailmessage_free(carray_get(tab, i)); carray_free(tab); err: return res; } static int release_read_mbox(struct mailmbox_folder * folder) { int r; r = mailmbox_read_unlock(folder); return mboxdriver_mbox_error_to_mail_error(r); } static int acquire_read_mbox(struct mailmbox_folder * folder) { int r; r = mailmbox_validate_read_lock(folder); return mboxdriver_mbox_error_to_mail_error(r); } static int release_write_mbox(struct mailmbox_folder * folder) { int r; r = mailmbox_write_unlock(folder); return mboxdriver_mbox_error_to_mail_error(r); } static int acquire_write_mbox(struct mailmbox_folder * folder) { int r; int res; r = mailmbox_validate_write_lock(folder); if (r != MAILMBOX_NO_ERROR) { res = mboxdriver_mbox_error_to_mail_error(r); goto err; } if (folder->mb_written_uid < folder->mb_max_uid) { r = mailmbox_expunge_no_lock(folder); if (r != MAILMBOX_NO_ERROR) { res = mboxdriver_mbox_error_to_mail_error(r); goto unlock; } } return MAIL_NO_ERROR; unlock: mailmbox_write_unlock(folder); err: return res; } /* get message list with all valid written UID */ int mbox_get_uid_messages_list(struct mailmbox_folder * folder, mailsession * session, mailmessage_driver * driver, struct mailmessage_list ** result) { return mbox_get_locked_messages_list(folder, session, driver, acquire_write_mbox, release_write_mbox, result); } /* get message list */ int mbox_get_messages_list(struct mailmbox_folder * folder, mailsession * session, mailmessage_driver * driver, struct mailmessage_list ** result) { return mbox_get_locked_messages_list(folder, session, driver, acquire_read_mbox, release_read_mbox, result); } diff --git a/kmicromail/libetpan/generic/mboxstorage.c b/kmicromail/libetpan/generic/mboxstorage.c index 0a7dc93..4b55b2b 100644 --- a/kmicromail/libetpan/generic/mboxstorage.c +++ b/kmicromail/libetpan/generic/mboxstorage.c @@ -1,192 +1,192 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "mboxstorage.h" #include "mail.h" #include "mailmessage.h" #include "mboxdriver.h" #include "mboxdriver_cached.h" #include "maildriver.h" #include <stdlib.h> #include <string.h> /* mbox storage */ static int mbox_mailstorage_connect(struct mailstorage * storage); static int mbox_mailstorage_get_folder_session(struct mailstorage * storage, char * pathname, mailsession ** result); static void mbox_mailstorage_uninitialize(struct mailstorage * storage); static mailstorage_driver mbox_mailstorage_driver = { .sto_name = "mbox", .sto_connect = mbox_mailstorage_connect, .sto_get_folder_session = mbox_mailstorage_get_folder_session, .sto_uninitialize = mbox_mailstorage_uninitialize, }; int mbox_mailstorage_init(struct mailstorage * storage, char * mbox_pathname, int mbox_cached, char * mbox_cache_directory, char * mbox_flags_directory) { struct mbox_mailstorage * mbox_storage; - mbox_storage = malloc(sizeof(struct mbox_mailstorage)); + mbox_storage = malloc(sizeof(* mbox_storage)); if (mbox_storage == NULL) goto err; mbox_storage->mbox_pathname = strdup(mbox_pathname); if (mbox_storage->mbox_pathname == NULL) goto free; mbox_storage->mbox_cached = mbox_cached; if (mbox_cached && (mbox_cache_directory != NULL) && (mbox_flags_directory != NULL)) { mbox_storage->mbox_cache_directory = strdup(mbox_cache_directory); if (mbox_storage->mbox_cache_directory == NULL) goto free_pathname; mbox_storage->mbox_flags_directory = strdup(mbox_flags_directory); if (mbox_storage->mbox_flags_directory == NULL) goto free_cache_directory; } else { mbox_storage->mbox_cached = FALSE; mbox_storage->mbox_cache_directory = NULL; mbox_storage->mbox_flags_directory = NULL; } storage->sto_data = mbox_storage; storage->sto_driver = &mbox_mailstorage_driver; return MAIL_NO_ERROR; free_cache_directory: free(mbox_storage->mbox_cache_directory); free_pathname: free(mbox_storage->mbox_pathname); free: free(mbox_storage); err: return MAIL_ERROR_MEMORY; } static void mbox_mailstorage_uninitialize(struct mailstorage * storage) { struct mbox_mailstorage * mbox_storage; mbox_storage = storage->sto_data; if (mbox_storage->mbox_flags_directory != NULL) free(mbox_storage->mbox_flags_directory); if (mbox_storage->mbox_cache_directory != NULL) free(mbox_storage->mbox_cache_directory); free(mbox_storage->mbox_pathname); free(mbox_storage); storage->sto_data = NULL; } static int mbox_mailstorage_connect(struct mailstorage * storage) { struct mbox_mailstorage * mbox_storage; mailsession_driver * driver; int r; int res; mailsession * session; mbox_storage = storage->sto_data; if (mbox_storage->mbox_cached) driver = mbox_cached_session_driver; else driver = mbox_session_driver; session = mailsession_new(driver); if (session == NULL) { res = MAIL_ERROR_MEMORY; goto err; } if (mbox_storage->mbox_cached) { r = mailsession_parameters(session, MBOXDRIVER_CACHED_SET_CACHE_DIRECTORY, mbox_storage->mbox_cache_directory); if (r != MAIL_NO_ERROR) { res = r; goto free; } r = mailsession_parameters(session, MBOXDRIVER_CACHED_SET_FLAGS_DIRECTORY, mbox_storage->mbox_flags_directory); if (r != MAIL_NO_ERROR) { res = r; goto free; } } r = mailsession_connect_path(session, mbox_storage->mbox_pathname); switch (r) { case MAIL_NO_ERROR_NON_AUTHENTICATED: case MAIL_NO_ERROR_AUTHENTICATED: case MAIL_NO_ERROR: break; default: res = r; goto free; } storage->sto_session = session; return MAIL_NO_ERROR; free: mailsession_free(session); err: return res; } static int mbox_mailstorage_get_folder_session(struct mailstorage * storage, char * pathname, mailsession ** result) { * result = storage->sto_session; return MAIL_NO_ERROR; } diff --git a/kmicromail/libetpan/generic/mhdriver.c b/kmicromail/libetpan/generic/mhdriver.c index af38d27..05a6a4f 100644 --- a/kmicromail/libetpan/generic/mhdriver.c +++ b/kmicromail/libetpan/generic/mhdriver.c @@ -1,866 +1,875 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "mhdriver.h" #include <stdio.h> #include <sys/types.h> #include <dirent.h> #include <unistd.h> #include <sys/stat.h> #include <ctype.h> #include <fcntl.h> #include <sys/mman.h> #include <stdlib.h> #include <string.h> #include "mailmh.h" #include "maildriver_tools.h" #include "mhdriver_tools.h" #include "mhdriver_message.h" #include "mailmessage.h" static int mhdriver_initialize(mailsession * session); static void mhdriver_uninitialize(mailsession * session); static int mhdriver_connect_path(mailsession * session, char * path); static int mhdriver_logout(mailsession * session); static int mhdriver_build_folder_name(mailsession * session, char * mb, char * name, char ** result); static int mhdriver_create_folder(mailsession * session, char * mb); static int mhdriver_delete_folder(mailsession * session, char * mb); static int mhdriver_rename_folder(mailsession * session, char * mb, char * new_name); static int mhdriver_select_folder(mailsession * session, char * mb); static int mhdriver_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); static int mhdriver_messages_number(mailsession * session, char * mb, uint32_t * result); static int mhdriver_list_folders(mailsession * session, char * mb, struct mail_list ** result); static int mhdriver_lsub_folders(mailsession * session, char * mb, struct mail_list ** result); static int mhdriver_subscribe_folder(mailsession * session, char * mb); static int mhdriver_unsubscribe_folder(mailsession * session, char * mb); static int mhdriver_append_message(mailsession * session, char * message, size_t size); +static int mhdriver_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags); static int mhdriver_copy_message(mailsession * session, uint32_t num, char * mb); static int mhdriver_remove_message(mailsession * session, uint32_t num); static int mhdriver_move_message(mailsession * session, uint32_t num, char * mb); static int mhdriver_get_messages_list(mailsession * session, struct mailmessage_list ** result); static int mhdriver_get_message(mailsession * session, uint32_t num, mailmessage ** result); static int mhdriver_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result); static mailsession_driver local_mh_session_driver = { .sess_name = "mh", .sess_initialize = mhdriver_initialize, .sess_uninitialize = mhdriver_uninitialize, .sess_parameters = NULL, .sess_connect_stream = NULL, .sess_connect_path = mhdriver_connect_path, .sess_starttls = NULL, .sess_login = NULL, .sess_logout = mhdriver_logout, .sess_noop = NULL, .sess_build_folder_name = mhdriver_build_folder_name, .sess_create_folder = mhdriver_create_folder, .sess_delete_folder = mhdriver_delete_folder, .sess_rename_folder = mhdriver_rename_folder, .sess_check_folder = NULL, .sess_examine_folder = NULL, .sess_select_folder = mhdriver_select_folder, .sess_expunge_folder = NULL, .sess_status_folder = mhdriver_status_folder, .sess_messages_number = mhdriver_messages_number, .sess_recent_number = mhdriver_messages_number, .sess_unseen_number = mhdriver_messages_number, .sess_list_folders = mhdriver_list_folders, .sess_lsub_folders = mhdriver_lsub_folders, .sess_subscribe_folder = mhdriver_subscribe_folder, .sess_unsubscribe_folder = mhdriver_unsubscribe_folder, .sess_append_message = mhdriver_append_message, + .sess_append_message_flags = mhdriver_append_message_flags, .sess_copy_message = mhdriver_copy_message, .sess_move_message = mhdriver_move_message, .sess_get_messages_list = mhdriver_get_messages_list, .sess_get_envelopes_list = maildriver_generic_get_envelopes_list, .sess_remove_message = mhdriver_remove_message, #if 0 .sess_search_messages = maildriver_generic_search_messages, #endif .sess_get_message = mhdriver_get_message, .sess_get_message_by_uid = mhdriver_get_message_by_uid, }; mailsession_driver * mh_session_driver = &local_mh_session_driver; static inline struct mh_session_state_data * get_data(mailsession * session) { return session->sess_data; } static inline struct mailmh * get_mh_session(mailsession * session) { return get_data(session)->mh_session; } static inline struct mailmh_folder * get_mh_cur_folder(mailsession * session) { return get_data(session)->mh_cur_folder; } static int add_to_list(mailsession * session, char * mb) { char * new_mb; struct mh_session_state_data * data; int r; data = get_data(session); new_mb = strdup(mb); if (new_mb == NULL) return -1; r = clist_append(data->mh_subscribed_list, new_mb); if (r < 0) { free(mb); return -1; } return 0; } static int remove_from_list(mailsession * session, char * mb) { clistiter * cur; struct mh_session_state_data * data; data = get_data(session); for(cur = clist_begin(data->mh_subscribed_list) ; cur != NULL ; cur = clist_next(cur)) { char * cur_name; cur_name = clist_content(cur); if (strcmp(cur_name, mb) == 0) { clist_delete(data->mh_subscribed_list, cur); free(cur_name); return 0; } } return -1; } static int mhdriver_initialize(mailsession * session) { struct mh_session_state_data * data; data = malloc(sizeof(* data)); if (data == NULL) goto err; data->mh_session = NULL; data->mh_cur_folder = NULL; data->mh_subscribed_list = clist_new(); if (data->mh_subscribed_list == NULL) goto free; session->sess_data = data; return MAIL_NO_ERROR; free: free(data); err: return MAIL_ERROR_MEMORY; } static void mhdriver_uninitialize(mailsession * session) { struct mh_session_state_data * data; data = get_data(session); if (data->mh_session != NULL) mailmh_free(data->mh_session); clist_foreach(data->mh_subscribed_list, (clist_func) free, NULL); clist_free(data->mh_subscribed_list); free(data); session->sess_data = NULL; } static int mhdriver_connect_path(mailsession * session, char * path) { struct mailmh * mh; if (get_mh_session(session) != NULL) return MAIL_ERROR_BAD_STATE; mh = mailmh_new(path); if (mh == NULL) return MAIL_ERROR_MEMORY; get_data(session)->mh_session = mh; return MAIL_NO_ERROR; } static int mhdriver_logout(mailsession * session) { struct mailmh * mh; mh = get_mh_session(session); if (mh == NULL) return MAIL_ERROR_BAD_STATE; mailmh_free(mh); get_data(session)->mh_session = NULL; return MAIL_NO_ERROR; } /* folders operations */ static int mhdriver_build_folder_name(mailsession * session, char * mb, char * name, char ** result) { char * folder_name; folder_name = malloc(strlen(mb) + 2 + strlen(name)); if (folder_name == NULL) return MAIL_ERROR_MEMORY; strcpy(folder_name, mb); strcat(folder_name, "/"); strcat(folder_name, name); * result = folder_name; return MAIL_NO_ERROR; } static int get_parent(mailsession * session, char * mb, struct mailmh_folder ** result_folder, char ** result_name) { char * name; size_t length; int i; char * parent_name; struct mailmh_folder * parent; struct mailmh * mh; mh = get_mh_session(session); if (mh == NULL) return MAIL_ERROR_BAD_STATE; length = strlen(mb); for(i = length - 1 ; i >= 0 ; i--) if (mb[i] == '/') break; name = mb + i + 1; parent_name = malloc(i + 1); /* strndup(mb, i) */ if (parent_name == NULL) return MAIL_ERROR_MEMORY; strncpy(parent_name, mb, i); parent_name[i] = '\0'; parent = mailmh_folder_find(mh->mh_main, parent_name); free(parent_name); if (parent == NULL) return MAIL_ERROR_FOLDER_NOT_FOUND; * result_folder = parent; * result_name = name; return MAIL_NO_ERROR; } static int mhdriver_create_folder(mailsession * session, char * mb) { int r; struct mailmh_folder * parent; char * name; r = get_parent(session, mb, &parent, &name); if (r != MAIL_NO_ERROR) return r; r = mailmh_folder_add_subfolder(parent, name); return mhdriver_mh_error_to_mail_error(r); } static int mhdriver_delete_folder(mailsession * session, char * mb) { int r; struct mailmh_folder * folder; struct mailmh * mh; mh = get_mh_session(session); if (mh == NULL) return MAIL_ERROR_BAD_STATE; folder = mailmh_folder_find(mh->mh_main, mb); if (folder == NULL) return MAIL_ERROR_FOLDER_NOT_FOUND; if (get_mh_cur_folder(session) == folder) get_data(session)->mh_cur_folder = NULL; r = mailmh_folder_remove_subfolder(folder); return mhdriver_mh_error_to_mail_error(r); } static int mhdriver_rename_folder(mailsession * session, char * mb, char * new_name) { struct mailmh_folder * src_folder; struct mailmh_folder * dst_folder; char * name; struct mailmh * mh; int r; r = get_parent(session, new_name, &dst_folder, &name); if (r != MAIL_NO_ERROR) return r; mh = get_mh_session(session); if (mh == NULL) return MAIL_ERROR_BAD_STATE; src_folder = mailmh_folder_find(mh->mh_main, mb); if (src_folder == NULL) return MAIL_ERROR_FOLDER_NOT_FOUND; if (get_mh_cur_folder(session) == src_folder) get_data(session)->mh_cur_folder = NULL; r = mailmh_folder_rename_subfolder(src_folder, dst_folder, name); return mhdriver_mh_error_to_mail_error(r); } static int mhdriver_select_folder(mailsession * session, char * mb) { struct mailmh_folder * folder; struct mailmh * mh; int r; mh = get_mh_session(session); if (mh == NULL) return MAIL_ERROR_BAD_STATE; r = mailmh_folder_update(mh->mh_main); folder = mailmh_folder_find(mh->mh_main, mb); if (folder == NULL) return MAIL_ERROR_FOLDER_NOT_FOUND; get_data(session)->mh_cur_folder = folder; r = mailmh_folder_update(folder); return mhdriver_mh_error_to_mail_error(r); } static int mhdriver_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { uint32_t count; int r; r = mhdriver_messages_number(session, mb, &count); if (r != MAIL_NO_ERROR) return r; * result_messages = count; * result_recent = count; * result_unseen = count; return MAIL_NO_ERROR; } static int mhdriver_messages_number(mailsession * session, char * mb, uint32_t * result) { struct mailmh_folder * folder; uint32_t count; struct mailmh * mh; unsigned int i; mh = get_mh_session(session); if (mh == NULL) return MAIL_ERROR_BAD_STATE; if (mb != NULL) { folder = mailmh_folder_find(mh->mh_main, mb); if (folder == NULL) return MAIL_ERROR_FOLDER_NOT_FOUND; } else { folder = get_mh_cur_folder(session); if (folder == NULL) return MAIL_ERROR_BAD_STATE; } mailmh_folder_update(folder); count = 0; for (i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i ++) { struct mailmh_msg_info * msg_info; msg_info = carray_get(folder->fl_msgs_tab, i); if (msg_info != NULL) count ++; } * result = count; return MAIL_NO_ERROR; } static int get_list_folders(struct mailmh_folder * folder, clist ** result) { unsigned int i; clist * list; char * new_filename; int res; int r; list = * result; new_filename = strdup(folder->fl_filename); if (new_filename == NULL) { res = MAIL_ERROR_MEMORY; goto free; } r = mailmh_folder_update(folder); switch (r) { case MAILMH_NO_ERROR: break; default: res = mhdriver_mh_error_to_mail_error(r); goto free; } r = clist_append(list, new_filename); if (r < 0) { free(new_filename); res = MAIL_ERROR_MEMORY; goto free; } if (folder->fl_subfolders_tab != NULL) { for(i = 0 ; i < carray_count(folder->fl_subfolders_tab) ; i++) { struct mailmh_folder * subfolder; subfolder = carray_get(folder->fl_subfolders_tab, i); r = get_list_folders(subfolder, &list); if (r != MAIL_NO_ERROR) { res = MAIL_ERROR_MEMORY; goto free; } } } * result = list; return MAIL_NO_ERROR; free: clist_foreach(list, (clist_func) free, NULL); clist_free(list); return res; } static int mhdriver_list_folders(mailsession * session, char * mb, struct mail_list ** result) { clist * list; int r; struct mailmh * mh; struct mail_list * ml; mh = get_mh_session(session); if (mh == NULL) return MAIL_ERROR_BAD_STATE; list = clist_new(); if (list == NULL) return MAIL_ERROR_MEMORY; r = get_list_folders(mh->mh_main, &list); if (r != MAIL_NO_ERROR) return r; ml = mail_list_new(list); if (ml == NULL) goto free; * result = ml; return MAIL_NO_ERROR; free: clist_foreach(list, (clist_func) free, NULL); clist_free(list); return MAIL_ERROR_MEMORY; } static int mhdriver_lsub_folders(mailsession * session, char * mb, struct mail_list ** result) { clist * subscribed; clist * lsub_result; clistiter * cur; struct mail_list * lsub; size_t length; int r; length = strlen(mb); subscribed = get_data(session)->mh_subscribed_list; lsub_result = clist_new(); if (lsub_result == NULL) return MAIL_ERROR_MEMORY; for(cur = clist_begin(subscribed) ; cur != NULL ; cur = clist_next(cur)) { char * cur_mb; char * new_mb; cur_mb = clist_content(cur); if (strncmp(mb, cur_mb, length) == 0) { new_mb = strdup(cur_mb); if (new_mb == NULL) goto free_list; r = clist_append(lsub_result, new_mb); if (r < 0) { free(new_mb); goto free_list; } } } lsub = mail_list_new(lsub_result); if (lsub == NULL) goto free_list; * result = lsub; return MAIL_NO_ERROR; free_list: clist_foreach(lsub_result, (clist_func) free, NULL); clist_free(lsub_result); return MAIL_ERROR_MEMORY; } static int mhdriver_subscribe_folder(mailsession * session, char * mb) { int r; r = add_to_list(session, mb); if (r < 0) return MAIL_ERROR_SUBSCRIBE; return MAIL_NO_ERROR; } static int mhdriver_unsubscribe_folder(mailsession * session, char * mb) { int r; r = remove_from_list(session, mb); if (r < 0) return MAIL_ERROR_UNSUBSCRIBE; return MAIL_NO_ERROR; } /* messages operations */ static int mhdriver_append_message(mailsession * session, char * message, size_t size) { int r; struct mailmh_folder * folder; folder = get_mh_cur_folder(session); if (folder == NULL) return MAIL_ERROR_BAD_STATE; r = mailmh_folder_add_message(folder, message, size); switch (r) { case MAILMH_ERROR_FILE: return MAIL_ERROR_DISKSPACE; default: return mhdriver_mh_error_to_mail_error(r); } } +static int mhdriver_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags) +{ + return mhdriver_append_message(session, message, size); +} + static int mhdriver_copy_message(mailsession * session, uint32_t num, char * mb) { int fd; int r; struct mailmh_folder * folder; struct mailmh * mh; int res; mh = get_mh_session(session); if (mh == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } folder = get_mh_cur_folder(session); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } r = mailmh_folder_get_message_fd(folder, num, O_RDONLY, &fd); if (r != MAIL_NO_ERROR) { res = r; goto err; } folder = mailmh_folder_find(mh->mh_main, mb); if (folder == NULL) { res = MAIL_ERROR_FOLDER_NOT_FOUND; goto close; } r = mailmh_folder_add_message_file(folder, fd); if (r != MAIL_NO_ERROR) { res = MAIL_ERROR_COPY; goto close; } close(fd); return MAIL_NO_ERROR; close: close(fd); err: return res; } static int mhdriver_remove_message(mailsession * session, uint32_t num) { int r; struct mailmh_folder * folder; folder = get_mh_cur_folder(session); if (folder == NULL) return MAIL_ERROR_DELETE; r = mailmh_folder_remove_message(folder, num); return mhdriver_mh_error_to_mail_error(r); } static int mhdriver_move_message(mailsession * session, uint32_t num, char * mb) { int r; struct mailmh_folder * src_folder; struct mailmh_folder * dest_folder; struct mailmh * mh; mh = get_mh_session(session); if (mh == NULL) return MAIL_ERROR_BAD_STATE; src_folder = get_mh_cur_folder(session); if (src_folder == NULL) return MAIL_ERROR_BAD_STATE; dest_folder = mailmh_folder_find(mh->mh_main, mb); if (dest_folder == NULL) return MAIL_ERROR_FOLDER_NOT_FOUND; r = mailmh_folder_move_message(dest_folder, src_folder, num); return mhdriver_mh_error_to_mail_error(r); } static int mhdriver_get_messages_list(mailsession * session, struct mailmessage_list ** result) { struct mailmh_folder * folder; int res; folder = get_mh_cur_folder(session); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } mailmh_folder_update(folder); return mh_get_messages_list(folder, session, mh_message_driver, result); err: return res; } static int mhdriver_get_message(mailsession * session, uint32_t num, mailmessage ** result) { mailmessage * msg_info; int r; msg_info = mailmessage_new(); if (msg_info == NULL) return MAIL_ERROR_MEMORY; r = mailmessage_init(msg_info, session, mh_message_driver, num, 0); if (r != MAIL_NO_ERROR) { mailmessage_free(msg_info); return r; } * result = msg_info; return MAIL_NO_ERROR; } static int mhdriver_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result) { uint32_t index; char *p; struct mailmh_msg_info * mh_msg_info; struct mh_session_state_data * mh_data; chashdatum key; chashdatum data; int r; time_t mtime; char * mtime_p; if (uid == NULL) return MAIL_ERROR_INVAL; index = strtoul(uid, &p, 10); if (p == uid || * p != '-') return MAIL_ERROR_INVAL; mh_data = session->sess_data; #if 0 mh_msg_info = cinthash_find(mh_data->mh_cur_folder->fl_msgs_hash, index); #endif key.data = &index; key.len = sizeof(index); r = chash_get(mh_data->mh_cur_folder->fl_msgs_hash, &key, &data); if (r < 0) return MAIL_ERROR_MSG_NOT_FOUND; mh_msg_info = data.data; mtime_p = p + 1; mtime = strtoul(mtime_p, &p, 10); if ((* p == '-') && (mtime == mh_msg_info->msg_mtime)) { size_t size; char *size_p; size_p = p + 1; size = strtoul(size_p, &p, 10); if ((* p == '\0') && (size == mh_msg_info->msg_size)) return mhdriver_get_message(session, index, result); } else if (* p != '-') { return MAIL_ERROR_INVAL; } return MAIL_ERROR_MSG_NOT_FOUND; } diff --git a/kmicromail/libetpan/generic/mhdriver_cached.c b/kmicromail/libetpan/generic/mhdriver_cached.c index 5c35089..04aa523 100644 --- a/kmicromail/libetpan/generic/mhdriver_cached.c +++ b/kmicromail/libetpan/generic/mhdriver_cached.c @@ -1,1232 +1,1315 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "mhdriver_cached.h" #include <stdio.h> #include <sys/types.h> #include <dirent.h> #include <unistd.h> #include <sys/stat.h> #include <ctype.h> #include <fcntl.h> #include <sys/mman.h> #include <stdlib.h> #include <string.h> #include "mail.h" #include "mail_cache_db.h" #include "generic_cache.h" #include "imfcache.h" #include "mhdriver.h" #include "mhdriver_cached_message.h" #include "mailmh.h" #include "maildriver_tools.h" #include "mhdriver_tools.h" #include "mailmessage.h" static int mhdriver_cached_initialize(mailsession * session); static void mhdriver_cached_uninitialize(mailsession * session); static int mhdriver_cached_parameters(mailsession * session, int id, void * value); static int mhdriver_cached_connect_path(mailsession * session, char * path); static int mhdriver_cached_logout(mailsession * session); static int mhdriver_cached_build_folder_name(mailsession * session, char * mb, char * name, char ** result); static int mhdriver_cached_create_folder(mailsession * session, char * mb); static int mhdriver_cached_delete_folder(mailsession * session, char * mb); static int mhdriver_cached_rename_folder(mailsession * session, char * mb, char * new_name); static int mhdriver_cached_check_folder(mailsession * session); static int mhdriver_cached_select_folder(mailsession * session, char * mb); static int mhdriver_cached_expunge_folder(mailsession * session); static int mhdriver_cached_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); static int mhdriver_cached_messages_number(mailsession * session, char * mb, uint32_t * result); static int mhdriver_cached_recent_number(mailsession * session, char * mb, uint32_t * result); static int mhdriver_cached_unseen_number(mailsession * session, char * mb, uint32_t * result); static int mhdriver_cached_list_folders(mailsession * session, char * mb, struct mail_list ** result); static int mhdriver_cached_lsub_folders(mailsession * session, char * mb, struct mail_list ** result); static int mhdriver_cached_subscribe_folder(mailsession * session, char * mb); static int mhdriver_cached_unsubscribe_folder(mailsession * session, char * mb); static int mhdriver_cached_append_message(mailsession * session, char * message, size_t size); +static int mhdriver_cached_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags); static int mhdriver_cached_copy_message(mailsession * session, uint32_t num, char * mb); static int mhdriver_cached_remove_message(mailsession * session, uint32_t num); static int mhdriver_cached_move_message(mailsession * session, uint32_t num, char * mb); static int mhdriver_cached_get_messages_list(mailsession * session, struct mailmessage_list ** result); static int mhdriver_cached_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list); static int mhdriver_cached_get_message(mailsession * session, uint32_t num, mailmessage ** result); static int mhdriver_cached_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result); static mailsession_driver local_mh_cached_session_driver = { .sess_name = "mh-cached", .sess_initialize = mhdriver_cached_initialize, .sess_uninitialize = mhdriver_cached_uninitialize, .sess_parameters = mhdriver_cached_parameters, .sess_connect_stream = NULL, .sess_connect_path = mhdriver_cached_connect_path, .sess_starttls = NULL, .sess_login = NULL, .sess_logout = mhdriver_cached_logout, .sess_noop = NULL, .sess_build_folder_name = mhdriver_cached_build_folder_name, .sess_create_folder = mhdriver_cached_create_folder, .sess_delete_folder = mhdriver_cached_delete_folder, .sess_rename_folder = mhdriver_cached_rename_folder, .sess_check_folder = mhdriver_cached_check_folder, .sess_examine_folder = NULL, .sess_select_folder = mhdriver_cached_select_folder, .sess_expunge_folder = mhdriver_cached_expunge_folder, .sess_status_folder = mhdriver_cached_status_folder, .sess_messages_number = mhdriver_cached_messages_number, .sess_recent_number = mhdriver_cached_recent_number, .sess_unseen_number = mhdriver_cached_unseen_number, .sess_list_folders = mhdriver_cached_list_folders, .sess_lsub_folders = mhdriver_cached_lsub_folders, .sess_subscribe_folder = mhdriver_cached_subscribe_folder, .sess_unsubscribe_folder = mhdriver_cached_unsubscribe_folder, .sess_append_message = mhdriver_cached_append_message, + .sess_append_message_flags = mhdriver_cached_append_message_flags, .sess_copy_message = mhdriver_cached_copy_message, .sess_move_message = mhdriver_cached_move_message, .sess_get_messages_list = mhdriver_cached_get_messages_list, .sess_get_envelopes_list = mhdriver_cached_get_envelopes_list, .sess_remove_message = mhdriver_cached_remove_message, #if 0 .sess_search_messages = maildriver_generic_search_messages, #endif .sess_get_message = mhdriver_cached_get_message, .sess_get_message_by_uid = mhdriver_cached_get_message_by_uid, }; mailsession_driver * mh_cached_session_driver = &local_mh_cached_session_driver; #define ENV_NAME "env.db" #define FLAGS_NAME "flags.db" static inline struct mh_cached_session_state_data * get_cached_data(mailsession * session) { return session->sess_data; } static inline mailsession * get_ancestor(mailsession * session) { return get_cached_data(session)->mh_ancestor; } static inline struct mh_session_state_data * get_ancestor_data(mailsession * session) { return get_ancestor(session)->sess_data; } static inline struct mailmh * get_mh_session(mailsession * session) { return get_ancestor_data(session)->mh_session; } static inline struct mailmh_folder * get_mh_cur_folder(mailsession * session) { return get_ancestor_data(session)->mh_cur_folder; } #define FILENAME_MAX_UID "max-uid" /* write max uid current value */ static int write_max_uid_value(mailsession * session) { int r; char filename[PATH_MAX]; FILE * f; int res; struct mh_cached_session_state_data * cached_data; struct mh_session_state_data * ancestor_data; int fd; MMAPString * mmapstr; size_t cur_token; cached_data = get_cached_data(session); ancestor_data = get_ancestor_data(session); if (cached_data->mh_quoted_mb == NULL) return MAIL_ERROR_BAD_STATE; snprintf(filename, PATH_MAX, "%s/%s/%s", cached_data->mh_cache_directory, cached_data->mh_quoted_mb, FILENAME_MAX_UID); fd = creat(filename, S_IRUSR | S_IWUSR); if (fd < 0) { res = MAIL_ERROR_FILE; goto err; } f = fdopen(fd, "w"); if (f == NULL) { close(fd); res = MAIL_ERROR_FILE; goto err; } mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto close; } r = mail_serialize_clear(mmapstr, &cur_token); if (r != MAIL_NO_ERROR) { res = r; goto free_mmapstr; } r = mailimf_cache_int_write(mmapstr, &cur_token, ancestor_data->mh_cur_folder->fl_max_index); if (r != MAIL_NO_ERROR) { res = r; goto free_mmapstr; } fwrite(mmapstr->str, 1, mmapstr->len, f); mmap_string_free(mmapstr); fclose(f); return MAIL_NO_ERROR; free_mmapstr: mmap_string_free(mmapstr); close: fclose(f); err: return res; } static int read_max_uid_value(mailsession * session) { int r; char filename[PATH_MAX]; FILE * f; uint32_t written_uid; int res; struct mh_cached_session_state_data * cached_data; struct mh_session_state_data * ancestor_data; MMAPString * mmapstr; size_t cur_token; char buf[sizeof(uint32_t)]; size_t read_size; cached_data = get_cached_data(session); ancestor_data = get_ancestor_data(session); snprintf(filename, PATH_MAX, "%s/%s/%s", cached_data->mh_cache_directory, cached_data->mh_quoted_mb, FILENAME_MAX_UID); f = fopen(filename, "r"); if (f == NULL) { res = MAIL_ERROR_FILE; goto err; } read_size = fread(buf, 1, sizeof(uint32_t), f); mmapstr = mmap_string_new_len(buf, read_size); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto close; } cur_token = 0; r = mailimf_cache_int_read(mmapstr, &cur_token, &written_uid); if (r != MAIL_NO_ERROR) { fclose(f); res = r; goto free_mmapstr; } mmap_string_free(mmapstr); fclose(f); if (written_uid > ancestor_data->mh_cur_folder->fl_max_index) ancestor_data->mh_cur_folder->fl_max_index = written_uid; return MAIL_NO_ERROR; free_mmapstr: mmap_string_free(mmapstr); close: fclose(f); err: return res; } static int mhdriver_cached_initialize(mailsession * session) { struct mh_cached_session_state_data * data; data = malloc(sizeof(* data)); if (data == NULL) goto err; data->mh_flags_store = mail_flags_store_new(); if (data->mh_flags_store == NULL) goto free; data->mh_ancestor = mailsession_new(mh_session_driver); if (data->mh_ancestor == NULL) goto free_store; data->mh_quoted_mb = NULL; session->sess_data = data; return MAIL_NO_ERROR; free_store: mail_flags_store_free(data->mh_flags_store); free: free(data); err: return MAIL_ERROR_MEMORY; } static void free_state(struct mh_cached_session_state_data * mh_data) { if (mh_data->mh_quoted_mb) { free(mh_data->mh_quoted_mb); mh_data->mh_quoted_mb = NULL; } } static int mh_flags_store_process(char * flags_directory, char * quoted_mb, struct mail_flags_store * flags_store) { char filename_flags[PATH_MAX]; struct mail_cache_db * cache_db_flags; MMAPString * mmapstr; unsigned int i; int r; int res; if (carray_count(flags_store->fls_tab) == 0) return MAIL_NO_ERROR; if (quoted_mb == NULL) return MAIL_NO_ERROR; snprintf(filename_flags, PATH_MAX, "%s/%s/%s", flags_directory, quoted_mb, FLAGS_NAME); r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_FILE; goto err; } mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto close_db_flags; } for(i = 0 ; i < carray_count(flags_store->fls_tab) ; i ++) { mailmessage * msg; msg = carray_get(flags_store->fls_tab, i); r = mhdriver_write_cached_flags(cache_db_flags, mmapstr, msg->msg_uid, msg->msg_flags); } mmap_string_free(mmapstr); mail_cache_db_close_unlock(filename_flags, cache_db_flags); mail_flags_store_clear(flags_store); return MAIL_NO_ERROR; close_db_flags: mail_cache_db_close_unlock(filename_flags, cache_db_flags); err: return res; } static void mhdriver_cached_uninitialize(mailsession * session) { struct mh_cached_session_state_data * data; data = get_cached_data(session); mh_flags_store_process(data->mh_flags_directory, data->mh_quoted_mb, data->mh_flags_store); mail_flags_store_free(data->mh_flags_store); free_state(data); mailsession_free(data->mh_ancestor); free(data); session->sess_data = NULL; } static int mhdriver_cached_parameters(mailsession * session, int id, void * value) { struct mh_cached_session_state_data * cached_data; int r; cached_data = get_cached_data(session); switch (id) { case MHDRIVER_CACHED_SET_CACHE_DIRECTORY: strncpy(cached_data->mh_cache_directory, value, PATH_MAX); cached_data->mh_cache_directory[PATH_MAX - 1] = '\0'; r = generic_cache_create_dir(cached_data->mh_cache_directory); if (r != MAIL_NO_ERROR) return r; return MAIL_NO_ERROR; case MHDRIVER_CACHED_SET_FLAGS_DIRECTORY: strncpy(cached_data->mh_flags_directory, value, PATH_MAX); cached_data->mh_flags_directory[PATH_MAX - 1] = '\0'; r = generic_cache_create_dir(cached_data->mh_flags_directory); if (r != MAIL_NO_ERROR) return r; return MAIL_NO_ERROR; } return MAIL_ERROR_INVAL; } static int mhdriver_cached_connect_path(mailsession * session, char * path) { return mailsession_connect_path(get_ancestor(session), path); } static int mhdriver_cached_logout(mailsession * session) { int r; struct mh_cached_session_state_data * cached_data; r = write_max_uid_value(session); cached_data = get_cached_data(session); mh_flags_store_process(cached_data->mh_flags_directory, cached_data->mh_quoted_mb, cached_data->mh_flags_store); return mailsession_logout(get_ancestor(session)); } static int mhdriver_cached_check_folder(mailsession * session) { struct mh_cached_session_state_data * cached_data; cached_data = get_cached_data(session); mh_flags_store_process(cached_data->mh_flags_directory, cached_data->mh_quoted_mb, cached_data->mh_flags_store); return MAIL_NO_ERROR; } /* folders operations */ static int mhdriver_cached_build_folder_name(mailsession * session, char * mb, char * name, char ** result) { return mailsession_build_folder_name(get_ancestor(session), mb, name, result); } static int mhdriver_cached_create_folder(mailsession * session, char * mb) { return mailsession_create_folder(get_ancestor(session), mb); } static int mhdriver_cached_delete_folder(mailsession * session, char * mb) { return mailsession_delete_folder(get_ancestor(session), mb); } static int mhdriver_cached_rename_folder(mailsession * session, char * mb, char * new_name) { return mailsession_rename_folder(get_ancestor(session), mb, new_name); } static int get_cache_directory(mailsession * session, char * path, char ** result) { char * quoted_mb; char dirname[PATH_MAX]; int res; int r; struct mh_cached_session_state_data * cached_data; cached_data = get_cached_data(session); quoted_mb = maildriver_quote_mailbox(path); if (quoted_mb == NULL) { res = MAIL_ERROR_MEMORY; goto err; } snprintf(dirname, PATH_MAX, "%s/%s", cached_data->mh_cache_directory, quoted_mb); r = generic_cache_create_dir(dirname); if (r != MAIL_NO_ERROR) { res = r; goto free; } snprintf(dirname, PATH_MAX, "%s/%s", cached_data->mh_flags_directory, quoted_mb); r = generic_cache_create_dir(dirname); if (r != MAIL_NO_ERROR) { res = r; goto free; } * result = quoted_mb; return MAIL_NO_ERROR; free: free(quoted_mb); err: return res; } static int mhdriver_cached_select_folder(mailsession * session, char * mb) { int r; int res; char * quoted_mb; struct mh_cached_session_state_data * cached_data; cached_data = get_cached_data(session); mh_flags_store_process(cached_data->mh_flags_directory, cached_data->mh_quoted_mb, cached_data->mh_flags_store); r = get_cache_directory(session, mb, "ed_mb); if (r != MAIL_NO_ERROR) { res = r; goto err; } r = mailsession_select_folder(get_ancestor(session), mb); if (r != MAIL_NO_ERROR) { res = r; goto free; } r = write_max_uid_value(session); free_state(cached_data); cached_data->mh_quoted_mb = quoted_mb; r = read_max_uid_value(session); return MAIL_NO_ERROR; free: free(quoted_mb); err: return res; } static int mhdriver_cached_expunge_folder(mailsession * session) { struct mailmh_folder * folder; int res; char filename_flags[PATH_MAX]; struct mail_cache_db * cache_db_flags; MMAPString * mmapstr; struct mh_cached_session_state_data * cached_data; unsigned int i; int r; cached_data = get_cached_data(session); if (cached_data->mh_quoted_mb == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } mh_flags_store_process(cached_data->mh_flags_directory, cached_data->mh_quoted_mb, cached_data->mh_flags_store); folder = get_mh_cur_folder(session); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } snprintf(filename_flags, PATH_MAX, "%s/%s/%s", cached_data->mh_flags_directory, cached_data->mh_quoted_mb, FLAGS_NAME); r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_FILE; goto err; } mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto close_db_flags; } for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i++) { struct mailmh_msg_info * mh_info; struct mail_flags * flags; mh_info = carray_get(folder->fl_msgs_tab, i); if (mh_info == NULL) continue; r = mhdriver_get_cached_flags(cache_db_flags, mmapstr, session, mh_info->msg_index, &flags); if (r != MAIL_NO_ERROR) continue; if (flags->fl_flags & MAIL_FLAG_DELETED) { r = mailmh_folder_remove_message(folder, mh_info->msg_index); } mail_flags_free(flags); } mmap_string_free(mmapstr); mail_cache_db_close_unlock(filename_flags, cache_db_flags); mailmh_folder_update(folder); return MAIL_NO_ERROR; close_db_flags: mail_cache_db_close_unlock(filename_flags, cache_db_flags); err: return res; } static int mhdriver_cached_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { struct mailmh_folder * folder; int res; char filename_flags[PATH_MAX]; struct mail_cache_db * cache_db_flags; MMAPString * mmapstr; struct mh_cached_session_state_data * cached_data; unsigned int i; int r; uint32_t count; uint32_t recent; uint32_t unseen; r = mhdriver_cached_select_folder(session, mb); if (r != MAIL_NO_ERROR) { res = r; goto err; } count = 0; recent = 0; unseen = 0; folder = get_mh_cur_folder(session); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } cached_data = get_cached_data(session); if (cached_data->mh_quoted_mb == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } snprintf(filename_flags, PATH_MAX, "%s/%s/%s", cached_data->mh_flags_directory, cached_data->mh_quoted_mb, FLAGS_NAME); r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_FILE; goto err; } mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto close_db_flags; } for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i++) { struct mailmh_msg_info * mh_info; struct mail_flags * flags; mh_info = carray_get(folder->fl_msgs_tab, i); if (mh_info == NULL) continue; count ++; r = mhdriver_get_cached_flags(cache_db_flags, mmapstr, session, mh_info->msg_index, &flags); if (r != MAIL_NO_ERROR) { recent ++; unseen ++; continue; } if ((flags->fl_flags & MAIL_FLAG_NEW) != 0) { recent ++; } if ((flags->fl_flags & MAIL_FLAG_SEEN) == 0) { unseen ++; } mail_flags_free(flags); } mmap_string_free(mmapstr); mail_cache_db_close_unlock(filename_flags, cache_db_flags); * result_messages = count; * result_recent = recent; * result_unseen = unseen; return MAIL_NO_ERROR; close_db_flags: mail_cache_db_close_unlock(filename_flags, cache_db_flags); err: return res; } static int mhdriver_cached_messages_number(mailsession * session, char * mb, uint32_t * result) { return mailsession_messages_number(get_ancestor(session), mb, result); } static int mhdriver_cached_recent_number(mailsession * session, char * mb, uint32_t * result) { uint32_t messages; uint32_t recent; uint32_t unseen; int r; r = mhdriver_cached_status_folder(session, mb, &messages, &recent, &unseen); if (r != MAIL_NO_ERROR) return r; * result = recent; return MAIL_NO_ERROR; } static int mhdriver_cached_unseen_number(mailsession * session, char * mb, uint32_t * result) { uint32_t messages; uint32_t recent; uint32_t unseen; int r; r = mhdriver_cached_status_folder(session, mb, &messages, &recent, &unseen); if (r != MAIL_NO_ERROR) return r; * result = recent; return MAIL_NO_ERROR; } static int mhdriver_cached_list_folders(mailsession * session, char * mb, struct mail_list ** result) { return mailsession_list_folders(get_ancestor(session), mb, result); } static int mhdriver_cached_lsub_folders(mailsession * session, char * mb, struct mail_list ** result) { return mailsession_lsub_folders(get_ancestor(session), mb, result); } static int mhdriver_cached_subscribe_folder(mailsession * session, char * mb) { return mailsession_subscribe_folder(get_ancestor(session), mb); } static int mhdriver_cached_unsubscribe_folder(mailsession * session, char * mb) { return mailsession_unsubscribe_folder(get_ancestor(session), mb); } /* messages operations */ static int mhdriver_cached_append_message(mailsession * session, char * message, size_t size) { - return mailsession_append_message(get_ancestor(session), message, size); + return mhdriver_cached_append_message_flags(session, + message, size, NULL); +} + +static int mhdriver_cached_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags) +{ + int r; + struct mailmh_folder * folder; + struct mailmh_msg_info * msg_info; + chashdatum key; + chashdatum value; + uint32_t uid; + struct mh_cached_session_state_data * data; + char filename_flags[PATH_MAX]; + struct mail_cache_db * cache_db_flags; + MMAPString * mmapstr; + char keyname[PATH_MAX]; + + folder = get_mh_cur_folder(session); + if (folder == NULL) + return MAIL_ERROR_BAD_STATE; + + r = mailmh_folder_add_message_uid(folder, + message, size, &uid); + + switch (r) { + case MAILMH_ERROR_FILE: + return MAIL_ERROR_DISKSPACE; + + case MAILMH_NO_ERROR: + break; + + default: + return mhdriver_mh_error_to_mail_error(r); + } + + if (flags == NULL) + goto exit; + + key.data = &uid; + key.len = sizeof(uid); + r = chash_get(folder->fl_msgs_hash, &key, &value); + if (r < 0) + return MAIL_ERROR_CACHE_MISS; + + msg_info = value.data; + + data = get_cached_data(session); + + snprintf(filename_flags, PATH_MAX, "%s/%s/%s", + data->mh_flags_directory, data->mh_quoted_mb, FLAGS_NAME); + + r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); + if (r < 0) + goto exit; + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) + goto close_db_flags; + + snprintf(keyname, PATH_MAX, "%u-%lu-%lu-flags", + uid, (unsigned long) msg_info->msg_mtime, + (unsigned long) msg_info->msg_size); + + r = mhdriver_write_cached_flags(cache_db_flags, mmapstr, keyname, flags); + + mmap_string_free(mmapstr); + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + + if (r != MAIL_NO_ERROR) + goto exit; + + return MAIL_NO_ERROR; + + close_db_flags: + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + exit: + return MAIL_NO_ERROR; } static int mhdriver_cached_copy_message(mailsession * session, uint32_t num, char * mb) { return mailsession_copy_message(get_ancestor(session), num, mb); } static int mhdriver_cached_remove_message(mailsession * session, uint32_t num) { return mailsession_remove_message(get_ancestor(session), num); } static int mhdriver_cached_move_message(mailsession * session, uint32_t num, char * mb) { return mailsession_move_message(get_ancestor(session), num, mb); } static int mhdriver_cached_get_messages_list(mailsession * session, struct mailmessage_list ** result) { struct mailmh_folder * folder; int res; folder = get_mh_cur_folder(session); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } return mh_get_messages_list(folder, session, mh_cached_message_driver, result); err: return res; } static int get_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr, mailsession * session, uint32_t num, struct mailimf_fields ** result) { int r; char keyname[PATH_MAX]; struct mailimf_fields * fields; int res; struct mailmh_folder * folder; struct mailmh_msg_info * msg_info; chashdatum key; chashdatum data; folder = get_mh_cur_folder(session); #if 0 msg_info = cinthash_find(mh_data->mh_cur_folder->fl_msgs_hash, num); if (msg_info == NULL) return MAIL_ERROR_CACHE_MISS; #endif key.data = # key.len = sizeof(num); r = chash_get(folder->fl_msgs_hash, &key, &data); if (r < 0) return MAIL_ERROR_CACHE_MISS; msg_info = data.data; - snprintf(keyname, PATH_MAX, "%u-%u-%u-envelope", - num, (uint32_t) msg_info->msg_mtime, msg_info->msg_size); + snprintf(keyname, PATH_MAX, "%u-%lu-%lu-envelope", + num, (unsigned long) msg_info->msg_mtime, + (unsigned long) msg_info->msg_size); r = generic_cache_fields_read(cache_db, mmapstr, keyname, &fields); if (r != MAIL_NO_ERROR) { res = r; goto err; } * result = fields; return MAIL_NO_ERROR; err: return res; } static int write_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr, mailsession * session, uint32_t num, struct mailimf_fields * fields) { int r; char keyname[PATH_MAX]; int res; struct mailmh_folder * folder; chashdatum key; chashdatum data; struct mailmh_msg_info * msg_info; folder = get_mh_cur_folder(session); #if 0 msg_info = cinthash_find(mh_data->mh_cur_folder->fl_msgs_hash, num); if (msg_info == NULL) { res = MAIL_ERROR_CACHE_MISS; goto err; } #endif key.data = # key.len = sizeof(num); r = chash_get(folder->fl_msgs_hash, &key, &data); if (r < 0) return MAIL_ERROR_CACHE_MISS; msg_info = data.data; - snprintf(keyname, PATH_MAX, "%u-%u-%u-envelope", - num, (uint32_t) msg_info->msg_mtime, msg_info->msg_size); + snprintf(keyname, PATH_MAX, "%u-%lu-%lu-envelope", + num, (unsigned long) msg_info->msg_mtime, + (unsigned long) msg_info->msg_size); r = generic_cache_fields_write(cache_db, mmapstr, keyname, fields); if (r != MAIL_NO_ERROR) { res = r; goto err; } return MAIL_NO_ERROR; err: return res; } static int mhdriver_cached_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list) { int r; unsigned int i; char filename_env[PATH_MAX]; char filename_flags[PATH_MAX]; struct mail_cache_db * cache_db_env; struct mail_cache_db * cache_db_flags; MMAPString * mmapstr; int res; struct mh_cached_session_state_data * cached_data; cached_data = get_cached_data(session); if (cached_data->mh_quoted_mb == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } mh_flags_store_process(cached_data->mh_flags_directory, cached_data->mh_quoted_mb, cached_data->mh_flags_store); mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto err; } snprintf(filename_env, PATH_MAX, "%s/%s/%s", cached_data->mh_cache_directory, cached_data->mh_quoted_mb, ENV_NAME); r = mail_cache_db_open_lock(filename_env, &cache_db_env); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_mmapstr; } snprintf(filename_flags, PATH_MAX, "%s/%s/%s", cached_data->mh_flags_directory, cached_data->mh_quoted_mb, FLAGS_NAME); r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_MEMORY; goto close_db_env; } /* fill with cached */ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; struct mailimf_fields * fields; struct mail_flags * flags; msg = carray_get(env_list->msg_tab, i); if (msg->msg_fields == NULL) { r = get_cached_envelope(cache_db_env, mmapstr, msg->msg_session, msg->msg_index, &fields); if (r == MAIL_NO_ERROR) { msg->msg_cached = TRUE; msg->msg_fields = fields; } } if (msg->msg_flags == NULL) { r = mhdriver_get_cached_flags(cache_db_flags, mmapstr, session, msg->msg_index, &flags); if (r == MAIL_NO_ERROR) { msg->msg_flags = flags; } } } mail_cache_db_close_unlock(filename_flags, cache_db_flags); mail_cache_db_close_unlock(filename_env, cache_db_env); r = mailsession_get_envelopes_list(get_ancestor(session), env_list); if (r != MAIL_NO_ERROR) { res = r; goto free_mmapstr; } r = mail_cache_db_open_lock(filename_env, &cache_db_env); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_mmapstr; } r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_MEMORY; goto close_db_env; } /* add flags */ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; msg = carray_get(env_list->msg_tab, i); if (msg->msg_flags == NULL) msg->msg_flags = mail_flags_new_empty(); } /* must write cache */ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; msg = carray_get(env_list->msg_tab, i); if (msg->msg_fields != NULL) { if (!msg->msg_cached) { r = write_cached_envelope(cache_db_env, mmapstr, session, msg->msg_index, msg->msg_fields); } } if (msg->msg_flags != NULL) { r = mhdriver_write_cached_flags(cache_db_flags, mmapstr, msg->msg_uid, msg->msg_flags); } } /* flush cache */ maildriver_cache_clean_up(cache_db_env, cache_db_flags, env_list); mail_cache_db_close_unlock(filename_flags, cache_db_flags); mail_cache_db_close_unlock(filename_env, cache_db_env); mmap_string_free(mmapstr); return MAIL_NO_ERROR; close_db_env: mail_cache_db_close_unlock(filename_env, cache_db_env); free_mmapstr: mmap_string_free(mmapstr); err: return res; } static int mhdriver_cached_get_message(mailsession * session, uint32_t num, mailmessage ** result) { mailmessage * msg_info; int r; msg_info = mailmessage_new(); if (msg_info == NULL) return MAIL_ERROR_MEMORY; r = mailmessage_init(msg_info, session, mh_cached_message_driver, num, 0); if (r != MAIL_NO_ERROR) return r; * result = msg_info; return MAIL_NO_ERROR; } static int mhdriver_cached_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result) { uint32_t index; char *p; struct mailmh_msg_info * mh_msg_info; struct mailmh_folder * folder; time_t mtime; char * mtime_p; chashdatum key; chashdatum data; int r; if (uid == NULL) return MAIL_ERROR_INVAL; index = strtoul(uid, &p, 10); if (p == uid || * p != '-') return MAIL_ERROR_INVAL; folder = get_mh_cur_folder(session); mh_msg_info = NULL; key.data = &index; key.len = sizeof(index); r = chash_get(folder->fl_msgs_hash, &key, &data); if (r < 0) return MAIL_ERROR_MSG_NOT_FOUND; mh_msg_info = data.data; mtime_p = p + 1; mtime = strtoul(mtime_p, &p, 10); if ((* p == '-') && (mtime == mh_msg_info->msg_mtime)) { size_t size; char *size_p; size_p = p + 1; size = strtoul(size_p, &p, 10); if ((* p == '\0') && (size == mh_msg_info->msg_size)) return mhdriver_cached_get_message(session, index, result); } else if (*p != '-') { return MAIL_ERROR_INVAL; } return MAIL_ERROR_MSG_NOT_FOUND; } diff --git a/kmicromail/libetpan/generic/mhdriver_cached_message.c b/kmicromail/libetpan/generic/mhdriver_cached_message.c index f716fb9..f69868d 100644 --- a/kmicromail/libetpan/generic/mhdriver_cached_message.c +++ b/kmicromail/libetpan/generic/mhdriver_cached_message.c @@ -1,338 +1,338 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "mhdriver_message.h" #include "mailmessage_tools.h" #include "mhdriver_tools.h" #include "mhdriver_cached.h" #include "mailmh.h" #include "generic_cache.h" #include "mail_cache_db.h" #include <unistd.h> #include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <stdlib.h> static int mh_prefetch(mailmessage * msg_info); static void mh_prefetch_free(struct generic_message_t * msg); static int mh_initialize(mailmessage * msg_info); static int mh_fetch_size(mailmessage * msg_info, size_t * result); static int mh_get_flags(mailmessage * msg_info, struct mail_flags ** result); static void mh_uninitialize(mailmessage * msg_info); static void mh_flush(mailmessage * msg_info); static void mh_check(mailmessage * msg_info); static int mh_fetch_header(mailmessage * msg_info, char ** result, size_t * result_len); static mailmessage_driver local_mh_cached_message_driver = { .msg_name = "mh-cached", .msg_initialize = mh_initialize, .msg_uninitialize = mh_uninitialize, .msg_flush = mh_flush, .msg_check = mh_check, .msg_fetch_result_free = mailmessage_generic_fetch_result_free, .msg_fetch = mailmessage_generic_fetch, .msg_fetch_header = mh_fetch_header, .msg_fetch_body = mailmessage_generic_fetch_body, .msg_fetch_size = mh_fetch_size, .msg_get_bodystructure = mailmessage_generic_get_bodystructure, .msg_fetch_section = mailmessage_generic_fetch_section, .msg_fetch_section_header = mailmessage_generic_fetch_section_header, .msg_fetch_section_mime = mailmessage_generic_fetch_section_mime, .msg_fetch_section_body = mailmessage_generic_fetch_section_body, .msg_fetch_envelope = mailmessage_generic_fetch_envelope, .msg_get_flags = mh_get_flags, }; mailmessage_driver * mh_cached_message_driver = &local_mh_cached_message_driver; static inline struct mh_cached_session_state_data * get_cached_session_data(mailmessage * msg) { return msg->msg_session->sess_data; } static inline mailsession * get_ancestor_session(mailmessage * msg) { return get_cached_session_data(msg)->mh_ancestor; } static inline struct mh_session_state_data * get_ancestor_session_data(mailmessage * msg) { return get_ancestor_session(msg)->sess_data; } static inline struct mailmh * get_mh_session(mailmessage * msg) { return get_ancestor_session_data(msg)->mh_session; } static inline struct mailmh_folder * get_mh_cur_folder(mailmessage * msg) { return get_ancestor_session_data(msg)->mh_cur_folder; } static int mh_prefetch(mailmessage * msg_info) { struct generic_message_t * msg; int r; char * msg_content; size_t msg_length; r = mhdriver_fetch_message(get_ancestor_session(msg_info), msg_info->msg_index, &msg_content, &msg_length); if (r != MAIL_NO_ERROR) return r; msg = msg_info->msg_data; msg->msg_message = msg_content; msg->msg_length = msg_length; return MAIL_NO_ERROR; } static void mh_prefetch_free(struct generic_message_t * msg) { if (msg->msg_message != NULL) { mmap_string_unref(msg->msg_message); msg->msg_message = NULL; } } static int mh_initialize(mailmessage * msg_info) { struct generic_message_t * msg; int r; char * uid; char static_uid[PATH_MAX]; struct mailmh_msg_info * mh_msg_info; chashdatum key; chashdatum data; struct mailmh_folder * folder; folder = get_mh_cur_folder(msg_info); key.data = &msg_info->msg_index; key.len = sizeof(msg_info->msg_index); r = chash_get(folder->fl_msgs_hash, &key, &data); if (r < 0) return MAIL_ERROR_INVAL; mh_msg_info = data.data; - snprintf(static_uid, PATH_MAX, "%u-%lu-%u", msg_info->msg_index, - mh_msg_info->msg_mtime, mh_msg_info->msg_size); + snprintf(static_uid, PATH_MAX, "%u-%lu-%lu", msg_info->msg_index, + mh_msg_info->msg_mtime, (unsigned long) mh_msg_info->msg_size); uid = strdup(static_uid); if (uid == NULL) return MAIL_ERROR_MEMORY; r = mailmessage_generic_initialize(msg_info); if (r != MAIL_NO_ERROR) { free(uid); return r; } msg = msg_info->msg_data; msg->msg_prefetch = mh_prefetch; msg->msg_prefetch_free = mh_prefetch_free; msg_info->msg_uid = uid; return MAIL_NO_ERROR; } static void mh_uninitialize(mailmessage * msg_info) { mailmessage_generic_uninitialize(msg_info); } #define FLAGS_NAME "flags.db" static void mh_flush(mailmessage * msg_info) { mailmessage_generic_flush(msg_info); } static void mh_check(mailmessage * msg_info) { int r; if (msg_info->msg_flags != NULL) { r = mail_flags_store_set(get_cached_session_data(msg_info)->mh_flags_store, msg_info); /* ignore errors */ } } static int mh_fetch_size(mailmessage * msg_info, size_t * result) { int r; size_t size; r = mhdriver_fetch_size(get_ancestor_session(msg_info), msg_info->msg_index, &size); if (r != MAIL_NO_ERROR) return r; * result = size; return MAIL_NO_ERROR; } static int mh_get_flags(mailmessage * msg_info, struct mail_flags ** result) { int r; struct mail_flags * flags; struct mail_cache_db * cache_db_flags; char filename_flags[PATH_MAX]; int res; struct mh_cached_session_state_data * cached_data; MMAPString * mmapstr; if (msg_info->msg_flags != NULL) { * result = msg_info->msg_flags; return MAIL_NO_ERROR; } cached_data = get_cached_session_data(msg_info); flags = mail_flags_store_get(cached_data->mh_flags_store, msg_info->msg_index); if (flags == NULL) { if (cached_data->mh_quoted_mb == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } snprintf(filename_flags, PATH_MAX, "%s/%s/%s", cached_data->mh_flags_directory, cached_data->mh_quoted_mb, FLAGS_NAME); r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_MEMORY; goto err; } mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto close_db_flags; } r = mhdriver_get_cached_flags(cache_db_flags, mmapstr, msg_info->msg_session, msg_info->msg_index, &flags); if (r != MAIL_NO_ERROR) { flags = mail_flags_new_empty(); if (flags == NULL) { res = MAIL_ERROR_MEMORY; goto free_mmapstr; } } mmap_string_free(mmapstr); mail_cache_db_close_unlock(filename_flags, cache_db_flags); } msg_info->msg_flags = flags; * result = flags; return MAIL_NO_ERROR; free_mmapstr: mmap_string_free(mmapstr); close_db_flags: mail_cache_db_close_unlock(filename_flags, cache_db_flags); err: return res; } static int mh_fetch_header(mailmessage * msg_info, char ** result, size_t * result_len) { struct generic_message_t * msg; int r; char * msg_content; size_t msg_length; msg = msg_info->msg_data; if (msg->msg_message != NULL) { return mailmessage_generic_fetch_header(msg_info, result, result_len); } else { r = mhdriver_fetch_header(get_ancestor_session(msg_info), msg_info->msg_index, &msg_content, &msg_length); if (r != MAIL_NO_ERROR) return r; * result = msg_content; * result_len = msg_length; return MAIL_NO_ERROR; } } diff --git a/kmicromail/libetpan/generic/mhdriver_message.c b/kmicromail/libetpan/generic/mhdriver_message.c index 2c023e7..aafd2d9 100644 --- a/kmicromail/libetpan/generic/mhdriver_message.c +++ b/kmicromail/libetpan/generic/mhdriver_message.c @@ -1,212 +1,213 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "mhdriver_message.h" #include "mailmessage_tools.h" #include "mhdriver_tools.h" #include "mhdriver.h" #include "mailmh.h" #include <unistd.h> #include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <stdlib.h> static int mh_prefetch(mailmessage * msg_info); static void mh_prefetch_free(struct generic_message_t * msg); static int mh_initialize(mailmessage * msg_info); static int mh_fetch_size(mailmessage * msg_info, size_t * result); static int mh_fetch_header(mailmessage * msg_info, char ** result, size_t * result_len); static mailmessage_driver local_mh_message_driver = { .msg_name = "mh", .msg_initialize = mh_initialize, .msg_uninitialize = mailmessage_generic_uninitialize, .msg_flush = mailmessage_generic_flush, .msg_check = NULL, .msg_fetch_result_free = mailmessage_generic_fetch_result_free, .msg_fetch = mailmessage_generic_fetch, .msg_fetch_header = mh_fetch_header, .msg_fetch_body = mailmessage_generic_fetch_body, .msg_fetch_size = mh_fetch_size, .msg_get_bodystructure = mailmessage_generic_get_bodystructure, .msg_fetch_section = mailmessage_generic_fetch_section, .msg_fetch_section_header = mailmessage_generic_fetch_section_header, .msg_fetch_section_mime = mailmessage_generic_fetch_section_mime, .msg_fetch_section_body = mailmessage_generic_fetch_section_body, .msg_fetch_envelope = mailmessage_generic_fetch_envelope, .msg_get_flags = NULL, }; mailmessage_driver * mh_message_driver = &local_mh_message_driver; static int mh_prefetch(mailmessage * msg_info) { struct generic_message_t * msg; int r; char * msg_content; size_t msg_length; r = mhdriver_fetch_message(msg_info->msg_session, msg_info->msg_index, &msg_content, &msg_length); if (r != MAIL_NO_ERROR) return r; msg = msg_info->msg_data; msg->msg_message = msg_content; msg->msg_length = msg_length; return MAIL_NO_ERROR; } static void mh_prefetch_free(struct generic_message_t * msg) { if (msg->msg_message != NULL) { mmap_string_unref(msg->msg_message); msg->msg_message = NULL; } } static inline struct mh_session_state_data * get_data(mailmessage * msg) { return msg->msg_session->sess_data; } static inline struct mailmh_folder * get_mh_cur_folder(mailmessage * msg) { return get_data(msg)->mh_cur_folder; } static int mh_initialize(mailmessage * msg_info) { struct generic_message_t * msg; int r; char * uid; char static_uid[PATH_MAX]; struct mailmh_msg_info * mh_msg_info; chashdatum key; chashdatum value; key.data = &msg_info->msg_index; key.len = sizeof(msg_info->msg_index); r = chash_get(get_mh_cur_folder(msg_info)->fl_msgs_hash, &key, &value); if (r < 0) return MAIL_ERROR_INVAL; mh_msg_info = value.data; - snprintf(static_uid, PATH_MAX, "%u-%lu-%u", msg_info->msg_index, - mh_msg_info->msg_mtime, mh_msg_info->msg_size); + snprintf(static_uid, PATH_MAX, "%u-%lu-%lu", msg_info->msg_index, + (unsigned long) mh_msg_info->msg_mtime, + (unsigned long) mh_msg_info->msg_size); uid = strdup(static_uid); if (uid == NULL) return MAIL_ERROR_MEMORY; r = mailmessage_generic_initialize(msg_info); if (r != MAIL_NO_ERROR) { free(uid); return r; } msg = msg_info->msg_data; msg->msg_prefetch = mh_prefetch; msg->msg_prefetch_free = mh_prefetch_free; msg_info->msg_uid = uid; return MAIL_NO_ERROR; } static int mh_fetch_size(mailmessage * msg_info, size_t * result) { int r; size_t size; r = mhdriver_fetch_size(msg_info->msg_session, msg_info->msg_index, &size); if (r != MAIL_NO_ERROR) return r; * result = size; return MAIL_NO_ERROR; } static int mh_fetch_header(mailmessage * msg_info, char ** result, size_t * result_len) { struct generic_message_t * msg; int r; char * msg_content; size_t msg_length; msg = msg_info->msg_data; if (msg->msg_message != NULL) { r = mailmessage_generic_fetch_header(msg_info, result, result_len); return r; } else { r = mhdriver_fetch_header(msg_info->msg_session, msg_info->msg_index, &msg_content, &msg_length); if (r != MAIL_NO_ERROR) return r; * result = msg_content; * result_len = msg_length; return MAIL_NO_ERROR; } } diff --git a/kmicromail/libetpan/generic/mhdriver_tools.c b/kmicromail/libetpan/generic/mhdriver_tools.c index cb863fa..c15bb6d 100644 --- a/kmicromail/libetpan/generic/mhdriver_tools.c +++ b/kmicromail/libetpan/generic/mhdriver_tools.c @@ -1,475 +1,476 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "mhdriver_tools.h" #include "mailmessage.h" #include "mhdriver.h" #include "mhdriver_cached.h" #include "maildriver_types.h" #include "mailmh.h" #include "generic_cache.h" #include "imfcache.h" #include "mail_cache_db.h" #include <unistd.h> #include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <stdlib.h> int mhdriver_mh_error_to_mail_error(int error) { switch (error) { case MAILMH_NO_ERROR: return MAIL_NO_ERROR; case MAILMH_ERROR_FOLDER: return MAIL_NO_ERROR; case MAILMH_ERROR_MEMORY: return MAIL_ERROR_MEMORY; case MAILMH_ERROR_FILE: return MAIL_ERROR_FILE; case MAILMH_ERROR_COULD_NOT_ALLOC_MSG: return MAIL_ERROR_APPEND; case MAILMH_ERROR_RENAME: return MAIL_ERROR_RENAME; case MAILMH_ERROR_MSG_NOT_FOUND: return MAIL_ERROR_MSG_NOT_FOUND; default: return MAIL_ERROR_INVAL; } } static inline struct mh_session_state_data * get_data(mailsession * session) { return session->sess_data; } static inline struct mailmh_folder * get_mh_cur_folder(mailsession * session) { return get_data(session)->mh_cur_folder; } static inline struct mh_cached_session_state_data * cached_get_data(mailsession * session) { return session->sess_data; } static inline mailsession * cached_get_ancestor(mailsession * session) { return cached_get_data(session)->mh_ancestor; } static inline struct mh_session_state_data * cached_get_ancestor_data(mailsession * session) { return get_data(cached_get_ancestor(session)); } static inline struct mailmh_folder * cached_get_mh_cur_folder(mailsession * session) { return get_mh_cur_folder(cached_get_ancestor(session)); } int mhdriver_fetch_message(mailsession * session, uint32_t index, char ** result, size_t * result_len) { size_t size; size_t cur_token; struct mailmh_folder * folder; int fd; MMAPString * mmapstr; char * str; int res; int r; folder = get_mh_cur_folder(session); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } r = mailmh_folder_get_message_fd(folder, index, O_RDONLY, &fd); switch (r) { case MAILMH_NO_ERROR: break; default: res = mhdriver_mh_error_to_mail_error(r); goto close; } r = mhdriver_fetch_size(session, index, &size); switch (r) { case MAILMH_NO_ERROR: break; default: res = mhdriver_mh_error_to_mail_error(r); goto close; } str = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); if (str == MAP_FAILED) { res = MAIL_ERROR_FETCH; goto close; } /* strip "From " header for broken implementations */ /* XXX - called twice, make a function */ cur_token = 0; if (strncmp("From ", str, size) == 0) { cur_token += 5; while (str[cur_token] != '\n') { if (cur_token >= size) break; cur_token ++; } } mmapstr = mmap_string_new_len(str + cur_token, size - cur_token); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto unmap; } if (mmap_string_ref(mmapstr) != 0) { res = MAIL_ERROR_MEMORY; goto free_str; } munmap(str, size); close(fd); * result = mmapstr->str; * result_len = mmapstr->len; return MAIL_NO_ERROR; free_str: mmap_string_free(mmapstr); unmap: munmap(str, size); close: close(fd); err: return res; } int mhdriver_fetch_header(mailsession * session, uint32_t index, char ** result, size_t * result_len) { size_t size; size_t cur_token; size_t begin; struct mailmh_folder * folder; int fd; MMAPString * mmapstr; char * str; int res; int r; folder = get_mh_cur_folder(session); if (folder == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } r = mailmh_folder_get_message_fd(folder, index, O_RDONLY, &fd); switch (r) { case MAILMH_NO_ERROR: break; default: res = mhdriver_mh_error_to_mail_error(r); goto close; } r = mhdriver_fetch_size(session, index, &size); switch (r) { case MAILMH_NO_ERROR: break; default: res = mhdriver_mh_error_to_mail_error(r); goto close; } str = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); if (str == MAP_FAILED) { res = MAIL_ERROR_FETCH; goto close; } /* strip "From " header for broken implementations */ cur_token = 0; if (size > 5) { if (strncmp("From ", str, size) == 0) { cur_token += 5; while (str[cur_token] != '\n') { if (cur_token >= size) break; cur_token ++; } } } begin = cur_token; while (1) { r = mailimf_ignore_field_parse(str, size, &cur_token); if (r == MAILIMF_NO_ERROR) { /* do nothing */ } else break; } mailimf_crlf_parse(str, size, &cur_token); mmapstr = mmap_string_new_len(str + begin, cur_token - begin); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto unmap; } if (mmap_string_ref(mmapstr) != 0) { res = MAIL_ERROR_MEMORY; goto free_str; } munmap(str, size); close(fd); * result = mmapstr->str; * result_len = mmapstr->len; return MAIL_NO_ERROR; free_str: mmap_string_free(mmapstr); unmap: munmap(str, size); close: close(fd); err: return res; } int mhdriver_fetch_size(mailsession * session, uint32_t index, size_t * result) { struct mailmh_folder * folder; int r; struct stat buf; char * name; folder = get_mh_cur_folder(session); if (folder == NULL) return MAIL_ERROR_FETCH; r = mailmh_folder_get_message_filename(folder, index, &name); switch (r) { case MAILMH_NO_ERROR: break; default: return mhdriver_mh_error_to_mail_error(r); } r = stat(name, &buf); free(name); if (r == -1) return MAIL_ERROR_FETCH; * result = buf.st_size; return MAIL_NO_ERROR; } int mhdriver_get_cached_flags(struct mail_cache_db * cache_db, MMAPString * mmapstr, mailsession * session, uint32_t num, struct mail_flags ** result) { int r; char keyname[PATH_MAX]; struct mail_flags * flags; int res; struct mailmh_msg_info * msg_info; chashdatum key; chashdatum data; struct mailmh_folder * folder; folder = cached_get_mh_cur_folder(session); #if 0 msg_info = cinthash_find(mh_data->cur_folder->fl_msgs_hash, num); if (msg_info == NULL) return MAIL_ERROR_CACHE_MISS; #endif key.data = # key.len = sizeof(num); r = chash_get(folder->fl_msgs_hash, &key, &data); if (r < 0) return MAIL_ERROR_CACHE_MISS; msg_info = data.data; - snprintf(keyname, PATH_MAX, "%u-%u-%u-flags", - num, (uint32_t) msg_info->msg_mtime, msg_info->msg_size); + snprintf(keyname, PATH_MAX, "%u-%lu-%lu-flags", + num, (unsigned long) msg_info->msg_mtime, + (unsigned long) msg_info->msg_size); r = generic_cache_flags_read(cache_db, mmapstr, keyname, &flags); if (r != MAIL_NO_ERROR) { res = r; goto err; } * result = flags; return MAIL_NO_ERROR; err: return res; } int mhdriver_write_cached_flags(struct mail_cache_db * cache_db, MMAPString * mmapstr, char * uid, struct mail_flags * flags) { int r; char keyname[PATH_MAX]; int res; snprintf(keyname, PATH_MAX, "%s-flags", uid); r = generic_cache_flags_write(cache_db, mmapstr, keyname, flags); if (r != MAIL_NO_ERROR) { res = r; goto err; } return MAIL_NO_ERROR; err: return res; } int mh_get_messages_list(struct mailmh_folder * folder, mailsession * session, mailmessage_driver * driver, struct mailmessage_list ** result) { unsigned int i; struct mailmessage_list * env_list; int r; carray * tab; int res; tab = carray_new(128); if (tab == NULL) { res = MAIL_ERROR_MEMORY; goto err; } for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i++) { struct mailmh_msg_info * mh_info; mailmessage * msg; mh_info = carray_get(folder->fl_msgs_tab, i); if (mh_info == NULL) continue; msg = mailmessage_new(); if (msg == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } r = mailmessage_init(msg, session, driver, mh_info->msg_index, mh_info->msg_size); if (r != MAIL_NO_ERROR) { res = r; goto free_list; } r = carray_add(tab, msg, NULL); if (r < 0) { mailmessage_free(msg); res = MAIL_ERROR_MEMORY; goto free_list; } } env_list = mailmessage_list_new(tab); if (env_list == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } * result = env_list; return MAIL_NO_ERROR; free_list: for(i = 0 ; i < carray_count(tab) ; i ++) mailmessage_free(carray_get(tab, i)); carray_free(tab); err: return res; } diff --git a/kmicromail/libetpan/generic/mhstorage.c b/kmicromail/libetpan/generic/mhstorage.c index 32fc26b..715b961 100644 --- a/kmicromail/libetpan/generic/mhstorage.c +++ b/kmicromail/libetpan/generic/mhstorage.c @@ -1,192 +1,192 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "mhstorage.h" #include "mhdriver.h" #include "mhdriver_cached.h" #include "mail.h" #include <stdlib.h> #include <string.h> /* mh storage */ static int mh_mailstorage_connect(struct mailstorage * storage); static int mh_mailstorage_get_folder_session(struct mailstorage * storage, char * pathname, mailsession ** result); static void mh_mailstorage_uninitialize(struct mailstorage * storage); static mailstorage_driver mh_mailstorage_driver = { .sto_name = "mh", .sto_connect = mh_mailstorage_connect, .sto_get_folder_session = mh_mailstorage_get_folder_session, .sto_uninitialize = mh_mailstorage_uninitialize, }; int mh_mailstorage_init(struct mailstorage * storage, char * mh_pathname, int mh_cached, char * mh_cache_directory, char * mh_flags_directory) { struct mh_mailstorage * mh_storage; - mh_storage = malloc(sizeof(struct mh_mailstorage)); + mh_storage = malloc(sizeof(* mh_storage)); if (mh_storage == NULL) goto err; mh_storage->mh_pathname = strdup(mh_pathname); if (mh_storage->mh_pathname == NULL) goto free; mh_storage->mh_cached = mh_cached; if (mh_cached && (mh_cache_directory != NULL) && (mh_flags_directory != NULL)) { mh_storage->mh_cache_directory = strdup(mh_cache_directory); if (mh_storage->mh_cache_directory == NULL) goto free_pathname; mh_storage->mh_flags_directory = strdup(mh_flags_directory); if (mh_storage->mh_flags_directory == NULL) goto free_cache_directory; } else { mh_storage->mh_cached = FALSE; mh_storage->mh_cache_directory = NULL; mh_storage->mh_flags_directory = NULL; } storage->sto_data = mh_storage; storage->sto_driver = &mh_mailstorage_driver; return MAIL_NO_ERROR; free_cache_directory: free(mh_storage->mh_cache_directory); free_pathname: free(mh_storage->mh_pathname); free: free(mh_storage); err: return MAIL_ERROR_MEMORY; } static void mh_mailstorage_uninitialize(struct mailstorage * storage) { struct mh_mailstorage * mh_storage; mh_storage = storage->sto_data; if (mh_storage->mh_flags_directory != NULL) free(mh_storage->mh_flags_directory); if (mh_storage->mh_cache_directory != NULL) free(mh_storage->mh_cache_directory); free(mh_storage->mh_pathname); free(mh_storage); storage->sto_data = NULL; } static int mh_mailstorage_connect(struct mailstorage * storage) { struct mh_mailstorage * mh_storage; mailsession_driver * driver; int r; int res; mailsession * session; mh_storage = storage->sto_data; if (mh_storage->mh_cached) driver = mh_cached_session_driver; else driver = mh_session_driver; session = mailsession_new(driver); if (session == NULL) { res = MAIL_ERROR_MEMORY; goto err; } if (mh_storage->mh_cached) { r = mailsession_parameters(session, MHDRIVER_CACHED_SET_CACHE_DIRECTORY, mh_storage->mh_cache_directory); if (r != MAIL_NO_ERROR) { res = r; goto free; } r = mailsession_parameters(session, MHDRIVER_CACHED_SET_FLAGS_DIRECTORY, mh_storage->mh_flags_directory); if (r != MAIL_NO_ERROR) { res = r; goto free; } } r = mailsession_connect_path(session, mh_storage->mh_pathname); switch (r) { case MAIL_NO_ERROR_NON_AUTHENTICATED: case MAIL_NO_ERROR_AUTHENTICATED: case MAIL_NO_ERROR: break; default: res = r; goto free; } storage->sto_session = session; return MAIL_NO_ERROR; free: mailsession_free(session); err: return res; } static int mh_mailstorage_get_folder_session(struct mailstorage * storage, char * pathname, mailsession ** result) { int r; r = mailsession_select_folder(storage->sto_session, pathname); if (r != MAIL_NO_ERROR) return r; * result = storage->sto_session; return MAIL_NO_ERROR; } diff --git a/kmicromail/libetpan/generic/nntpdriver.c b/kmicromail/libetpan/generic/nntpdriver.c index fde5f1a..1b65838 100644 --- a/kmicromail/libetpan/generic/nntpdriver.c +++ b/kmicromail/libetpan/generic/nntpdriver.c @@ -1,1170 +1,1180 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "nntpdriver.h" #include <string.h> #include <stdlib.h> #include "mail.h" #include "mailmessage.h" #include "nntpdriver_tools.h" #include "maildriver_tools.h" #include "nntpdriver_message.h" static int nntpdriver_initialize(mailsession * session); static void nntpdriver_uninitialize(mailsession * session); static int nntpdriver_parameters(mailsession * session, int id, void * value); static int nntpdriver_connect_stream(mailsession * session, mailstream * s); static int nntpdriver_login(mailsession * session, char * userid, char * password); static int nntpdriver_logout(mailsession * session); static int nntpdriver_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); static int nntpdriver_messages_number(mailsession * session, char * mb, uint32_t * result); static int nntpdriver_append_message(mailsession * session, char * message, size_t size); +static int nntpdriver_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags); + static int nntpdriver_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list); static int nntpdriver_get_messages_list(mailsession * session, struct mailmessage_list ** result); static int nntpdriver_list_folders(mailsession * session, char * mb, struct mail_list ** result); static int nntpdriver_lsub_folders(mailsession * session, char * mb, struct mail_list ** result); static int nntpdriver_subscribe_folder(mailsession * session, char * mb); static int nntpdriver_unsubscribe_folder(mailsession * session, char * mb); static int nntpdriver_get_message(mailsession * session, uint32_t num, mailmessage ** result); static int nntpdriver_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result); static int nntpdriver_noop(mailsession * session); static mailsession_driver local_nntp_session_driver = { .sess_name = "nntp", .sess_initialize = nntpdriver_initialize, .sess_uninitialize = nntpdriver_uninitialize, .sess_parameters = nntpdriver_parameters, .sess_connect_stream = nntpdriver_connect_stream, .sess_connect_path = NULL, .sess_starttls = NULL, .sess_login = nntpdriver_login, .sess_logout = nntpdriver_logout, .sess_noop = nntpdriver_noop, .sess_build_folder_name = NULL, .sess_create_folder = NULL, .sess_delete_folder = NULL, .sess_rename_folder = NULL, .sess_check_folder = NULL, .sess_examine_folder = NULL, .sess_select_folder = nntpdriver_select_folder, .sess_expunge_folder = NULL, .sess_status_folder = nntpdriver_status_folder, .sess_messages_number = nntpdriver_messages_number, .sess_recent_number = nntpdriver_messages_number, .sess_unseen_number = nntpdriver_messages_number, .sess_list_folders = nntpdriver_list_folders, .sess_lsub_folders = nntpdriver_lsub_folders, .sess_subscribe_folder = nntpdriver_subscribe_folder, .sess_unsubscribe_folder = nntpdriver_unsubscribe_folder, .sess_append_message = nntpdriver_append_message, + .sess_append_message_flags = nntpdriver_append_message_flags, .sess_copy_message = NULL, .sess_move_message = NULL, .sess_get_messages_list = nntpdriver_get_messages_list, .sess_get_envelopes_list = nntpdriver_get_envelopes_list, .sess_remove_message = NULL, #if 0 .sess_search_messages = maildriver_generic_search_messages, #endif .sess_get_message = nntpdriver_get_message, .sess_get_message_by_uid = nntpdriver_get_message_by_uid, }; mailsession_driver * nntp_session_driver = &local_nntp_session_driver; static inline struct nntp_session_state_data * get_data(mailsession * session) { return session->sess_data; } static inline newsnntp * get_nntp_session(mailsession * session) { return get_data(session)->nntp_session; } static int nntpdriver_initialize(mailsession * session) { struct nntp_session_state_data * data; newsnntp * nntp; nntp = newsnntp_new(0, NULL); if (nntp == NULL) goto err; data = malloc(sizeof(* data)); if (data == NULL) goto free; data->nntp_session = nntp; data->nntp_userid = NULL; data->nntp_password = NULL; data->nntp_group_info = NULL; data->nntp_group_name = NULL; data->nntp_subscribed_list = clist_new(); if (data->nntp_subscribed_list == NULL) goto free_data; data->nntp_max_articles = 0; data->nntp_mode_reader = FALSE; session->sess_data = data; return MAIL_NO_ERROR; free_data: free(data); free: newsnntp_free(nntp); err: return MAIL_ERROR_MEMORY; } static void nntpdriver_uninitialize(mailsession * session) { struct nntp_session_state_data * data; data = get_data(session); clist_foreach(data->nntp_subscribed_list, (clist_func) free, NULL); clist_free(data->nntp_subscribed_list); if (data->nntp_group_info != NULL) newsnntp_group_free(data->nntp_group_info); if (data->nntp_group_name != NULL) free(data->nntp_group_name); if (data->nntp_userid != NULL) free(data->nntp_userid); if (data->nntp_password != NULL) free(data->nntp_password); newsnntp_free(data->nntp_session); free(data); session->sess_data = NULL; } static int nntpdriver_parameters(mailsession * session, int id, void * value) { struct nntp_session_state_data * data; data = get_data(session); switch (id) { case NNTPDRIVER_SET_MAX_ARTICLES: { uint32_t * param; param = value; data->nntp_max_articles = * param; return MAIL_NO_ERROR; } } return MAIL_ERROR_INVAL; } static int add_to_list(mailsession * session, char * mb) { char * new_mb; int r; struct nntp_session_state_data * data; data = get_data(session); new_mb = strdup(mb); if (new_mb == NULL) return -1; r = clist_append(data->nntp_subscribed_list, new_mb); if (r < 0) { free(mb); return -1; } return 0; } static int remove_from_list(mailsession * session, char * mb) { clistiter * cur; struct nntp_session_state_data * data; data = get_data(session); for(cur = clist_begin(data->nntp_subscribed_list) ; cur != NULL ; cur = clist_next(cur)) { char * cur_name; cur_name = clist_content(cur); if (strcmp(cur_name, mb) == 0) { clist_delete(data->nntp_subscribed_list, cur); free(cur_name); return 0; } } return -1; } static int nntpdriver_connect_stream(mailsession * session, mailstream * s) { int r; r = newsnntp_connect(get_nntp_session(session), s); switch (r) { case NEWSNNTP_NO_ERROR: return MAIL_NO_ERROR_NON_AUTHENTICATED; default: return nntpdriver_nntp_error_to_mail_error(r); } } static int nntpdriver_login(mailsession * session, char * userid, char * password) { struct nntp_session_state_data * data; char * new_userid; char * new_password; data = get_data(session); if (userid != NULL) { new_userid = strdup(userid); if (new_userid == NULL) goto err; } else new_userid = NULL; if (password != NULL) { new_password = strdup(password); if (new_password == NULL) goto free_uid; } else new_password = NULL; data->nntp_userid = new_userid; data->nntp_password = new_password; return MAIL_NO_ERROR; free_uid: if (new_userid != NULL) free(new_userid); err: return MAIL_ERROR_MEMORY; } static int nntpdriver_logout(mailsession * session) { int r; r = newsnntp_quit(get_nntp_session(session)); return nntpdriver_nntp_error_to_mail_error(r); } static int nntpdriver_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { uint32_t count; int r; r = nntpdriver_select_folder(session, mb); if (r != MAIL_NO_ERROR) return r; r = nntpdriver_messages_number(session, mb, &count); if (r != MAIL_NO_ERROR) return r; * result_messages = count; * result_recent = count; * result_unseen = count; return MAIL_NO_ERROR; } static int nntpdriver_messages_number(mailsession * session, char * mb, uint32_t * result) { int r; struct nntp_session_state_data * data; if (mb != NULL) { r = nntpdriver_select_folder(session, mb); if (r != MAIL_NO_ERROR) return r; } data = get_data(session); if (data->nntp_group_info == NULL) return MAIL_ERROR_FOLDER_NOT_FOUND; * result = data->nntp_group_info->grp_last - data->nntp_group_info->grp_first + 1; return MAIL_NO_ERROR; } static int nntpdriver_list_folders(mailsession * session, char * mb, struct mail_list ** result) { int r; clist * group_list; newsnntp * nntp; clistiter * cur; char * new_mb; int done; clist * list; struct mail_list * ml; int res; nntp = get_nntp_session(session); new_mb = NULL; if ((mb != NULL) && (*mb != '\0')) { new_mb = malloc(strlen(mb) + 3); if (new_mb == NULL) { res = MAIL_ERROR_MEMORY; goto err; } strcpy(new_mb, mb); strcat(new_mb, ".*"); } done = FALSE; do { if (new_mb != NULL) r = newsnntp_list_active(nntp, new_mb, &group_list); else r = newsnntp_list(nntp, &group_list); switch (r) { case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME: r = nntpdriver_authenticate_user(session); if (r != MAIL_NO_ERROR) { res = r; goto err; } break; case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD: r = nntpdriver_authenticate_password(session); if (r != MAIL_NO_ERROR) { res = r; goto err; } break; case NEWSNNTP_NO_ERROR: if (new_mb != NULL) free(new_mb); done = TRUE; break; default: if (new_mb != NULL) free(new_mb); return nntpdriver_nntp_error_to_mail_error(r); } } while (!done); list = clist_new(); if (list == NULL) { res = MAIL_ERROR_MEMORY; goto err; } for(cur = clist_begin(group_list) ; cur != NULL ; cur = clist_next(cur)) { struct newsnntp_group_info * info; char * new_name; info = clist_content(cur); new_name = strdup(info->grp_name); if (new_name == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, new_name); if (r < 0) { free(new_name); res = MAIL_ERROR_MEMORY; goto free_list; } } ml = mail_list_new(list); if (ml == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } newsnntp_list_free(group_list); * result = ml; return MAIL_NO_ERROR; free_list: clist_foreach(list, (clist_func) free, NULL); clist_free(list); newsnntp_list_free(group_list); err: return res; } static int nntpdriver_lsub_folders(mailsession * session, char * mb, struct mail_list ** result) { clist * subscribed; clist * lsub_result; clistiter * cur; struct mail_list * lsub; size_t length; int res; int r; struct nntp_session_state_data * data; length = strlen(mb); data = get_data(session); subscribed = data->nntp_subscribed_list; lsub_result = clist_new(); if (lsub_result == NULL) { res = MAIL_ERROR_MEMORY; goto err; } for(cur = clist_begin(subscribed) ; cur != NULL ; cur = clist_next(cur)) { char * cur_mb; char * new_mb; cur_mb = clist_content(cur); if (strncmp(mb, cur_mb, length) == 0) { new_mb = strdup(cur_mb); if (new_mb == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(lsub_result, new_mb); if (r < 0) { free(new_mb); res = MAIL_ERROR_MEMORY; goto free_list; } } } lsub = mail_list_new(lsub_result); if (lsub == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } * result = lsub; return MAIL_NO_ERROR; free_list: clist_foreach(lsub_result, (clist_func) free, NULL); clist_free(lsub_result); err: return res; } static int nntpdriver_subscribe_folder(mailsession * session, char * mb) { int r; r = add_to_list(session, mb); if (r < 0) return MAIL_ERROR_SUBSCRIBE; return MAIL_NO_ERROR; } static int nntpdriver_unsubscribe_folder(mailsession * session, char * mb) { int r; r = remove_from_list(session, mb); if (r < 0) return MAIL_ERROR_UNSUBSCRIBE; return MAIL_NO_ERROR; } /* messages operations */ static int nntpdriver_append_message(mailsession * session, char * message, size_t size) { int r; struct nntp_session_state_data * data; data = get_data(session); do { r = newsnntp_post(get_nntp_session(session), message, size); switch (r) { case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME: r = nntpdriver_authenticate_user(session); if (r != MAIL_NO_ERROR) return r; break; case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD: r = nntpdriver_authenticate_password(session); if (r != MAIL_NO_ERROR) return r; break; default: return nntpdriver_nntp_error_to_mail_error(r); } } while (1); } +static int nntpdriver_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags) +{ + return nntpdriver_append_message(session, message, size); +} + static int xover_resp_to_fields(struct newsnntp_xover_resp_item * item, struct mailimf_fields ** result); static int nntpdriver_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list) { newsnntp * nntp; int r; struct nntp_session_state_data * data; clist * list; int done; clistiter * cur; uint32_t first_seq; unsigned int i; nntp = get_nntp_session(session); data = get_data(session); if (data->nntp_group_info == NULL) return MAIL_ERROR_BAD_STATE; first_seq = data->nntp_group_info->grp_first; if (carray_count(env_list->msg_tab) > 0) { mailmessage * msg; msg = carray_get(env_list->msg_tab, 0); first_seq = msg->msg_index; } if (carray_count(env_list->msg_tab) > 0) { i = carray_count(env_list->msg_tab) - 1; while (1) { mailmessage * msg; msg = carray_get(env_list->msg_tab, i); if (msg->msg_fields != NULL) { first_seq = msg->msg_index + 1; break; } if (i == 0) break; i --; } } if (first_seq > data->nntp_group_info->grp_last) { list = NULL; } else { done = FALSE; do { r = newsnntp_xover_range(nntp, first_seq, data->nntp_group_info->grp_last, &list); switch (r) { case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME: r = nntpdriver_authenticate_user(session); if (r != MAIL_NO_ERROR) return r; break; case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD: r = nntpdriver_authenticate_password(session); if (r != MAIL_NO_ERROR) return r; break; case NEWSNNTP_NO_ERROR: done = TRUE; break; default: return nntpdriver_nntp_error_to_mail_error(r); } } while (!done); } #if 0 i = 0; j = 0; if (list != NULL) { for(cur = clist_begin(list) ; cur != NULL ; cur = clist_next(cur)) { struct newsnntp_xover_resp_item * item; struct mailimf_fields * fields; item = clist_content(cur); while (i < carray_count(env_list->msg_tab)) { mailmessage * info; info = carray_get(env_list->msg_tab, i); if (item->ovr_article == info->msg_index) { if (info->fields == NULL) { r = xover_resp_to_fields(item, &fields); if (r == MAIL_NO_ERROR) { info->fields = fields; } info->size = item->ovr_size; carray_set(env_list->msg_tab, j, info); j ++; i ++; break; } else { carray_set(env_list->msg_tab, j, info); j ++; } } else { if (info->fields != NULL) { carray_set(env_list->msg_tab, j, info); j ++; } else { if (info->flags != NULL) { info->flags->flags &= ~MAIL_FLAG_NEW; info->flags->flags |= MAIL_FLAG_SEEN | MAIL_FLAG_DELETED; mailmessage_check(info); } mailmessage_free(info); carray_set(env_list->msg_tab, i, NULL); } } i ++; } } } while (i < carray_count(env_list->msg_tab)) { mailmessage * info; info = carray_get(env_list->msg_tab, i); if (info->fields != NULL) { carray_set(env_list->msg_tab, j, info); j ++; } else { if (info->flags != NULL) { info->flags->flags &= ~MAIL_FLAG_NEW; info->flags->flags |= MAIL_FLAG_SEEN | MAIL_FLAG_DELETED; mailmessage_check(info); } mailmessage_free(info); carray_set(env_list->msg_tab, i, NULL); } i ++; } r = carray_set_size(env_list->msg_tab, j); if (r < 0) { if (list != NULL) newsnntp_xover_resp_list_free(list); return MAIL_ERROR_MEMORY; } #endif i = 0; if (list != NULL) { for(cur = clist_begin(list) ; cur != NULL ; cur = clist_next(cur)) { struct newsnntp_xover_resp_item * item; struct mailimf_fields * fields; item = clist_content(cur); while (i < carray_count(env_list->msg_tab)) { mailmessage * info; info = carray_get(env_list->msg_tab, i); if (item->ovr_article == info->msg_index) { if (info->msg_fields == NULL) { r = xover_resp_to_fields(item, &fields); if (r == MAIL_NO_ERROR) { info->msg_fields = fields; } info->msg_size = item->ovr_size; i ++; break; } } #if 0 else if ((info->fields == NULL) && (info->flags != NULL)) { info->flags->flags &= ~MAIL_FLAG_NEW; info->flags->flags |= MAIL_FLAG_CANCELLED; mailmessage_check(info); } #endif i ++; } } } #if 0 while (i < env_list->msg_tab->len) { mailmessage * info; info = carray_get(env_list->msg_tab, i); if ((info->fields == NULL) && (info->flags != NULL)) { info->flags->flags &= ~MAIL_FLAG_NEW; info->flags->flags |= MAIL_FLAG_CANCELLED; mailmessage_check(info); } i ++; } #endif if (list != NULL) newsnntp_xover_resp_list_free(list); return MAIL_NO_ERROR; } static int xover_resp_to_fields(struct newsnntp_xover_resp_item * item, struct mailimf_fields ** result) { size_t cur_token; clist * list; int r; struct mailimf_fields * fields; int res; list = clist_new(); if (list == NULL) { res = MAIL_ERROR_MEMORY; goto err; } if (item->ovr_subject != NULL) { char * subject_str; struct mailimf_subject * subject; struct mailimf_field * field; subject_str = strdup(item->ovr_subject); if (subject_str == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } subject = mailimf_subject_new(subject_str); if (subject == NULL) { free(subject_str); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_SUBJECT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, subject, NULL, NULL, NULL); if (field == NULL) { mailimf_subject_free(subject); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r < 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } } if (item->ovr_author != NULL) { struct mailimf_mailbox_list * mb_list; struct mailimf_from * from; struct mailimf_field * field; cur_token = 0; r = mailimf_mailbox_list_parse(item->ovr_author, strlen(item->ovr_author), &cur_token, &mb_list); switch (r) { case MAILIMF_NO_ERROR: from = mailimf_from_new(mb_list); if (from == NULL) { mailimf_mailbox_list_free(mb_list); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_FROM, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, from, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (field == NULL) { mailimf_from_free(from); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r < 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } break; case MAILIMF_ERROR_PARSE: break; default: res = maildriver_imf_error_to_mail_error(r); goto free_list; } } if (item->ovr_date != NULL) { struct mailimf_date_time * date_time; struct mailimf_orig_date * orig_date; struct mailimf_field * field; cur_token = 0; r = mailimf_date_time_parse(item->ovr_date, strlen(item->ovr_date), &cur_token, &date_time); switch (r) { case MAILIMF_NO_ERROR: orig_date = mailimf_orig_date_new(date_time); if (orig_date == NULL) { mailimf_date_time_free(date_time); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_ORIG_DATE, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, orig_date, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL); if (field == NULL) { mailimf_orig_date_free(orig_date); res = MAIL_ERROR_MEMORY; goto free_list; } r = clist_append(list, field); if (r < 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } break; case MAILIMF_ERROR_PARSE: break; default: res = maildriver_imf_error_to_mail_error(r); goto free_list; } } if (item->ovr_message_id != NULL) { char * msgid_str; struct mailimf_message_id * msgid; struct mailimf_field * field; cur_token = 0; r = mailimf_msg_id_parse(item->ovr_message_id, strlen(item->ovr_message_id), &cur_token, &msgid_str); switch (r) { case MAILIMF_NO_ERROR: msgid = mailimf_message_id_new(msgid_str); if (msgid == NULL) { mailimf_msg_id_free(msgid_str); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_MESSAGE_ID, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, msgid, NULL, NULL, NULL, NULL, NULL, NULL); r = clist_append(list, field); if (r < 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } break; case MAILIMF_ERROR_PARSE: break; default: res = maildriver_imf_error_to_mail_error(r); goto free_list; } } if (item->ovr_references != NULL) { clist * msgid_list; struct mailimf_references * references; struct mailimf_field * field; cur_token = 0; r = mailimf_msg_id_list_parse(item->ovr_references, strlen(item->ovr_references), &cur_token, &msgid_list); switch (r) { case MAILIMF_NO_ERROR: references = mailimf_references_new(msgid_list); if (references == NULL) { clist_foreach(msgid_list, (clist_func) mailimf_msg_id_free, NULL); clist_free(msgid_list); res = MAIL_ERROR_MEMORY; goto free_list; } field = mailimf_field_new(MAILIMF_FIELD_REFERENCES, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, references, NULL, NULL, NULL, NULL); r = clist_append(list, field); if (r < 0) { mailimf_field_free(field); res = MAIL_ERROR_MEMORY; goto free_list; } case MAILIMF_ERROR_PARSE: break; default: res = maildriver_imf_error_to_mail_error(r); goto free_list; } } fields = mailimf_fields_new(list); if (fields == NULL) { res = MAIL_ERROR_MEMORY; goto free_list; } * result = fields; return MAIL_NO_ERROR; free_list: clist_foreach(list, (clist_func) mailimf_field_free, NULL); clist_free(list); err: return res; } /* get messages list with group info */ static int nntpdriver_get_messages_list(mailsession * session, struct mailmessage_list ** result) { return nntp_get_messages_list(session, session, nntp_message_driver, result); } static int nntpdriver_get_message(mailsession * session, uint32_t num, mailmessage ** result) { mailmessage * msg_info; int r; msg_info = mailmessage_new(); if (msg_info == NULL) return MAIL_ERROR_MEMORY; r = mailmessage_init(msg_info, session, nntp_message_driver, num, 0); if (r != MAIL_NO_ERROR) { mailmessage_free(msg_info); return r; } * result = msg_info; return MAIL_NO_ERROR; } static int nntpdriver_noop(mailsession * session) { newsnntp * nntp; int r; struct tm tm; nntp = get_nntp_session(session); r = newsnntp_date(nntp, &tm); return nntpdriver_nntp_error_to_mail_error(r); } static int nntpdriver_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result) { uint32_t num; char * p; if (uid == NULL) return MAIL_ERROR_INVAL; num = strtoul(uid, &p, 10); if ((p == uid) || (* p != '\0')) return MAIL_ERROR_INVAL; return nntpdriver_get_message(session, num, result); } diff --git a/kmicromail/libetpan/generic/nntpdriver_cached.c b/kmicromail/libetpan/generic/nntpdriver_cached.c index 1f8a8af..0343a65 100644 --- a/kmicromail/libetpan/generic/nntpdriver_cached.c +++ b/kmicromail/libetpan/generic/nntpdriver_cached.c @@ -1,1048 +1,1058 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "nntpdriver_cached.h" #include "libetpan-config.h" #include <string.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include "mail_cache_db.h" #include "mail.h" #include "mailmessage.h" #include "maildriver_tools.h" #include "nntpdriver.h" #include "maildriver.h" #include "newsnntp.h" #include "generic_cache.h" #include "imfcache.h" #include "maillock.h" #include "nntpdriver_cached_message.h" #include "nntpdriver_tools.h" static int nntpdriver_cached_initialize(mailsession * session); static void nntpdriver_cached_uninitialize(mailsession * session); static int nntpdriver_cached_parameters(mailsession * session, int id, void * value); static int nntpdriver_cached_connect_stream(mailsession * session, mailstream * s); static int nntpdriver_cached_login(mailsession * session, char * userid, char * password); static int nntpdriver_cached_logout(mailsession * session); static int nntpdriver_cached_check_folder(mailsession * session); static int nntpdriver_cached_select_folder(mailsession * session, char * mb); static int nntpdriver_cached_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); static int nntpdriver_cached_messages_number(mailsession * session, char * mb, uint32_t * result); static int nntpdriver_cached_recent_number(mailsession * session, char * mb, uint32_t * result); static int nntpdriver_cached_unseen_number(mailsession * session, char * mb, uint32_t * result); static int nntpdriver_cached_append_message(mailsession * session, char * message, size_t size); +static int nntpdriver_cached_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags); + static int nntpdriver_cached_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list); static int nntpdriver_cached_get_messages_list(mailsession * session, struct mailmessage_list ** result); static int nntpdriver_cached_list_folders(mailsession * session, char * mb, struct mail_list ** result); static int nntpdriver_cached_lsub_folders(mailsession * session, char * mb, struct mail_list ** result); static int nntpdriver_cached_subscribe_folder(mailsession * session, char * mb); static int nntpdriver_cached_unsubscribe_folder(mailsession * session, char * mb); static int nntpdriver_cached_get_message(mailsession * session, uint32_t num, mailmessage ** result); static int nntpdriver_cached_noop(mailsession * session); static int nntpdriver_cached_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result); static mailsession_driver local_nntp_cached_session_driver = { .sess_name = "nntp-cached", .sess_initialize = nntpdriver_cached_initialize, .sess_uninitialize = nntpdriver_cached_uninitialize, .sess_parameters = nntpdriver_cached_parameters, .sess_connect_stream = nntpdriver_cached_connect_stream, .sess_connect_path = NULL, .sess_starttls = NULL, .sess_login = nntpdriver_cached_login, .sess_logout = nntpdriver_cached_logout, .sess_noop = nntpdriver_cached_noop, .sess_build_folder_name = NULL, .sess_create_folder = NULL, .sess_delete_folder = NULL, .sess_rename_folder = NULL, .sess_check_folder = nntpdriver_cached_check_folder, .sess_examine_folder = NULL, .sess_select_folder = nntpdriver_cached_select_folder, .sess_expunge_folder = NULL, .sess_status_folder = nntpdriver_cached_status_folder, .sess_messages_number = nntpdriver_cached_messages_number, .sess_recent_number = nntpdriver_cached_recent_number, .sess_unseen_number = nntpdriver_cached_unseen_number, .sess_list_folders = nntpdriver_cached_list_folders, .sess_lsub_folders = nntpdriver_cached_lsub_folders, .sess_subscribe_folder = nntpdriver_cached_subscribe_folder, .sess_unsubscribe_folder = nntpdriver_cached_unsubscribe_folder, .sess_append_message = nntpdriver_cached_append_message, + .sess_append_message_flags = nntpdriver_cached_append_message_flags, .sess_copy_message = NULL, .sess_move_message = NULL, .sess_get_messages_list = nntpdriver_cached_get_messages_list, .sess_get_envelopes_list = nntpdriver_cached_get_envelopes_list, .sess_remove_message = NULL, #if 0 .sess_search_messages = maildriver_generic_search_messages, #endif .sess_get_message = nntpdriver_cached_get_message, .sess_get_message_by_uid = nntpdriver_cached_get_message_by_uid, }; mailsession_driver * nntp_cached_session_driver = &local_nntp_cached_session_driver; #define ENV_NAME "env.db" #define FLAGS_NAME "flags.db" static void read_article_seq(mailsession * session, uint32_t * pfirst, uint32_t * plast); static void write_article_seq(mailsession * session, uint32_t first, uint32_t last); static inline struct nntp_cached_session_state_data * get_cached_data(mailsession * session) { return session->sess_data; } static inline mailsession * get_ancestor(mailsession * session) { return get_cached_data(session)->nntp_ancestor; } static inline struct nntp_session_state_data * get_ancestor_data(mailsession * session) { return get_ancestor(session)->sess_data; } static inline newsnntp * get_nntp_session(mailsession * session) { return get_ancestor_data(session)->nntp_session; } static int nntpdriver_cached_initialize(mailsession * session) { struct nntp_cached_session_state_data * data; data = malloc(sizeof(* data)); if (data == NULL) goto err; data->nntp_flags_store = mail_flags_store_new(); if (data->nntp_flags_store == NULL) goto free; data->nntp_ancestor = mailsession_new(nntp_session_driver); if (data->nntp_ancestor == NULL) goto free_store; session->sess_data = data; return MAIL_NO_ERROR; free_store: mail_flags_store_free(data->nntp_flags_store); free: free(data); err: return MAIL_ERROR_MEMORY; } static int nntp_flags_store_process(char * flags_directory, char * group_name, struct mail_flags_store * flags_store) { char filename_flags[PATH_MAX]; struct mail_cache_db * cache_db_flags; MMAPString * mmapstr; unsigned int i; int r; int res; if (carray_count(flags_store->fls_tab) == 0) return MAIL_NO_ERROR; if (group_name == NULL) return MAIL_NO_ERROR; snprintf(filename_flags, PATH_MAX, "%s/%s/%s", flags_directory, group_name, FLAGS_NAME); r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_FILE; goto err; } mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto close_db_flags; } for(i = 0 ; i < carray_count(flags_store->fls_tab) ; i ++) { mailmessage * msg; msg = carray_get(flags_store->fls_tab, i); r = nntpdriver_write_cached_flags(cache_db_flags, mmapstr, msg->msg_index, msg->msg_flags); } mmap_string_free(mmapstr); mail_cache_db_close_unlock(filename_flags, cache_db_flags); mail_flags_store_clear(flags_store); return MAIL_NO_ERROR; close_db_flags: mail_cache_db_close_unlock(filename_flags, cache_db_flags); err: return res; } static void nntpdriver_cached_uninitialize(mailsession * session) { struct nntp_cached_session_state_data * cached_data; struct nntp_session_state_data * ancestor_data; cached_data = get_cached_data(session); ancestor_data = get_ancestor_data(session); nntp_flags_store_process(cached_data->nntp_flags_directory, ancestor_data->nntp_group_name, cached_data->nntp_flags_store); mail_flags_store_free(cached_data->nntp_flags_store); mailsession_free(cached_data->nntp_ancestor); free(cached_data); session->sess_data = NULL; } static int nntpdriver_cached_parameters(mailsession * session, int id, void * value) { struct nntp_cached_session_state_data * cached_data; int r; cached_data = get_cached_data(session); switch (id) { case NNTPDRIVER_CACHED_SET_CACHE_DIRECTORY: strncpy(cached_data->nntp_cache_directory, value, PATH_MAX); cached_data->nntp_cache_directory[PATH_MAX - 1] = '\0'; r = generic_cache_create_dir(cached_data->nntp_cache_directory); if (r != MAIL_NO_ERROR) return r; return MAIL_NO_ERROR; case NNTPDRIVER_CACHED_SET_FLAGS_DIRECTORY: strncpy(cached_data->nntp_flags_directory, value, PATH_MAX); cached_data->nntp_flags_directory[PATH_MAX - 1] = '\0'; r = generic_cache_create_dir(cached_data->nntp_flags_directory); if (r != MAIL_NO_ERROR) return r; return MAIL_NO_ERROR; default: return mailsession_parameters(get_ancestor(session), id, value); } } static int nntpdriver_cached_connect_stream(mailsession * session, mailstream * s) { return mailsession_connect_stream(get_ancestor(session), s); } static int nntpdriver_cached_login(mailsession * session, char * userid, char * password) { return mailsession_login(get_ancestor(session), userid, password); } static int nntpdriver_cached_logout(mailsession * session) { struct nntp_cached_session_state_data * cached_data; struct nntp_session_state_data * ancestor_data; cached_data = get_cached_data(session); ancestor_data = get_ancestor_data(session); nntp_flags_store_process(cached_data->nntp_flags_directory, ancestor_data->nntp_group_name, cached_data->nntp_flags_store); return mailsession_logout(get_ancestor(session)); } static int nntpdriver_cached_select_folder(mailsession * session, char * mb) { int r; struct nntp_session_state_data * ancestor_data; struct nntp_cached_session_state_data * cached_data; int res; char key[PATH_MAX]; cached_data = get_cached_data(session); ancestor_data = get_ancestor_data(session); nntp_flags_store_process(cached_data->nntp_flags_directory, ancestor_data->nntp_group_name, cached_data->nntp_flags_store); r = mailsession_select_folder(get_ancestor(session), mb); if (r != MAIL_NO_ERROR) return r; if (ancestor_data->nntp_group_name == NULL) return MAIL_ERROR_BAD_STATE; snprintf(key, PATH_MAX, "%s/%s", cached_data->nntp_cache_directory, ancestor_data->nntp_group_name); r = generic_cache_create_dir(key); if (r != MAIL_NO_ERROR) { res = r; goto err; } snprintf(key, PATH_MAX, "%s/%s", cached_data->nntp_flags_directory, ancestor_data->nntp_group_name); r = generic_cache_create_dir(key); if (r != MAIL_NO_ERROR) { res = r; goto err; } return MAIL_NO_ERROR; err: return res; } static int nntpdriver_cached_check_folder(mailsession * session) { struct nntp_session_state_data * ancestor_data; struct nntp_cached_session_state_data * cached_data; cached_data = get_cached_data(session); ancestor_data = get_ancestor_data(session); nntp_flags_store_process(cached_data->nntp_flags_directory, ancestor_data->nntp_group_name, cached_data->nntp_flags_store); return MAIL_NO_ERROR; } static int nntpdriver_cached_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { int res; struct nntp_cached_session_state_data * cached_data; struct nntp_session_state_data * ancestor_data; char filename_flags[PATH_MAX]; struct mail_cache_db * cache_db_flags; MMAPString * mmapstr; uint32_t i; int r; uint32_t recent; uint32_t unseen; uint32_t first; uint32_t last; uint32_t count; uint32_t additionnal; r = nntpdriver_cached_select_folder(session, mb); if (r != MAIL_NO_ERROR) { res = r; goto err; } read_article_seq(session, &first, &last); count = 0; recent = 0; unseen = 0; ancestor_data = get_ancestor_data(session); cached_data = get_cached_data(session); if (ancestor_data->nntp_group_name == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } if (ancestor_data->nntp_group_info->grp_first > first) first = ancestor_data->nntp_group_info->grp_first; if (last < first) last = ancestor_data->nntp_group_info->grp_last; snprintf(filename_flags, PATH_MAX, "%s/%s/%s", cached_data->nntp_flags_directory, ancestor_data->nntp_group_name, FLAGS_NAME); r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_MEMORY; goto err; } mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto close_db_flags; } for(i = first ; i <= last ; i++) { struct mail_flags * flags; r = nntpdriver_get_cached_flags(cache_db_flags, mmapstr, i, &flags); if (r == MAIL_NO_ERROR) { if ((flags->fl_flags & MAIL_FLAG_CANCELLED) != 0) { continue; } count ++; if ((flags->fl_flags & MAIL_FLAG_NEW) != 0) { recent ++; } if ((flags->fl_flags & MAIL_FLAG_SEEN) == 0) { unseen ++; } mail_flags_free(flags); } } if ((count == 0) && (first != last)) { count = last - first + 1; recent = count; unseen = count; } additionnal = ancestor_data->nntp_group_info->grp_last - last; recent += additionnal; unseen += additionnal; mmap_string_free(mmapstr); mail_cache_db_close_unlock(filename_flags, cache_db_flags); * result_messages = count; * result_recent = recent; * result_unseen = unseen; return MAIL_NO_ERROR; close_db_flags: mail_cache_db_close_unlock(filename_flags, cache_db_flags); err: return res; } static int nntpdriver_cached_messages_number(mailsession * session, char * mb, uint32_t * result) { uint32_t messages; uint32_t recent; uint32_t unseen; int r; r = nntpdriver_cached_status_folder(session, mb, &messages, &recent, &unseen); if (r != MAIL_NO_ERROR) return r; * result = messages; return MAIL_NO_ERROR; } static int nntpdriver_cached_recent_number(mailsession * session, char * mb, uint32_t * result) { uint32_t messages; uint32_t recent; uint32_t unseen; int r; r = nntpdriver_cached_status_folder(session, mb, &messages, &recent, &unseen); if (r != MAIL_NO_ERROR) return r; * result = recent; return MAIL_NO_ERROR; } static int nntpdriver_cached_unseen_number(mailsession * session, char * mb, uint32_t * result) { uint32_t messages; uint32_t recent; uint32_t unseen; int r; r = nntpdriver_cached_status_folder(session, mb, &messages, &recent, &unseen); if (r != MAIL_NO_ERROR) return r; * result = unseen; return MAIL_NO_ERROR; } static int nntpdriver_cached_list_folders(mailsession * session, char * mb, struct mail_list ** result) { return mailsession_list_folders(get_ancestor(session), mb, result); } static int nntpdriver_cached_lsub_folders(mailsession * session, char * mb, struct mail_list ** result) { return mailsession_lsub_folders(get_ancestor(session), mb, result); } static int nntpdriver_cached_subscribe_folder(mailsession * session, char * mb) { return mailsession_subscribe_folder(get_ancestor(session), mb); } static int nntpdriver_cached_unsubscribe_folder(mailsession * session, char * mb) { return mailsession_unsubscribe_folder(get_ancestor(session), mb); } /* messages operations */ static int nntpdriver_cached_append_message(mailsession * session, char * message, size_t size) { return mailsession_append_message(get_ancestor(session), message, size); } +static int nntpdriver_cached_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags) +{ + return nntpdriver_cached_append_message(session, message, size); +} + static int get_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr, mailsession * session, uint32_t num, struct mailimf_fields ** result) { char keyname[PATH_MAX]; int r; struct mailimf_fields * fields; int res; snprintf(keyname, PATH_MAX, "%i-envelope", num); r = generic_cache_fields_read(cache_db, mmapstr, keyname, &fields); if (r != MAIL_NO_ERROR) { res = r; goto err; } * result = fields; return MAIL_NO_ERROR; err: return res; } static int write_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr, mailsession * session, uint32_t num, struct mailimf_fields * fields) { int r; int res; char keyname[PATH_MAX]; snprintf(keyname, PATH_MAX, "%i-envelope", num); r = generic_cache_fields_write(cache_db, mmapstr, keyname, fields); if (r != MAIL_NO_ERROR) { res = r; goto err; } return MAIL_NO_ERROR; err: return res; } #define SEQ_FILENAME "articles-seq" static void read_article_seq(mailsession * session, uint32_t * pfirst, uint32_t * plast) { FILE * f; struct nntp_session_state_data * ancestor_data; uint32_t first; uint32_t last; char seq_filename[PATH_MAX]; struct nntp_cached_session_state_data * cached_data; int r; first = 0; last = 0; cached_data = get_cached_data(session); ancestor_data = get_ancestor_data(session); if (ancestor_data->nntp_group_name == NULL) return; snprintf(seq_filename, PATH_MAX, "%s/%s/%s", cached_data->nntp_cache_directory, ancestor_data->nntp_group_name, SEQ_FILENAME); f = fopen(seq_filename, "r"); if (f != NULL) { int fd; fd = fileno(f); r = maillock_read_lock(seq_filename, fd); if (r == 0) { MMAPString * mmapstr; size_t cur_token; char buf[sizeof(uint32_t) * 2]; size_t read_size; read_size = fread(buf, 1, sizeof(uint32_t) * 2, f); mmapstr = mmap_string_new_len(buf, read_size); if (mmapstr != NULL) { cur_token = 0; r = mailimf_cache_int_read(mmapstr, &cur_token, &first); r = mailimf_cache_int_read(mmapstr, &cur_token, &last); mmap_string_free(mmapstr); } maillock_read_unlock(seq_filename, fd); } fclose(f); } * pfirst = first; * plast = last; } static void write_article_seq(mailsession * session, uint32_t first, uint32_t last) { FILE * f; struct nntp_session_state_data * ancestor_data; char seq_filename[PATH_MAX]; struct nntp_cached_session_state_data * cached_data; int r; int fd; cached_data = get_cached_data(session); ancestor_data = get_ancestor_data(session); if (ancestor_data->nntp_group_name == NULL) return; snprintf(seq_filename, PATH_MAX, "%s/%s/%s", cached_data->nntp_cache_directory, ancestor_data->nntp_group_name, SEQ_FILENAME); fd = creat(seq_filename, S_IRUSR | S_IWUSR); if (fd < 0) return; f = fdopen(fd, "w"); if (f != NULL) { r = maillock_write_lock(seq_filename, fd); if (r == 0) { MMAPString * mmapstr; size_t cur_token; mmapstr = mmap_string_new(""); if (mmapstr != NULL) { r = mail_serialize_clear(mmapstr, &cur_token); if (r == MAIL_NO_ERROR) { r = mailimf_cache_int_write(mmapstr, &cur_token, first); r = mailimf_cache_int_write(mmapstr, &cur_token, last); fwrite(mmapstr->str, 1, mmapstr->len, f); } mmap_string_free(mmapstr); } maillock_write_unlock(seq_filename, fd); } fclose(f); } else close(fd); } static void get_uid_from_filename(char * filename) { char * p; if (strcmp(filename, SEQ_FILENAME) == 0) * filename = 0; p = strstr(filename, "-header"); if (p != NULL) * p = 0; } static int nntpdriver_cached_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list) { int r; unsigned int i; struct nntp_cached_session_state_data * cached_data; uint32_t first; uint32_t last; struct nntp_session_state_data * ancestor_data; char filename_env[PATH_MAX]; char filename_flags[PATH_MAX]; struct mail_cache_db * cache_db_env; struct mail_cache_db * cache_db_flags; MMAPString * mmapstr; int res; char cache_dir[PATH_MAX]; cached_data = get_cached_data(session); ancestor_data = get_ancestor_data(session); nntp_flags_store_process(cached_data->nntp_flags_directory, ancestor_data->nntp_group_name, cached_data->nntp_flags_store); if (ancestor_data->nntp_group_name == NULL) { res = MAIL_ERROR_BAD_STATE; goto err; } /* read articles sequence */ read_article_seq(session, &first, &last); mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto err; } snprintf(filename_env, PATH_MAX, "%s/%s/%s", cached_data->nntp_cache_directory, ancestor_data->nntp_group_name, ENV_NAME); r = mail_cache_db_open_lock(filename_env, &cache_db_env); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_mmapstr; } snprintf(filename_flags, PATH_MAX, "%s/%s/%s", cached_data->nntp_flags_directory, ancestor_data->nntp_group_name, FLAGS_NAME); /* fill with cached */ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; struct mailimf_fields * fields; msg = carray_get(env_list->msg_tab, i); if ((msg->msg_index < first) || (msg->msg_index > last)) continue; if (msg->msg_fields == NULL) { r = get_cached_envelope(cache_db_env, mmapstr, session, msg->msg_index, &fields); if (r == MAIL_NO_ERROR) { msg->msg_fields = fields; msg->msg_cached = TRUE; } } } mail_cache_db_close_unlock(filename_env, cache_db_env); r = mailsession_get_envelopes_list(get_ancestor(session), env_list); if (r != MAIL_NO_ERROR) { res = r; goto free_mmapstr; } r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_mmapstr; } /* add flags */ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; msg = carray_get(env_list->msg_tab, i); if (msg->msg_flags == NULL) { struct mail_flags * flags; r = nntpdriver_get_cached_flags(cache_db_flags, mmapstr, msg->msg_index, &flags); if (r == MAIL_NO_ERROR) { msg->msg_flags = flags; } else { msg->msg_flags = mail_flags_new_empty(); if (msg->msg_fields == NULL) { msg->msg_flags->fl_flags |= MAIL_FLAG_CANCELLED; mailmessage_check(msg); } } } } mail_cache_db_close_unlock(filename_flags, cache_db_flags); r = mail_cache_db_open_lock(filename_env, &cache_db_env); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_mmapstr; } r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_MEMORY; goto close_db_env; } /* must write cache */ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; msg = carray_get(env_list->msg_tab, i); if (msg->msg_fields != NULL) { if (!msg->msg_cached) { r = write_cached_envelope(cache_db_env, mmapstr, session, msg->msg_index, msg->msg_fields); } } if (msg->msg_flags != NULL) { r = nntpdriver_write_cached_flags(cache_db_flags, mmapstr, msg->msg_index, msg->msg_flags); } } first = 0; last = 0; if (carray_count(env_list->msg_tab) > 0) { mailmessage * msg; msg = carray_get(env_list->msg_tab, 0); first = msg->msg_index; msg = carray_get(env_list->msg_tab, carray_count(env_list->msg_tab) - 1); last = msg->msg_index; } /* write articles sequence */ write_article_seq(session, first, last); /* flush cache */ maildriver_cache_clean_up(cache_db_env, cache_db_flags, env_list); /* remove cache files */ snprintf(cache_dir, PATH_MAX, "%s/%s", cached_data->nntp_cache_directory, ancestor_data->nntp_group_name); mail_cache_db_close_unlock(filename_flags, cache_db_flags); mail_cache_db_close_unlock(filename_env, cache_db_env); mmap_string_free(mmapstr); maildriver_message_cache_clean_up(cache_dir, env_list, get_uid_from_filename); return MAIL_NO_ERROR; close_db_env: mail_cache_db_close_unlock(filename_env, cache_db_env); free_mmapstr: mmap_string_free(mmapstr); err: return res; } static int nntpdriver_cached_get_messages_list(mailsession * session, struct mailmessage_list ** result) { return nntp_get_messages_list(get_ancestor(session), session, nntp_cached_message_driver, result); } static int nntpdriver_cached_get_message(mailsession * session, uint32_t num, mailmessage ** result) { mailmessage * msg_info; int r; msg_info = mailmessage_new(); if (msg_info == NULL) return MAIL_ERROR_MEMORY; r = mailmessage_init(msg_info, session, nntp_cached_message_driver, num, 0); if (r != MAIL_NO_ERROR) { mailmessage_free(msg_info); return r; } * result = msg_info; return MAIL_NO_ERROR; } static int nntpdriver_cached_noop(mailsession * session) { return mailsession_noop(get_ancestor(session)); } static int nntpdriver_cached_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result) { uint32_t num; char * p; if (uid == NULL) return MAIL_ERROR_INVAL; num = strtoul(uid, &p, 10); if ((p == uid) || (* p != '\0')) return MAIL_ERROR_INVAL; return nntpdriver_cached_get_message(session, num, result); } diff --git a/kmicromail/libetpan/generic/nntpstorage.c b/kmicromail/libetpan/generic/nntpstorage.c index 5ba333b..89974cd 100644 --- a/kmicromail/libetpan/generic/nntpstorage.c +++ b/kmicromail/libetpan/generic/nntpstorage.c @@ -1,267 +1,267 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "nntpstorage.h" #include <stdlib.h> #include <string.h> #include "maildriver.h" #include "nntpdriver.h" #include "nntpdriver_cached.h" #include "mailstorage_tools.h" #include "mail.h" /* nntp storage */ #define NNTP_DEFAULT_PORT 119 #define NNTPS_DEFAULT_PORT 563 static int nntp_mailstorage_connect(struct mailstorage * storage); static int nntp_mailstorage_get_folder_session(struct mailstorage * storage, char * pathname, mailsession ** result); static void nntp_mailstorage_uninitialize(struct mailstorage * storage); static mailstorage_driver nntp_mailstorage_driver = { .sto_name = "nntp", .sto_connect = nntp_mailstorage_connect, .sto_get_folder_session = nntp_mailstorage_get_folder_session, .sto_uninitialize = nntp_mailstorage_uninitialize, }; int nntp_mailstorage_init(struct mailstorage * storage, char * nn_servername, uint16_t nn_port, char * nn_command, int nn_connection_type, int nn_auth_type, char * nn_login, char * nn_password, int nn_cached, char * nn_cache_directory, char * nn_flags_directory) { struct nntp_mailstorage * nntp_storage; int res; - nntp_storage = malloc(sizeof(struct nntp_mailstorage)); + nntp_storage = malloc(sizeof(* nntp_storage)); if (nntp_storage == NULL) { res = MAIL_ERROR_MEMORY; goto err; } nntp_storage->nntp_servername = strdup(nn_servername); if (nntp_storage->nntp_servername == NULL) { res = MAIL_ERROR_MEMORY; goto free; } nntp_storage->nntp_connection_type = nn_connection_type; if (nn_port == 0) { switch (nn_connection_type) { case CONNECTION_TYPE_PLAIN: case CONNECTION_TYPE_COMMAND: nn_port = NNTP_DEFAULT_PORT; break; case CONNECTION_TYPE_TLS: case CONNECTION_TYPE_COMMAND_TLS: nn_port = NNTPS_DEFAULT_PORT; break; default: res = MAIL_ERROR_INVAL; goto free_servername; } } nntp_storage->nntp_port = nn_port; if (nn_command != NULL) { nntp_storage->nntp_command = strdup(nn_command); if (nntp_storage->nntp_command == NULL) { res = MAIL_ERROR_MEMORY; goto free_servername; } } else nntp_storage->nntp_command = NULL; nntp_storage->nntp_auth_type = nn_auth_type; if (nn_login != NULL) { nntp_storage->nntp_login = strdup(nn_login); if (nntp_storage->nntp_login == NULL) { res = MAIL_ERROR_MEMORY; goto free_command; } } else nntp_storage->nntp_login = NULL; if (nn_password != NULL) { nntp_storage->nntp_password = strdup(nn_password); if (nntp_storage->nntp_password == NULL) { res = MAIL_ERROR_MEMORY; goto free_login; } } else nntp_storage->nntp_password = NULL; nntp_storage->nntp_cached = nn_cached; if (nn_cached && (nn_cache_directory != NULL) && (nn_flags_directory != NULL)) { nntp_storage->nntp_cache_directory = strdup(nn_cache_directory); if (nntp_storage->nntp_cache_directory == NULL) { res = MAIL_ERROR_MEMORY; goto free_password; } nntp_storage->nntp_flags_directory = strdup(nn_flags_directory); if (nntp_storage->nntp_flags_directory == NULL) { res = MAIL_ERROR_MEMORY; goto free_cache_directory; } } else { nntp_storage->nntp_cached = FALSE; nntp_storage->nntp_cache_directory = NULL; nntp_storage->nntp_flags_directory = NULL; } storage->sto_data = nntp_storage; storage->sto_driver = &nntp_mailstorage_driver; return MAIL_NO_ERROR; free_cache_directory: free(nntp_storage->nntp_cache_directory); free_password: free(nntp_storage->nntp_password); free_login: free(nntp_storage->nntp_login); free_command: free(nn_command); free_servername: free(nntp_storage->nntp_servername); free: free(nntp_storage); err: return res; } static void nntp_mailstorage_uninitialize(struct mailstorage * storage) { struct nntp_mailstorage * nntp_storage; nntp_storage = storage->sto_data; if (nntp_storage->nntp_flags_directory != NULL) free(nntp_storage->nntp_flags_directory); if (nntp_storage->nntp_cache_directory != NULL) free(nntp_storage->nntp_cache_directory); if (nntp_storage->nntp_password != NULL) free(nntp_storage->nntp_password); if (nntp_storage->nntp_login != NULL) free(nntp_storage->nntp_login); if (nntp_storage->nntp_command != NULL) free(nntp_storage->nntp_command); free(nntp_storage->nntp_servername); free(nntp_storage); storage->sto_data = NULL; } static int nntp_mailstorage_connect(struct mailstorage * storage) { struct nntp_mailstorage * nntp_storage; mailsession_driver * driver; int r; int res; mailsession * session; nntp_storage = storage->sto_data; if (nntp_storage->nntp_cached) driver = nntp_cached_session_driver; else driver = nntp_session_driver; r = mailstorage_generic_connect(driver, nntp_storage->nntp_servername, nntp_storage->nntp_port, nntp_storage->nntp_command, nntp_storage->nntp_connection_type, NNTPDRIVER_CACHED_SET_CACHE_DIRECTORY, nntp_storage->nntp_cache_directory, NNTPDRIVER_CACHED_SET_FLAGS_DIRECTORY, nntp_storage->nntp_flags_directory, &session); switch (r) { case MAIL_NO_ERROR_NON_AUTHENTICATED: case MAIL_NO_ERROR_AUTHENTICATED: case MAIL_NO_ERROR: break; default: res = r; goto err; } r = mailstorage_generic_auth(session, r, nntp_storage->nntp_connection_type, nntp_storage->nntp_login, nntp_storage->nntp_password); if (r != MAIL_NO_ERROR) { res = r; goto free; } storage->sto_session = session; return MAIL_NO_ERROR; free: mailsession_free(session); err: return res; } static int nntp_mailstorage_get_folder_session(struct mailstorage * storage, char * pathname, mailsession ** result) { int r; r = mailsession_select_folder(storage->sto_session, pathname); * result = storage->sto_session; return MAIL_NO_ERROR; } diff --git a/kmicromail/libetpan/generic/pop3driver.c b/kmicromail/libetpan/generic/pop3driver.c index 20b0fc2..375879e 100644 --- a/kmicromail/libetpan/generic/pop3driver.c +++ b/kmicromail/libetpan/generic/pop3driver.c @@ -1,387 +1,388 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "pop3driver.h" #include <string.h> #include <stdlib.h> #include "pop3driver_message.h" #include "maildriver_tools.h" #include "pop3driver_tools.h" #include "mailmessage.h" static int pop3driver_initialize(mailsession * session); static void pop3driver_uninitialize(mailsession * session); static int pop3driver_parameters(mailsession * session, int id, void * value); static int pop3driver_connect_stream(mailsession * session, mailstream * s); static int pop3driver_starttls(mailsession * session); static int pop3driver_login(mailsession * session, char * userid, char * password); static int pop3driver_logout(mailsession * session); static int pop3driver_noop(mailsession * session); static int pop3driver_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); static int pop3driver_messages_number(mailsession * session, char * mb, uint32_t * result); static int pop3driver_remove_message(mailsession * session, uint32_t num); static int pop3driver_get_messages_list(mailsession * session, struct mailmessage_list ** result); static int pop3driver_get_message(mailsession * session, uint32_t num, mailmessage ** result); static mailsession_driver local_pop3_session_driver = { .sess_name = "pop3", .sess_initialize = pop3driver_initialize, .sess_uninitialize = pop3driver_uninitialize, .sess_parameters = pop3driver_parameters, .sess_connect_stream = pop3driver_connect_stream, .sess_connect_path = NULL, .sess_starttls = pop3driver_starttls, .sess_login = pop3driver_login, .sess_logout = pop3driver_logout, .sess_noop = pop3driver_noop, .sess_build_folder_name = NULL, .sess_create_folder = NULL, .sess_delete_folder = NULL, .sess_rename_folder = NULL, .sess_check_folder = NULL, .sess_examine_folder = NULL, .sess_select_folder = NULL, .sess_expunge_folder = NULL, .sess_status_folder = pop3driver_status_folder, .sess_messages_number = pop3driver_messages_number, .sess_recent_number = pop3driver_messages_number, .sess_unseen_number = pop3driver_messages_number, .sess_list_folders = NULL, .sess_lsub_folders = NULL, .sess_subscribe_folder = NULL, .sess_unsubscribe_folder = NULL, .sess_append_message = NULL, + .sess_append_message_flags = NULL, .sess_copy_message = NULL, .sess_move_message = NULL, .sess_get_messages_list = pop3driver_get_messages_list, .sess_get_envelopes_list = maildriver_generic_get_envelopes_list, .sess_remove_message = pop3driver_remove_message, #if 0 .sess_search_messages = maildriver_generic_search_messages, #endif .sess_get_message = pop3driver_get_message, .sess_get_message_by_uid = NULL, }; mailsession_driver * pop3_session_driver = &local_pop3_session_driver; static inline struct pop3_session_state_data * get_data(mailsession * session) { return session->sess_data; } static mailpop3 * get_pop3_session(mailsession * session) { return get_data(session)->pop3_session; } static int pop3driver_initialize(mailsession * session) { struct pop3_session_state_data * data; mailpop3 * pop3; pop3 = mailpop3_new(0, NULL); if (session == NULL) goto err; data = malloc(sizeof(* data)); if (data == NULL) goto free; data->pop3_session = pop3; data->pop3_auth_type = POP3DRIVER_AUTH_TYPE_PLAIN; session->sess_data = data; return MAIL_NO_ERROR; free: mailpop3_free(pop3); err: return MAIL_ERROR_MEMORY; } static void pop3driver_uninitialize(mailsession * session) { struct pop3_session_state_data * data; data = get_data(session); mailpop3_free(data->pop3_session); free(data); session->sess_data = data; } static int pop3driver_connect_stream(mailsession * session, mailstream * s) { int r; r = mailpop3_connect(get_pop3_session(session), s); switch (r) { case MAILPOP3_NO_ERROR: return MAIL_NO_ERROR_NON_AUTHENTICATED; default: return pop3driver_pop3_error_to_mail_error(r); } } static int pop3driver_starttls(mailsession * session) { int r; int fd; mailstream_low * low; mailstream_low * new_low; mailpop3 * pop3; pop3 = get_pop3_session(session); r = mailpop3_stls(pop3); switch (r) { case MAILPOP3_NO_ERROR: break; default: return pop3driver_pop3_error_to_mail_error(r); } low = mailstream_get_low(pop3->pop3_stream); fd = mailstream_low_get_fd(low); if (fd == -1) return MAIL_ERROR_STREAM; new_low = mailstream_low_ssl_open(fd); if (new_low == NULL) return MAIL_ERROR_STREAM; mailstream_low_free(low); mailstream_set_low(pop3->pop3_stream, new_low); return MAIL_NO_ERROR; } static int pop3driver_parameters(mailsession * session, int id, void * value) { struct pop3_session_state_data * data; data = get_data(session); switch (id) { case POP3DRIVER_SET_AUTH_TYPE: { int * param; param = value; data->pop3_auth_type = * param; return MAIL_NO_ERROR; } } return MAIL_ERROR_INVAL; } static int pop3driver_login(mailsession * session, char * userid, char * password) { int r; carray * msg_tab; struct pop3_session_state_data * data; data = get_data(session); switch (data->pop3_auth_type) { case POP3DRIVER_AUTH_TYPE_TRY_APOP: r = mailpop3_login_apop(get_pop3_session(session), userid, password); if (r != MAILPOP3_NO_ERROR) r = mailpop3_login(get_pop3_session(session), userid, password); break; case POP3DRIVER_AUTH_TYPE_APOP: r = mailpop3_login_apop(get_pop3_session(session), userid, password); break; default: case POP3DRIVER_AUTH_TYPE_PLAIN: r = mailpop3_login(get_pop3_session(session), userid, password); break; } mailpop3_list(get_pop3_session(session), &msg_tab); return pop3driver_pop3_error_to_mail_error(r); } static int pop3driver_logout(mailsession * session) { int r; r = mailpop3_quit(get_pop3_session(session)); return pop3driver_pop3_error_to_mail_error(r); } static int pop3driver_noop(mailsession * session) { int r; r = mailpop3_noop(get_pop3_session(session)); return pop3driver_pop3_error_to_mail_error(r); } static int pop3driver_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { uint32_t count; int r; r = pop3driver_messages_number(session, mb, &count); if (r != MAIL_NO_ERROR) return r; * result_messages = count; * result_recent = count; * result_unseen = count; return MAIL_NO_ERROR; } static int pop3driver_messages_number(mailsession * session, char * mb, uint32_t * result) { carray * msg_tab; mailpop3_list(get_pop3_session(session), &msg_tab); * result = carray_count(msg_tab) - get_pop3_session(session)->pop3_deleted_count; return MAIL_NO_ERROR; } /* messages operations */ static int pop3driver_remove_message(mailsession * session, uint32_t num) { mailpop3 * pop3; int r; pop3 = get_pop3_session(session); r = mailpop3_dele(pop3, num); switch (r) { case MAILPOP3_ERROR_BAD_STATE: return MAIL_ERROR_BAD_STATE; case MAILPOP3_ERROR_NO_SUCH_MESSAGE: return MAIL_ERROR_MSG_NOT_FOUND; case MAILPOP3_ERROR_STREAM: return MAIL_ERROR_STREAM; case MAILPOP3_NO_ERROR: return MAIL_NO_ERROR; default: return MAIL_ERROR_REMOVE; } } static int pop3driver_get_messages_list(mailsession * session, struct mailmessage_list ** result) { mailpop3 * pop3; pop3 = get_pop3_session(session); return pop3_get_messages_list(pop3, session, pop3_message_driver, result); } static int pop3driver_get_message(mailsession * session, uint32_t num, mailmessage ** result) { mailmessage * msg_info; int r; msg_info = mailmessage_new(); if (msg_info == NULL) return MAIL_ERROR_MEMORY; r = mailmessage_init(msg_info, session, pop3_message_driver, num, 0); if (r != MAIL_NO_ERROR) { mailmessage_free(msg_info); return r; } * result = msg_info; return MAIL_NO_ERROR; } diff --git a/kmicromail/libetpan/generic/pop3driver_cached.c b/kmicromail/libetpan/generic/pop3driver_cached.c index 6f97303..24f624b 100644 --- a/kmicromail/libetpan/generic/pop3driver_cached.c +++ b/kmicromail/libetpan/generic/pop3driver_cached.c @@ -1,857 +1,899 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "pop3driver_cached.h" #include "libetpan-config.h" #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <string.h> #include <unistd.h> #include <stdlib.h> #include "mail.h" #include "mail_cache_db.h" #include "maildriver.h" #include "mailmessage.h" #include "pop3driver.h" #include "mailpop3.h" #include "generic_cache.h" #include "imfcache.h" #include "pop3driver_cached_message.h" #include "pop3driver_tools.h" #include "maildriver_tools.h" static int pop3driver_cached_initialize(mailsession * session); static void pop3driver_cached_uninitialize(mailsession * session); static int pop3driver_cached_parameters(mailsession * session, int id, void * value); static int pop3driver_cached_connect_stream(mailsession * session, mailstream * s); static int pop3driver_cached_starttls(mailsession * session); static int pop3driver_cached_login(mailsession * session, char * userid, char * password); static int pop3driver_cached_logout(mailsession * session); static int pop3driver_cached_check_folder(mailsession * session); static int pop3driver_cached_noop(mailsession * session); static int pop3driver_cached_expunge_folder(mailsession * session); static int pop3driver_cached_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); static int pop3driver_cached_messages_number(mailsession * session, char * mb, uint32_t * result); static int pop3driver_cached_recent_number(mailsession * session, char * mb, uint32_t * result); static int pop3driver_cached_unseen_number(mailsession * session, char * mb, uint32_t * result); static int pop3driver_cached_remove_message(mailsession * session, uint32_t num); static int pop3driver_cached_get_messages_list(mailsession * session, struct mailmessage_list ** result); static int pop3driver_cached_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list); static int pop3driver_cached_get_message(mailsession * session, uint32_t num, mailmessage ** result); +static int pop3driver_cached_get_message_by_uid(mailsession * session, + const char * uid, mailmessage ** result); + static mailsession_driver local_pop3_cached_session_driver = { .sess_name = "pop3-cached", .sess_initialize = pop3driver_cached_initialize, .sess_uninitialize = pop3driver_cached_uninitialize, .sess_parameters = pop3driver_cached_parameters, .sess_connect_stream = pop3driver_cached_connect_stream, .sess_connect_path = NULL, .sess_starttls = pop3driver_cached_starttls, .sess_login = pop3driver_cached_login, .sess_logout = pop3driver_cached_logout, .sess_noop = pop3driver_cached_noop, .sess_build_folder_name = NULL, .sess_create_folder = NULL, .sess_delete_folder = NULL, .sess_rename_folder = NULL, .sess_check_folder = pop3driver_cached_check_folder, .sess_examine_folder = NULL, .sess_select_folder = NULL, .sess_expunge_folder = pop3driver_cached_expunge_folder, .sess_status_folder = pop3driver_cached_status_folder, .sess_messages_number = pop3driver_cached_messages_number, .sess_recent_number = pop3driver_cached_recent_number, .sess_unseen_number = pop3driver_cached_unseen_number, .sess_list_folders = NULL, .sess_lsub_folders = NULL, .sess_subscribe_folder = NULL, .sess_unsubscribe_folder = NULL, .sess_append_message = NULL, + .sess_append_message_flags = NULL, .sess_copy_message = NULL, .sess_move_message = NULL, .sess_get_messages_list = pop3driver_cached_get_messages_list, .sess_get_envelopes_list = pop3driver_cached_get_envelopes_list, .sess_remove_message = pop3driver_cached_remove_message, #if 0 .sess_search_messages = maildriver_generic_search_messages, #endif .sess_get_message = pop3driver_cached_get_message, - .sess_get_message_by_uid = NULL, + .sess_get_message_by_uid = pop3driver_cached_get_message_by_uid, }; mailsession_driver * pop3_cached_session_driver = &local_pop3_cached_session_driver; #define ENV_NAME "env.db" #define FLAGS_NAME "flags.db" static inline struct pop3_cached_session_state_data * get_cached_data(mailsession * session) { return session->sess_data; } static inline mailsession * get_ancestor(mailsession * session) { return get_cached_data(session)->pop3_ancestor; } static inline struct pop3_session_state_data * get_ancestor_data(mailsession * session) { return get_ancestor(session)->sess_data; } static inline mailpop3 * get_pop3_session(mailsession * session) { return get_ancestor_data(session)->pop3_session; } static int pop3driver_cached_initialize(mailsession * session) { struct pop3_cached_session_state_data * data; data = malloc(sizeof(* data)); if (data == NULL) goto err; data->pop3_flags_store = mail_flags_store_new(); if (data->pop3_flags_store == NULL) goto free_data; data->pop3_ancestor = mailsession_new(pop3_session_driver); if (data->pop3_ancestor == NULL) goto free_store; data->pop3_flags_hash = chash_new(128, CHASH_COPYNONE); if (data->pop3_flags_hash == NULL) goto free_session; session->sess_data = data; return MAIL_NO_ERROR; free_session: mailsession_free(data->pop3_ancestor); free_store: mail_flags_store_free(data->pop3_flags_store); free_data: free(data); err: return MAIL_ERROR_MEMORY; } static int pop3_flags_store_process(char * flags_directory, struct mail_flags_store * flags_store) { char filename_flags[PATH_MAX]; struct mail_cache_db * cache_db_flags; MMAPString * mmapstr; unsigned int i; int r; int res; if (carray_count(flags_store->fls_tab) == 0) return MAIL_NO_ERROR; snprintf(filename_flags, PATH_MAX, "%s/%s", flags_directory, FLAGS_NAME); r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_FILE; goto err; } mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto close_db_flags; } for(i = 0 ; i < carray_count(flags_store->fls_tab) ; i ++) { mailmessage * msg; msg = carray_get(flags_store->fls_tab, i); r = pop3driver_write_cached_flags(cache_db_flags, mmapstr, msg->msg_uid, msg->msg_flags); } mmap_string_free(mmapstr); mail_cache_db_close_unlock(filename_flags, cache_db_flags); mail_flags_store_clear(flags_store); return MAIL_NO_ERROR; close_db_flags: mail_cache_db_close_unlock(filename_flags, cache_db_flags); err: return res; } static void pop3driver_cached_uninitialize(mailsession * session) { struct pop3_cached_session_state_data * data; data = get_cached_data(session); pop3_flags_store_process(data->pop3_flags_directory, data->pop3_flags_store); mail_flags_store_free(data->pop3_flags_store); chash_free(data->pop3_flags_hash); mailsession_free(data->pop3_ancestor); free(data); session->sess_data = data; } static int pop3driver_cached_check_folder(mailsession * session) { struct pop3_cached_session_state_data * pop3_data; pop3_data = get_cached_data(session); pop3_flags_store_process(pop3_data->pop3_flags_directory, pop3_data->pop3_flags_store); return MAIL_NO_ERROR; } static int pop3driver_cached_parameters(mailsession * session, int id, void * value) { struct pop3_cached_session_state_data * data; int r; data = get_cached_data(session); switch (id) { case POP3DRIVER_CACHED_SET_CACHE_DIRECTORY: strncpy(data->pop3_cache_directory, value, PATH_MAX); data->pop3_cache_directory[PATH_MAX - 1] = '\0'; r = generic_cache_create_dir(data->pop3_cache_directory); if (r != MAIL_NO_ERROR) return r; return MAIL_NO_ERROR; case POP3DRIVER_CACHED_SET_FLAGS_DIRECTORY: strncpy(data->pop3_flags_directory, value, PATH_MAX); data->pop3_flags_directory[PATH_MAX - 1] = '\0'; r = generic_cache_create_dir(data->pop3_flags_directory); if (r != MAIL_NO_ERROR) return r; return MAIL_NO_ERROR; default: return mailsession_parameters(data->pop3_ancestor, id, value); } } static int pop3driver_cached_connect_stream(mailsession * session, mailstream * s) { int r; r = mailsession_connect_stream(get_ancestor(session), s); if (r != MAIL_NO_ERROR) return r; return MAIL_NO_ERROR; } static int pop3driver_cached_starttls(mailsession * session) { return mailsession_starttls(get_ancestor(session)); } static int pop3driver_cached_login(mailsession * session, char * userid, char * password) { return mailsession_login(get_ancestor(session), userid, password); } static int pop3driver_cached_logout(mailsession * session) { struct pop3_cached_session_state_data * cached_data; cached_data = get_cached_data(session); pop3_flags_store_process(cached_data->pop3_flags_directory, cached_data->pop3_flags_store); return mailsession_logout(get_ancestor(session)); } static int pop3driver_cached_noop(mailsession * session) { return mailsession_noop(get_ancestor(session)); } static int pop3driver_cached_expunge_folder(mailsession * session) { int res; struct pop3_cached_session_state_data * cached_data; char filename_flags[PATH_MAX]; struct mail_cache_db * cache_db_flags; MMAPString * mmapstr; unsigned int i; int r; carray * msg_tab; mailpop3 * pop3; pop3 = get_pop3_session(session); cached_data = get_cached_data(session); pop3_flags_store_process(cached_data->pop3_flags_directory, cached_data->pop3_flags_store); snprintf(filename_flags, PATH_MAX, "%s/%s", cached_data->pop3_flags_directory, FLAGS_NAME); r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_MEMORY; goto err; } mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto close_db_flags; } mailpop3_list(pop3, &msg_tab); for(i = 0 ; i < carray_count(msg_tab) ; i++) { struct mailpop3_msg_info * pop3_info; struct mail_flags * flags; pop3_info = carray_get(msg_tab, i); if (pop3_info == NULL) continue; if (pop3_info->msg_deleted) continue; r = pop3driver_get_cached_flags(cache_db_flags, mmapstr, session, pop3_info->msg_index, &flags); if (r != MAIL_NO_ERROR) continue; if (flags->fl_flags & MAIL_FLAG_DELETED) { r = mailpop3_dele(pop3, pop3_info->msg_index); } mail_flags_free(flags); } mmap_string_free(mmapstr); mail_cache_db_close_unlock(filename_flags, cache_db_flags); return MAIL_NO_ERROR; close_db_flags: mail_cache_db_close_unlock(filename_flags, cache_db_flags); err: return res; } static int pop3driver_cached_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen) { int res; struct pop3_cached_session_state_data * cached_data; char filename_flags[PATH_MAX]; struct mail_cache_db * cache_db_flags; MMAPString * mmapstr; unsigned int i; int r; carray * msg_tab; mailpop3 * pop3; uint32_t recent; uint32_t unseen; recent = 0; unseen = 0; pop3 = get_pop3_session(session); cached_data = get_cached_data(session); pop3_flags_store_process(cached_data->pop3_flags_directory, cached_data->pop3_flags_store); snprintf(filename_flags, PATH_MAX, "%s/%s", cached_data->pop3_flags_directory, FLAGS_NAME); r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_MEMORY; goto err; } mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto close_db_flags; } mailpop3_list(pop3, &msg_tab); for(i = 0 ; i < carray_count(msg_tab) ; i++) { struct mailpop3_msg_info * pop3_info; struct mail_flags * flags; pop3_info = carray_get(msg_tab, i); if (pop3_info == NULL) continue; if (pop3_info->msg_deleted) continue; r = pop3driver_get_cached_flags(cache_db_flags, mmapstr, session, pop3_info->msg_index, &flags); if (r != MAIL_NO_ERROR) { recent ++; unseen ++; continue; } if ((flags->fl_flags & MAIL_FLAG_NEW) != 0) { recent ++; } if ((flags->fl_flags & MAIL_FLAG_SEEN) == 0) { unseen ++; } mail_flags_free(flags); } mmap_string_free(mmapstr); mail_cache_db_close_unlock(filename_flags, cache_db_flags); * result_messages = carray_count(msg_tab) - pop3->pop3_deleted_count; * result_recent = recent; * result_unseen = unseen; return MAIL_NO_ERROR; close_db_flags: mail_cache_db_close_unlock(filename_flags, cache_db_flags); err: return res; } static int pop3driver_cached_messages_number(mailsession * session, char * mb, uint32_t * result) { return mailsession_messages_number(get_ancestor(session), mb, result); } static int pop3driver_cached_recent_number(mailsession * session, char * mb, uint32_t * result) { uint32_t messages; uint32_t recent; uint32_t unseen; int r; r = pop3driver_cached_status_folder(session, mb, &messages, &recent, &unseen); if (r != MAIL_NO_ERROR) return r; * result = recent; return MAIL_NO_ERROR; } static int pop3driver_cached_unseen_number(mailsession * session, char * mb, uint32_t * result) { uint32_t messages; uint32_t recent; uint32_t unseen; int r; r = pop3driver_cached_status_folder(session, mb, &messages, &recent, &unseen); if (r != MAIL_NO_ERROR) return r; * result = unseen; return MAIL_NO_ERROR; } /* messages operations */ static int pop3driver_cached_remove_message(mailsession * session, uint32_t num) { return mailsession_remove_message(get_ancestor(session), num); } static int pop3driver_cached_get_messages_list(mailsession * session, struct mailmessage_list ** result) { mailpop3 * pop3; pop3 = get_pop3_session(session); return pop3_get_messages_list(pop3, session, pop3_cached_message_driver, result); } static int get_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr, mailsession * session, uint32_t num, struct mailimf_fields ** result) { int r; char keyname[PATH_MAX]; struct mailpop3_msg_info * info; struct mailimf_fields * fields; int res; mailpop3 * pop3; pop3 = get_pop3_session(session); r = mailpop3_get_msg_info(pop3, num, &info); switch (r) { case MAILPOP3_ERROR_BAD_STATE: return MAIL_ERROR_BAD_STATE; case MAILPOP3_ERROR_NO_SUCH_MESSAGE: return MAIL_ERROR_MSG_NOT_FOUND; case MAILPOP3_NO_ERROR: break; default: return MAIL_ERROR_FETCH; } snprintf(keyname, PATH_MAX, "%s-envelope", info->msg_uidl); r = generic_cache_fields_read(cache_db, mmapstr, keyname, &fields); if (r != MAIL_NO_ERROR) { res = r; goto err; } * result = fields; return MAIL_NO_ERROR; err: return res; } static int write_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr, mailsession * session, uint32_t num, struct mailimf_fields * fields) { int r; char keyname[PATH_MAX]; int res; struct mailpop3_msg_info * info; mailpop3 * pop3; pop3 = get_pop3_session(session); r = mailpop3_get_msg_info(pop3, num, &info); switch (r) { case MAILPOP3_ERROR_BAD_STATE: return MAIL_ERROR_BAD_STATE; case MAILPOP3_ERROR_NO_SUCH_MESSAGE: return MAIL_ERROR_MSG_NOT_FOUND; case MAILPOP3_NO_ERROR: break; default: return MAIL_ERROR_FETCH; } snprintf(keyname, PATH_MAX, "%s-envelope", info->msg_uidl); r = generic_cache_fields_write(cache_db, mmapstr, keyname, fields); if (r != MAIL_NO_ERROR) { res = r; goto err; } return MAIL_NO_ERROR; err: return res; } static void get_uid_from_filename(char * filename) { char * p; p = strstr(filename, "-header"); if (p != NULL) * p = 0; } static int pop3driver_cached_get_envelopes_list(mailsession * session, struct mailmessage_list * env_list) { int r; unsigned int i; struct pop3_cached_session_state_data * cached_data; char filename_env[PATH_MAX]; char filename_flags[PATH_MAX]; struct mail_cache_db * cache_db_env; struct mail_cache_db * cache_db_flags; MMAPString * mmapstr; int res; cached_data = get_cached_data(session); pop3_flags_store_process(cached_data->pop3_flags_directory, cached_data->pop3_flags_store); snprintf(filename_env, PATH_MAX, "%s/%s", cached_data->pop3_cache_directory, ENV_NAME); mmapstr = mmap_string_new(""); if (mmapstr == NULL) { res = MAIL_ERROR_MEMORY; goto err; } r = mail_cache_db_open_lock(filename_env, &cache_db_env); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_mmapstr; } snprintf(filename_flags, PATH_MAX, "%s/%s", cached_data->pop3_flags_directory, FLAGS_NAME); r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_MEMORY; goto close_db_env; } /* fill with cached */ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; struct mailimf_fields * fields; struct mail_flags * flags; msg = carray_get(env_list->msg_tab, i); if (msg->msg_fields == NULL) { r = get_cached_envelope(cache_db_env, mmapstr, session, msg->msg_index, &fields); if (r == MAIL_NO_ERROR) { msg->msg_cached = TRUE; msg->msg_fields = fields; } } if (msg->msg_flags == NULL) { r = pop3driver_get_cached_flags(cache_db_flags, mmapstr, session, msg->msg_index, &flags); if (r == MAIL_NO_ERROR) { msg->msg_flags = flags; } } } mail_cache_db_close_unlock(filename_flags, cache_db_flags); mail_cache_db_close_unlock(filename_env, cache_db_env); r = maildriver_generic_get_envelopes_list(session, env_list); if (r != MAIL_NO_ERROR) { res = r; goto free_mmapstr; } /* add flags */ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; msg = carray_get(env_list->msg_tab, i); if (msg->msg_flags == NULL) msg->msg_flags = mail_flags_new_empty(); } r = mail_cache_db_open_lock(filename_env, &cache_db_env); if (r < 0) { res = MAIL_ERROR_MEMORY; goto free_mmapstr; } r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); if (r < 0) { res = MAIL_ERROR_MEMORY; goto close_db_env; } /* must write cache */ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { mailmessage * msg; msg = carray_get(env_list->msg_tab, i); if (msg->msg_fields != NULL) { if (!msg->msg_cached) { r = write_cached_envelope(cache_db_env, mmapstr, session, msg->msg_index, msg->msg_fields); } } if (msg->msg_flags != NULL) { r = pop3driver_write_cached_flags(cache_db_flags, mmapstr, msg->msg_uid, msg->msg_flags); } } /* flush cache */ maildriver_cache_clean_up(cache_db_env, cache_db_flags, env_list); mail_cache_db_close_unlock(filename_flags, cache_db_flags); mail_cache_db_close_unlock(filename_env, cache_db_env); mmap_string_free(mmapstr); /* remove cache files */ maildriver_message_cache_clean_up(cached_data->pop3_cache_directory, env_list, get_uid_from_filename); return MAIL_NO_ERROR; close_db_env: mail_cache_db_close_unlock(filename_env, cache_db_env); free_mmapstr: mmap_string_free(mmapstr); err: return res; } static int pop3driver_cached_get_message(mailsession * session, uint32_t num, mailmessage ** result) { mailmessage * msg_info; int r; msg_info = mailmessage_new(); if (msg_info == NULL) return MAIL_ERROR_MEMORY; r = mailmessage_init(msg_info, session, pop3_cached_message_driver, num, 0); if (r != MAIL_NO_ERROR) { mailmessage_free(msg_info); return r; } * result = msg_info; return MAIL_NO_ERROR; } + +static int pop3driver_cached_get_message_by_uid(mailsession * session, + const char * uid, mailmessage ** result) +{ + mailpop3 * pop3; + struct mailpop3_msg_info * msg_info; + int found; + unsigned int i; + + if (uid == NULL) + return MAIL_ERROR_INVAL; + + pop3 = get_pop3_session(session); + + found = 0; + + /* iterate all messages and look for uid */ + for(i = 0 ; i < carray_count(pop3->pop3_msg_tab) ; i++) { + msg_info = carray_get(pop3->pop3_msg_tab, i); + + if (msg_info == NULL) + continue; + + if (msg_info->msg_deleted) + continue; + + /* uid found, stop looking */ + if (strcmp(msg_info->msg_uidl, uid) == 0) { + found = 1; + break; + } + } + + if (!found) + return MAIL_ERROR_MSG_NOT_FOUND; + + return pop3driver_cached_get_message(session, msg_info->msg_index, result); +} diff --git a/kmicromail/libetpan/generic/pop3driver_message.c b/kmicromail/libetpan/generic/pop3driver_message.c index 77bd94c..357bb2e 100644 --- a/kmicromail/libetpan/generic/pop3driver_message.c +++ b/kmicromail/libetpan/generic/pop3driver_message.c @@ -1,159 +1,193 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "pop3driver_message.h" #include "mailmessage_tools.h" #include "pop3driver_tools.h" #include "pop3driver.h" #include "mailpop3.h" +#include <stdlib.h> +#include <string.h> static int pop3_prefetch(mailmessage * msg_info); static void pop3_prefetch_free(struct generic_message_t * msg); static int pop3_initialize(mailmessage * msg_info); static int pop3_fetch_header(mailmessage * msg_info, char ** result, size_t * result_len); static int pop3_fetch_size(mailmessage * msg_info, size_t * result); static mailmessage_driver local_pop3_message_driver = { .msg_name = "pop3", .msg_initialize = pop3_initialize, .msg_uninitialize = mailmessage_generic_uninitialize, .msg_flush = mailmessage_generic_flush, .msg_check = NULL, .msg_fetch_result_free = mailmessage_generic_fetch_result_free, .msg_fetch = mailmessage_generic_fetch, .msg_fetch_header = pop3_fetch_header, .msg_fetch_body = mailmessage_generic_fetch_body, .msg_fetch_size = pop3_fetch_size, .msg_get_bodystructure = mailmessage_generic_get_bodystructure, .msg_fetch_section = mailmessage_generic_fetch_section, .msg_fetch_section_header = mailmessage_generic_fetch_section_header, .msg_fetch_section_mime = mailmessage_generic_fetch_section_mime, .msg_fetch_section_body = mailmessage_generic_fetch_section_body, .msg_fetch_envelope = mailmessage_generic_fetch_envelope, .msg_get_flags = NULL, }; mailmessage_driver * pop3_message_driver = &local_pop3_message_driver; +static inline struct pop3_session_state_data * +get_data(mailsession * session) +{ + return session->sess_data; +} + + +static mailpop3 * get_pop3_session(mailsession * session) +{ + return get_data(session)->pop3_session; +} + static int pop3_prefetch(mailmessage * msg_info) { char * msg_content; size_t msg_length; struct generic_message_t * msg; int r; r = pop3driver_retr(msg_info->msg_session, msg_info->msg_index, &msg_content, &msg_length); if (r != MAIL_NO_ERROR) return r; msg = msg_info->msg_data; msg->msg_message = msg_content; msg->msg_length = msg_length; return MAIL_NO_ERROR; } static void pop3_prefetch_free(struct generic_message_t * msg) { if (msg->msg_message != NULL) { mmap_string_unref(msg->msg_message); msg->msg_message = NULL; } } static int pop3_initialize(mailmessage * msg_info) { struct generic_message_t * msg; int r; + char * uid; + struct mailpop3_msg_info * info; + mailpop3 * pop3; + + pop3 = get_pop3_session(msg_info->msg_session); + + r = mailpop3_get_msg_info(pop3, msg_info->msg_index, &info); + switch (r) { + case MAILPOP3_NO_ERROR: + break; + default: + return pop3driver_pop3_error_to_mail_error(r); + } + + uid = strdup(info->msg_uidl); + if (uid == NULL) + return MAIL_ERROR_MEMORY; r = mailmessage_generic_initialize(msg_info); - if (r != MAIL_NO_ERROR) + if (r != MAIL_NO_ERROR) { + free(uid); return r; + } msg = msg_info->msg_data; msg->msg_prefetch = pop3_prefetch; msg->msg_prefetch_free = pop3_prefetch_free; + msg_info->msg_uid = uid; return MAIL_NO_ERROR; } static int pop3_fetch_header(mailmessage * msg_info, char ** result, size_t * result_len) { struct generic_message_t * msg; char * headers; size_t headers_length; int r; msg = msg_info->msg_data; if (msg->msg_message != NULL) return mailmessage_generic_fetch_header(msg_info, result, result_len); r = pop3driver_header(msg_info->msg_session, msg_info->msg_index, &headers, &headers_length); if (r != MAIL_NO_ERROR) return r; * result = headers; * result_len = headers_length; return MAIL_NO_ERROR; } static int pop3_fetch_size(mailmessage * msg_info, size_t * result) { return pop3driver_size(msg_info->msg_session, msg_info->msg_index, result); } diff --git a/kmicromail/libetpan/generic/pop3storage.c b/kmicromail/libetpan/generic/pop3storage.c index 8e7a94e..375aeaf 100644 --- a/kmicromail/libetpan/generic/pop3storage.c +++ b/kmicromail/libetpan/generic/pop3storage.c @@ -1,284 +1,284 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "pop3storage.h" #include <stdlib.h> #include <string.h> #include "mail.h" #include "mailstorage_tools.h" #include "maildriver.h" /* pop3 storage */ #define POP3_DEFAULT_PORT 110 #define POP3S_DEFAULT_PORT 995 static int pop3_mailstorage_connect(struct mailstorage * storage); static int pop3_mailstorage_get_folder_session(struct mailstorage * storage, char * pathname, mailsession ** result); static void pop3_mailstorage_uninitialize(struct mailstorage * storage); static mailstorage_driver pop3_mailstorage_driver = { .sto_name = "pop3", .sto_connect = pop3_mailstorage_connect, .sto_get_folder_session = pop3_mailstorage_get_folder_session, .sto_uninitialize = pop3_mailstorage_uninitialize, }; int pop3_mailstorage_init(struct mailstorage * storage, char * pop3_servername, uint16_t pop3_port, char * pop3_command, int pop3_connection_type, int pop3_auth_type, char * pop3_login, char * pop3_password, int pop3_cached, char * pop3_cache_directory, char * pop3_flags_directory) { struct pop3_mailstorage * pop3_storage; - pop3_storage = malloc(sizeof(struct pop3_mailstorage)); + pop3_storage = malloc(sizeof(* pop3_storage)); if (pop3_storage == NULL) goto err; pop3_storage->pop3_servername = strdup(pop3_servername); if (pop3_storage->pop3_servername == NULL) goto free; pop3_storage->pop3_connection_type = pop3_connection_type; if (pop3_port == 0) { switch (pop3_connection_type) { case CONNECTION_TYPE_PLAIN: case CONNECTION_TYPE_TRY_STARTTLS: case CONNECTION_TYPE_STARTTLS: case CONNECTION_TYPE_COMMAND: case CONNECTION_TYPE_COMMAND_TRY_STARTTLS: case CONNECTION_TYPE_COMMAND_STARTTLS: pop3_port = POP3_DEFAULT_PORT; break; case CONNECTION_TYPE_TLS: case CONNECTION_TYPE_COMMAND_TLS: pop3_port = POP3S_DEFAULT_PORT; break; } } pop3_storage->pop3_port = pop3_port; if (pop3_command != NULL) { pop3_storage->pop3_command = strdup(pop3_command); if (pop3_storage->pop3_command == NULL) goto free_servername; } else pop3_storage->pop3_command = NULL; pop3_storage->pop3_auth_type = pop3_auth_type; if (pop3_login != NULL) { pop3_storage->pop3_login = strdup(pop3_login); if (pop3_storage->pop3_login == NULL) goto free_command; } else pop3_storage->pop3_login = NULL; if (pop3_password != NULL) { pop3_storage->pop3_password = strdup(pop3_password); if (pop3_storage->pop3_password == NULL) goto free_login; } else pop3_storage->pop3_password = NULL; pop3_storage->pop3_cached = pop3_cached; if (pop3_cached && (pop3_cache_directory != NULL) && (pop3_flags_directory != NULL)) { pop3_storage->pop3_cache_directory = strdup(pop3_cache_directory); if (pop3_storage->pop3_cache_directory == NULL) goto free_password; pop3_storage->pop3_flags_directory = strdup(pop3_flags_directory); if (pop3_storage->pop3_flags_directory == NULL) goto free_cache_directory; } else { pop3_storage->pop3_cached = FALSE; pop3_storage->pop3_cache_directory = NULL; pop3_storage->pop3_flags_directory = NULL; } storage->sto_data = pop3_storage; storage->sto_driver = &pop3_mailstorage_driver; return MAIL_NO_ERROR; free_cache_directory: free(pop3_storage->pop3_cache_directory); free_password: if (pop3_storage->pop3_password != NULL) free(pop3_storage->pop3_password); free_login: if (pop3_storage->pop3_login != NULL) free(pop3_storage->pop3_login); free_command: if (pop3_storage->pop3_command != NULL) free(pop3_storage->pop3_command); free_servername: if (pop3_storage->pop3_servername != NULL) free(pop3_storage->pop3_servername); free: free(pop3_storage); err: return MAIL_ERROR_MEMORY; } static void pop3_mailstorage_uninitialize(struct mailstorage * storage) { struct pop3_mailstorage * pop3_storage; pop3_storage = storage->sto_data; if (pop3_storage->pop3_flags_directory != NULL) free(pop3_storage->pop3_flags_directory); if (pop3_storage->pop3_cache_directory != NULL) free(pop3_storage->pop3_cache_directory); if (pop3_storage->pop3_password != NULL) free(pop3_storage->pop3_password); if (pop3_storage->pop3_login != NULL) free(pop3_storage->pop3_login); if (pop3_storage->pop3_command != NULL) free(pop3_storage->pop3_command); free(pop3_storage->pop3_servername); free(pop3_storage); storage->sto_data = pop3_storage; } static int pop3_mailstorage_connect(struct mailstorage * storage) { struct pop3_mailstorage * pop3_storage; mailsession_driver * driver; int r; int res; mailsession * session; int auth_type; pop3_storage = storage->sto_data; if (pop3_storage->pop3_cached) driver = pop3_cached_session_driver; else driver = pop3_session_driver; r = mailstorage_generic_connect(driver, pop3_storage->pop3_servername, pop3_storage->pop3_port, pop3_storage->pop3_command, pop3_storage->pop3_connection_type, POP3DRIVER_CACHED_SET_CACHE_DIRECTORY, pop3_storage->pop3_cache_directory, POP3DRIVER_CACHED_SET_FLAGS_DIRECTORY, pop3_storage->pop3_flags_directory, &session); switch (r) { case MAIL_NO_ERROR_NON_AUTHENTICATED: case MAIL_NO_ERROR_AUTHENTICATED: case MAIL_NO_ERROR: break; default: res = r; goto err; } auth_type = -1; switch (pop3_storage->pop3_auth_type) { case POP3_AUTH_TYPE_PLAIN: auth_type = POP3DRIVER_AUTH_TYPE_PLAIN; break; case POP3_AUTH_TYPE_APOP: auth_type = POP3DRIVER_AUTH_TYPE_APOP; break; case POP3_AUTH_TYPE_TRY_APOP: auth_type = POP3DRIVER_AUTH_TYPE_TRY_APOP; break; } if (auth_type != -1) { mailsession_parameters(session, POP3DRIVER_SET_AUTH_TYPE, &auth_type); } r = mailstorage_generic_auth(session, r, pop3_storage->pop3_auth_type, pop3_storage->pop3_login, pop3_storage->pop3_password); if (r != MAIL_NO_ERROR) { if (pop3_storage->pop3_auth_type == POP3_AUTH_TYPE_TRY_APOP) { /* try in clear authentication */ mailsession_free(session); pop3_storage->pop3_auth_type = POP3_AUTH_TYPE_PLAIN; r = mailstorage_connect(storage); if (r != MAIL_NO_ERROR) { res = r; return res; } pop3_storage->pop3_auth_type = POP3_AUTH_TYPE_TRY_APOP; return MAIL_NO_ERROR; } res = r; goto free; } storage->sto_session = session; return MAIL_NO_ERROR; free: mailsession_free(session); err: return res; } static int pop3_mailstorage_get_folder_session(struct mailstorage * storage, char * pathname, mailsession ** result) { * result = storage->sto_session; return MAIL_NO_ERROR; } diff --git a/kmicromail/libetpan/imap/mailimap.c b/kmicromail/libetpan/imap/mailimap.c index c8fbfee..76d9454 100644 --- a/kmicromail/libetpan/imap/mailimap.c +++ b/kmicromail/libetpan/imap/mailimap.c @@ -1,2161 +1,2161 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "mailimap.h" #include "mailimap_parser.h" #include "mailimap_sender.h" #include "mail.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #ifdef DEBUG #include "mailimap_print.h" #endif /* RFC 2060 : IMAP4rev1 draft-crispin-imapv-15 RFC 2222 : Simple Authentication and Security Layer 2061 IMAP4 Compatibility with IMAP2bis. M. Crispin. December 1996. (Format: TXT=5867 bytes) (Obsoletes RFC1730) (Status: INFORMATIONAL) 2062 Internet Message Access Protocol - Obsolete Syntax. M. Crispin. December 1996. (Format: TXT=14222 bytes) (Status: INFORMATIONAL) 2086 IMAP4 ACL extension. J. Myers. January 1997. (Format: TXT=13925 bytes) (Status: PROPOSED STANDARD) 2087 IMAP4 QUOTA extension. J. Myers. January 1997. (Format: TXT=8542 bytes) (Status: PROPOSED STANDARD) 2088 IMAP4 non-synchronizing literals. J. Myers. January 1997. (Format: TXT=4052 bytes) (Status: PROPOSED STANDARD) 2177 IMAP4 IDLE command. B. Leiba. June 1997. (Format: TXT=6770 bytes) (Status: PROPOSED STANDARD) 2180 IMAP4 Multi-Accessed Mailbox Practice. M. Gahrns. July 1997. (Format: TXT=24750 bytes) (Status: INFORMATIONAL) 2192 IMAP URL Scheme. C. Newman. September 1997. (Format: TXT=31426 bytes) (Status: PROPOSED STANDARD) 2193 IMAP4 Mailbox Referrals. M. Gahrns. September 1997. (Format: TXT=16248 bytes) (Status: PROPOSED STANDARD) 2195 IMAP/POP AUTHorize Extension for Simple Challenge/Response. J. Klensin, R. Catoe, P. Krumviede. September 1997. (Format: TXT=10468 bytes) (Obsoletes RFC2095) (Status: PROPOSED STANDARD) 2221 IMAP4 Login Referrals. M. Gahrns. October 1997. (Format: TXT=9251 bytes) (Status: PROPOSED STANDARD) 2342 IMAP4 Namespace. M. Gahrns, C. Newman. May 1998. (Format: TXT=19489 bytes) (Status: PROPOSED STANDARD) 2359 IMAP4 UIDPLUS extension. J. Myers. June 1998. (Format: TXT=10862 bytes) (Status: PROPOSED STANDARD) 2595 Using TLS with IMAP, POP3 and ACAP. C. Newman. June 1999. (Format: TXT=32440 bytes) (Status: PROPOSED STANDARD) 2683 IMAP4 Implementation Recommendations. B. Leiba. September 1999. (Format: TXT=56300 bytes) (Status: INFORMATIONAL) 2971 IMAP4 ID extension. T. Showalter. October 2000. (Format: TXT=14670 bytes) (Status: PROPOSED STANDARD) http://www.ietf.org/ids.by.wg/imapext.html */ static char * read_line(mailimap * session); static int send_current_tag(mailimap * session); static int parse_response(mailimap * session, struct mailimap_response ** result); static int parse_greeting(mailimap * session, struct mailimap_greeting ** result); /* struct mailimap_response_info * */ static void resp_text_store(mailimap * session, struct mailimap_resp_text * resp_text) { struct mailimap_resp_text_code * resp_text_code; resp_text_code = resp_text->rsp_code; if (resp_text_code != NULL) { switch (resp_text_code->rc_type) { case MAILIMAP_RESP_TEXT_CODE_ALERT: if (session->imap_response_info) if (session->imap_response_info->rsp_alert != NULL) free(session->imap_response_info->rsp_alert); session->imap_response_info->rsp_alert = strdup(resp_text->rsp_text); break; case MAILIMAP_RESP_TEXT_CODE_BADCHARSET: if (session->imap_response_info) { if (session->imap_response_info->rsp_badcharset != NULL) { clist_foreach(resp_text_code->rc_data.rc_badcharset, (clist_func) mailimap_astring_free, NULL); clist_free(resp_text_code->rc_data.rc_badcharset); } session->imap_response_info->rsp_badcharset = resp_text_code->rc_data.rc_badcharset; resp_text_code->rc_data.rc_badcharset = NULL; } break; case MAILIMAP_RESP_TEXT_CODE_CAPABILITY_DATA: if (session->imap_connection_info) { if (session->imap_connection_info->imap_capability != NULL) mailimap_capability_data_free(session->imap_connection_info->imap_capability); session->imap_connection_info->imap_capability = resp_text_code->rc_data.rc_cap_data; /* detach before free */ resp_text_code->rc_data.rc_cap_data = NULL; } break; case MAILIMAP_RESP_TEXT_CODE_PARSE: if (session->imap_response_info) { if (session->imap_response_info->rsp_parse != NULL) free(session->imap_response_info->rsp_parse); session->imap_response_info->rsp_parse = strdup(resp_text->rsp_text); } break; case MAILIMAP_RESP_TEXT_CODE_PERMANENTFLAGS: if (session->imap_selection_info) { if (session->imap_selection_info->sel_perm_flags != NULL) { clist_foreach(session->imap_selection_info->sel_perm_flags, (clist_func) mailimap_flag_perm_free, NULL); clist_free(session->imap_selection_info->sel_perm_flags); } session->imap_selection_info->sel_perm_flags = resp_text_code->rc_data.rc_perm_flags; /* detach before free */ resp_text_code->rc_data.rc_perm_flags = NULL; } break; case MAILIMAP_RESP_TEXT_CODE_READ_ONLY: if (session->imap_selection_info) session->imap_selection_info->sel_perm = MAILIMAP_MAILBOX_READONLY; break; case MAILIMAP_RESP_TEXT_CODE_READ_WRITE: if (session->imap_selection_info) session->imap_selection_info->sel_perm = MAILIMAP_MAILBOX_READWRITE; break; case MAILIMAP_RESP_TEXT_CODE_TRY_CREATE: if (session->imap_response_info) session->imap_response_info->rsp_trycreate = TRUE; break; case MAILIMAP_RESP_TEXT_CODE_UIDNEXT: if (session->imap_selection_info) session->imap_selection_info->sel_uidnext = resp_text_code->rc_data.rc_uidnext; break; case MAILIMAP_RESP_TEXT_CODE_UIDVALIDITY: if (session->imap_selection_info) session->imap_selection_info->sel_uidvalidity = resp_text_code->rc_data.rc_uidvalidity; break; case MAILIMAP_RESP_TEXT_CODE_UNSEEN: if (session->imap_selection_info) session->imap_selection_info->sel_first_unseen = resp_text_code->rc_data.rc_first_unseen; break; } } } static void resp_cond_state_store(mailimap * session, struct mailimap_resp_cond_state * resp_cond_state) { resp_text_store(session, resp_cond_state->rsp_text); } static void mailbox_data_store(mailimap * session, struct mailimap_mailbox_data * mb_data) { int r; switch (mb_data->mbd_type) { case MAILIMAP_MAILBOX_DATA_FLAGS: if (session->imap_selection_info) { if (session->imap_selection_info->sel_flags != NULL) mailimap_flag_list_free(session->imap_selection_info->sel_flags); session->imap_selection_info->sel_flags = mb_data->mbd_data.mbd_flags; mb_data->mbd_data.mbd_flags = NULL; } break; case MAILIMAP_MAILBOX_DATA_LIST: if (session->imap_response_info) { r = clist_append(session->imap_response_info->rsp_mailbox_list, mb_data->mbd_data.mbd_list); if (r == 0) mb_data->mbd_data.mbd_list = NULL; else { /* TODO must handle error case */ } } break; case MAILIMAP_MAILBOX_DATA_LSUB: if (session->imap_response_info) { r = clist_append(session->imap_response_info->rsp_mailbox_lsub, mb_data->mbd_data.mbd_lsub); if (r == 0) mb_data->mbd_data.mbd_lsub = NULL; else { /* TODO must handle error case */ } } break; case MAILIMAP_MAILBOX_DATA_SEARCH: if (session->imap_response_info) { if (session->imap_response_info->rsp_search_result != NULL) { if (mb_data->mbd_data.mbd_search != NULL) { clist_concat(session->imap_response_info->rsp_search_result, mb_data->mbd_data.mbd_search); clist_free(mb_data->mbd_data.mbd_search); mb_data->mbd_data.mbd_search = NULL; } } else { if (mb_data->mbd_data.mbd_search != NULL) { session->imap_response_info->rsp_search_result = mb_data->mbd_data.mbd_search; mb_data->mbd_data.mbd_search = NULL; } } } break; case MAILIMAP_MAILBOX_DATA_STATUS: if (session->imap_response_info) { if (session->imap_response_info->rsp_status != NULL) mailimap_mailbox_data_status_free(session->imap_response_info->rsp_status); session->imap_response_info->rsp_status = mb_data->mbd_data.mbd_status; #if 0 if (session->imap_selection_info != NULL) { clistiter * cur; for(cur = clist_begin(mb_data->status->status_info_list) ; cur != NULL ; cur = clist_next(cur)) { struct mailimap_status_info * info; info = clist_content(cur); switch (info->att) { case MAILIMAP_STATUS_ATT_MESSAGES: session->imap_selection_info->exists = info->value; break; case MAILIMAP_STATUS_ATT_RECENT: session->imap_selection_info->recent = info->value; break; case MAILIMAP_STATUS_ATT_UIDNEXT: session->imap_selection_info->uidnext = info->value; break; case MAILIMAP_STATUS_ATT_UIDVALIDITY: session->imap_selection_info->uidvalidity = info->value; break; case MAILIMAP_STATUS_ATT_UNSEEN: session->imap_selection_info->unseen = info->value; break; } } } #endif #if 0 mailimap_mailbox_data_status_free(mb_data->status); #endif mb_data->mbd_data.mbd_status = NULL; } break; case MAILIMAP_MAILBOX_DATA_EXISTS: if (session->imap_selection_info) session->imap_selection_info->sel_exists = mb_data->mbd_data.mbd_exists; break; case MAILIMAP_MAILBOX_DATA_RECENT: if (session->imap_selection_info) session->imap_selection_info->sel_recent = mb_data->mbd_data.mbd_recent; break; } } static void message_data_store(mailimap * session, struct mailimap_message_data * msg_data) { uint32_t * expunged; int r; switch (msg_data->mdt_type) { case MAILIMAP_MESSAGE_DATA_EXPUNGE: if (session->imap_response_info) { expunged = mailimap_number_alloc_new(msg_data->mdt_number); if (expunged != NULL) { r = clist_append(session->imap_response_info->rsp_expunged, expunged); if (r == 0) { /* do nothing */ } else { /* TODO : must handle error case */ mailimap_number_alloc_free(expunged); } if (session->imap_selection_info != NULL) session->imap_selection_info->sel_exists --; } } break; case MAILIMAP_MESSAGE_DATA_FETCH: r = clist_append(session->imap_response_info->rsp_fetch_list, msg_data->mdt_msg_att); if (r == 0) { msg_data->mdt_msg_att->att_number = msg_data->mdt_number; msg_data->mdt_msg_att = NULL; } else { /* TODO : must handle error case */ } break; } } static void cont_req_or_resp_data_store(mailimap * session, struct mailimap_cont_req_or_resp_data * cont_req_or_resp_data) { if (cont_req_or_resp_data->rsp_type == MAILIMAP_RESP_RESP_DATA) { struct mailimap_response_data * resp_data; resp_data = cont_req_or_resp_data->rsp_data.rsp_resp_data; switch (resp_data->rsp_type) { case MAILIMAP_RESP_DATA_TYPE_COND_STATE: resp_cond_state_store(session, resp_data->rsp_data.rsp_cond_state); break; case MAILIMAP_RESP_DATA_TYPE_MAILBOX_DATA: mailbox_data_store(session, resp_data->rsp_data.rsp_mailbox_data); break; case MAILIMAP_RESP_DATA_TYPE_MESSAGE_DATA: message_data_store(session, resp_data->rsp_data.rsp_message_data); break; case MAILIMAP_RESP_DATA_TYPE_CAPABILITY_DATA: if (session->imap_connection_info) { if (session->imap_connection_info->imap_capability != NULL) mailimap_capability_data_free(session->imap_connection_info->imap_capability); session->imap_connection_info->imap_capability = resp_data->rsp_data.rsp_capability_data; resp_data->rsp_data.rsp_capability_data = NULL; } break; } } } static void response_tagged_store(mailimap * session, struct mailimap_response_tagged * tagged) { resp_cond_state_store(session, tagged->rsp_cond_state); } static void resp_cond_bye_store(mailimap * session, struct mailimap_resp_cond_bye * resp_cond_bye) { resp_text_store(session, resp_cond_bye->rsp_text); } static void response_fatal_store(mailimap * session, struct mailimap_response_fatal * fatal) { resp_cond_bye_store(session, fatal->rsp_bye); } static void response_done_store(mailimap * session, struct mailimap_response_done * resp_done) { switch(resp_done->rsp_type) { case MAILIMAP_RESP_DONE_TYPE_TAGGED: response_tagged_store(session, resp_done->rsp_data.rsp_tagged); break; case MAILIMAP_RESP_DONE_TYPE_FATAL: response_fatal_store(session, resp_done->rsp_data.rsp_fatal); break; } } static void response_store(mailimap * session, struct mailimap_response * response) { clistiter * cur; if (session->imap_response_info) { mailimap_response_info_free(session->imap_response_info); session->imap_response_info = NULL; } session->imap_response_info = mailimap_response_info_new(); if (session->imap_response_info == NULL) { /* ignored error */ return; } if (response->rsp_cont_req_or_resp_data_list != NULL) { for(cur = clist_begin(response->rsp_cont_req_or_resp_data_list) ; cur != NULL ; cur = clist_next(cur)) { struct mailimap_cont_req_or_resp_data * cont_req_or_resp_data; cont_req_or_resp_data = clist_content(cur); cont_req_or_resp_data_store(session, cont_req_or_resp_data); } } response_done_store(session, response->rsp_resp_done); } static void resp_cond_auth_store(mailimap * session, struct mailimap_resp_cond_auth * cond_auth) { resp_text_store(session, cond_auth->rsp_text); } static void greeting_store(mailimap * session, struct mailimap_greeting * greeting) { switch (greeting->gr_type) { case MAILIMAP_GREETING_RESP_COND_AUTH: resp_cond_auth_store(session, greeting->gr_data.gr_auth); break; case MAILIMAP_GREETING_RESP_COND_BYE: resp_cond_bye_store(session, greeting->gr_data.gr_bye); break; } } int mailimap_connect(mailimap * session, mailstream * s) { struct mailimap_greeting * greeting; int r; int auth_type; struct mailimap_connection_info * connection_info; if (session->imap_state != MAILIMAP_STATE_DISCONNECTED) return MAILIMAP_ERROR_BAD_STATE; session->imap_stream = s; if (session->imap_connection_info) mailimap_connection_info_free(session->imap_connection_info); connection_info = mailimap_connection_info_new(); if (connection_info != NULL) session->imap_connection_info = connection_info; if (read_line(session) == NULL) { return MAILIMAP_ERROR_STREAM; } r = parse_greeting(session, &greeting); if (r != MAILIMAP_NO_ERROR) { return r; } auth_type = greeting->gr_data.gr_auth->rsp_type; mailimap_greeting_free(greeting); switch (auth_type) { case MAILIMAP_RESP_COND_AUTH_PREAUTH: session->imap_state = MAILIMAP_STATE_AUTHENTICATED; return MAILIMAP_NO_ERROR_AUTHENTICATED; default: session->imap_state = MAILIMAP_STATE_NON_AUTHENTICATED; return MAILIMAP_NO_ERROR_NON_AUTHENTICATED; } } /* ********************************************************************** */ int mailimap_append(mailimap * session, const char * mailbox, struct mailimap_flag_list * flag_list, struct mailimap_date_time * date_time, const char * literal, size_t literal_size) { struct mailimap_response * response; int r; int error_code; struct mailimap_continue_req * cont_req; size_t index; if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) && (session->imap_state != MAILIMAP_STATE_SELECTED)) return MAILIMAP_ERROR_BAD_STATE; r = send_current_tag(session); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_append_send(session->imap_stream, mailbox, flag_list, date_time, literal_size); if (r != MAILIMAP_NO_ERROR) return r; if (mailstream_flush(session->imap_stream) == -1) return MAILIMAP_ERROR_STREAM; if (read_line(session) == NULL) return MAILIMAP_ERROR_STREAM; index = 0; r = mailimap_continue_req_parse(session->imap_stream, session->imap_stream_buffer, &index, &cont_req, session->imap_progr_rate, session->imap_progr_fun); if (r == MAILIMAP_NO_ERROR) mailimap_continue_req_free(cont_req); if (r == MAILIMAP_ERROR_PARSE) { r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) return r; mailimap_response_free(response); return MAILIMAP_ERROR_APPEND; } r = mailimap_literal_data_send(session->imap_stream, literal, literal_size, session->imap_progr_rate, session->imap_progr_fun); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_crlf_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; if (mailstream_flush(session->imap_stream) == -1) return MAILIMAP_ERROR_STREAM; if (read_line(session) == NULL) return MAILIMAP_ERROR_STREAM; r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) return r; error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type; mailimap_response_free(response); switch (error_code) { case MAILIMAP_RESP_COND_STATE_OK: return MAILIMAP_NO_ERROR; default: return MAILIMAP_ERROR_APPEND; } } /* gboolean mailimap_authenticate(mailimap * session, gchar * auth_type) { } gboolean mailimap_authenticate_resp_send(mailimap * session, gchar * base64) { } */ int mailimap_noop(mailimap * session) { struct mailimap_response * response; int r; int error_code; r = send_current_tag(session); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_noop_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_crlf_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; if (mailstream_flush(session->imap_stream) == -1) return MAILIMAP_ERROR_STREAM; if (read_line(session) == NULL) return MAILIMAP_ERROR_STREAM; r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) return r; error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type; mailimap_response_free(response); switch (error_code) { case MAILIMAP_RESP_COND_STATE_OK: return MAILIMAP_NO_ERROR; default: return MAILIMAP_ERROR_NOOP; } } int mailimap_logout(mailimap * session) { struct mailimap_response * response; int r; int error_code; int res; r = send_current_tag(session); if (r != MAILIMAP_NO_ERROR) { res = r; goto close; } r = mailimap_logout_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) { res = r; goto close; } r = mailimap_crlf_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) { res = r; goto close; } if (mailstream_flush(session->imap_stream) == -1) { res = MAILIMAP_ERROR_STREAM; goto close; } if (read_line(session) == NULL) { res = MAILIMAP_ERROR_STREAM; goto close; } r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) { res = r; goto close; } error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type; mailimap_response_free(response); switch (error_code) { case MAILIMAP_RESP_COND_STATE_OK: if (session->imap_connection_info) { mailimap_connection_info_free(session->imap_connection_info); session->imap_connection_info = NULL; } res = MAILIMAP_NO_ERROR; goto close; default: res = MAILIMAP_ERROR_LOGOUT; goto close; } close: mailstream_close(session->imap_stream); session->imap_stream = NULL; session->imap_state = MAILIMAP_STATE_DISCONNECTED; return res; } /* send the results back to the caller */ /* duplicate the result */ static struct mailimap_capability * mailimap_capability_dup(struct mailimap_capability * orig_cap) { struct mailimap_capability * cap; char * auth_type; char * name; name = NULL; auth_type = NULL; switch (orig_cap->cap_type) { case MAILIMAP_CAPABILITY_NAME: name = strdup(orig_cap->cap_data.cap_name); if (name == NULL) goto err; break; case MAILIMAP_CAPABILITY_AUTH_TYPE: auth_type = strdup(orig_cap->cap_data.cap_auth_type); if (auth_type == NULL) goto err; break; } cap = mailimap_capability_new(orig_cap->cap_type, auth_type, name); if (cap == NULL) goto free; return cap; free: if (name != NULL) free(name); if (auth_type != NULL) free(auth_type); err: return NULL; } static struct mailimap_capability_data * mailimap_capability_data_dup(struct mailimap_capability_data * orig_cap_data) { struct mailimap_capability_data * cap_data; struct mailimap_capability * cap_dup; clist * list; clistiter * cur; int r; list = clist_new(); if (list == NULL) goto err; for(cur = clist_begin(orig_cap_data->cap_list) ; cur != NULL ; cur = clist_next(cur)) { struct mailimap_capability * cap; cap = clist_content(cur); cap_dup = mailimap_capability_dup(cap); if (cap_dup == NULL) goto list; r = clist_append(list, cap_dup); if (r < 0) { mailimap_capability_free(cap_dup); goto list; } } cap_data = mailimap_capability_data_new(list); if (cap_data == NULL) goto list; return cap_data; list: clist_foreach(list, (clist_func) mailimap_capability_free, NULL); clist_free(list); err: return NULL; } int mailimap_capability(mailimap * session, struct mailimap_capability_data ** result) { struct mailimap_response * response; int r; int error_code; struct mailimap_capability_data * cap_data; r = send_current_tag(session); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_capability_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_crlf_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; if (mailstream_flush(session->imap_stream) == -1) return MAILIMAP_ERROR_STREAM; if (read_line(session) == NULL) return MAILIMAP_ERROR_STREAM; r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) return r; error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type; mailimap_response_free(response); switch (error_code) { case MAILIMAP_RESP_COND_STATE_OK: cap_data = mailimap_capability_data_dup(session->imap_connection_info->imap_capability); if (cap_data == NULL) return MAILIMAP_ERROR_MEMORY; * result = cap_data; return MAILIMAP_NO_ERROR; default: return MAILIMAP_ERROR_CAPABILITY; } } int mailimap_check(mailimap * session) { struct mailimap_response * response; int r; int error_code; if (session->imap_state != MAILIMAP_STATE_SELECTED) return MAILIMAP_ERROR_BAD_STATE; r = send_current_tag(session); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_check_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_crlf_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; if (mailstream_flush(session->imap_stream) == -1) return MAILIMAP_ERROR_STREAM; if (read_line(session) == NULL) return MAILIMAP_ERROR_STREAM; r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) return r; error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type; mailimap_response_free(response); switch (error_code) { case MAILIMAP_RESP_COND_STATE_OK: return MAILIMAP_NO_ERROR; default: return MAILIMAP_ERROR_CHECK; } } int mailimap_close(mailimap * session) { struct mailimap_response * response; int r; int error_code; if (session->imap_state != MAILIMAP_STATE_SELECTED) return MAILIMAP_ERROR_BAD_STATE; r = send_current_tag(session); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_close_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_crlf_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; if (mailstream_flush(session->imap_stream) == -1) return MAILIMAP_ERROR_STREAM; if (read_line(session) == NULL) return MAILIMAP_ERROR_STREAM; r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) return r; error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type; mailimap_response_free(response); switch (error_code) { case MAILIMAP_RESP_COND_STATE_OK: /* leave selected state */ mailimap_selection_info_free(session->imap_selection_info); session->imap_selection_info = NULL; session->imap_state = MAILIMAP_STATE_AUTHENTICATED; return MAILIMAP_NO_ERROR; default: return MAILIMAP_ERROR_CLOSE; } } int mailimap_expunge(mailimap * session) { struct mailimap_response * response; int r; int error_code; if (session->imap_state != MAILIMAP_STATE_SELECTED) return MAILIMAP_ERROR_BAD_STATE; r = send_current_tag(session); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_expunge_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_crlf_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; if (mailstream_flush(session->imap_stream) == -1) return MAILIMAP_ERROR_STREAM; if (read_line(session) == NULL) return MAILIMAP_ERROR_STREAM; r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) return r; error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type; mailimap_response_free(response); switch (error_code) { case MAILIMAP_RESP_COND_STATE_OK: return MAILIMAP_NO_ERROR; default: return MAILIMAP_ERROR_EXPUNGE; } } int mailimap_copy(mailimap * session, struct mailimap_set * set, const char * mb) { struct mailimap_response * response; int r; int error_code; if (session->imap_state != MAILIMAP_STATE_SELECTED) return MAILIMAP_ERROR_BAD_STATE; r = send_current_tag(session); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_copy_send(session->imap_stream, set, mb); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_crlf_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; if (mailstream_flush(session->imap_stream) == -1) return MAILIMAP_ERROR_STREAM; if (read_line(session) == NULL) return MAILIMAP_ERROR_STREAM; r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) return r; error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type; mailimap_response_free(response); switch (error_code) { case MAILIMAP_RESP_COND_STATE_OK: return MAILIMAP_NO_ERROR; default: return MAILIMAP_ERROR_COPY; } } int mailimap_uid_copy(mailimap * session, struct mailimap_set * set, const char * mb) { struct mailimap_response * response; int r; int error_code; if (session->imap_state != MAILIMAP_STATE_SELECTED) return MAILIMAP_ERROR_BAD_STATE; r = send_current_tag(session); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_uid_copy_send(session->imap_stream, set, mb); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_crlf_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; if (mailstream_flush(session->imap_stream) == -1) return MAILIMAP_ERROR_STREAM; if (read_line(session) == NULL) return MAILIMAP_ERROR_STREAM; r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) return r; error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type; mailimap_response_free(response); switch (error_code) { case MAILIMAP_RESP_COND_STATE_OK: return MAILIMAP_NO_ERROR; default: return MAILIMAP_ERROR_UID_COPY; } } int mailimap_create(mailimap * session, const char * mb) { struct mailimap_response * response; int r; int error_code; if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) && (session->imap_state != MAILIMAP_STATE_SELECTED)) return MAILIMAP_ERROR_BAD_STATE; r = send_current_tag(session); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_create_send(session->imap_stream, mb); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_crlf_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; if (mailstream_flush(session->imap_stream) == -1) return MAILIMAP_ERROR_STREAM; if (read_line(session) == NULL) return MAILIMAP_ERROR_STREAM; r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) return r; error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type; mailimap_response_free(response); switch (error_code) { case MAILIMAP_RESP_COND_STATE_OK: return MAILIMAP_NO_ERROR; default: return MAILIMAP_ERROR_CREATE; } } int mailimap_delete(mailimap * session, const char * mb) { struct mailimap_response * response; int r; int error_code; if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) && (session->imap_state != MAILIMAP_STATE_SELECTED)) return MAILIMAP_ERROR_BAD_STATE; r = send_current_tag(session); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_delete_send(session->imap_stream, mb); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_crlf_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; if (mailstream_flush(session->imap_stream) == -1) return MAILIMAP_ERROR_STREAM; if (read_line(session) == NULL) return MAILIMAP_ERROR_STREAM; r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) return r; error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type; mailimap_response_free(response); switch (error_code) { case MAILIMAP_RESP_COND_STATE_OK: return MAILIMAP_NO_ERROR; default: return MAILIMAP_ERROR_DELETE; } } int mailimap_examine(mailimap * session, const char * mb) { struct mailimap_response * response; int r; int error_code; if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) && (session->imap_state != MAILIMAP_STATE_SELECTED)) return MAILIMAP_ERROR_BAD_STATE; r = send_current_tag(session); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_examine_send(session->imap_stream, mb); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_crlf_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; if (mailstream_flush(session->imap_stream) == -1) return MAILIMAP_ERROR_STREAM; if (read_line(session) == NULL) return MAILIMAP_ERROR_STREAM; if (session->imap_selection_info != NULL) mailimap_selection_info_free(session->imap_selection_info); session->imap_selection_info = mailimap_selection_info_new(); r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) return r; error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type; mailimap_response_free(response); switch (error_code) { case MAILIMAP_RESP_COND_STATE_OK: session->imap_state = MAILIMAP_STATE_SELECTED; return MAILIMAP_NO_ERROR; default: mailimap_selection_info_free(session->imap_selection_info); session->imap_selection_info = NULL; session->imap_state = MAILIMAP_STATE_AUTHENTICATED; return MAILIMAP_ERROR_EXAMINE; } } int mailimap_fetch(mailimap * session, struct mailimap_set * set, struct mailimap_fetch_type * fetch_type, clist ** result) { struct mailimap_response * response; int r; int error_code; if (session->imap_state != MAILIMAP_STATE_SELECTED) return MAILIMAP_ERROR_BAD_STATE; r = send_current_tag(session); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_fetch_send(session->imap_stream, set, fetch_type); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_crlf_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; if (mailstream_flush(session->imap_stream) == -1) return MAILIMAP_ERROR_STREAM; if (read_line(session) == NULL) return MAILIMAP_ERROR_STREAM; r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) return r; * result = session->imap_response_info->rsp_fetch_list; session->imap_response_info->rsp_fetch_list = NULL; error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type; mailimap_response_free(response); switch (error_code) { case MAILIMAP_RESP_COND_STATE_OK: return MAILIMAP_NO_ERROR; default: return MAILIMAP_ERROR_FETCH; } } void mailimap_fetch_list_free(clist * fetch_list) { clist_foreach(fetch_list, (clist_func) mailimap_msg_att_free, NULL); clist_free(fetch_list); } int mailimap_uid_fetch(mailimap * session, struct mailimap_set * set, struct mailimap_fetch_type * fetch_type, clist ** result) { struct mailimap_response * response; int r; int error_code; if (session->imap_state != MAILIMAP_STATE_SELECTED) return MAILIMAP_ERROR_BAD_STATE; r = send_current_tag(session); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_uid_fetch_send(session->imap_stream, set, fetch_type); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_crlf_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; if (mailstream_flush(session->imap_stream) == -1) return MAILIMAP_ERROR_STREAM; if (read_line(session) == NULL) return MAILIMAP_ERROR_STREAM; r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) return r; * result = session->imap_response_info->rsp_fetch_list; session->imap_response_info->rsp_fetch_list = NULL; error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type; mailimap_response_free(response); switch (error_code) { case MAILIMAP_RESP_COND_STATE_OK: return MAILIMAP_NO_ERROR; default: return MAILIMAP_ERROR_UID_FETCH; } } int mailimap_list(mailimap * session, const char * mb, const char * list_mb, clist ** result) { struct mailimap_response * response; int r; int error_code; if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) && (session->imap_state != MAILIMAP_STATE_SELECTED)) return MAILIMAP_ERROR_BAD_STATE; r = send_current_tag(session); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_list_send(session->imap_stream, mb, list_mb); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_crlf_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; if (mailstream_flush(session->imap_stream) == -1) return MAILIMAP_ERROR_STREAM; if (read_line(session) == NULL) return MAILIMAP_ERROR_STREAM; r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) return r; * result = session->imap_response_info->rsp_mailbox_list; session->imap_response_info->rsp_mailbox_list = NULL; error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type; mailimap_response_free(response); switch (error_code) { case MAILIMAP_RESP_COND_STATE_OK: return MAILIMAP_NO_ERROR; default: return MAILIMAP_ERROR_LIST; } } int mailimap_login(mailimap * session, const char * userid, const char * password) { struct mailimap_response * response; int r; int error_code; if (session->imap_state != MAILIMAP_STATE_NON_AUTHENTICATED) return MAILIMAP_ERROR_BAD_STATE; r = send_current_tag(session); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_login_send(session->imap_stream, userid, password); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_crlf_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; if (mailstream_flush(session->imap_stream) == -1) return MAILIMAP_ERROR_STREAM; if (read_line(session) == NULL) return MAILIMAP_ERROR_STREAM; r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) return r; error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type; mailimap_response_free(response); switch (error_code) { case MAILIMAP_RESP_COND_STATE_OK: session->imap_state = MAILIMAP_STATE_AUTHENTICATED; return MAILIMAP_NO_ERROR; default: return MAILIMAP_ERROR_LOGIN; } } int mailimap_lsub(mailimap * session, const char * mb, const char * list_mb, clist ** result) { struct mailimap_response * response; int r; int error_code; if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) && (session->imap_state != MAILIMAP_STATE_SELECTED)) return MAILIMAP_ERROR_BAD_STATE; r = send_current_tag(session); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_lsub_send(session->imap_stream, mb, list_mb); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_crlf_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; if (mailstream_flush(session->imap_stream) == -1) return MAILIMAP_ERROR_STREAM; if (read_line(session) == NULL) return MAILIMAP_ERROR_STREAM; r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) return r; * result = session->imap_response_info->rsp_mailbox_lsub; session->imap_response_info->rsp_mailbox_lsub = NULL; error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type; mailimap_response_free(response); switch (error_code) { case MAILIMAP_RESP_COND_STATE_OK: return MAILIMAP_NO_ERROR; default: return MAILIMAP_ERROR_LSUB; } } void mailimap_list_result_free(clist * list) { clist_foreach(list, (clist_func) mailimap_mailbox_list_free, NULL); clist_free(list); } int mailimap_rename(mailimap * session, const char * mb, const char * new_name) { struct mailimap_response * response; int r; int error_code; if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) && (session->imap_state != MAILIMAP_STATE_SELECTED)) return MAILIMAP_ERROR_BAD_STATE; r = send_current_tag(session); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_rename_send(session->imap_stream, mb, new_name); if (r != MAILIMAP_NO_ERROR) return r; if (!mailimap_crlf_send(session->imap_stream)) if (r != MAILIMAP_NO_ERROR) return r; if (mailstream_flush(session->imap_stream) == -1) return MAILIMAP_ERROR_STREAM; if (read_line(session) == NULL) return MAILIMAP_ERROR_STREAM; r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) return r; error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type; mailimap_response_free(response); switch (error_code) { case MAILIMAP_RESP_COND_STATE_OK: return MAILIMAP_NO_ERROR; default: return MAILIMAP_ERROR_RENAME; } } int mailimap_search(mailimap * session, const char * charset, struct mailimap_search_key * key, clist ** result) { struct mailimap_response * response; int r; int error_code; if (session->imap_state != MAILIMAP_STATE_SELECTED) return MAILIMAP_ERROR_BAD_STATE; r = send_current_tag(session); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_search_send(session->imap_stream, charset, key); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_crlf_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; if (mailstream_flush(session->imap_stream) == -1) return MAILIMAP_ERROR_STREAM; if (read_line(session) == NULL) return MAILIMAP_ERROR_STREAM; r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) return r; * result = session->imap_response_info->rsp_search_result; session->imap_response_info->rsp_search_result = NULL; error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type; mailimap_response_free(response); switch (error_code) { case MAILIMAP_RESP_COND_STATE_OK: return MAILIMAP_NO_ERROR; default: return MAILIMAP_ERROR_SEARCH; } } int mailimap_uid_search(mailimap * session, const char * charset, struct mailimap_search_key * key, clist ** result) { struct mailimap_response * response; int r; int error_code; if (session->imap_state != MAILIMAP_STATE_SELECTED) return MAILIMAP_ERROR_BAD_STATE; r = send_current_tag(session); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_uid_search_send(session->imap_stream, charset, key); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_crlf_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; if (mailstream_flush(session->imap_stream) == -1) return MAILIMAP_ERROR_STREAM; if (read_line(session) == NULL) return MAILIMAP_ERROR_STREAM; r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) return r; * result = session->imap_response_info->rsp_search_result; session->imap_response_info->rsp_search_result = NULL; error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type; mailimap_response_free(response); switch (error_code) { case MAILIMAP_RESP_COND_STATE_OK: return MAILIMAP_NO_ERROR; default: return MAILIMAP_ERROR_UID_SEARCH; } } void mailimap_search_result_free(clist * search_result) { clist_foreach(search_result, (clist_func) free, NULL); clist_free(search_result); } int mailimap_select(mailimap * session, const char * mb) { struct mailimap_response * response; int r; int error_code; if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) && (session->imap_state != MAILIMAP_STATE_SELECTED)) return MAILIMAP_ERROR_BAD_STATE; r = send_current_tag(session); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_select_send(session->imap_stream, mb); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_crlf_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; if (mailstream_flush(session->imap_stream) == -1) return MAILIMAP_ERROR_STREAM; if (read_line(session) == NULL) return MAILIMAP_ERROR_STREAM; if (session->imap_selection_info != NULL) mailimap_selection_info_free(session->imap_selection_info); session->imap_selection_info = mailimap_selection_info_new(); r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) return r; error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type; mailimap_response_free(response); switch (error_code) { case MAILIMAP_RESP_COND_STATE_OK: session->imap_state = MAILIMAP_STATE_SELECTED; return MAILIMAP_NO_ERROR; default: mailimap_selection_info_free(session->imap_selection_info); session->imap_selection_info = NULL; session->imap_state = MAILIMAP_STATE_AUTHENTICATED; return MAILIMAP_ERROR_SELECT; } } int mailimap_status(mailimap * session, const char * mb, struct mailimap_status_att_list * status_att_list, struct mailimap_mailbox_data_status ** result) { struct mailimap_response * response; int r; int error_code; if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) && (session->imap_state != MAILIMAP_STATE_SELECTED)) return MAILIMAP_ERROR_BAD_STATE; r = send_current_tag(session); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_status_send(session->imap_stream, mb, status_att_list); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_crlf_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; if (mailstream_flush(session->imap_stream) == -1) return MAILIMAP_ERROR_STREAM; if (read_line(session) == NULL) return MAILIMAP_ERROR_STREAM; r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) return r; * result = session->imap_response_info->rsp_status; session->imap_response_info->rsp_status = NULL; error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type; mailimap_response_free(response); switch (error_code) { case MAILIMAP_RESP_COND_STATE_OK: return MAILIMAP_NO_ERROR; default: return MAILIMAP_ERROR_STATUS; } } int mailimap_store(mailimap * session, struct mailimap_set * set, struct mailimap_store_att_flags * store_att_flags) { struct mailimap_response * response; int r; int error_code; if (session->imap_state != MAILIMAP_STATE_SELECTED) return MAILIMAP_ERROR_BAD_STATE; r = send_current_tag(session); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_store_send(session->imap_stream, set, store_att_flags); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_crlf_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; if (mailstream_flush(session->imap_stream) == -1) return MAILIMAP_ERROR_STREAM; if (read_line(session) == NULL) return MAILIMAP_ERROR_STREAM; r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) return r; error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type; mailimap_response_free(response); switch (error_code) { case MAILIMAP_RESP_COND_STATE_OK: return MAILIMAP_NO_ERROR; default: return MAILIMAP_ERROR_STORE; } } int mailimap_uid_store(mailimap * session, struct mailimap_set * set, struct mailimap_store_att_flags * store_att_flags) { struct mailimap_response * response; int r; int error_code; if (session->imap_state != MAILIMAP_STATE_SELECTED) return MAILIMAP_ERROR_BAD_STATE; r = send_current_tag(session); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_uid_store_send(session->imap_stream, set, store_att_flags); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_crlf_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; if (mailstream_flush(session->imap_stream) == -1) return MAILIMAP_ERROR_STREAM; if (read_line(session) == NULL) return MAILIMAP_ERROR_STREAM; r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) return r; error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type; mailimap_response_free(response); switch (error_code) { case MAILIMAP_RESP_COND_STATE_OK: return MAILIMAP_NO_ERROR; default: return MAILIMAP_ERROR_UID_STORE; } } int mailimap_subscribe(mailimap * session, const char * mb) { struct mailimap_response * response; int r; int error_code; if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) && (session->imap_state != MAILIMAP_STATE_SELECTED)) return MAILIMAP_ERROR_BAD_STATE; r = send_current_tag(session); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_subscribe_send(session->imap_stream, mb); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_crlf_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; if (mailstream_flush(session->imap_stream) == -1) return MAILIMAP_ERROR_STREAM; if (read_line(session) == NULL) return MAILIMAP_ERROR_STREAM; r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) return r; error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type; mailimap_response_free(response); switch (error_code) { case MAILIMAP_RESP_COND_STATE_OK: return MAILIMAP_NO_ERROR; default: return MAILIMAP_ERROR_SUBSCRIBE; } } int mailimap_unsubscribe(mailimap * session, const char * mb) { struct mailimap_response * response; int r; int error_code; if ((session->imap_state != MAILIMAP_STATE_AUTHENTICATED) && (session->imap_state != MAILIMAP_STATE_SELECTED)) return MAILIMAP_ERROR_BAD_STATE; r = send_current_tag(session); if (r != MAILIMAP_NO_ERROR) return r; - r = mailimap_subscribe_send(session->imap_stream, mb); + r = mailimap_unsubscribe_send(session->imap_stream, mb); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_crlf_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; if (mailstream_flush(session->imap_stream) == -1) return MAILIMAP_ERROR_STREAM; if (read_line(session) == NULL) return MAILIMAP_ERROR_STREAM; r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) return r; error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type; mailimap_response_free(response); switch (error_code) { case MAILIMAP_RESP_COND_STATE_OK: return MAILIMAP_NO_ERROR; default: return MAILIMAP_ERROR_UNSUBSCRIBE; } } int mailimap_starttls(mailimap * session) { struct mailimap_response * response; int r; int error_code; r = send_current_tag(session); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_starttls_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_crlf_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; if (mailstream_flush(session->imap_stream) == -1) return MAILIMAP_ERROR_STREAM; if (read_line(session) == NULL) return MAILIMAP_ERROR_STREAM; r = parse_response(session, &response); if (r != MAILIMAP_NO_ERROR) return r; error_code = response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type; mailimap_response_free(response); switch (error_code) { case MAILIMAP_RESP_COND_STATE_OK: return MAILIMAP_NO_ERROR; default: return MAILIMAP_ERROR_STARTTLS; } } static char * read_line(mailimap * session) { return mailstream_read_line(session->imap_stream, session->imap_stream_buffer); } static int send_current_tag(mailimap * session) { char tag_str[15]; int r; session->imap_tag ++; snprintf(tag_str, 15, "%i", session->imap_tag); r = mailimap_tag_send(session->imap_stream, tag_str); if (r != MAILIMAP_NO_ERROR) return r; r = mailimap_space_send(session->imap_stream); if (r != MAILIMAP_NO_ERROR) return r; return MAILIMAP_NO_ERROR; } static int parse_response(mailimap * session, struct mailimap_response ** result) { size_t index; struct mailimap_response * response; char tag_str[15]; int r; index = 0; session->imap_response = NULL; r = mailimap_response_parse(session->imap_stream, session->imap_stream_buffer, &index, &response, session->imap_progr_rate, session->imap_progr_fun); if (r != MAILIMAP_NO_ERROR) return r; #if 0 mailimap_response_print(response); #endif response_store(session, response); if (mmap_string_assign(session->imap_response_buffer, response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_text->rsp_text) == NULL) return MAILIMAP_ERROR_MEMORY; session->imap_response = session->imap_response_buffer->str; if (response->rsp_resp_done->rsp_type == MAILIMAP_RESP_DONE_TYPE_FATAL) return MAILIMAP_ERROR_FATAL; snprintf(tag_str, 15, "%i", session->imap_tag); if (strcmp(response->rsp_resp_done->rsp_data.rsp_tagged->rsp_tag, tag_str) != 0) return MAILIMAP_ERROR_PROTOCOL; if (response->rsp_resp_done->rsp_data.rsp_tagged->rsp_cond_state->rsp_type == MAILIMAP_RESP_COND_STATE_BAD) return MAILIMAP_ERROR_PROTOCOL; * result = response; return MAILIMAP_NO_ERROR; } static int parse_greeting(mailimap * session, struct mailimap_greeting ** result) { size_t index; struct mailimap_greeting * greeting; int r; index = 0; session->imap_response = NULL; r = mailimap_greeting_parse(session->imap_stream, session->imap_stream_buffer, &index, &greeting, session->imap_progr_rate, session->imap_progr_fun); if (r != MAILIMAP_NO_ERROR) return r; #if 0 mailimap_greeting_print(greeting); #endif greeting_store(session, greeting); if (greeting->gr_type == MAILIMAP_GREETING_RESP_COND_BYE) { if (mmap_string_assign(session->imap_response_buffer, greeting->gr_data.gr_bye->rsp_text->rsp_text) == NULL) return MAILIMAP_ERROR_MEMORY; session->imap_response = session->imap_response_buffer->str; return MAILIMAP_ERROR_DONT_ACCEPT_CONNECTION; } if (mmap_string_assign(session->imap_response_buffer, greeting->gr_data.gr_auth->rsp_text->rsp_text) == NULL) return MAILIMAP_ERROR_MEMORY; session->imap_response = session->imap_response_buffer->str; * result = greeting; return MAILIMAP_NO_ERROR; } mailimap * mailimap_new(size_t imap_progr_rate, progress_function * imap_progr_fun) { mailimap * f; f = malloc(sizeof(* f)); if (f == NULL) goto err; f->imap_response = NULL; f->imap_stream = NULL; f->imap_progr_rate = imap_progr_rate; f->imap_progr_fun = imap_progr_fun; f->imap_stream_buffer = mmap_string_new(""); if (f->imap_stream_buffer == NULL) goto free_f; f->imap_response_buffer = mmap_string_new(""); if (f->imap_response_buffer == NULL) goto free_stream_buffer; f->imap_state = MAILIMAP_STATE_DISCONNECTED; f->imap_tag = 0; f->imap_selection_info = NULL; f->imap_response_info = NULL; f->imap_connection_info = NULL; return f; free_stream_buffer: mmap_string_free(f->imap_stream_buffer); free_f: free(f); err: return NULL; } void mailimap_free(mailimap * session) { if (session->imap_stream) mailimap_logout(session); mmap_string_free(session->imap_response_buffer); mmap_string_free(session->imap_stream_buffer); if (session->imap_response_info) mailimap_response_info_free(session->imap_response_info); if (session->imap_selection_info) mailimap_selection_info_free(session->imap_selection_info); if (session->imap_connection_info) mailimap_connection_info_free(session->imap_connection_info); free(session); } diff --git a/kmicromail/libetpan/imap/mailimap_keywords.c b/kmicromail/libetpan/imap/mailimap_keywords.c index b277aed..4ec156e 100644 --- a/kmicromail/libetpan/imap/mailimap_keywords.c +++ b/kmicromail/libetpan/imap/mailimap_keywords.c @@ -1,353 +1,353 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "mailimap_keywords.h" #include "mailimap_types.h" #include <string.h> #include <stdio.h> #ifndef UNSTRICT_SYNTAX #define UNSTRICT_SYNTAX #endif struct mailimap_token_value { int value; const char * str; }; int mailimap_token_case_insensitive_parse(mailstream * fd, MMAPString * buffer, size_t * index, const char * token) { int len; - int cur_token; + size_t cur_token; int r; cur_token = * index; len = strlen(token); #ifdef UNSTRICT_SYNTAX r = mailimap_space_parse(fd, buffer, &cur_token); if ((r != MAILIMAP_NO_ERROR) && (r != MAILIMAP_ERROR_PARSE)) return r; #endif if (strncasecmp(buffer->str + cur_token, token, len) == 0) { cur_token += len; * index = cur_token; return MAILIMAP_NO_ERROR; } else return MAILIMAP_ERROR_PARSE; } static int is_space_or_tab(char ch) { return (ch == ' ') || (ch == '\t'); } int mailimap_char_parse(mailstream * fd, MMAPString * buffer, size_t * index, char token) { int cur_token; cur_token = * index; if (buffer->str[cur_token] == token) { cur_token ++; * index = cur_token; return MAILIMAP_NO_ERROR; } else return MAILIMAP_ERROR_PARSE; } int mailimap_space_parse(mailstream * fd, MMAPString * buffer, size_t * index) { #ifdef UNSTRICT_SYNTAX /* can accept unstrict syntax */ size_t cur_token; cur_token = * index; while (is_space_or_tab(* (buffer->str + cur_token))) cur_token ++; if (cur_token == * index) return MAILIMAP_ERROR_PARSE; * index = cur_token; return MAILIMAP_NO_ERROR; #else return mailimap_char_parse(fd, buffer, index, ' '); #endif } #define mailimap_get_token_str(index, tab) \ mailimap_get_token_str_size(index, tab, \ sizeof(tab) / sizeof(struct mailimap_token_value)) #define mailimap_get_token_value(fd, buffer, index, tab) \ mailimap_get_token_value_size(fd, buffer, index, tab, \ sizeof(tab) / sizeof(struct mailimap_token_value)) static const char * mailimap_get_token_str_size(int index, struct mailimap_token_value * tab, size_t size) { size_t i; for(i = 0 ; i < size ; i++) if (index == tab[i].value) return tab[i].str; return NULL; } static int mailimap_get_token_value_size(mailstream * fd, MMAPString * buffer, size_t * index, struct mailimap_token_value * tab, size_t size) { size_t i; int r; #ifdef UNSTRICT_SYNTAX /* can accept unstrict syntax */ r = mailimap_space_parse(fd, buffer, index); if ((r != MAILIMAP_NO_ERROR) && (r != MAILIMAP_ERROR_PARSE)) return r; #endif for(i = 0 ; i < size ; i++) { r = mailimap_token_case_insensitive_parse(fd, buffer, index, tab[i].str); if (r == MAILIMAP_NO_ERROR) return tab[i].value; } return -1; } static struct mailimap_token_value status_att_tab[] = { {MAILIMAP_STATUS_ATT_MESSAGES, "MESSAGES"}, {MAILIMAP_STATUS_ATT_RECENT, "RECENT"}, {MAILIMAP_STATUS_ATT_UIDNEXT, "UIDNEXT"}, {MAILIMAP_STATUS_ATT_UIDVALIDITY, "UIDVALIDITY"}, {MAILIMAP_STATUS_ATT_UNSEEN, "UNSEEN"} }; int mailimap_status_att_get_token_value(mailstream * fd, MMAPString * buffer, size_t * index) { int r; #ifdef UNSTRICT_SYNTAX /* can accept unstrict syntax */ r = mailimap_space_parse(fd, buffer, index); if ((r != MAILIMAP_NO_ERROR) && (r != MAILIMAP_ERROR_PARSE)) return r; #endif return mailimap_get_token_value(fd, buffer, index, status_att_tab); } const char * mailimap_status_att_get_token_str(size_t index) { return mailimap_get_token_str(index, status_att_tab); } static struct mailimap_token_value month_tab[] = { {1, "Jan"}, {2, "Feb"}, {3, "Mar"}, {4, "Apr"}, {5, "May"}, {6, "Jun"}, {7, "Jul"}, {8, "Aug"}, {9, "Sep"}, {10, "Oct"}, {11, "Nov"}, {12, "Dec"} }; int mailimap_month_get_token_value(mailstream * fd, MMAPString * buffer, size_t * index) { return mailimap_get_token_value(fd, buffer, index, month_tab); } const char * mailimap_month_get_token_str(size_t index) { return mailimap_get_token_str(index, month_tab); } static struct mailimap_token_value mailimap_flag_tab[] = { {MAILIMAP_FLAG_ANSWERED, "\\Answered"}, {MAILIMAP_FLAG_FLAGGED, "\\Flagged"}, {MAILIMAP_FLAG_DELETED, "\\Deleted"}, {MAILIMAP_FLAG_SEEN, "\\Seen"}, {MAILIMAP_FLAG_DRAFT, "\\Draft"} }; int mailimap_flag_get_token_value(mailstream * fd, MMAPString * buffer, size_t * index) { return mailimap_get_token_value(fd, buffer, index, mailimap_flag_tab); } const char * mailimap_flag_get_token_str(size_t index) { return mailimap_get_token_str(index, mailimap_flag_tab); } static struct mailimap_token_value encoding_tab[] = { {MAILIMAP_BODY_FLD_ENC_7BIT, "7BIT"}, {MAILIMAP_BODY_FLD_ENC_8BIT, "8BIT"}, {MAILIMAP_BODY_FLD_ENC_BINARY, "BINARY"}, {MAILIMAP_BODY_FLD_ENC_BASE64, "BASE64"}, {MAILIMAP_BODY_FLD_ENC_QUOTED_PRINTABLE, "QUOTED-PRINTABLE"} }; int mailimap_encoding_get_token_value(mailstream * fd, MMAPString * buffer, size_t * index) { return mailimap_get_token_value(fd, buffer, index, encoding_tab); } static struct mailimap_token_value mbx_list_sflag_tab[] = { {MAILIMAP_MBX_LIST_SFLAG_MARKED, "\\Marked"}, {MAILIMAP_MBX_LIST_SFLAG_NOSELECT, "\\Noselect"}, {MAILIMAP_MBX_LIST_SFLAG_UNMARKED, "\\Unmarked"} }; int mailimap_mbx_list_sflag_get_token_value(mailstream * fd, MMAPString * buffer, size_t * index) { return mailimap_get_token_value(fd, buffer, index, mbx_list_sflag_tab); } static struct mailimap_token_value media_basic_tab[] = { {MAILIMAP_MEDIA_BASIC_APPLICATION, "APPLICATION"}, {MAILIMAP_MEDIA_BASIC_AUDIO, "AUDIO"}, {MAILIMAP_MEDIA_BASIC_IMAGE, "IMAGE"}, {MAILIMAP_MEDIA_BASIC_MESSAGE, "MESSAGE"}, {MAILIMAP_MEDIA_BASIC_VIDEO, "VIDEO"} }; int mailimap_media_basic_get_token_value(mailstream * fd, MMAPString * buffer, size_t * index) { return mailimap_get_token_value(fd, buffer, index, media_basic_tab); } static struct mailimap_token_value resp_cond_state_tab[] = { {MAILIMAP_RESP_COND_STATE_OK, "OK"}, {MAILIMAP_RESP_COND_STATE_NO, "NO"}, {MAILIMAP_RESP_COND_STATE_BAD, "BAD"} }; int mailimap_resp_cond_state_get_token_value(mailstream * fd, MMAPString * buffer, size_t * index) { return mailimap_get_token_value(fd, buffer, index, resp_cond_state_tab); } static struct mailimap_token_value resp_text_code_1_tab[] = { {MAILIMAP_RESP_TEXT_CODE_ALERT, "ALERT"}, {MAILIMAP_RESP_TEXT_CODE_PARSE, "PARSE"}, {MAILIMAP_RESP_TEXT_CODE_READ_ONLY, "READ-ONLY"}, {MAILIMAP_RESP_TEXT_CODE_READ_WRITE, "READ-WRITE"}, {MAILIMAP_RESP_TEXT_CODE_TRY_CREATE, "TRYCREATE"} }; int mailimap_resp_text_code_1_get_token_value(mailstream * fd, MMAPString * buffer, size_t * index) { return mailimap_get_token_value(fd, buffer, index, resp_text_code_1_tab); } static struct mailimap_token_value resp_text_code_2_tab[] = { {MAILIMAP_RESP_TEXT_CODE_UIDNEXT, "UIDNEXT"}, {MAILIMAP_RESP_TEXT_CODE_UIDVALIDITY, "UIDVALIDITY"}, {MAILIMAP_RESP_TEXT_CODE_UNSEEN, "UNSEEN"}, }; int mailimap_resp_text_code_2_get_token_value(mailstream * fd, MMAPString * buffer, size_t * index) { return mailimap_get_token_value(fd, buffer, index, resp_text_code_2_tab); } static struct mailimap_token_value section_msgtext_tab[] = { {MAILIMAP_SECTION_MSGTEXT_HEADER_FIELDS_NOT, "HEADER.FIELDS.NOT"}, {MAILIMAP_SECTION_MSGTEXT_HEADER_FIELDS, "HEADER.FIELDS"}, {MAILIMAP_SECTION_MSGTEXT_HEADER, "HEADER"}, {MAILIMAP_SECTION_MSGTEXT_TEXT, "TEXT"} }; int mailimap_section_msgtext_get_token_value(mailstream * fd, MMAPString * buffer, size_t * index) { return mailimap_get_token_value(fd, buffer, index, section_msgtext_tab); } diff --git a/kmicromail/libetpan/imf/mailimf.c b/kmicromail/libetpan/imf/mailimf.c index 84d81a1..e0164b8 100644 --- a/kmicromail/libetpan/imf/mailimf.c +++ b/kmicromail/libetpan/imf/mailimf.c @@ -1,7585 +1,7585 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "mailimf.h" /* RFC 2822 RFC 2821 ... A message-originating SMTP system SHOULD NOT send a message that already contains a Return-path header. SMTP servers performing a relay function MUST NOT inspect the message data, and especially not to the extent needed to determine if Return-path headers are present. SMTP servers making final delivery MAY remove Return-path headers before adding their own. */ #include <ctype.h> -#include <mmapstring.h> +#include "mmapstring.h" #include <stdlib.h> #include <string.h> #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif static inline int is_dtext(char ch); static int mailimf_quoted_pair_parse(const char * message, size_t length, size_t * index, char * result); static int mailimf_ccontent_parse(const char * message, size_t length, size_t * index); static int mailimf_comment_fws_ccontent_parse(const char * message, size_t length, size_t * index); static inline int mailimf_comment_parse(const char * message, size_t length, size_t * index); static int mailimf_qcontent_parse(const char * message, size_t length, size_t * index, char * ch); static int mailimf_phrase_parse(const char * message, size_t length, size_t * index, char ** result); static int mailimf_unstructured_parse(const char * message, size_t length, size_t * index, char ** result); static int mailimf_ignore_unstructured_parse(const char * message, size_t length, size_t * index); static int mailimf_day_of_week_parse(const char * message, size_t length, size_t * index, int * result); static int mailimf_day_name_parse(const char * message, size_t length, size_t * index, int * result); static int mailimf_date_parse(const char * message, size_t length, size_t * index, int * pday, int * pmonth, int * pyear); static int mailimf_year_parse(const char * message, size_t length, size_t * index, int * result); static int mailimf_month_parse(const char * message, size_t length, size_t * index, int * result); static int mailimf_month_name_parse(const char * message, size_t length, size_t * index, int * result); static int mailimf_day_parse(const char * message, size_t length, size_t * index, int * result); static int mailimf_time_parse(const char * message, size_t length, size_t * index, int * phour, int * pmin, int * psec, int * zone); static int mailimf_time_of_day_parse(const char * message, size_t length, size_t * index, int * phour, int * pmin, int * psec); static int mailimf_hour_parse(const char * message, size_t length, size_t * index, int * result); static int mailimf_minute_parse(const char * message, size_t length, size_t * index, int * result); static int mailimf_second_parse(const char * message, size_t length, size_t * index, int * result); static int mailimf_zone_parse(const char * message, size_t length, size_t * index, int * result); static int mailimf_name_addr_parse(const char * message, size_t length, size_t * index, char ** pdisplay_name, char ** pangle_addr); static int mailimf_angle_addr_parse(const char * message, size_t length, size_t * index, char ** result); static int mailimf_group_parse(const char * message, size_t length, size_t * index, struct mailimf_group ** result); static int mailimf_display_name_parse(const char * message, size_t length, size_t * index, char ** result); static int mailimf_addr_spec_parse(const char * message, size_t length, size_t * index, char ** address); #if 0 static int mailimf_local_part_parse(const char * message, size_t length, size_t * index, char ** result); static int mailimf_domain_parse(const char * message, size_t length, size_t * index, char ** result); #endif #if 0 static int mailimf_domain_literal_parse(const char * message, size_t length, size_t * index, char ** result); #endif #if 0 static int mailimf_dcontent_parse(const char * message, size_t length, size_t * index, char * result); #endif static int mailimf_orig_date_parse(const char * message, size_t length, size_t * index, struct mailimf_orig_date ** result); static int mailimf_from_parse(const char * message, size_t length, size_t * index, struct mailimf_from ** result); static int mailimf_sender_parse(const char * message, size_t length, size_t * index, struct mailimf_sender ** result); static int mailimf_reply_to_parse(const char * message, size_t length, size_t * index, struct mailimf_reply_to ** result); static int mailimf_to_parse(const char * message, size_t length, size_t * index, struct mailimf_to ** result); static int mailimf_cc_parse(const char * message, size_t length, size_t * index, struct mailimf_cc ** result); static int mailimf_bcc_parse(const char * message, size_t length, size_t * index, struct mailimf_bcc ** result); static int mailimf_message_id_parse(const char * message, size_t length, size_t * index, struct mailimf_message_id ** result); static int mailimf_in_reply_to_parse(const char * message, size_t length, size_t * index, struct mailimf_in_reply_to ** result); #if 0 static int mailimf_references_parse(const char * message, size_t length, size_t * index, struct mailimf_references ** result); #endif static int mailimf_unstrict_msg_id_parse(const char * message, size_t length, size_t * index, char ** result); #if 0 static int mailimf_id_left_parse(const char * message, size_t length, size_t * index, char ** result); static int mailimf_id_right_parse(const char * message, size_t length, size_t * index, char ** result); #endif #if 0 static int mailimf_no_fold_quote_parse(const char * message, size_t length, size_t * index, char ** result); static int mailimf_no_fold_literal_parse(const char * message, size_t length, size_t * index, char ** result); #endif static int mailimf_subject_parse(const char * message, size_t length, size_t * index, struct mailimf_subject ** result); static int mailimf_comments_parse(const char * message, size_t length, size_t * index, struct mailimf_comments ** result); static int mailimf_keywords_parse(const char * message, size_t length, size_t * index, struct mailimf_keywords ** result); static int mailimf_resent_date_parse(const char * message, size_t length, size_t * index, struct mailimf_orig_date ** result); static int mailimf_resent_from_parse(const char * message, size_t length, size_t * index, struct mailimf_from ** result); static int mailimf_resent_sender_parse(const char * message, size_t length, size_t * index, struct mailimf_sender ** result); static int mailimf_resent_to_parse(const char * message, size_t length, size_t * index, struct mailimf_to ** result); static int mailimf_resent_cc_parse(const char * message, size_t length, size_t * index, struct mailimf_cc ** result); static int mailimf_resent_bcc_parse(const char * message, size_t length, size_t * index, struct mailimf_bcc ** result); static int mailimf_resent_msg_id_parse(const char * message, size_t length, size_t * index, struct mailimf_message_id ** result); static int mailimf_return_parse(const char * message, size_t length, size_t * index, struct mailimf_return ** result); static int mailimf_path_parse(const char * message, size_t length, size_t * index, struct mailimf_path ** result); static int mailimf_optional_field_parse(const char * message, size_t length, size_t * index, struct mailimf_optional_field ** result); static int mailimf_field_name_parse(const char * message, size_t length, size_t * index, char ** result); /* *************************************************************** */ static inline int is_digit(char ch) { return (ch >= '0') && (ch <= '9'); } static int mailimf_digit_parse(const char * message, size_t length, size_t * index, int * result) { size_t cur_token; cur_token = * index; if (cur_token >= length) return MAILIMF_ERROR_PARSE; if (is_digit(message[cur_token])) { * result = message[cur_token] - '0'; cur_token ++; * index = cur_token; return MAILIMF_NO_ERROR; } else return MAILIMF_ERROR_PARSE; } int mailimf_number_parse(const char * message, size_t length, size_t * index, uint32_t * result) { size_t cur_token; int digit; uint32_t number; int parsed; int r; cur_token = * index; parsed = FALSE; number = 0; while (1) { r = mailimf_digit_parse(message, length, &cur_token, &digit); if (r != MAILIMF_NO_ERROR) { if (r == MAILIMF_ERROR_PARSE) break; else return r; } number *= 10; number += digit; parsed = TRUE; } if (!parsed) return MAILIMF_ERROR_PARSE; * result = number; * index = cur_token; return MAILIMF_NO_ERROR; } int mailimf_char_parse(const char * message, size_t length, size_t * index, char token) { size_t cur_token; cur_token = * index; if (cur_token >= length) return MAILIMF_ERROR_PARSE; if (message[cur_token] == token) { cur_token ++; * index = cur_token; return MAILIMF_NO_ERROR; } else return MAILIMF_ERROR_PARSE; } int mailimf_unstrict_char_parse(const char * message, size_t length, size_t * index, char token) { size_t cur_token; int r; cur_token = * index; r = mailimf_cfws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) return r; r = mailimf_char_parse(message, length, &cur_token, token); if (r != MAILIMF_NO_ERROR) return r; * index = cur_token; return MAILIMF_NO_ERROR; } int mailimf_token_case_insensitive_len_parse(const char * message, size_t length, size_t * index, char * token, size_t token_length) { size_t cur_token; cur_token = * index; if (cur_token + token_length - 1 >= length) return MAILIMF_ERROR_PARSE; if (strncasecmp(message + cur_token, token, token_length) == 0) { cur_token += token_length; * index = cur_token; return MAILIMF_NO_ERROR; } else return MAILIMF_ERROR_PARSE; } static int mailimf_oparenth_parse(const char * message, size_t length, size_t * index) { return mailimf_char_parse(message, length, index, '('); } static int mailimf_cparenth_parse(const char * message, size_t length, size_t * index) { return mailimf_char_parse(message, length, index, ')'); } static int mailimf_comma_parse(const char * message, size_t length, size_t * index) { return mailimf_unstrict_char_parse(message, length, index, ','); } static int mailimf_dquote_parse(const char * message, size_t length, size_t * index) { return mailimf_char_parse(message, length, index, '\"'); } static int mailimf_colon_parse(const char * message, size_t length, size_t * index) { return mailimf_unstrict_char_parse(message, length, index, ':'); } static int mailimf_semi_colon_parse(const char * message, size_t length, size_t * index) { return mailimf_unstrict_char_parse(message, length, index, ';'); } static int mailimf_plus_parse(const char * message, size_t length, size_t * index) { return mailimf_unstrict_char_parse(message, length, index, '+'); } static int mailimf_minus_parse(const char * message, size_t length, size_t * index) { return mailimf_unstrict_char_parse(message, length, index, '-'); } static int mailimf_lower_parse(const char * message, size_t length, size_t * index) { return mailimf_unstrict_char_parse(message, length, index, '<'); } static int mailimf_greater_parse(const char * message, size_t length, size_t * index) { return mailimf_unstrict_char_parse(message, length, index, '>'); } #if 0 static int mailimf_obracket_parse(const char * message, size_t length, size_t * index) { return mailimf_unstrict_char_parse(message, length, index, '['); } static int mailimf_cbracket_parse(const char * message, size_t length, size_t * index) { return mailimf_unstrict_char_parse(message, length, index, ']'); } #endif static int mailimf_at_sign_parse(const char * message, size_t length, size_t * index) { return mailimf_unstrict_char_parse(message, length, index, '@'); } static int mailimf_point_parse(const char * message, size_t length, size_t * index) { return mailimf_unstrict_char_parse(message, length, index, '.'); } int mailimf_custom_string_parse(const char * message, size_t length, size_t * index, char ** result, int (* is_custom_char)(char)) { size_t begin; size_t end; char * gstr; begin = * index; end = begin; if (end >= length) return MAILIMF_ERROR_PARSE; while (is_custom_char(message[end])) { end ++; if (end >= length) break; } if (end != begin) { /* gstr = strndup(message + begin, end - begin); */ gstr = malloc(end - begin + 1); if (gstr == NULL) return MAILIMF_ERROR_MEMORY; strncpy(gstr, message + begin, end - begin); gstr[end - begin] = '\0'; * index = end; * result = gstr; return MAILIMF_NO_ERROR; } else return MAILIMF_ERROR_PARSE; } typedef int mailimf_struct_parser(const char * message, size_t length, size_t * index, void * result); typedef int mailimf_struct_destructor(void * result); static int mailimf_struct_multiple_parse(const char * message, size_t length, size_t * index, clist ** result, mailimf_struct_parser * parser, mailimf_struct_destructor * destructor) { clist * struct_list; size_t cur_token; void * value; int r; int res; cur_token = * index; r = parser(message, length, &cur_token, &value); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } struct_list = clist_new(); if (struct_list == NULL) { destructor(value); res = MAILIMF_ERROR_MEMORY; goto err; } r = clist_append(struct_list, value); if (r < 0) { destructor(value); res = MAILIMF_ERROR_MEMORY; goto free; } while (1) { r = parser(message, length, &cur_token, &value); if (r != MAILIMF_NO_ERROR) { if (r == MAILIMF_ERROR_PARSE) break; else { res = r; goto free; } } r = clist_append(struct_list, value); if (r < 0) { (* destructor)(value); res = MAILIMF_ERROR_MEMORY; goto free; } } * result = struct_list; * index = cur_token; return MAILIMF_NO_ERROR; free: clist_foreach(struct_list, (clist_func) destructor, NULL); clist_free(struct_list); err: return res; } static int mailimf_struct_list_parse(const char * message, size_t length, size_t * index, clist ** result, char symbol, mailimf_struct_parser * parser, mailimf_struct_destructor * destructor) { clist * struct_list; size_t cur_token; void * value; size_t final_token; int r; int res; cur_token = * index; r = parser(message, length, &cur_token, &value); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } struct_list = clist_new(); if (struct_list == NULL) { destructor(value); res = MAILIMF_ERROR_MEMORY; goto err; } r = clist_append(struct_list, value); if (r < 0) { destructor(value); res = MAILIMF_ERROR_MEMORY; goto free; } final_token = cur_token; while (1) { r = mailimf_unstrict_char_parse(message, length, &cur_token, symbol); if (r != MAILIMF_NO_ERROR) { if (r == MAILIMF_ERROR_PARSE) break; else { res = r; goto free; } } r = parser(message, length, &cur_token, &value); if (r != MAILIMF_NO_ERROR) { if (r == MAILIMF_ERROR_PARSE) break; else { res = r; goto free; } } r = clist_append(struct_list, value); if (r < 0) { destructor(value); res = MAILIMF_ERROR_MEMORY; goto free; } final_token = cur_token; } * result = struct_list; * index = final_token; return MAILIMF_NO_ERROR; free: clist_foreach(struct_list, (clist_func) destructor, NULL); clist_free(struct_list); err: return res; } static inline int mailimf_wsp_parse(const char * message, size_t length, size_t * index) { size_t cur_token; cur_token = * index; if (cur_token >= length) return MAILIMF_ERROR_PARSE; if ((message[cur_token] != ' ') && (message[cur_token] != '\t')) return MAILIMF_ERROR_PARSE; cur_token ++; * index = cur_token; return MAILIMF_NO_ERROR; } int mailimf_crlf_parse(const char * message, size_t length, size_t * index) { size_t cur_token; int r; cur_token = * index; r = mailimf_char_parse(message, length, &cur_token, '\r'); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) return r; r = mailimf_char_parse(message, length, &cur_token, '\n'); if (r != MAILIMF_NO_ERROR) return r; * index = cur_token; return MAILIMF_NO_ERROR; } static int mailimf_unstrict_crlf_parse(const char * message, size_t length, size_t * index) { size_t cur_token; int r; cur_token = * index; mailimf_cfws_parse(message, length, &cur_token); r = mailimf_char_parse(message, length, &cur_token, '\r'); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) return r; r = mailimf_char_parse(message, length, &cur_token, '\n'); if (r != MAILIMF_NO_ERROR) return r; * index = cur_token; return MAILIMF_NO_ERROR; } /* ************************************************************************ */ /* RFC 2822 grammar */ /* NO-WS-CTL = %d1-8 / ; US-ASCII control characters %d11 / ; that do not include the %d12 / ; carriage return, line feed, %d14-31 / ; and white space characters %d127 */ static inline int is_no_ws_ctl(char ch) { if ((ch == 9) || (ch == 10) || (ch == 13)) return FALSE; if (ch == 127) return TRUE; return (ch >= 1) && (ch <= 31); } /* text = %d1-9 / ; Characters excluding CR and LF %d11 / %d12 / %d14-127 / obs-text */ /* specials = "(" / ")" / ; Special characters used in "<" / ">" / ; other parts of the syntax "[" / "]" / ":" / ";" / "@" / "\" / "," / "." / DQUOTE */ /* quoted-pair = ("\" text) / obs-qp */ static inline int mailimf_quoted_pair_parse(const char * message, size_t length, size_t * index, char * result) { size_t cur_token; cur_token = * index; if (cur_token + 1 >= length) return MAILIMF_ERROR_PARSE; if (message[cur_token] != '\\') return MAILIMF_ERROR_PARSE; cur_token ++; * result = message[cur_token]; cur_token ++; * index = cur_token; return MAILIMF_NO_ERROR; } /* FWS = ([*WSP CRLF] 1*WSP) / ; Folding white space obs-FWS */ int mailimf_fws_parse(const char * message, size_t length, size_t * index) { size_t cur_token; size_t final_token; int fws_1; int fws_2; int fws_3; int r; cur_token = * index; fws_1 = FALSE; while (1) { r = mailimf_wsp_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { if (r == MAILIMF_ERROR_PARSE) break; else return r; } fws_1 = TRUE; } final_token = cur_token; r = mailimf_crlf_parse(message, length, &cur_token); switch (r) { case MAILIMF_NO_ERROR: fws_2 = TRUE; break; case MAILIMF_ERROR_PARSE: fws_2 = FALSE; break; default: return r; } fws_3 = FALSE; if (fws_2) { while (1) { r = mailimf_wsp_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { if (r == MAILIMF_ERROR_PARSE) break; else return r; } fws_3 = TRUE; } } if ((!fws_1) && (!fws_3)) return MAILIMF_ERROR_PARSE; if (!fws_3) cur_token = final_token; * index = cur_token; return MAILIMF_NO_ERROR; } /* ctext = NO-WS-CTL / ; Non white space controls %d33-39 / ; The rest of the US-ASCII %d42-91 / ; characters not including "(", %d93-126 ; ")", or "\" */ static inline int is_ctext(char ch) { unsigned char uch = (unsigned char) ch; if (is_no_ws_ctl(ch)) return TRUE; if (uch < 33) return FALSE; if ((uch == 40) || (uch == 41)) return FALSE; if (uch == 92) return FALSE; if (uch == 127) return FALSE; return TRUE; } /* ccontent = ctext / quoted-pair / comment */ static inline int mailimf_ccontent_parse(const char * message, size_t length, size_t * index) { size_t cur_token; char ch; int r; cur_token = * index; if (cur_token >= length) return MAILIMF_ERROR_PARSE; if (is_ctext(message[cur_token])) { cur_token ++; } else { r = mailimf_quoted_pair_parse(message, length, &cur_token, &ch); if (r == MAILIMF_ERROR_PARSE) r = mailimf_comment_parse(message, length, &cur_token); if (r == MAILIMF_ERROR_PARSE) return r; } * index = cur_token; return MAILIMF_NO_ERROR; } /* [FWS] ccontent */ static inline int mailimf_comment_fws_ccontent_parse(const char * message, size_t length, size_t * index) { size_t cur_token; int r; cur_token = * index; r = mailimf_fws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) return r; r = mailimf_ccontent_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) return r; * index = cur_token; return MAILIMF_NO_ERROR; } /* comment = "(" *([FWS] ccontent) [FWS] ")" */ static inline int mailimf_comment_parse(const char * message, size_t length, size_t * index) { size_t cur_token; int r; cur_token = * index; r = mailimf_oparenth_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) return r; while (1) { r = mailimf_comment_fws_ccontent_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { if (r == MAILIMF_ERROR_PARSE) break; else return r; } } r = mailimf_fws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) return r; r = mailimf_cparenth_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) return r; * index = cur_token; return MAILIMF_NO_ERROR; } /* [FWS] comment */ static inline int mailimf_cfws_fws_comment_parse(const char * message, size_t length, size_t * index) { size_t cur_token; int r; cur_token = * index; r = mailimf_fws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) return r; r = mailimf_comment_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) return r; * index = cur_token; return MAILIMF_NO_ERROR; } /* CFWS = *([FWS] comment) (([FWS] comment) / FWS) */ int mailimf_cfws_parse(const char * message, size_t length, size_t * index) { size_t cur_token; int has_comment; int r; cur_token = * index; has_comment = FALSE; while (1) { r = mailimf_cfws_fws_comment_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { if (r == MAILIMF_ERROR_PARSE) break; else return r; } has_comment = TRUE; } if (!has_comment) { r = mailimf_fws_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) return r; } * index = cur_token; return MAILIMF_NO_ERROR; } /* atext = ALPHA / DIGIT / ; Any character except controls, "!" / "#" / ; SP, and specials. "$" / "%" / ; Used for atoms "&" / "'" / "*" / "+" / "-" / "/" / "=" / "?" / "^" / "_" / "`" / "{" / "|" / "}" / "~" */ static inline int is_atext(char ch) { switch (ch) { case ' ': case '\t': case '\n': case '\r': #if 0 case '(': case ')': #endif case '<': case '>': #if 0 case '@': #endif case ',': case '"': case ':': case ';': return FALSE; default: return TRUE; } } /* atom = [CFWS] 1*atext [CFWS] */ int mailimf_atom_parse(const char * message, size_t length, size_t * index, char ** result) { size_t cur_token; int r; int res; char * atom; size_t end; cur_token = * index; r = mailimf_cfws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { res = r; goto err; } end = cur_token; if (end >= length) { res = MAILIMF_ERROR_PARSE; goto err; } while (is_atext(message[end])) { end ++; if (end >= length) break; } if (end == cur_token) { res = MAILIMF_ERROR_PARSE; goto err; } atom = malloc(end - cur_token + 1); if (atom == NULL) { res = MAILIMF_ERROR_MEMORY; goto err; } strncpy(atom, message + cur_token, end - cur_token); atom[end - cur_token] = '\0'; cur_token = end; * index = cur_token; * result = atom; return MAILIMF_NO_ERROR; err: return res; } int mailimf_fws_atom_parse(const char * message, size_t length, size_t * index, char ** result) { size_t cur_token; int r; int res; char * atom; size_t end; cur_token = * index; r = mailimf_fws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { res = r; goto err; } end = cur_token; if (end >= length) { res = MAILIMF_ERROR_PARSE; goto err; } while (is_atext(message[end])) { end ++; if (end >= length) break; } if (end == cur_token) { res = MAILIMF_ERROR_PARSE; goto err; } atom = malloc(end - cur_token + 1); if (atom == NULL) { res = MAILIMF_ERROR_MEMORY; goto err; } strncpy(atom, message + cur_token, end - cur_token); atom[end - cur_token] = '\0'; cur_token = end; * index = cur_token; * result = atom; return MAILIMF_NO_ERROR; err: return res; } /* dot-atom = [CFWS] dot-atom-text [CFWS] */ #if 0 static int mailimf_dot_atom_parse(const char * message, size_t length, size_t * index, char ** result) { return mailimf_atom_parse(message, length, index, result); } #endif /* dot-atom-text = 1*atext *("." 1*atext) */ #if 0 static int mailimf_dot_atom_text_parse(const char * message, size_t length, size_t * index, char ** result) { return mailimf_atom_parse(message, length, index, result); } #endif /* qtext = NO-WS-CTL / ; Non white space controls %d33 / ; The rest of the US-ASCII %d35-91 / ; characters not including "\" %d93-126 ; or the quote character */ static inline int is_qtext(char ch) { unsigned char uch = (unsigned char) ch; if (is_no_ws_ctl(ch)) return TRUE; if (uch < 33) return FALSE; if (uch == 34) return FALSE; if (uch == 92) return FALSE; if (uch == 127) return FALSE; return TRUE; } /* qcontent = qtext / quoted-pair */ static int mailimf_qcontent_parse(const char * message, size_t length, size_t * index, char * result) { size_t cur_token; char ch; int r; cur_token = * index; if (cur_token >= length) return MAILIMF_ERROR_PARSE; if (is_qtext(message[cur_token])) { ch = message[cur_token]; cur_token ++; } else { r = mailimf_quoted_pair_parse(message, length, &cur_token, &ch); if (r != MAILIMF_NO_ERROR) return r; } * result = ch; * index = cur_token; return MAILIMF_NO_ERROR; } /* quoted-string = [CFWS] DQUOTE *([FWS] qcontent) [FWS] DQUOTE [CFWS] */ int mailimf_quoted_string_parse(const char * message, size_t length, size_t * index, char ** result) { size_t cur_token; MMAPString * gstr; char ch; char * str; int r; int res; cur_token = * index; r = mailimf_cfws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { res = r; goto err; } r = mailimf_dquote_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } gstr = mmap_string_new(""); if (gstr == NULL) { res = MAILIMF_ERROR_MEMORY; goto err; } #if 0 if (mmap_string_append_c(gstr, '\"') == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_gstr; } #endif while (1) { r = mailimf_fws_parse(message, length, &cur_token); if (r == MAILIMF_NO_ERROR) { if (mmap_string_append_c(gstr, ' ') == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_gstr; } } else if (r != MAILIMF_ERROR_PARSE) { res = r; goto free_gstr; } r = mailimf_qcontent_parse(message, length, &cur_token, &ch); if (r == MAILIMF_NO_ERROR) { if (mmap_string_append_c(gstr, ch) == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_gstr; } } else if (r == MAILIMF_ERROR_PARSE) break; else { res = r; goto free_gstr; } } r = mailimf_dquote_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_gstr; } #if 0 if (mmap_string_append_c(gstr, '\"') == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_gstr; } #endif str = strdup(gstr->str); if (str == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_gstr; } mmap_string_free(gstr); * index = cur_token; * result = str; return MAILIMF_NO_ERROR; free_gstr: mmap_string_free(gstr); err: return res; } int mailimf_fws_quoted_string_parse(const char * message, size_t length, size_t * index, char ** result) { size_t cur_token; MMAPString * gstr; char ch; char * str; int r; int res; cur_token = * index; r = mailimf_fws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { res = r; goto err; } r = mailimf_dquote_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } gstr = mmap_string_new(""); if (gstr == NULL) { res = MAILIMF_ERROR_MEMORY; goto err; } #if 0 if (mmap_string_append_c(gstr, '\"') == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_gstr; } #endif while (1) { r = mailimf_fws_parse(message, length, &cur_token); if (r == MAILIMF_NO_ERROR) { if (mmap_string_append_c(gstr, ' ') == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_gstr; } } else if (r != MAILIMF_ERROR_PARSE) { res = r; goto free_gstr; } r = mailimf_qcontent_parse(message, length, &cur_token, &ch); if (r == MAILIMF_NO_ERROR) { if (mmap_string_append_c(gstr, ch) == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_gstr; } } else if (r == MAILIMF_ERROR_PARSE) break; else { res = r; goto free_gstr; } } r = mailimf_dquote_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_gstr; } #if 0 if (mmap_string_append_c(gstr, '\"') == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_gstr; } #endif str = strdup(gstr->str); if (str == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_gstr; } mmap_string_free(gstr); * index = cur_token; * result = str; return MAILIMF_NO_ERROR; free_gstr: mmap_string_free(gstr); err: return res; } /* word = atom / quoted-string */ int mailimf_word_parse(const char * message, size_t length, size_t * index, char ** result) { size_t cur_token; char * word; int r; cur_token = * index; r = mailimf_atom_parse(message, length, &cur_token, &word); if (r == MAILIMF_ERROR_PARSE) r = mailimf_quoted_string_parse(message, length, &cur_token, &word); if (r != MAILIMF_NO_ERROR) return r; * result = word; * index = cur_token; return MAILIMF_NO_ERROR; } int mailimf_fws_word_parse(const char * message, size_t length, size_t * index, char ** result) { size_t cur_token; char * word; int r; cur_token = * index; r = mailimf_fws_atom_parse(message, length, &cur_token, &word); if (r == MAILIMF_ERROR_PARSE) r = mailimf_fws_quoted_string_parse(message, length, &cur_token, &word); if (r != MAILIMF_NO_ERROR) return r; * result = word; * index = cur_token; return MAILIMF_NO_ERROR; } /* phrase = 1*word / obs-phrase */ static int mailimf_phrase_parse(const char * message, size_t length, size_t * index, char ** result) { MMAPString * gphrase; char * word; int first; size_t cur_token; int r; int res; char * str; cur_token = * index; gphrase = mmap_string_new(""); if (gphrase == NULL) { res = MAILIMF_ERROR_MEMORY; goto err; } first = TRUE; while (1) { r = mailimf_fws_word_parse(message, length, &cur_token, &word); if (r == MAILIMF_NO_ERROR) { if (!first) { if (mmap_string_append_c(gphrase, ' ') == NULL) { mailimf_word_free(word); res = MAILIMF_ERROR_MEMORY; goto free; } } if (mmap_string_append(gphrase, word) == NULL) { mailimf_word_free(word); res = MAILIMF_ERROR_MEMORY; goto free; } mailimf_word_free(word); first = FALSE; } else if (r == MAILIMF_ERROR_PARSE) break; else { res = r; goto free; } } if (first) { res = MAILIMF_ERROR_PARSE; goto free; } str = strdup(gphrase->str); if (str == NULL) { res = MAILIMF_ERROR_MEMORY; goto free; } mmap_string_free(gphrase); * result = str; * index = cur_token; return MAILIMF_NO_ERROR; free: mmap_string_free(gphrase); err: return res; } /* utext = NO-WS-CTL / ; Non white space controls %d33-126 / ; The rest of US-ASCII obs-utext added : WSP */ enum { UNSTRUCTURED_START, UNSTRUCTURED_CR, UNSTRUCTURED_LF, UNSTRUCTURED_WSP, UNSTRUCTURED_OUT }; static int mailimf_unstructured_parse(const char * message, size_t length, size_t * index, char ** result) { size_t cur_token; int state; size_t begin; size_t terminal; char * str; cur_token = * index; while (1) { int r; r = mailimf_wsp_parse(message, length, &cur_token); if (r == MAILIMF_NO_ERROR) { /* do nothing */ } else if (r == MAILIMF_ERROR_PARSE) break; else { return r; } } state = UNSTRUCTURED_START; begin = cur_token; terminal = cur_token; while (state != UNSTRUCTURED_OUT) { switch(state) { case UNSTRUCTURED_START: if (cur_token >= length) return MAILIMF_ERROR_PARSE; terminal = cur_token; switch(message[cur_token]) { case '\r': state = UNSTRUCTURED_CR; break; case '\n': state = UNSTRUCTURED_LF; break; default: state = UNSTRUCTURED_START; break; } break; case UNSTRUCTURED_CR: if (cur_token >= length) return MAILIMF_ERROR_PARSE; switch(message[cur_token]) { case '\n': state = UNSTRUCTURED_LF; break; default: state = UNSTRUCTURED_START; break; } break; case UNSTRUCTURED_LF: if (cur_token >= length) { state = UNSTRUCTURED_OUT; break; } switch(message[cur_token]) { case '\t': case ' ': state = UNSTRUCTURED_WSP; break; default: state = UNSTRUCTURED_OUT; break; } break; case UNSTRUCTURED_WSP: if (cur_token >= length) return MAILIMF_ERROR_PARSE; switch(message[cur_token]) { case '\r': state = UNSTRUCTURED_CR; break; case '\n': state = UNSTRUCTURED_LF; break; default: state = UNSTRUCTURED_START; break; } break; } cur_token ++; } str = malloc(terminal - begin + 1); if (str == NULL) return MAILIMF_ERROR_MEMORY; strncpy(str, message + begin, terminal - begin); str[terminal - begin] = '\0'; * index = terminal; * result = str; return MAILIMF_NO_ERROR; } static int mailimf_ignore_unstructured_parse(const char * message, size_t length, size_t * index) { size_t cur_token; int state; size_t terminal; cur_token = * index; state = UNSTRUCTURED_START; terminal = cur_token; while (state != UNSTRUCTURED_OUT) { switch(state) { case UNSTRUCTURED_START: if (cur_token >= length) return MAILIMF_ERROR_PARSE; terminal = cur_token; switch(message[cur_token]) { case '\r': state = UNSTRUCTURED_CR; break; case '\n': state = UNSTRUCTURED_LF; break; default: state = UNSTRUCTURED_START; break; } break; case UNSTRUCTURED_CR: if (cur_token >= length) return MAILIMF_ERROR_PARSE; switch(message[cur_token]) { case '\n': state = UNSTRUCTURED_LF; break; default: state = UNSTRUCTURED_START; break; } break; case UNSTRUCTURED_LF: if (cur_token >= length) { state = UNSTRUCTURED_OUT; break; } switch(message[cur_token]) { case '\t': case ' ': state = UNSTRUCTURED_WSP; break; default: state = UNSTRUCTURED_OUT; break; } break; case UNSTRUCTURED_WSP: if (cur_token >= length) return MAILIMF_ERROR_PARSE; switch(message[cur_token]) { case '\r': state = UNSTRUCTURED_CR; break; case '\n': state = UNSTRUCTURED_LF; break; default: state = UNSTRUCTURED_START; break; } break; } cur_token ++; } * index = terminal; return MAILIMF_NO_ERROR; } int mailimf_ignore_field_parse(const char * message, size_t length, size_t * index) { int has_field; size_t cur_token; int state; size_t terminal; has_field = FALSE; cur_token = * index; terminal = cur_token; state = UNSTRUCTURED_START; /* check if this is not a beginning CRLF */ if (cur_token >= length) return MAILIMF_ERROR_PARSE; switch (message[cur_token]) { case '\r': return MAILIMF_ERROR_PARSE; case '\n': return MAILIMF_ERROR_PARSE; } while (state != UNSTRUCTURED_OUT) { switch(state) { case UNSTRUCTURED_START: if (cur_token >= length) return MAILIMF_ERROR_PARSE; switch(message[cur_token]) { case '\r': state = UNSTRUCTURED_CR; break; case '\n': state = UNSTRUCTURED_LF; break; case ':': has_field = TRUE; state = UNSTRUCTURED_START; break; default: state = UNSTRUCTURED_START; break; } break; case UNSTRUCTURED_CR: if (cur_token >= length) return MAILIMF_ERROR_PARSE; switch(message[cur_token]) { case '\n': state = UNSTRUCTURED_LF; break; case ':': has_field = TRUE; state = UNSTRUCTURED_START; break; default: state = UNSTRUCTURED_START; break; } break; case UNSTRUCTURED_LF: if (cur_token >= length) { terminal = cur_token; state = UNSTRUCTURED_OUT; break; } switch(message[cur_token]) { case '\t': case ' ': state = UNSTRUCTURED_WSP; break; default: terminal = cur_token; state = UNSTRUCTURED_OUT; break; } break; case UNSTRUCTURED_WSP: if (cur_token >= length) return MAILIMF_ERROR_PARSE; switch(message[cur_token]) { case '\r': state = UNSTRUCTURED_CR; break; case '\n': state = UNSTRUCTURED_LF; break; case ':': has_field = TRUE; state = UNSTRUCTURED_START; break; default: state = UNSTRUCTURED_START; break; } break; } cur_token ++; } if (!has_field) return MAILIMF_ERROR_PARSE; * index = terminal; return MAILIMF_NO_ERROR; } /* date-time = [ day-of-week "," ] date FWS time [CFWS] */ int mailimf_date_time_parse(const char * message, size_t length, size_t * index, struct mailimf_date_time ** result) { size_t cur_token; int day_of_week; struct mailimf_date_time * date_time; int day; int month; int year; int hour; int min; int sec; int zone; int r; cur_token = * index; day_of_week = -1; r = mailimf_day_of_week_parse(message, length, &cur_token, &day_of_week); if (r == MAILIMF_NO_ERROR) { r = mailimf_comma_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) return r; } else if (r != MAILIMF_ERROR_PARSE) return r; r = mailimf_date_parse(message, length, &cur_token, &day, &month, &year); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_fws_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_time_parse(message, length, &cur_token, &hour, &min, &sec, &zone); if (r != MAILIMF_NO_ERROR) return r; date_time = mailimf_date_time_new(day, month, year, hour, min, sec, zone); if (date_time == NULL) return MAILIMF_ERROR_MEMORY; * index = cur_token; * result = date_time; return MAILIMF_NO_ERROR; } /* day-of-week = ([FWS] day-name) / obs-day-of-week */ static int mailimf_day_of_week_parse(const char * message, size_t length, size_t * index, int * result) { size_t cur_token; int day_of_week; int r; cur_token = * index; r = mailimf_cfws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) return r; r = mailimf_day_name_parse(message, length, &cur_token, &day_of_week); if (r != MAILIMF_NO_ERROR) return r; * index = cur_token; * result = day_of_week; return MAILIMF_NO_ERROR; } /* day-name = "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun" */ struct mailimf_token_value { int value; char * str; }; static struct mailimf_token_value day_names[] = { {1, "Mon"}, {2, "Tue"}, {3, "Wed"}, {4, "Thu"}, {5, "Fri"}, {6, "Sat"}, {7, "Sun"}, }; enum { DAY_NAME_START, DAY_NAME_T, DAY_NAME_S }; static int guess_day_name(const char * message, size_t length, size_t index) { int state; state = DAY_NAME_START; while (1) { if (index >= length) return -1; switch(state) { case DAY_NAME_START: switch((char) toupper((unsigned char) message[index])) { case 'M': /* Mon */ return 1; break; case 'T': /* Tue Thu */ state = DAY_NAME_T; break; case 'W': /* Wed */ return 3; case 'F': return 5; case 'S': /* Sat Sun */ state = DAY_NAME_S; break; default: return -1; } break; case DAY_NAME_T: switch((char) toupper((unsigned char) message[index])) { case 'U': return 2; case 'H': return 4; default: return -1; } break; case DAY_NAME_S: switch((char) toupper((unsigned char) message[index])) { case 'A': return 6; case 'U': return 7; default: return -1; } break; } index ++; } } static int mailimf_day_name_parse(const char * message, size_t length, size_t * index, int * result) { size_t cur_token; int day_of_week; int guessed_day; int r; cur_token = * index; guessed_day = guess_day_name(message, length, cur_token); if (guessed_day == -1) return MAILIMF_ERROR_PARSE; r = mailimf_token_case_insensitive_parse(message, length, &cur_token, day_names[guessed_day - 1].str); if (r != MAILIMF_NO_ERROR) return r; day_of_week = guessed_day; * result = day_of_week; * index = cur_token; return MAILIMF_NO_ERROR; } /* date = day month year */ static int mailimf_date_parse(const char * message, size_t length, size_t * index, int * pday, int * pmonth, int * pyear) { size_t cur_token; int day; int month; int year; int r; cur_token = * index; r = mailimf_day_parse(message, length, &cur_token, &day); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_month_parse(message, length, &cur_token, &month); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_year_parse(message, length, &cur_token, &year); if (r != MAILIMF_NO_ERROR) return r; * pday = day; * pmonth = month; * pyear = year; * index = cur_token; return MAILIMF_NO_ERROR; } /* year = 4*DIGIT / obs-year */ static int mailimf_year_parse(const char * message, size_t length, size_t * index, int * result) { uint32_t number; size_t cur_token; int r; cur_token = * index; r = mailimf_cfws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) return r; r = mailimf_number_parse(message, length, &cur_token, &number); if (r != MAILIMF_NO_ERROR) return r; * index = cur_token; * result = number; return MAILIMF_NO_ERROR; } /* month = (FWS month-name FWS) / obs-month */ static int mailimf_month_parse(const char * message, size_t length, size_t * index, int * result) { size_t cur_token; int month; int r; cur_token = * index; r = mailimf_cfws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) return r; r = mailimf_month_name_parse(message, length, &cur_token, &month); if (r != MAILIMF_NO_ERROR) return r; * result = month; * index = cur_token; return MAILIMF_NO_ERROR; } /* month-name = "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" / "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec" */ static struct mailimf_token_value month_names[] = { {1, "Jan"}, {2, "Feb"}, {3, "Mar"}, {4, "Apr"}, {5, "May"}, {6, "Jun"}, {7, "Jul"}, {8, "Aug"}, {9, "Sep"}, {10, "Oct"}, {11, "Nov"}, {12, "Dec"}, }; enum { MONTH_START, MONTH_J, MONTH_JU, MONTH_M, MONTH_MA, MONTH_A }; static int guess_month(const char * message, size_t length, size_t index) { int state; state = MONTH_START; while (1) { if (index >= length) return -1; switch(state) { case MONTH_START: switch((char) toupper((unsigned char) message[index])) { case 'J': /* Jan Jun Jul */ state = MONTH_J; break; case 'F': /* Feb */ return 2; case 'M': /* Mar May */ state = MONTH_M; break; case 'A': /* Apr Aug */ state = MONTH_A; break; case 'S': /* Sep */ return 9; case 'O': /* Oct */ return 10; case 'N': /* Nov */ return 11; case 'D': /* Dec */ return 12; default: return -1; } break; case MONTH_J: switch((char) toupper((unsigned char) message[index])) { case 'A': return 1; case 'U': state = MONTH_JU; break; default: return -1; } break; case MONTH_JU: switch((char) toupper((unsigned char) message[index])) { case 'N': return 6; case 'L': return 7; default: return -1; } break; case MONTH_M: switch((char) toupper((unsigned char) message[index])) { case 'A': state = MONTH_MA; break; default: return -1; } break; case MONTH_MA: switch((char) toupper((unsigned char) message[index])) { case 'Y': return 5; case 'R': return 3; default: return -1; } break; case MONTH_A: switch((char) toupper((unsigned char) message[index])) { case 'P': return 4; case 'U': return 8; default: return -1; } break; } index ++; } } static int mailimf_month_name_parse(const char * message, size_t length, size_t * index, int * result) { size_t cur_token; int month; int guessed_month; int r; cur_token = * index; guessed_month = guess_month(message, length, cur_token); if (guessed_month == -1) return MAILIMF_ERROR_PARSE; r = mailimf_token_case_insensitive_parse(message, length, &cur_token, month_names[guessed_month - 1].str); if (r != MAILIMF_NO_ERROR) return r; month = guessed_month; * result = month; * index = cur_token; return MAILIMF_NO_ERROR; } /* day = ([FWS] 1*2DIGIT) / obs-day */ static int mailimf_day_parse(const char * message, size_t length, size_t * index, int * result) { size_t cur_token; uint32_t day; int r; cur_token = * index; r = mailimf_cfws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) return r; r = mailimf_number_parse(message, length, &cur_token, &day); if (r != MAILIMF_NO_ERROR) return r; * result = day; * index = cur_token; return MAILIMF_NO_ERROR; } /* time = time-of-day FWS zone */ static int mailimf_time_parse(const char * message, size_t length, size_t * index, int * phour, int * pmin, int * psec, int * pzone) { size_t cur_token; int hour; int min; int sec; int zone; int r; cur_token = * index; r = mailimf_cfws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) return r; r = mailimf_time_of_day_parse(message, length, &cur_token, &hour, &min, &sec); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_fws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) return r; r = mailimf_zone_parse(message, length, &cur_token, &zone); if (r == MAILIMF_NO_ERROR) { /* do nothing */ } else if (r == MAILIMF_ERROR_PARSE) { zone = 0; } else { return r; } * phour = hour; * pmin = min; * psec = sec; * pzone = zone; * index = cur_token; return MAILIMF_NO_ERROR; } /* time-of-day = hour ":" minute [ ":" second ] */ static int mailimf_time_of_day_parse(const char * message, size_t length, size_t * index, int * phour, int * pmin, int * psec) { int hour; int min; int sec; size_t cur_token; int r; cur_token = * index; r = mailimf_hour_parse(message, length, &cur_token, &hour); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_colon_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_minute_parse(message, length, &cur_token, &min); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_colon_parse(message, length, &cur_token); if (r == MAILIMF_NO_ERROR) { r = mailimf_second_parse(message, length, &cur_token, &sec); if (r != MAILIMF_NO_ERROR) return r; } else if (r == MAILIMF_ERROR_PARSE) sec = 0; else return r; * phour = hour; * pmin = min; * psec = sec; * index = cur_token; return MAILIMF_NO_ERROR; } /* hour = 2DIGIT / obs-hour */ static int mailimf_hour_parse(const char * message, size_t length, size_t * index, int * result) { uint32_t hour; int r; r = mailimf_number_parse(message, length, index, &hour); if (r != MAILIMF_NO_ERROR) return r; * result = hour; return MAILIMF_NO_ERROR; } /* minute = 2DIGIT / obs-minute */ static int mailimf_minute_parse(const char * message, size_t length, size_t * index, int * result) { uint32_t minute; int r; r = mailimf_number_parse(message, length, index, &minute); if (r != MAILIMF_NO_ERROR) return r; * result = minute; return MAILIMF_NO_ERROR; } /* second = 2DIGIT / obs-second */ static int mailimf_second_parse(const char * message, size_t length, size_t * index, int * result) { uint32_t second; int r; r = mailimf_number_parse(message, length, index, &second); if (r != MAILIMF_NO_ERROR) return r; * result = second; return MAILIMF_NO_ERROR; } /* zone = (( "+" / "-" ) 4DIGIT) / obs-zone */ /* obs-zone = "UT" / "GMT" / ; Universal Time ; North American UT ; offsets "EST" / "EDT" / ; Eastern: - 5/ - 4 "CST" / "CDT" / ; Central: - 6/ - 5 "MST" / "MDT" / ; Mountain: - 7/ - 6 "PST" / "PDT" / ; Pacific: - 8/ - 7 %d65-73 / ; Military zones - "A" %d75-90 / ; through "I" and "K" %d97-105 / ; through "Z", both %d107-122 ; upper and lower case */ enum { STATE_ZONE_1 = 0, STATE_ZONE_2 = 1, STATE_ZONE_3 = 2, STATE_ZONE_OK = 3, STATE_ZONE_ERR = 4, STATE_ZONE_CONT = 5, }; static int mailimf_zone_parse(const char * message, size_t length, size_t * index, int * result) { uint32_t zone; int sign; size_t cur_token; int r; cur_token = * index; if (cur_token + 1 < length) { if ((message[cur_token] == 'U') && (message[cur_token] == 'T')) { * result = TRUE; * index = cur_token + 2; return MAILIMF_NO_ERROR; } } if (cur_token + 2 < length) { int state; state = STATE_ZONE_1; while (state <= 2) { switch (state) { case STATE_ZONE_1: switch (message[cur_token]) { case 'G': if (message[cur_token + 1] == 'M' && message[cur_token + 2] == 'T') { zone = 0; state = STATE_ZONE_OK; } else { state = STATE_ZONE_ERR; } break; case 'E': zone = -5; state = STATE_ZONE_2; break; case 'C': zone = -6; state = STATE_ZONE_2; break; case 'M': zone = -7; state = STATE_ZONE_2; break; case 'P': zone = -8; state = STATE_ZONE_2; break; default: state = STATE_ZONE_CONT; break; } break; case STATE_ZONE_2: switch (message[cur_token + 1]) { case 'S': state = STATE_ZONE_3; break; case 'D': zone ++; state = STATE_ZONE_3; break; default: state = STATE_ZONE_ERR; break; } break; case STATE_ZONE_3: if (message[cur_token + 2] == 'T') { zone *= 100; state = STATE_ZONE_OK; } else state = STATE_ZONE_ERR; break; } } switch (state) { case STATE_ZONE_OK: * result = zone; * index = cur_token + 3; return MAILIMF_NO_ERROR; case STATE_ZONE_ERR: return MAILIMF_ERROR_PARSE; } } sign = 1; r = mailimf_plus_parse(message, length, &cur_token); if (r == MAILIMF_NO_ERROR) sign = 1; if (r == MAILIMF_ERROR_PARSE) { r = mailimf_minus_parse(message, length, &cur_token); if (r == MAILIMF_NO_ERROR) sign = -1; } if (r == MAILIMF_NO_ERROR) { /* do nothing */ } else if (r == MAILIMF_ERROR_PARSE) sign = 1; else return r; r = mailimf_number_parse(message, length, &cur_token, &zone); if (r != MAILIMF_NO_ERROR) return r; zone = zone * sign; * index = cur_token; * result = zone; return MAILIMF_NO_ERROR; } /* address = mailbox / group */ int mailimf_address_parse(const char * message, size_t length, size_t * index, struct mailimf_address ** result) { int type; size_t cur_token; struct mailimf_mailbox * mailbox; struct mailimf_group * group; struct mailimf_address * address; int r; int res; cur_token = * index; mailbox = NULL; group = NULL; type = MAILIMF_ADDRESS_ERROR; /* XXX - removes a gcc warning */ r = mailimf_group_parse(message, length, &cur_token, &group); if (r == MAILIMF_NO_ERROR) type = MAILIMF_ADDRESS_GROUP; if (r == MAILIMF_ERROR_PARSE) { r = mailimf_mailbox_parse(message, length, &cur_token, &mailbox); if (r == MAILIMF_NO_ERROR) type = MAILIMF_ADDRESS_MAILBOX; } if (r != MAILIMF_NO_ERROR) { res = r; goto err; } address = mailimf_address_new(type, mailbox, group); if (address == NULL) { res = MAILIMF_ERROR_MEMORY; goto free; } * result = address; * index = cur_token; return MAILIMF_NO_ERROR; free: if (mailbox != NULL) mailimf_mailbox_free(mailbox); if (group != NULL) mailimf_group_free(group); err: return res; } /* mailbox = name-addr / addr-spec */ int mailimf_mailbox_parse(const char * message, size_t length, size_t * index, struct mailimf_mailbox ** result) { size_t cur_token; char * display_name; struct mailimf_mailbox * mailbox; char * addr_spec; int r; int res; cur_token = * index; display_name = NULL; addr_spec = NULL; r = mailimf_name_addr_parse(message, length, &cur_token, &display_name, &addr_spec); if (r == MAILIMF_ERROR_PARSE) r = mailimf_addr_spec_parse(message, length, &cur_token, &addr_spec); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } mailbox = mailimf_mailbox_new(display_name, addr_spec); if (mailbox == NULL) { res = MAILIMF_ERROR_MEMORY; goto free; } * result = mailbox; * index = cur_token; return MAILIMF_NO_ERROR; free: if (display_name != NULL) mailimf_display_name_free(display_name); if (addr_spec != NULL) mailimf_addr_spec_free(addr_spec); err: return res; } /* name-addr = [display-name] angle-addr */ static int mailimf_name_addr_parse(const char * message, size_t length, size_t * index, char ** pdisplay_name, char ** pangle_addr) { char * display_name; char * angle_addr; size_t cur_token; int r; int res; cur_token = * index; display_name = NULL; angle_addr = NULL; r = mailimf_display_name_parse(message, length, &cur_token, &display_name); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { res = r; goto err; } r = mailimf_angle_addr_parse(message, length, &cur_token, &angle_addr); if (r != MAILIMF_NO_ERROR) { res = r; goto free_display_name; } * pdisplay_name = display_name; * pangle_addr = angle_addr; * index = cur_token; return MAILIMF_NO_ERROR; free_display_name: if (display_name != NULL) mailimf_display_name_free(display_name); err: return res; } /* angle-addr = [CFWS] "<" addr-spec ">" [CFWS] / obs-angle-addr */ static int mailimf_angle_addr_parse(const char * message, size_t length, size_t * index, char ** result) { size_t cur_token; char * addr_spec; int r; cur_token = * index; r = mailimf_cfws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) return r; r = mailimf_lower_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_addr_spec_parse(message, length, &cur_token, &addr_spec); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_greater_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { free(addr_spec); return r; } * result = addr_spec; * index = cur_token; return MAILIMF_NO_ERROR; } /* group = display-name ":" [mailbox-list / CFWS] ";" [CFWS] */ static int mailimf_group_parse(const char * message, size_t length, size_t * index, struct mailimf_group ** result) { size_t cur_token; char * display_name; struct mailimf_mailbox_list * mailbox_list; struct mailimf_group * group; int r; int res; cur_token = * index; mailbox_list = NULL; r = mailimf_display_name_parse(message, length, &cur_token, &display_name); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_colon_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_display_name; } r = mailimf_mailbox_list_parse(message, length, &cur_token, &mailbox_list); switch (r) { case MAILIMF_NO_ERROR: break; case MAILIMF_ERROR_PARSE: r = mailimf_cfws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) return r; break; default: return r; } r = mailimf_semi_colon_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_mailbox_list; } group = mailimf_group_new(display_name, mailbox_list); if (group == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_mailbox_list; } * index = cur_token; * result = group; return MAILIMF_NO_ERROR; free_mailbox_list: mailimf_mailbox_list_free(mailbox_list); free_display_name: mailimf_display_name_free(display_name); err: return res; } /* display-name = phrase */ static int mailimf_display_name_parse(const char * message, size_t length, size_t * index, char ** result) { return mailimf_phrase_parse(message, length, index, result); } /* mailbox-list = (mailbox *("," mailbox)) / obs-mbox-list */ int mailimf_mailbox_list_parse(const char * message, size_t length, size_t * index, struct mailimf_mailbox_list ** result) { size_t cur_token; clist * list; struct mailimf_mailbox_list * mailbox_list; int r; int res; cur_token = * index; r = mailimf_struct_list_parse(message, length, &cur_token, &list, ',', (mailimf_struct_parser *) mailimf_mailbox_parse, (mailimf_struct_destructor *) mailimf_mailbox_free); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } mailbox_list = mailimf_mailbox_list_new(list); if (mailbox_list == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_list; } * result = mailbox_list; * index = cur_token; return MAILIMF_NO_ERROR; free_list: clist_foreach(list, (clist_func) mailimf_mailbox_free, NULL); clist_free(list); err: return res; } /* address-list = (address *("," address)) / obs-addr-list */ int mailimf_address_list_parse(const char * message, size_t length, size_t * index, struct mailimf_address_list ** result) { size_t cur_token; clist * list; struct mailimf_address_list * address_list; int r; int res; cur_token = * index; r = mailimf_struct_list_parse(message, length, &cur_token, &list, ',', (mailimf_struct_parser *) mailimf_address_parse, (mailimf_struct_destructor *) mailimf_address_free); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } address_list = mailimf_address_list_new(list); if (address_list == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_list; } * result = address_list; * index = cur_token; return MAILIMF_NO_ERROR; free_list: clist_foreach(list, (clist_func) mailimf_address_free, NULL); clist_free(list); err: return res; } /* addr-spec = local-part "@" domain */ static int mailimf_addr_spec_parse(const char * message, size_t length, size_t * index, char ** result) { size_t cur_token; #if 0 char * local_part; char * domain; #endif char * addr_spec; int r; int res; size_t begin; size_t end; int final; size_t count; const char * src; char * dest; size_t i; cur_token = * index; r = mailimf_cfws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { res = r; goto err; } end = cur_token; if (end >= length) { res = MAILIMF_ERROR_PARSE; goto err; } begin = cur_token; final = FALSE; while (1) { switch (message[end]) { case '>': case ',': case '\r': case '\n': case '(': case ')': case ':': case ';': final = TRUE; break; } if (final) break; end ++; if (end >= length) break; } if (end == begin) { res = MAILIMF_ERROR_PARSE; goto err; } addr_spec = malloc(end - cur_token + 1); if (addr_spec == NULL) { res = MAILIMF_ERROR_MEMORY; goto err; } count = end - cur_token; src = message + cur_token; dest = addr_spec; for(i = 0 ; i < count ; i ++) { if ((* src != ' ') && (* src != '\t')) { * dest = * src; dest ++; } src ++; } * dest = '\0'; #if 0 strncpy(addr_spec, message + cur_token, end - cur_token); addr_spec[end - cur_token] = '\0'; #endif cur_token = end; #if 0 r = mailimf_local_part_parse(message, length, &cur_token, &local_part); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_at_sign_parse(message, length, &cur_token); switch (r) { case MAILIMF_NO_ERROR: r = mailimf_domain_parse(message, length, &cur_token, &domain); if (r != MAILIMF_NO_ERROR) { res = r; goto free_local_part; } break; case MAILIMF_ERROR_PARSE: domain = NULL; break; default: res = r; goto free_local_part; } if (domain) { addr_spec = malloc(strlen(local_part) + strlen(domain) + 2); if (addr_spec == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_domain; } strcpy(addr_spec, local_part); strcat(addr_spec, "@"); strcat(addr_spec, domain); mailimf_domain_free(domain); mailimf_local_part_free(local_part); } else { addr_spec = local_part; } #endif * result = addr_spec; * index = cur_token; return MAILIMF_NO_ERROR; #if 0 free_domain: mailimf_domain_free(domain); free_local_part: mailimf_local_part_free(local_part); #endif err: return res; } /* local-part = dot-atom / quoted-string / obs-local-part */ #if 0 static int mailimf_local_part_parse(const char * message, size_t length, size_t * index, char ** result) { int r; r = mailimf_dot_atom_parse(message, length, index, result); switch (r) { case MAILIMF_NO_ERROR: return r; case MAILIMF_ERROR_PARSE: break; default: return r; } r = mailimf_quoted_string_parse(message, length, index, result); if (r != MAILIMF_NO_ERROR) return r; return MAILIMF_NO_ERROR; } #endif /* domain = dot-atom / domain-literal / obs-domain */ #if 0 static int mailimf_domain_parse(const char * message, size_t length, size_t * index, char ** result) { int r; r = mailimf_dot_atom_parse(message, length, index, result); switch (r) { case MAILIMF_NO_ERROR: return r; case MAILIMF_ERROR_PARSE: break; default: return r; } r = mailimf_domain_literal_parse(message, length, index, result); if (r != MAILIMF_NO_ERROR) return r; return MAILIMF_NO_ERROR; } #endif /* [FWS] dcontent */ #if 0 static int mailimf_domain_literal_fws_dcontent_parse(const char * message, size_t length, size_t * index) { size_t cur_token; char ch; int r; cur_token = * index; r = mailimf_cfws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) return r; r = mailimf_dcontent_parse(message, length, &cur_token, &ch); if (r != MAILIMF_NO_ERROR) return r; * index = cur_token; return MAILIMF_NO_ERROR; } #endif /* domain-literal = [CFWS] "[" *([FWS] dcontent) [FWS] "]" [CFWS] */ #if 0 static int mailimf_domain_literal_parse(const char * message, size_t length, size_t * index, char ** result) { size_t cur_token; int len; int begin; char * domain_literal; int r; cur_token = * index; r = mailimf_cfws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) return r; begin = cur_token; r = mailimf_obracket_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) return r; while (1) { r = mailimf_domain_literal_fws_dcontent_parse(message, length, &cur_token); if (r == MAILIMF_NO_ERROR) { /* do nothing */ } else if (r == MAILIMF_ERROR_PARSE) break; else return r; } r = mailimf_fws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) return r; r = mailimf_cbracket_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) return r; len = cur_token - begin; domain_literal = malloc(len + 1); if (domain_literal == NULL) return MAILIMF_ERROR_MEMORY; strncpy(domain_literal, message + begin, len); domain_literal[len] = '\0'; * result = domain_literal; * index = cur_token; return MAILIMF_NO_ERROR; } #endif /* dcontent = dtext / quoted-pair */ #if 0 static int mailimf_dcontent_parse(const char * message, size_t length, size_t * index, char * result) { size_t cur_token; char ch; int r; cur_token = * index; if (cur_token >= length) return MAILIMF_ERROR_PARSE; if (is_dtext(message[cur_token])) { ch = message[cur_token]; cur_token ++; } else { r = mailimf_quoted_pair_parse(message, length, &cur_token, &ch); if (r != MAILIMF_NO_ERROR) return r; } * index = cur_token; * result = ch; return MAILIMF_NO_ERROR; } #endif /* dtext = NO-WS-CTL / ; Non white space controls %d33-90 / ; The rest of the US-ASCII %d94-126 ; characters not including "[", ; "]", or "\" */ static inline int is_dtext(char ch) { unsigned char uch = (unsigned char) ch; if (is_no_ws_ctl(ch)) return TRUE; if (uch < 33) return FALSE; if ((uch >= 91) && (uch <= 93)) return FALSE; if (uch == 127) return FALSE; return TRUE; } /* message = (fields / obs-fields) [CRLF body] */ int mailimf_message_parse(const char * message, size_t length, size_t * index, struct mailimf_message ** result) { struct mailimf_fields * fields; struct mailimf_body * body; struct mailimf_message * msg; size_t cur_token; int r; int res; cur_token = * index; r = mailimf_fields_parse(message, length, &cur_token, &fields); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_crlf_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { res = r; goto err; } r = mailimf_body_parse(message, length, &cur_token, &body); if (r != MAILIMF_NO_ERROR) { res = r; goto free_fields; } msg = mailimf_message_new(fields, body); if (msg == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_body; } * index = cur_token; * result = msg; return MAILIMF_NO_ERROR; free_body: mailimf_body_free(body); free_fields: mailimf_fields_free(fields); err: return res; } /* body = *(*998text CRLF) *998text */ int mailimf_body_parse(const char * message, size_t length, size_t * index, struct mailimf_body ** result) { size_t cur_token; struct mailimf_body * body; cur_token = * index; body = mailimf_body_new(message + cur_token, length - cur_token); if (body == NULL) return MAILIMF_ERROR_MEMORY; cur_token = length; * result = body; * index = cur_token; return MAILIMF_NO_ERROR; } /* CHANGE TO THE RFC 2822 original : fields = *(trace *(resent-date / resent-from / resent-sender / resent-to / resent-cc / resent-bcc / resent-msg-id)) *(orig-date / from / sender / reply-to / to / cc / bcc / message-id / in-reply-to / references / subject / comments / keywords / optional-field) INTO THE FOLLOWING : */ /* resent-fields-list = *(resent-date / resent-from / resent-sender / resent-to / resent-cc / resent-bcc / resent-msg-id)) */ #if 0 enum { RESENT_HEADER_START, }; static int guess_resent_header_type(char * message, size_t length, size_t index) { int r; r = mailimf_token_case_insensitive_parse(message, length, &index, "Resent-"); if (r != MAILIMF_NO_ERROR) return MAILIMF_RESENT_FIELD_NONE; if (index >= length) return MAILIMF_RESENT_FIELD_NONE; switch(toupper(message[index])) { case 'D': return MAILIMF_RESENT_FIELD_DATE; case 'F': return MAILIMF_RESENT_FIELD_FROM; case 'S': return MAILIMF_RESENT_FIELD_SENDER; case 'T': return MAILIMF_RESENT_FIELD_TO; case 'C': return MAILIMF_RESENT_FIELD_CC; case 'B': return MAILIMF_RESENT_FIELD_BCC; case 'M': return MAILIMF_RESENT_FIELD_MSG_ID; default: return MAILIMF_RESENT_FIELD_NONE; } } #endif #if 0 static int mailimf_resent_field_parse(const char * message, size_t length, size_t * index, struct mailimf_resent_field ** result) { struct mailimf_orig_date * resent_date; struct mailimf_from * resent_from; struct mailimf_sender * resent_sender; struct mailimf_to* resent_to; struct mailimf_cc * resent_cc; struct mailimf_bcc * resent_bcc; struct mailimf_message_id * resent_msg_id; size_t cur_token; int type; struct mailimf_resent_field * resent_field; int r; int res; cur_token = * index; resent_date = NULL; resent_from = NULL; resent_sender = NULL; resent_to = NULL; resent_cc = NULL; resent_bcc = NULL; resent_msg_id = NULL; type = guess_resent_header_type(message, length, cur_token); switch(type) { case MAILIMF_RESENT_FIELD_DATE: r = mailimf_resent_date_parse(message, length, &cur_token, &resent_date); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } break; case MAILIMF_RESENT_FIELD_FROM: r = mailimf_resent_from_parse(message, length, &cur_token, &resent_from); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } break; case MAILIMF_RESENT_FIELD_SENDER: r = mailimf_resent_sender_parse(message, length, &cur_token, &resent_sender); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } break; case MAILIMF_RESENT_FIELD_TO: r = mailimf_resent_to_parse(message, length, &cur_token, &resent_to); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } break; case MAILIMF_RESENT_FIELD_CC: r= mailimf_resent_cc_parse(message, length, &cur_token, &resent_cc); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } break; case MAILIMF_RESENT_FIELD_BCC: r = mailimf_resent_bcc_parse(message, length, &cur_token, &resent_bcc); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } break; case MAILIMF_RESENT_FIELD_MSG_ID: r = mailimf_resent_msg_id_parse(message, length, &cur_token, &resent_msg_id); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } break; default: res = MAILIMF_ERROR_PARSE; goto err; } resent_field = mailimf_resent_field_new(type, resent_date, resent_from, resent_sender, resent_to, resent_cc, resent_bcc, resent_msg_id); if (resent_field == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_resent; } * result = resent_field; * index = cur_token; return MAILIMF_NO_ERROR; free_resent: if (resent_msg_id != NULL) mailimf_message_id_free(resent_msg_id); if (resent_bcc != NULL) mailimf_bcc_free(resent_bcc); if (resent_cc != NULL) mailimf_cc_free(resent_cc); if (resent_to != NULL) mailimf_to_free(resent_to); if (resent_sender != NULL) mailimf_sender_free(resent_sender); if (resent_from != NULL) mailimf_from_free(resent_from); if (resent_date != NULL) mailimf_orig_date_free(resent_date); err: return res; } #endif #if 0 static int mailimf_resent_fields_list_parse(const char * message, size_t length, size_t * index, struct mailimf_resent_fields_list ** result) { clist * list; size_t cur_token; struct mailimf_resent_fields_list * resent_fields_list; int r; int res; cur_token = * index; list = NULL; r = mailimf_struct_multiple_parse(message, length, &cur_token, &list, (mailimf_struct_parser *) mailimf_resent_field_parse, (mailimf_struct_destructor *) mailimf_resent_field_free); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } resent_fields_list = mailimf_resent_fields_list_new(list); if (resent_fields_list == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_list; } * result = resent_fields_list; * index = cur_token; return MAILIMF_NO_ERROR; free_list: clist_foreach(list, (clist_func) mailimf_resent_field_free, NULL); clist_free(list); err: return res; } #endif /* ([trace] [resent-fields-list]) */ #if 0 static int mailimf_trace_resent_fields_parse(const char * message, size_t length, size_t * index, struct mailimf_trace_resent_fields ** result) { size_t cur_token; struct mailimf_return * return_path; struct mailimf_resent_fields_list * resent_fields; struct mailimf_trace_resent_fields * trace_resent_fields; int res; int r; cur_token = * index; return_path = NULL; resent_fields = NULL; r = mailimf_return_parse(message, length, &cur_token, &return_path); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { res = r; goto err; } r = mailimf_resent_fields_list_parse(message, length, &cur_token, &resent_fields); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { res = r; goto err; } if ((return_path == NULL) && (resent_fields == NULL)) { res = MAILIMF_ERROR_PARSE; goto err; } trace_resent_fields = mailimf_trace_resent_fields_new(return_path, resent_fields); if (trace_resent_fields == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_resent_fields; } * result = trace_resent_fields; * index = cur_token; return MAILIMF_NO_ERROR; free_resent_fields: if (resent_fields != NULL) mailimf_resent_fields_list_free(resent_fields); if (return_path != NULL) mailimf_return_free(return_path); err: return res; } #endif /* delivering-info = *([trace] [resent-fields-list]) */ #if 0 static int mailimf_delivering_info_parse(const char * message, size_t length, size_t * index, struct mailimf_delivering_info ** result) { size_t cur_token; clist * list; struct mailimf_delivering_info * delivering_info; int r; int res; cur_token = * index; r = mailimf_struct_multiple_parse(message, length, &cur_token, &list, (mailimf_struct_parser *) mailimf_trace_resent_fields_parse, (mailimf_struct_destructor *) mailimf_trace_resent_fields_free); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } delivering_info = mailimf_delivering_info_new(list); if (delivering_info == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_list; } * result = delivering_info; * index = cur_token; return MAILIMF_NO_ERROR; free_list: clist_foreach(list, (clist_func) mailimf_trace_resent_fields_free, NULL); clist_free(list); err: return res; } #endif /* field = delivering-info / orig-date / from / sender / reply-to / to / cc / bcc / message-id / in-reply-to / references / subject / comments / keywords / optional-field */ enum { HEADER_START, HEADER_C, HEADER_R, HEADER_RE, HEADER_S, HEADER_RES, }; static int guess_header_type(const char * message, size_t length, size_t index) { int state; int r; state = HEADER_START; while (1) { if (index >= length) return MAILIMF_FIELD_NONE; switch(state) { case HEADER_START: switch((char) toupper((unsigned char) message[index])) { case 'B': return MAILIMF_FIELD_BCC; case 'C': state = HEADER_C; break; case 'D': return MAILIMF_FIELD_ORIG_DATE; case 'F': return MAILIMF_FIELD_FROM; case 'I': return MAILIMF_FIELD_IN_REPLY_TO; case 'K': return MAILIMF_FIELD_KEYWORDS; case 'M': return MAILIMF_FIELD_MESSAGE_ID; case 'R': state = HEADER_R; break; case 'T': return MAILIMF_FIELD_TO; break; case 'S': state = HEADER_S; break; default: return MAILIMF_FIELD_NONE; } break; case HEADER_C: switch((char) toupper((unsigned char) message[index])) { case 'O': return MAILIMF_FIELD_COMMENTS; case 'C': return MAILIMF_FIELD_CC; default: return MAILIMF_FIELD_NONE; } break; case HEADER_R: switch((char) toupper((unsigned char) message[index])) { case 'E': state = HEADER_RE; break; default: return MAILIMF_FIELD_NONE; } break; case HEADER_RE: switch((char) toupper((unsigned char) message[index])) { case 'F': return MAILIMF_FIELD_REFERENCES; case 'P': return MAILIMF_FIELD_REPLY_TO; case 'S': state = HEADER_RES; break; case 'T': return MAILIMF_FIELD_RETURN_PATH; default: return MAILIMF_FIELD_NONE; } break; case HEADER_S: switch((char) toupper((unsigned char) message[index])) { case 'E': return MAILIMF_FIELD_SENDER; case 'U': return MAILIMF_FIELD_SUBJECT; default: return MAILIMF_FIELD_NONE; } break; case HEADER_RES: r = mailimf_token_case_insensitive_parse(message, length, &index, "ent-"); if (r != MAILIMF_NO_ERROR) return MAILIMF_FIELD_NONE; if (index >= length) return MAILIMF_FIELD_NONE; switch((char) toupper((unsigned char) message[index])) { case 'D': return MAILIMF_FIELD_RESENT_DATE; case 'F': return MAILIMF_FIELD_RESENT_FROM; case 'S': return MAILIMF_FIELD_RESENT_SENDER; case 'T': return MAILIMF_FIELD_RESENT_TO; case 'C': return MAILIMF_FIELD_RESENT_CC; case 'B': return MAILIMF_FIELD_RESENT_BCC; case 'M': return MAILIMF_FIELD_RESENT_MSG_ID; default: return MAILIMF_FIELD_NONE; } break; } index ++; } } static int mailimf_field_parse(const char * message, size_t length, size_t * index, struct mailimf_field ** result) { size_t cur_token; int type; struct mailimf_return * return_path; struct mailimf_orig_date * resent_date; struct mailimf_from * resent_from; struct mailimf_sender * resent_sender; struct mailimf_to* resent_to; struct mailimf_cc * resent_cc; struct mailimf_bcc * resent_bcc; struct mailimf_message_id * resent_msg_id; struct mailimf_orig_date * orig_date; struct mailimf_from * from; struct mailimf_sender * sender; struct mailimf_reply_to * reply_to; struct mailimf_to * to; struct mailimf_cc * cc; struct mailimf_bcc * bcc; struct mailimf_message_id * message_id; struct mailimf_in_reply_to * in_reply_to; struct mailimf_references * references; struct mailimf_subject * subject; struct mailimf_comments * comments; struct mailimf_keywords * keywords; struct mailimf_optional_field * optional_field; struct mailimf_field * field; int guessed_type; int r; int res; cur_token = * index; return_path = NULL; resent_date = NULL; resent_from = NULL; resent_sender = NULL; resent_to = NULL; resent_cc = NULL; resent_bcc = NULL; resent_msg_id = NULL; orig_date = NULL; from = NULL; sender = NULL; reply_to = NULL; to = NULL; cc = NULL; bcc = NULL; message_id = NULL; in_reply_to = NULL; references = NULL; subject = NULL; comments = NULL; keywords = NULL; optional_field = NULL; guessed_type = guess_header_type(message, length, cur_token); type = MAILIMF_FIELD_NONE; switch (guessed_type) { case MAILIMF_FIELD_ORIG_DATE: r = mailimf_orig_date_parse(message, length, &cur_token, &orig_date); if (r == MAILIMF_NO_ERROR) type = MAILIMF_FIELD_ORIG_DATE; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_FROM: r = mailimf_from_parse(message, length, &cur_token, &from); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_SENDER: r = mailimf_sender_parse(message, length, &cur_token, &sender); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_REPLY_TO: r = mailimf_reply_to_parse(message, length, &cur_token, &reply_to); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_TO: r = mailimf_to_parse(message, length, &cur_token, &to); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_CC: r = mailimf_cc_parse(message, length, &cur_token, &cc); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_BCC: r = mailimf_bcc_parse(message, length, &cur_token, &bcc); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_MESSAGE_ID: r = mailimf_message_id_parse(message, length, &cur_token, &message_id); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_IN_REPLY_TO: r = mailimf_in_reply_to_parse(message, length, &cur_token, &in_reply_to); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_REFERENCES: r = mailimf_references_parse(message, length, &cur_token, &references); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_SUBJECT: r = mailimf_subject_parse(message, length, &cur_token, &subject); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_COMMENTS: r = mailimf_comments_parse(message, length, &cur_token, &comments); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_KEYWORDS: r = mailimf_keywords_parse(message, length, &cur_token, &keywords); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_RETURN_PATH: r = mailimf_return_parse(message, length, &cur_token, &return_path); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_RESENT_DATE: r = mailimf_resent_date_parse(message, length, &cur_token, &resent_date); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_RESENT_FROM: r = mailimf_resent_from_parse(message, length, &cur_token, &resent_from); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_RESENT_SENDER: r = mailimf_resent_sender_parse(message, length, &cur_token, &resent_sender); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_RESENT_TO: r = mailimf_resent_to_parse(message, length, &cur_token, &resent_to); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_RESENT_CC: r= mailimf_resent_cc_parse(message, length, &cur_token, &resent_cc); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_RESENT_BCC: r = mailimf_resent_bcc_parse(message, length, &cur_token, &resent_bcc); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_RESENT_MSG_ID: r = mailimf_resent_msg_id_parse(message, length, &cur_token, &resent_msg_id); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; } if (type == MAILIMF_FIELD_NONE) { r = mailimf_optional_field_parse(message, length, &cur_token, &optional_field); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } type = MAILIMF_FIELD_OPTIONAL_FIELD; } field = mailimf_field_new(type, return_path, resent_date, resent_from, resent_sender, resent_to, resent_cc, resent_bcc, resent_msg_id, orig_date, from, sender, reply_to, to, cc, bcc, message_id, in_reply_to, references, subject, comments, keywords, optional_field); if (field == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_field; } * result = field; * index = cur_token; return MAILIMF_NO_ERROR; free_field: if (return_path != NULL) mailimf_return_free(return_path); if (resent_date != NULL) mailimf_orig_date_free(resent_date); if (resent_from != NULL) mailimf_from_free(resent_from); if (resent_sender != NULL) mailimf_sender_free(resent_sender); if (resent_to != NULL) mailimf_to_free(resent_to); if (resent_cc != NULL) mailimf_cc_free(resent_cc); if (resent_bcc != NULL) mailimf_bcc_free(resent_bcc); if (resent_msg_id != NULL) mailimf_message_id_free(resent_msg_id); if (orig_date != NULL) mailimf_orig_date_free(orig_date); if (from != NULL) mailimf_from_free(from); if (sender != NULL) mailimf_sender_free(sender); if (reply_to != NULL) mailimf_reply_to_free(reply_to); if (to != NULL) mailimf_to_free(to); if (cc != NULL) mailimf_cc_free(cc); if (bcc != NULL) mailimf_bcc_free(bcc); if (message_id != NULL) mailimf_message_id_free(message_id); if (in_reply_to != NULL) mailimf_in_reply_to_free(in_reply_to); if (references != NULL) mailimf_references_free(references); if (subject != NULL) mailimf_subject_free(subject); if (comments != NULL) mailimf_comments_free(comments); if (keywords != NULL) mailimf_keywords_free(keywords); if (optional_field != NULL) mailimf_optional_field_free(optional_field); err: return res; } /* fields = *(delivering-info / orig-date / from / sender / reply-to / to / cc / bcc / message-id / in-reply-to / references / subject / comments / keywords / optional-field) */ #if 0 int mailimf_unparsed_fields_parse(const char * message, size_t length, size_t * index, struct mailimf_unparsed_fields ** result) { size_t cur_token; clist * list; struct mailimf_unparsed_fields * fields; int r; int res; cur_token = * index; list = NULL; r = mailimf_struct_multiple_parse(message, length, &cur_token, &list, (mailimf_struct_parser *) mailimf_optional_field_parse, (mailimf_struct_destructor *) mailimf_optional_field_free); /* if ((r = MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { res = r; goto err; } */ switch (r) { case MAILIMF_NO_ERROR: /* do nothing */ break; case MAILIMF_ERROR_PARSE: list = clist_new(); if (list == NULL) { res = MAILIMF_ERROR_MEMORY; goto err; } break; default: res = r; goto err; } fields = mailimf_unparsed_fields_new(list); if (fields == NULL) { res = MAILIMF_ERROR_MEMORY; goto free; } * result = fields; * index = cur_token; return MAILIMF_NO_ERROR; free: if (list != NULL) { clist_foreach(list, (clist_func) mailimf_optional_field_free, NULL); clist_free(list); } err: return res; } #endif int mailimf_fields_parse(const char * message, size_t length, size_t * index, struct mailimf_fields ** result) { size_t cur_token; clist * list; struct mailimf_fields * fields; int r; int res; cur_token = * index; list = NULL; r = mailimf_struct_multiple_parse(message, length, &cur_token, &list, (mailimf_struct_parser *) mailimf_field_parse, (mailimf_struct_destructor *) mailimf_field_free); /* if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { res = r; goto err; } */ switch (r) { case MAILIMF_NO_ERROR: /* do nothing */ break; case MAILIMF_ERROR_PARSE: list = clist_new(); if (list == NULL) { res = MAILIMF_ERROR_MEMORY; goto err; } break; default: res = r; goto err; } fields = mailimf_fields_new(list); if (fields == NULL) { res = MAILIMF_ERROR_MEMORY; goto free; } * result = fields; * index = cur_token; return MAILIMF_NO_ERROR; free: if (list != NULL) { clist_foreach(list, (clist_func) mailimf_field_free, NULL); clist_free(list); } err: return res; } /* orig-date = "Date:" date-time CRLF */ static int mailimf_orig_date_parse(const char * message, size_t length, size_t * index, struct mailimf_orig_date ** result) { struct mailimf_date_time * date_time; struct mailimf_orig_date * orig_date; size_t cur_token; int r; int res; cur_token = * index; r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "Date:"); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_date_time_parse(message, length, &cur_token, &date_time); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_ignore_unstructured_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_date_time; } r = mailimf_unstrict_crlf_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_date_time; } orig_date = mailimf_orig_date_new(date_time); if (orig_date == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_date_time; } * result = orig_date; * index = cur_token; return MAILIMF_NO_ERROR; free_date_time: mailimf_date_time_free(date_time); err: return res; } /* from = "From:" mailbox-list CRLF */ static int mailimf_from_parse(const char * message, size_t length, size_t * index, struct mailimf_from ** result) { struct mailimf_mailbox_list * mb_list; struct mailimf_from * from; size_t cur_token; int r; int res; cur_token = * index; r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "From"); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_colon_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_mailbox_list_parse(message, length, &cur_token, &mb_list); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_unstrict_crlf_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_mb_list; } from = mailimf_from_new(mb_list); if (from == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_mb_list; } * result = from; * index = cur_token; return MAILIMF_NO_ERROR; free_mb_list: mailimf_mailbox_list_free(mb_list); err: return res; } /* sender = "Sender:" mailbox CRLF */ static int mailimf_sender_parse(const char * message, size_t length, size_t * index, struct mailimf_sender ** result) { struct mailimf_mailbox * mb; struct mailimf_sender * sender; size_t cur_token; int r; int res; cur_token = * index; r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "Sender"); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_colon_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_mailbox_parse(message, length, &cur_token, &mb); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_unstrict_crlf_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_mb; } sender = mailimf_sender_new(mb); if (sender == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_mb; } * result = sender; * index = cur_token; return MAILIMF_NO_ERROR; free_mb: mailimf_mailbox_free(mb); err: return res; } /* reply-to = "Reply-To:" address-list CRLF */ static int mailimf_reply_to_parse(const char * message, size_t length, size_t * index, struct mailimf_reply_to ** result) { struct mailimf_address_list * addr_list; struct mailimf_reply_to * reply_to; size_t cur_token; int r; int res; cur_token = * index; r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "Reply-To"); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_colon_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_address_list_parse(message, length, &cur_token, &addr_list); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_unstrict_crlf_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_addr_list; } reply_to = mailimf_reply_to_new(addr_list); if (reply_to == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_addr_list; } * result = reply_to; * index = cur_token; return MAILIMF_NO_ERROR; free_addr_list: mailimf_address_list_free(addr_list); err: return res; } /* to = "To:" address-list CRLF */ static int mailimf_to_parse(const char * message, size_t length, size_t * index, struct mailimf_to ** result) { struct mailimf_address_list * addr_list; struct mailimf_to * to; size_t cur_token; int r; int res; cur_token = * index; r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "To"); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_colon_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_address_list_parse(message, length, &cur_token, &addr_list); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_unstrict_crlf_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_addr_list; } to = mailimf_to_new(addr_list); if (to == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_addr_list; } * result = to; * index = cur_token; return MAILIMF_NO_ERROR; free_addr_list: mailimf_address_list_free(addr_list); err: return res; } /* cc = "Cc:" address-list CRLF */ static int mailimf_cc_parse(const char * message, size_t length, size_t * index, struct mailimf_cc ** result) { struct mailimf_address_list * addr_list; struct mailimf_cc * cc; size_t cur_token; int r; int res; cur_token = * index; r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "Cc"); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_colon_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_address_list_parse(message, length, &cur_token, &addr_list); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_unstrict_crlf_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_addr_list; } cc = mailimf_cc_new(addr_list); if (cc == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_addr_list; } * result = cc; * index = cur_token; return MAILIMF_NO_ERROR; free_addr_list: mailimf_address_list_free(addr_list); err: return res; } /* bcc = "Bcc:" (address-list / [CFWS]) CRLF */ static int mailimf_bcc_parse(const char * message, size_t length, size_t * index, struct mailimf_bcc ** result) { struct mailimf_address_list * addr_list; struct mailimf_bcc * bcc; size_t cur_token; int r; int res; cur_token = * index; addr_list = NULL; r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "Bcc"); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_colon_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_address_list_parse(message, length, &cur_token, &addr_list); switch (r) { case MAILIMF_NO_ERROR: /* do nothing */ break; case MAILIMF_ERROR_PARSE: r = mailimf_cfws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { res = r; goto err; } break; default: res = r; goto err; } r = mailimf_unstrict_crlf_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_addr_list; } bcc = mailimf_bcc_new(addr_list); if (bcc == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_addr_list; } * result = bcc; * index = cur_token; return MAILIMF_NO_ERROR; free_addr_list: mailimf_address_list_free(addr_list); err: return res; } /* message-id = "Message-ID:" msg-id CRLF */ static int mailimf_message_id_parse(const char * message, size_t length, size_t * index, struct mailimf_message_id ** result) { char * value; size_t cur_token; struct mailimf_message_id * message_id; int r; int res; cur_token = * index; r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "Message-ID"); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_colon_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_msg_id_parse(message, length, &cur_token, &value); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_unstrict_crlf_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_value; } message_id = mailimf_message_id_new(value); if (message_id == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_value; } * result = message_id; * index = cur_token; return MAILIMF_NO_ERROR; free_value: mailimf_msg_id_free(value); err: return res; } /* in-reply-to = "In-Reply-To:" 1*msg-id CRLF */ int mailimf_msg_id_list_parse(const char * message, size_t length, size_t * index, clist ** result) { return mailimf_struct_multiple_parse(message, length, index, result, (mailimf_struct_parser *) mailimf_unstrict_msg_id_parse, (mailimf_struct_destructor *) mailimf_msg_id_free); } static int mailimf_in_reply_to_parse(const char * message, size_t length, size_t * index, struct mailimf_in_reply_to ** result) { struct mailimf_in_reply_to * in_reply_to; size_t cur_token; clist * msg_id_list; int res; int r; cur_token = * index; r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "In-Reply-To"); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_colon_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_msg_id_list_parse(message, length, &cur_token, &msg_id_list); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_unstrict_crlf_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_list; } in_reply_to = mailimf_in_reply_to_new(msg_id_list); if (in_reply_to == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_list; } * result = in_reply_to; * index = cur_token; return MAILIMF_NO_ERROR; free_list: clist_foreach(msg_id_list, (clist_func) mailimf_msg_id_free, NULL); clist_free(msg_id_list); err: return res; } /* references = "References:" 1*msg-id CRLF */ int mailimf_references_parse(const char * message, size_t length, size_t * index, struct mailimf_references ** result) { struct mailimf_references * references; size_t cur_token; clist * msg_id_list; int r; int res; cur_token = * index; r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "References"); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_colon_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_msg_id_list_parse(message, length, &cur_token, &msg_id_list); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_unstrict_crlf_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_list; } references = mailimf_references_new(msg_id_list); if (references == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_list; } * result = references; * index = cur_token; return MAILIMF_NO_ERROR; free_list: clist_foreach(msg_id_list, (clist_func) mailimf_msg_id_free, NULL); clist_free(msg_id_list); err: return res; } /* msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS] */ int mailimf_msg_id_parse(const char * message, size_t length, size_t * index, char ** result) { size_t cur_token; #if 0 char * id_left; char * id_right; #endif char * msg_id; int r; int res; cur_token = * index; r = mailimf_cfws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) return r; r = mailimf_lower_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_addr_spec_parse(message, length, &cur_token, &msg_id); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_greater_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { free(msg_id); res = r; goto err; } #if 0 r = mailimf_id_left_parse(message, length, &cur_token, &id_left); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_at_sign_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_id_left; } r = mailimf_id_right_parse(message, length, &cur_token, &id_right); if (r != MAILIMF_NO_ERROR) { res = r; goto free_id_left; } r = mailimf_greater_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_id_right; } msg_id = malloc(strlen(id_left) + strlen(id_right) + 2); if (msg_id == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_id_right; } strcpy(msg_id, id_left); strcat(msg_id, "@"); strcat(msg_id, id_right); mailimf_id_left_free(id_left); mailimf_id_right_free(id_right); #endif * result = msg_id; * index = cur_token; return MAILIMF_NO_ERROR; #if 0 free_id_right: mailimf_id_right_free(id_right); free_id_left: mailimf_id_left_free(id_left); #endif /* free: mailimf_atom_free(msg_id); */ err: return res; } static int mailimf_parse_unwanted_msg_id(const char * message, size_t length, size_t * index) { size_t cur_token; int r; char * word; int token_parsed; cur_token = * index; token_parsed = TRUE; while (token_parsed) { token_parsed = FALSE; r = mailimf_word_parse(message, length, &cur_token, &word); if (r == MAILIMF_NO_ERROR) { mailimf_word_free(word); token_parsed = TRUE; } else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else return r; r = mailimf_semi_colon_parse(message, length, &cur_token); if (r == MAILIMF_NO_ERROR) token_parsed = TRUE; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else return r; r = mailimf_comma_parse(message, length, &cur_token); if (r == MAILIMF_NO_ERROR) token_parsed = TRUE; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else return r; r = mailimf_plus_parse(message, length, &cur_token); if (r == MAILIMF_NO_ERROR) token_parsed = TRUE; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else return r; r = mailimf_colon_parse(message, length, &cur_token); if (r == MAILIMF_NO_ERROR) token_parsed = TRUE; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else return r; r = mailimf_point_parse(message, length, &cur_token); if (r == MAILIMF_NO_ERROR) token_parsed = TRUE; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else return r; r = mailimf_at_sign_parse(message, length, &cur_token); if (r == MAILIMF_NO_ERROR) token_parsed = TRUE; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else return r; } return MAILIMF_NO_ERROR; } static int mailimf_unstrict_msg_id_parse(const char * message, size_t length, size_t * index, char ** result) { char * msgid; size_t cur_token; int r; cur_token = * index; r = mailimf_cfws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) return r; r = mailimf_parse_unwanted_msg_id(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_msg_id_parse(message, length, &cur_token, &msgid); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_parse_unwanted_msg_id(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) return r; * result = msgid; * index = cur_token; return MAILIMF_NO_ERROR; } /* id-left = dot-atom-text / no-fold-quote / obs-id-left */ #if 0 static int mailimf_id_left_parse(const char * message, size_t length, size_t * index, char ** result) { int r; r = mailimf_dot_atom_text_parse(message, length, index, result); switch (r) { case MAILIMF_NO_ERROR: return MAILIMF_NO_ERROR; case MAILIMF_ERROR_PARSE: break; default: return r; } r = mailimf_no_fold_quote_parse(message, length, index, result); if (r != MAILIMF_NO_ERROR) return r; return MAILIMF_NO_ERROR; } #endif /* id-right = dot-atom-text / no-fold-literal / obs-id-right */ #if 0 static int mailimf_id_right_parse(const char * message, size_t length, size_t * index, char ** result) { int r; r = mailimf_dot_atom_text_parse(message, length, index, result); switch (r) { case MAILIMF_NO_ERROR: return MAILIMF_NO_ERROR; case MAILIMF_ERROR_PARSE: break; default: return r; } r = mailimf_no_fold_literal_parse(message, length, index, result); if (r != MAILIMF_NO_ERROR) return r; return MAILIMF_NO_ERROR; } #endif /* no-fold-quote = DQUOTE *(qtext / quoted-pair) DQUOTE */ #if 0 static int mailimf_no_fold_quote_char_parse(const char * message, size_t length, size_t * index, char * result) { char ch; size_t cur_token; int r; cur_token = * index; #if 0 r = mailimf_qtext_parse(message, length, &cur_token, &ch); #endif if (cur_token >= length) return MAILIMF_ERROR_PARSE; if (is_qtext(message[cur_token])) { ch = message[cur_token]; cur_token ++; } else { r = mailimf_quoted_pair_parse(message, length, &cur_token, &ch); if (r != MAILIMF_NO_ERROR) return r; } * index = cur_token; * result = ch; return MAILIMF_NO_ERROR; } #endif #if 0 static int mailimf_no_fold_quote_parse(const char * message, size_t length, size_t * index, char ** result) { size_t cur_token; size_t begin; char ch; char * no_fold_quote; int r; int res; begin = cur_token; r = mailimf_dquote_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } while (1) { r = mailimf_no_fold_quote_char_parse(message, length, &cur_token, &ch); if (r == MAILIMF_NO_ERROR) { /* do nothing */ } else if (r == MAILIMF_ERROR_PARSE) break; else { res = r; goto err; } } r = mailimf_dquote_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } /* no_fold_quote = strndup(message + begin, cur_token - begin); */ no_fold_quote = malloc(cur_token - begin + 1); if (no_fold_quote == NULL) { res = MAILIMF_ERROR_MEMORY; goto err; } strncpy(no_fold_quote, message + begin, cur_token - begin); no_fold_quote[cur_token - begin] = '\0'; * result = no_fold_quote; * index = cur_token; return MAILIMF_NO_ERROR; err: return res; } #endif /* no-fold-literal = "[" *(dtext / quoted-pair) "]" */ #if 0 static inline int mailimf_no_fold_literal_char_parse(const char * message, size_t length, size_t * index, char * result) { char ch; size_t cur_token; int r; cur_token = * index; #if 0 r = mailimf_dtext_parse(message, length, &cur_token, &ch); #endif if (cur_token >= length) return MAILIMF_ERROR_PARSE; if (is_dtext(message[cur_token])) { ch = message[cur_token]; cur_token ++; } else { r = mailimf_quoted_pair_parse(message, length, &cur_token, &ch); if (r != MAILIMF_NO_ERROR) return r; } * index = cur_token; * result = ch; return MAILIMF_NO_ERROR; } #endif #if 0 static int mailimf_no_fold_literal_parse(const char * message, size_t length, size_t * index, char ** result) { size_t cur_token; size_t begin; char ch; char * no_fold_literal; int r; int res; begin = cur_token; r = mailimf_obracket_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } while (1) { r = mailimf_no_fold_literal_char_parse(message, length, &cur_token, &ch); if (r == MAILIMF_NO_ERROR) { /* do nothing */ } else if (r == MAILIMF_ERROR_PARSE) break; else { res = r; goto err; } } r = mailimf_cbracket_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } /* no_fold_literal = strndup(message + begin, cur_token - begin); */ no_fold_literal = malloc(cur_token - begin + 1); if (no_fold_literal == NULL) { res = MAILIMF_NO_ERROR; goto err; } strncpy(no_fold_literal, message + begin, cur_token - begin); no_fold_literal[cur_token - begin] = '\0'; * result = no_fold_literal; * index = cur_token; return MAILIMF_NO_ERROR; err: return res; } #endif /* subject = "Subject:" unstructured CRLF */ static int mailimf_subject_parse(const char * message, size_t length, size_t * index, struct mailimf_subject ** result) { struct mailimf_subject * subject; char * value; size_t cur_token; int r; int res; cur_token = * index; r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "Subject"); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_colon_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_unstructured_parse(message, length, &cur_token, &value); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_unstrict_crlf_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_value; } subject = mailimf_subject_new(value); if (subject == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_value; } * result = subject; * index = cur_token; return MAILIMF_NO_ERROR; free_value: mailimf_unstructured_free(value); err: return res; } /* comments = "Comments:" unstructured CRLF */ static int mailimf_comments_parse(const char * message, size_t length, size_t * index, struct mailimf_comments ** result) { struct mailimf_comments * comments; char * value; size_t cur_token; int r; int res; cur_token = * index; r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "Comments"); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_colon_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_unstructured_parse(message, length, &cur_token, &value); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_unstrict_crlf_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_value; } comments = mailimf_comments_new(value); if (comments == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_value; } * result = comments; * index = cur_token; return MAILIMF_NO_ERROR; free_value: mailimf_unstructured_free(value); err: return res; } /* keywords = "Keywords:" phrase *("," phrase) CRLF */ static int mailimf_keywords_parse(const char * message, size_t length, size_t * index, struct mailimf_keywords ** result) { struct mailimf_keywords * keywords; clist * list; size_t cur_token; int r; int res; cur_token = * index; r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "Keywords"); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_colon_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_struct_list_parse(message, length, &cur_token, &list, ',', (mailimf_struct_parser *) mailimf_phrase_parse, (mailimf_struct_destructor *) mailimf_phrase_free); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_unstrict_crlf_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_list; } keywords = mailimf_keywords_new(list); if (keywords == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_list; } * result = keywords; * index = cur_token; return MAILIMF_NO_ERROR; free_list: clist_foreach(list, (clist_func) mailimf_phrase_free, NULL); clist_free(list); err: return res; } /* resent-date = "Resent-Date:" date-time CRLF */ static int mailimf_resent_date_parse(const char * message, size_t length, size_t * index, struct mailimf_orig_date ** result) { struct mailimf_orig_date * orig_date; struct mailimf_date_time * date_time; size_t cur_token; int r; int res; cur_token = * index; r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "Resent-Date"); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_colon_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_date_time_parse(message, length, &cur_token, &date_time); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_unstrict_crlf_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_date_time; } orig_date = mailimf_orig_date_new(date_time); if (orig_date == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_date_time; } * result = orig_date; * index = cur_token; return MAILIMF_NO_ERROR; free_date_time: mailimf_date_time_free(date_time); err: return res; } /* resent-from = "Resent-From:" mailbox-list CRLF */ static int mailimf_resent_from_parse(const char * message, size_t length, size_t * index, struct mailimf_from ** result) { struct mailimf_mailbox_list * mb_list; struct mailimf_from * from; size_t cur_token; int r; int res; cur_token = * index; r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "Resent-From"); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_colon_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_mailbox_list_parse(message, length, &cur_token, &mb_list); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_unstrict_crlf_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_mb_list; } from = mailimf_from_new(mb_list); if (from == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_mb_list; } * result = from; * index = cur_token; return MAILIMF_NO_ERROR; free_mb_list: mailimf_mailbox_list_free(mb_list); err: return res; } /* resent-sender = "Resent-Sender:" mailbox CRLF */ static int mailimf_resent_sender_parse(const char * message, size_t length, size_t * index, struct mailimf_sender ** result) { struct mailimf_mailbox * mb; struct mailimf_sender * sender; size_t cur_token; int r; int res; cur_token = length; r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "Resent-Sender"); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_colon_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_mailbox_parse(message, length, &cur_token, &mb); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_unstrict_crlf_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_mb; } sender = mailimf_sender_new(mb); if (sender == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_mb; } * result = sender; * index = cur_token; return MAILIMF_NO_ERROR; free_mb: mailimf_mailbox_free(mb); err: return res; } /* resent-to = "Resent-To:" address-list CRLF */ static int mailimf_resent_to_parse(const char * message, size_t length, size_t * index, struct mailimf_to ** result) { struct mailimf_address_list * addr_list; struct mailimf_to * to; size_t cur_token; int r; int res; cur_token = * index; r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "Resent-To"); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_colon_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_address_list_parse(message, length, &cur_token, &addr_list); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_unstrict_crlf_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_addr_list; } to = mailimf_to_new(addr_list); if (to == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_addr_list; } * result = to; * index = cur_token; return MAILIMF_NO_ERROR; free_addr_list: mailimf_address_list_free(addr_list); err: return res; } /* resent-cc = "Resent-Cc:" address-list CRLF */ static int mailimf_resent_cc_parse(const char * message, size_t length, size_t * index, struct mailimf_cc ** result) { struct mailimf_address_list * addr_list; struct mailimf_cc * cc; size_t cur_token; int r; int res; cur_token = * index; r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "Resent-Cc"); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_colon_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_address_list_parse(message, length, &cur_token, &addr_list); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_unstrict_crlf_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_addr_list; } cc = mailimf_cc_new(addr_list); if (cc == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_addr_list; } * result = cc; * index = cur_token; return MAILIMF_NO_ERROR; free_addr_list: mailimf_address_list_free(addr_list); err: return res; } /* resent-bcc = "Resent-Bcc:" (address-list / [CFWS]) CRLF */ static int mailimf_resent_bcc_parse(const char * message, size_t length, size_t * index, struct mailimf_bcc ** result) { struct mailimf_address_list * addr_list; struct mailimf_bcc * bcc; size_t cur_token; int r; int res; cur_token = * index; bcc = NULL; r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "Resent-Bcc"); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_colon_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_address_list_parse(message, length, &cur_token, &addr_list); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { res = r; goto err; } r = mailimf_unstrict_crlf_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_addr_list; } bcc = mailimf_bcc_new(addr_list); if (bcc == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_addr_list; } * result = bcc; * index = cur_token; return TRUE; free_addr_list: mailimf_address_list_free(addr_list); err: return res; } /* resent-msg-id = "Resent-Message-ID:" msg-id CRLF */ static int mailimf_resent_msg_id_parse(const char * message, size_t length, size_t * index, struct mailimf_message_id ** result) { char * value; size_t cur_token; struct mailimf_message_id * message_id; int r; int res; cur_token = * index; r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "Resent-Message-ID"); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_colon_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_msg_id_parse(message, length, &cur_token, &value); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_unstrict_crlf_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_value; } message_id = mailimf_message_id_new(value); if (message_id == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_value; } * result = message_id; * index = cur_token; return MAILIMF_NO_ERROR; free_value: mailimf_msg_id_free(value); err: return res; } /* trace = [return] 1*received */ #if 0 static int mailimf_trace_parse(const char * message, size_t length, size_t * index, struct mailimf_trace ** result) { size_t cur_token; struct mailimf_return * return_path; clist * received_list; struct mailimf_trace * trace; int r; int res; cur_token = * index; return_path = NULL; received_list = NULL; r = mailimf_return_parse(message, length, &cur_token, &return_path); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { res = r; goto err; } r = mailimf_struct_multiple_parse(message, length, &cur_token, &received_list, (mailimf_struct_parser *) mailimf_received_parse, (mailimf_struct_destructor *) mailimf_received_free); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { res = r; goto err; } if ((received_list == NULL) && (return_path == NULL)) { res = MAILIMF_ERROR_PARSE; goto free_return; } trace = mailimf_trace_new(return_path, received_list); if (trace == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_list; } * result = trace; * index = cur_token; return MAILIMF_NO_ERROR; free_list: clist_foreach(received_list, (clist_func) mailimf_received_free, NULL); clist_free(received_list); free_return: if (return_path != NULL) mailimf_return_free(return_path); err: return res; } #endif /* return = "Return-Path:" path CRLF */ static int mailimf_return_parse(const char * message, size_t length, size_t * index, struct mailimf_return ** result) { struct mailimf_path * path; struct mailimf_return * return_path; size_t cur_token; int r; int res; cur_token = * index; r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "Return-Path"); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_colon_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_path_parse(message, length, &cur_token, &path); if ( r!= MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_unstrict_crlf_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_path; } return_path = mailimf_return_new(path); if (return_path == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_path; } * result = return_path; * index = cur_token; return MAILIMF_NO_ERROR; free_path: mailimf_path_free(path); err: return res; } /* path = ([CFWS] "<" ([CFWS] / addr-spec) ">" [CFWS]) / obs-path */ static int mailimf_path_parse(const char * message, size_t length, size_t * index, struct mailimf_path ** result) { size_t cur_token; char * addr_spec; struct mailimf_path * path; int res; int r; cur_token = * index; addr_spec = NULL; r = mailimf_cfws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { res = r; goto err; } r = mailimf_lower_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_addr_spec_parse(message, length, &cur_token, &addr_spec); switch (r) { case MAILIMF_NO_ERROR: break; case MAILIMF_ERROR_PARSE: r = mailimf_cfws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { res = r; goto err; } break; default: return r; } r = mailimf_greater_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } path = mailimf_path_new(addr_spec); if (path == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_addr_spec; } * index = cur_token; * result = path; return MAILIMF_NO_ERROR; free_addr_spec: if (addr_spec == NULL) mailimf_addr_spec_free(addr_spec); err: return res; } /* received = "Received:" name-val-list ";" date-time CRLF */ #if 0 static int mailimf_received_parse(const char * message, size_t length, size_t * index, struct mailimf_received ** result) { size_t cur_token; struct mailimf_received * received; struct mailimf_name_val_list * name_val_list; struct mailimf_date_time * date_time; int r; int res; cur_token = * index; r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "Received"); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_colon_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_name_val_list_parse(message, length, &cur_token, &name_val_list); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_semi_colon_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_name_val_list; } r = mailimf_date_time_parse(message, length, &cur_token, &date_time); if (r != MAILIMF_NO_ERROR) { res = r; goto free_name_val_list; } r = mailimf_unstrict_crlf_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_date_time; } received = mailimf_received_new(name_val_list, date_time); if (received == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_date_time; } * index = cur_token; * result = received; return MAILIMF_NO_ERROR; free_date_time: mailimf_date_time_free(date_time); free_name_val_list: mailimf_name_val_list_free(name_val_list); err: return res; } #endif /* name-val-list = [CFWS] [name-val-pair *(CFWS name-val-pair)] */ #if 0 static int mailimf_name_val_list_parse(const char * message, size_t length, size_t * index, struct mailimf_name_val_list ** result) { size_t cur_token; struct mailimf_name_val_pair * pair; struct mailimf_name_val_list * name_val_list; clist* list; int res; int r; cur_token = * index; list = NULL; r = mailimf_name_val_pair_parse(message, length, &cur_token, &pair); if (r == MAILIMF_NO_ERROR){ size_t final_token; list = clist_new(); if (list == NULL) { mailimf_name_val_pair_free(pair); res = MAILIMF_ERROR_MEMORY; goto err; } r = clist_append(list, pair); if (r < 0) { mailimf_name_val_pair_free(pair); res = MAILIMF_ERROR_MEMORY; goto free_list; } final_token = cur_token; while (1) { r = mailimf_cfws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { res = r; goto free_list; } r = mailimf_name_val_pair_parse(message, length, &cur_token, &pair); if (r == MAILIMF_NO_ERROR) { /* do nothing */ } else if (r == MAILIMF_ERROR_PARSE) break; else { res = r; goto free_list; } r = clist_append(list, pair); if (r < 0) { mailimf_name_val_pair_free(pair); res = MAILIMF_ERROR_MEMORY; goto free_list; } final_token = cur_token; } cur_token = final_token; } name_val_list = mailimf_name_val_list_new(list); if (name_val_list == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_list; } * index = cur_token; * result = name_val_list; return MAILIMF_NO_ERROR; free_list: if (list != NULL) { clist_foreach(list, (clist_func) mailimf_name_val_pair_free, NULL); clist_free(list); } err: return res; } #endif /* name-val-pair = item-name CFWS item-value */ #if 0 static int mailimf_name_val_pair_parse(const char * message, size_t length, size_t * index, struct mailimf_name_val_pair ** result) { size_t cur_token; char * item_name; struct mailimf_item_value * item_value; struct mailimf_name_val_pair * name_val_pair; int r; int res; cur_token = * index; r = mailimf_cfws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { res = r; goto err; } r = mailimf_item_name_parse(message, length, &cur_token, &item_name); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_cfws_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_item_name; } r = mailimf_item_value_parse(message, length, &cur_token, &item_value); if (r != MAILIMF_NO_ERROR) { res = r; goto free_item_name; } name_val_pair = mailimf_name_val_pair_new(item_name, item_value); if (name_val_pair == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_item_value; } * result = name_val_pair; * index = cur_token; return MAILIMF_NO_ERROR; free_item_value: mailimf_item_value_free(item_value); free_item_name: mailimf_item_name_free(item_name); err: return res; } #endif /* item-name = ALPHA *(["-"] (ALPHA / DIGIT)) */ #if 0 static int mailimf_item_name_parse(const char * message, size_t length, size_t * index, char ** result) { size_t cur_token; size_t begin; char * item_name; char ch; int digit; int r; int res; cur_token = * index; begin = cur_token; r = mailimf_alpha_parse(message, length, &cur_token, &ch); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } while (1) { int minus_sign; minus_sign = mailimf_minus_parse(message, length, &cur_token); r = mailimf_alpha_parse(message, length, &cur_token, &ch); if (r == MAILIMF_ERROR_PARSE) r = mailimf_digit_parse(message, length, &cur_token, &digit); if (r == MAILIMF_NO_ERROR) { /* do nothing */ } if (r == MAILIMF_ERROR_PARSE) break; else if (r != MAILIMF_NO_ERROR) { res = r; goto err; } } item_name = strndup(message + begin, cur_token - begin); if (item_name == NULL) { res = MAILIMF_ERROR_MEMORY; goto err; } * index = cur_token; * result = item_name; return MAILIMF_NO_ERROR; err: return res; } #endif /* item-value = 1*angle-addr / addr-spec / atom / domain / msg-id */ #if 0 static int is_item_value_atext(char ch) { switch (ch) { case '\t': case ' ': case '\r': case '\n': case ';': return FALSE; default: return TRUE; } } static int mailimf_item_value_atom_parse(const char * message, size_t length, size_t * index, char ** result) { char * atom; size_t cur_token; int r; cur_token = * index; r = mailimf_cfws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) return r; r = mailimf_custom_string_parse(message, length, &cur_token, &atom, is_item_value_atext); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_cfws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) return r; * index = cur_token; * result = atom; return MAILIMF_NO_ERROR; } static int mailimf_item_value_parse(const char * message, size_t length, size_t * index, struct mailimf_item_value ** result) { size_t cur_token; clist * angle_addr_list; char * addr_spec; char * atom; char * domain; char * msg_id; int type; struct mailimf_item_value * item_value; int r; int res; cur_token = * index; angle_addr_list = NULL; addr_spec = NULL; atom = NULL; domain = NULL; msg_id = NULL; r = mailimf_struct_multiple_parse(message, length, &cur_token, &angle_addr_list, (mailimf_struct_parser *) mailimf_angle_addr_parse, (mailimf_struct_destructor *) mailimf_angle_addr_free); if (r == MAILIMF_NO_ERROR) type = MAILIMF_ITEM_VALUE_ANGLE_ADDR_LIST; if (r == MAILIMF_ERROR_PARSE) { r = mailimf_addr_spec_parse(message, length, &cur_token, &addr_spec); if (r == MAILIMF_NO_ERROR) type = MAILIMF_ITEM_VALUE_ADDR_SPEC; } if (r == MAILIMF_ERROR_PARSE) { r = mailimf_msg_id_parse(message, length, &cur_token, &msg_id); if (r == MAILIMF_NO_ERROR) type = MAILIMF_ITEM_VALUE_MSG_ID; } /* else if (mailimf_domain_parse(message, length, &cur_token, &domain)) type = MAILIMF_ITEM_VALUE_DOMAIN; */ /* else if (mailimf_atom_parse(message, length, &cur_token, &atom)) type = MAILIMF_ITEM_VALUE_ATOM; */ if (r == MAILIMF_ERROR_PARSE) { r = mailimf_item_value_atom_parse(message, length, &cur_token, &atom); if (r == MAILIMF_NO_ERROR) type = MAILIMF_ITEM_VALUE_ATOM; } if (r != MAILIMF_NO_ERROR) { res = r; goto err; } item_value = mailimf_item_value_new(type, angle_addr_list, addr_spec, atom, domain, msg_id); if (item_value == NULL) { res = MAILIMF_ERROR_MEMORY; goto free; } * result = item_value; * index = cur_token; return MAILIMF_NO_ERROR; free: if (angle_addr_list != NULL) { clist_foreach(angle_addr_list, (clist_func) mailimf_angle_addr_free, NULL); clist_free(angle_addr_list); } if (addr_spec != NULL) mailimf_addr_spec_free(addr_spec); if (atom != NULL) mailimf_atom_free(atom); if (domain != NULL) mailimf_domain_free(domain); if (msg_id != NULL) mailimf_msg_id_free(msg_id); err: return res; } #endif /* optional-field = field-name ":" unstructured CRLF */ static int mailimf_optional_field_parse(const char * message, size_t length, size_t * index, struct mailimf_optional_field ** result) { char * name; char * value; struct mailimf_optional_field * optional_field; size_t cur_token; int r; int res; cur_token = * index; r = mailimf_field_name_parse(message, length, &cur_token, &name); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_colon_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_name; } r = mailimf_unstructured_parse(message, length, &cur_token, &value); if (r != MAILIMF_NO_ERROR) { res = r; goto free_name; } r = mailimf_unstrict_crlf_parse(message, length, &cur_token); if (r != MAILIMF_NO_ERROR) { res = r; goto free_value; } optional_field = mailimf_optional_field_new(name, value); if (optional_field == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_value; } * result = optional_field; * index = cur_token; return MAILIMF_NO_ERROR; free_value: mailimf_unstructured_free(value); free_name: mailimf_field_name_free(name); err: return res; } /* field-name = 1*ftext */ static inline int is_ftext(char ch); static int mailimf_field_name_parse(const char * message, size_t length, size_t * index, char ** result) { char * field_name; size_t cur_token; size_t end; cur_token = * index; end = cur_token; if (end >= length) { return MAILIMF_ERROR_PARSE; } while (is_ftext(message[end])) { end ++; if (end >= length) break; } if (end == cur_token) { return MAILIMF_ERROR_PARSE; } /* field_name = strndup(message + cur_token, end - cur_token); */ field_name = malloc(end - cur_token + 1); if (field_name == NULL) { return MAILIMF_ERROR_MEMORY; } strncpy(field_name, message + cur_token, end - cur_token); field_name[end - cur_token] = '\0'; cur_token = end; * index = cur_token; * result = field_name; return MAILIMF_NO_ERROR; } /* ftext = %d33-57 / ; Any character except %d59-126 ; controls, SP, and ; ":". */ static inline int is_ftext(char ch) { unsigned char uch = (unsigned char) ch; if (uch < 33) return FALSE; if (uch == 58) return FALSE; return TRUE; } /* static int mailimf_ftext_parse(const char * message, size_t length, size_t * index, gchar * result) { return mailimf_typed_text_parse(message, length, index, result, is_ftext); } */ static int mailimf_envelope_field_parse(const char * message, size_t length, size_t * index, struct mailimf_field ** result) { size_t cur_token; int type; struct mailimf_orig_date * orig_date; struct mailimf_from * from; struct mailimf_sender * sender; struct mailimf_reply_to * reply_to; struct mailimf_to * to; struct mailimf_cc * cc; struct mailimf_bcc * bcc; struct mailimf_message_id * message_id; struct mailimf_in_reply_to * in_reply_to; struct mailimf_references * references; struct mailimf_subject * subject; struct mailimf_optional_field * optional_field; struct mailimf_field * field; int guessed_type; int r; int res; cur_token = * index; orig_date = NULL; from = NULL; sender = NULL; reply_to = NULL; to = NULL; cc = NULL; bcc = NULL; message_id = NULL; in_reply_to = NULL; references = NULL; subject = NULL; optional_field = NULL; guessed_type = guess_header_type(message, length, cur_token); type = MAILIMF_FIELD_NONE; switch (guessed_type) { case MAILIMF_FIELD_ORIG_DATE: r = mailimf_orig_date_parse(message, length, &cur_token, &orig_date); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_FROM: r = mailimf_from_parse(message, length, &cur_token, &from); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_SENDER: r = mailimf_sender_parse(message, length, &cur_token, &sender); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_REPLY_TO: r = mailimf_reply_to_parse(message, length, &cur_token, &reply_to); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_TO: r = mailimf_to_parse(message, length, &cur_token, &to); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_CC: r = mailimf_cc_parse(message, length, &cur_token, &cc); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_BCC: r = mailimf_bcc_parse(message, length, &cur_token, &bcc); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_MESSAGE_ID: r = mailimf_message_id_parse(message, length, &cur_token, &message_id); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_IN_REPLY_TO: r = mailimf_in_reply_to_parse(message, length, &cur_token, &in_reply_to); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_REFERENCES: r = mailimf_references_parse(message, length, &cur_token, &references); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; case MAILIMF_FIELD_SUBJECT: r = mailimf_subject_parse(message, length, &cur_token, &subject); if (r == MAILIMF_NO_ERROR) type = guessed_type; else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } break; } if (type == MAILIMF_FIELD_NONE) { res = MAILIMF_ERROR_PARSE; goto err; } field = mailimf_field_new(type, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, orig_date, from, sender, reply_to, to, cc, bcc, message_id, in_reply_to, references, subject, NULL, NULL, optional_field); if (field == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_field; } * result = field; * index = cur_token; return MAILIMF_NO_ERROR; free_field: if (orig_date != NULL) mailimf_orig_date_free(orig_date); if (from != NULL) mailimf_from_free(from); if (sender != NULL) mailimf_sender_free(sender); if (reply_to != NULL) mailimf_reply_to_free(reply_to); if (to != NULL) mailimf_to_free(to); if (cc != NULL) mailimf_cc_free(cc); if (bcc != NULL) mailimf_bcc_free(bcc); if (message_id != NULL) mailimf_message_id_free(message_id); if (in_reply_to != NULL) mailimf_in_reply_to_free(in_reply_to); if (references != NULL) mailimf_references_free(references); if (subject != NULL) mailimf_subject_free(subject); if (optional_field != NULL) mailimf_optional_field_free(optional_field); err: return res; } int mailimf_envelope_fields_parse(const char * message, size_t length, size_t * index, struct mailimf_fields ** result) { size_t cur_token; clist * list; struct mailimf_fields * fields; int r; int res; cur_token = * index; list = clist_new(); if (list == NULL) { res = MAILIMF_ERROR_MEMORY; goto err; } while (1) { struct mailimf_field * elt; r = mailimf_envelope_field_parse(message, length, &cur_token, &elt); if (r == MAILIMF_NO_ERROR) { r = clist_append(list, elt); if (r < 0) { res = MAILIMF_ERROR_MEMORY; goto free; } } else if (r == MAILIMF_ERROR_PARSE) { r = mailimf_ignore_field_parse(message, length, &cur_token); if (r == MAILIMF_NO_ERROR) { /* do nothing */ } else if (r == MAILIMF_ERROR_PARSE) { break; } else { res = r; goto free; } } else { res = r; goto free; } } fields = mailimf_fields_new(list); if (fields == NULL) { res = MAILIMF_ERROR_MEMORY; goto free; } * result = fields; * index = cur_token; return MAILIMF_NO_ERROR; free: if (list != NULL) { clist_foreach(list, (clist_func) mailimf_field_free, NULL); clist_free(list); } err: return res; } static int mailimf_envelope_or_optional_field_parse(const char * message, size_t length, size_t * index, struct mailimf_field ** result) { int r; size_t cur_token; struct mailimf_optional_field * optional_field; struct mailimf_field * field; r = mailimf_envelope_field_parse(message, length, index, result); if (r == MAILIMF_NO_ERROR) return MAILIMF_NO_ERROR; cur_token = * index; r = mailimf_optional_field_parse(message, length, &cur_token, &optional_field); if (r != MAILIMF_NO_ERROR) return r; field = mailimf_field_new(MAILIMF_FIELD_OPTIONAL_FIELD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, optional_field); if (field == NULL) { mailimf_optional_field_free(optional_field); return MAILIMF_ERROR_MEMORY; } * result = field; * index = cur_token; return MAILIMF_NO_ERROR; } int mailimf_envelope_and_optional_fields_parse(const char * message, size_t length, size_t * index, struct mailimf_fields ** result) { size_t cur_token; clist * list; struct mailimf_fields * fields; int r; int res; cur_token = * index; list = NULL; r = mailimf_struct_multiple_parse(message, length, &cur_token, &list, (mailimf_struct_parser *) mailimf_envelope_or_optional_field_parse, (mailimf_struct_destructor *) mailimf_field_free); switch (r) { case MAILIMF_NO_ERROR: /* do nothing */ break; case MAILIMF_ERROR_PARSE: list = clist_new(); if (list == NULL) { res = MAILIMF_ERROR_MEMORY; goto err; } break; default: res = r; goto err; } fields = mailimf_fields_new(list); if (fields == NULL) { res = MAILIMF_ERROR_MEMORY; goto free; } * result = fields; * index = cur_token; return MAILIMF_NO_ERROR; free: if (list != NULL) { clist_foreach(list, (clist_func) mailimf_field_free, NULL); clist_free(list); } err: return res; } static int mailimf_only_optional_field_parse(const char * message, size_t length, size_t * index, struct mailimf_field ** result) { int r; size_t cur_token; struct mailimf_optional_field * optional_field; struct mailimf_field * field; cur_token = * index; r = mailimf_optional_field_parse(message, length, &cur_token, &optional_field); if (r != MAILIMF_NO_ERROR) return r; field = mailimf_field_new(MAILIMF_FIELD_OPTIONAL_FIELD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, optional_field); if (field == NULL) { mailimf_optional_field_free(optional_field); return MAILIMF_ERROR_MEMORY; } * result = field; * index = cur_token; return MAILIMF_NO_ERROR; } int mailimf_optional_fields_parse(const char * message, size_t length, size_t * index, struct mailimf_fields ** result) { size_t cur_token; clist * list; struct mailimf_fields * fields; int r; int res; cur_token = * index; list = NULL; r = mailimf_struct_multiple_parse(message, length, &cur_token, &list, (mailimf_struct_parser *) mailimf_only_optional_field_parse, (mailimf_struct_destructor *) mailimf_field_free); switch (r) { case MAILIMF_NO_ERROR: /* do nothing */ break; case MAILIMF_ERROR_PARSE: list = clist_new(); if (list == NULL) { res = MAILIMF_ERROR_MEMORY; goto err; } break; default: res = r; goto err; } fields = mailimf_fields_new(list); if (fields == NULL) { res = MAILIMF_ERROR_MEMORY; goto free; } * result = fields; * index = cur_token; return MAILIMF_NO_ERROR; free: if (list != NULL) { clist_foreach(list, (clist_func) mailimf_field_free, NULL); clist_free(list); } err: return res; } diff --git a/kmicromail/libetpan/include/libetpan/libetpan.h b/kmicromail/libetpan/include/libetpan/libetpan.h index 3b4a107..fe5637d 100644 --- a/kmicromail/libetpan/include/libetpan/libetpan.h +++ b/kmicromail/libetpan/include/libetpan/libetpan.h @@ -1,104 +1,116 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #ifndef LIBETPAN_H #define LIBETPAN_H #ifdef __cplusplus extern "C" { #endif #include <libetpan/libetpan_version.h> #include <libetpan/maildriver.h> #include <libetpan/mailmessage.h> +#include <libetpan/mailfolder.h> #include <libetpan/mailstorage.h> #include <libetpan/mailthread.h> #include <libetpan/mailsmtp.h> #include <libetpan/charconv.h> /* mbox driver */ #include <libetpan/mboxdriver.h> #include <libetpan/mboxdriver_message.h> #include <libetpan/mboxdriver_cached.h> #include <libetpan/mboxdriver_cached_message.h> #include <libetpan/mboxstorage.h> /* MH driver */ #include <libetpan/mhdriver.h> #include <libetpan/mhdriver_message.h> #include <libetpan/mhdriver_cached.h> #include <libetpan/mhdriver_cached_message.h> #include <libetpan/mhstorage.h> /* IMAP4rev1 driver */ #include <libetpan/imapdriver.h> #include <libetpan/imapdriver_message.h> #include <libetpan/imapdriver_cached.h> #include <libetpan/imapdriver_cached_message.h> #include <libetpan/imapstorage.h> /* POP3 driver */ #include <libetpan/pop3driver.h> #include <libetpan/pop3driver_message.h> #include <libetpan/pop3driver_cached.h> #include <libetpan/pop3driver_cached_message.h> #include <libetpan/pop3storage.h> /* NNTP driver */ #include <libetpan/nntpdriver.h> #include <libetpan/nntpdriver_message.h> #include <libetpan/nntpdriver_cached.h> #include <libetpan/nntpdriver_cached_message.h> #include <libetpan/nntpstorage.h> /* maildir driver */ #include <libetpan/maildirdriver.h> #include <libetpan/maildirdriver_message.h> #include <libetpan/maildirdriver_cached.h> #include <libetpan/maildirdriver_cached_message.h> #include <libetpan/maildirstorage.h> +/* db driver */ +#include <libetpan/dbdriver.h> +#include <libetpan/dbdriver_message.h> +#include <libetpan/dbstorage.h> + /* message which content is given by a MIME structure */ #include <libetpan/mime_message_driver.h> /* message which content given by a string */ #include <libetpan/data_message_driver.h> +/* engine */ +#include <libetpan/mailprivacy.h> +#include <libetpan/mailengine.h> +#include <libetpan/mailprivacy_gnupg.h> +#include <libetpan/mailprivacy_smime.h> + #ifdef __cplusplus } #endif #endif diff --git a/kmicromail/libetpan/include/libetpan/maildir.h b/kmicromail/libetpan/include/libetpan/maildir.h index b782484..268dda1 100644 --- a/kmicromail/libetpan/include/libetpan/maildir.h +++ b/kmicromail/libetpan/include/libetpan/maildir.h @@ -1,60 +1,67 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001 - 2003 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #ifndef MAILDIR_H #define MAILDIR_H #include <libetpan/maildir_types.h> struct maildir * maildir_new(const char * path); void maildir_free(struct maildir * md); int maildir_update(struct maildir * md); +int maildir_message_add_uid(struct maildir * md, + const char * message, size_t size, + char * uid, size_t max_uid_len); + int maildir_message_add(struct maildir * md, const char * message, size_t size); +int maildir_message_add_file_uid(struct maildir * md, int fd, + char * uid, size_t max_uid_len); + int maildir_message_add_file(struct maildir * md, int fd); char * maildir_message_get(struct maildir * md, const char * uid); int maildir_message_remove(struct maildir * md, const char * uid); int maildir_message_change_flags(struct maildir * md, const char * uid, int new_flags); #endif diff --git a/kmicromail/libetpan/include/libetpan/maildirstorage.h b/kmicromail/libetpan/include/libetpan/maildirstorage.h index d17ea2c..73d7b20 100644 --- a/kmicromail/libetpan/include/libetpan/maildirstorage.h +++ b/kmicromail/libetpan/include/libetpan/maildirstorage.h @@ -1,69 +1,69 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #ifndef MAILDIRSTORAGE_H #define MAILDIRSTORAGE_H #include <libetpan/maildirdriver_types.h> #ifdef __cplusplus extern "C" { #endif /* - maildir_mailstorage_init is the constructor for a mbox storage. + maildir_mailstorage_init is the constructor for a maildir storage. @param storage this is the storage to initialize. @param pathname is the directory that contains the mailbox. @param cached if this value is != 0, a persistant cache will be stored on local system. @param cache_directory is the location of the cache @param flags_directory is the location of the flags */ int maildir_mailstorage_init(struct mailstorage * storage, char * md_pathname, int md_cached, char * md_cache_directory, char * md_flags_directory); #ifdef __cplusplus } #endif #endif diff --git a/kmicromail/libetpan/include/libetpan/maildriver.h b/kmicromail/libetpan/include/libetpan/maildriver.h index 7da9aea..c773190 100644 --- a/kmicromail/libetpan/include/libetpan/maildriver.h +++ b/kmicromail/libetpan/include/libetpan/maildriver.h @@ -1,543 +1,546 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #ifndef MAILDRIVER_H #define MAILDRIVER_H #include <libetpan/maildriver_types.h> #include <libetpan/maildriver_types_helper.h> #ifdef __cplusplus extern "C" { #endif /* mailsession */ /* mailsession_new creates a new session, using the given driver @return the created session is returned */ mailsession * mailsession_new(mailsession_driver * sess_driver); /* mailsession_free release the memory used by the session */ void mailsession_free(mailsession * session); /* mailsession_parameters is used to make calls specific to the driver @param id is the command to send to the driver, usually, commands can be found in the header of the driver @param value is the parameter of the specific call @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_parameters(mailsession * session, int id, void * value); /* There are drivers of two kinds : stream drivers (driver that connects to servers through TCP or other means of connection) and file drivers (driver that are based on filesystem) The following function can only be used by stream drivers. mailsession_connect_stream connects a stream to the session @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_connect_stream(mailsession * session, mailstream * s); /* The following function can only be used by file drivers. mailsession_connect_path selects the main path of the session @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_connect_path(mailsession * session, char * path); /* NOTE: works only on stream drivers mailsession_starttls switches the current connection to TLS (secure layer) @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_starttls(mailsession * session); /* mailsession_login notifies the login and the password to authenticate to the session @param userid the given string is only needed at this function call (it will be duplicated if necessary) @param password the given string is only needed at this function call (it will be duplicated if necessary) @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_login(mailsession * session, char * userid, char * password); /* NOTE: this function doesn't often work on filsystem drivers mailsession_logout deconnects the session and closes the stream. @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_logout(mailsession * session); /* mailsession_noop does no operation on the session, but it can be used to poll for the status of the connection. @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_noop(mailsession * session); /* NOTE: driver's specific should be used mailsession_build_folder_name will return an allocated string with that contains the complete path of the folder to create @param session the sesion @param mb is the parent mailbox @param name is the name of the folder to create @param result the complete path of the folder to create will be stored in (* result), this name have to be freed with free() @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_build_folder_name(mailsession * session, char * mb, char * name, char ** result); /* NOTE: driver's specific should be used mailsession_create_folder creates the folder that corresponds to the given name @param session the session @param mb is the name of the mailbox @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_create_folder(mailsession * session, char * mb); /* NOTE: driver's specific should be used mailsession_delete_folder deletes the folder that corresponds to the given name @param session the session @param mb is the name of the mailbox @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_delete_folder(mailsession * session, char * mb); /* mailsession_rename_folder changes the name of the folder @param session the session @param mb is the name of the mailbox whose name has to be changed @param new_name is the destination name (the parent of the new folder folder can be other) @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_rename_folder(mailsession * session, char * mb, char * new_name); /* mailsession_check_folder makes a checkpoint of the session @param session the session @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_check_folder(mailsession * session); /* NOTE: this function is not implemented in most drivers mailsession_examine_folder selects a mailbox as readonly @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_examine_folder(mailsession * session, char * mb); /* mailsession_select_folder selects a mailbox @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_select_folder(mailsession * session, char * mb); /* mailsession_expunge_folder deletes all messages marked \Deleted @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_expunge_folder(mailsession * session); /* mailsession_status_folder queries the status of the folder (number of messages, number of recent messages, number of unseen messages) @param session the session @param mb mailbox to query @param result_messages the number of messages is stored in (* result_messages) @param result_recent the number of messages is stored in (* result_recent) @param result_unseen the number of messages is stored in (* result_unseen) @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_status_folder(mailsession * session, char * mb, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); /* mailsession_messages_number queries the number of messages in the folder @param session the session @param mb mailbox to query @param result the number of messages is stored in (* result) @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_messages_number(mailsession * session, char * mb, uint32_t * result); /* mailsession_recent_number queries the number of recent messages in the folder @param session the session @param mb mailbox to query @param result the number of recent messages is stored in (* result) @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_recent_number(mailsession * session, char * mb, uint32_t * result); /* mailsession_unseen_number queries the number of unseen messages in the folder @param session the session @param mb mailbox to query @param result the number of unseen messages is stored in (* result) @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_unseen_number(mailsession * session, char * mb, uint32_t * result); /* NOTE: driver's specific should be used mailsession_list_folders returns the list of all sub-mailboxes of the given mailbox @param session the session @param mb the mailbox @param result list of mailboxes if stored in (* result), this structure have to be freed with mail_list_free() @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_list_folders(mailsession * session, char * mb, struct mail_list ** result); /* NOTE: driver's specific should be used mailsession_lsub_folders returns the list of subscribed sub-mailboxes of the given mailbox @param session the session @param mb the mailbox @param result list of mailboxes if stored in (* result), this structure have to be freed with mail_list_free() @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_lsub_folders(mailsession * session, char * mb, struct mail_list ** result); /* NOTE: driver's specific should be used mailsession_subscribe_folder subscribes to the given mailbox @param session the session @param mb the mailbox @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_subscribe_folder(mailsession * session, char * mb); /* NOTE: driver's specific should be used mailsession_unsubscribe_folder unsubscribes to the given mailbox @param session the session @param mb the mailbox @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_unsubscribe_folder(mailsession * session, char * mb); /* mailsession_append_message adds a RFC 2822 message to the current given mailbox @param session the session @param message is a string that contains the RFC 2822 message @param size this is the size of the message @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_append_message(mailsession * session, char * message, size_t size); +int mailsession_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags); + /* NOTE: some drivers does not implement this mailsession_copy_message copies a message whose number is given to a given mailbox. The mailbox must be accessible from the same session. @param session the session @param num the message number @param mb the destination mailbox @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_copy_message(mailsession * session, uint32_t num, char * mb); /* NOTE: some drivers does not implement this mailsession_move_message copies a message whose number is given to a given mailbox. The mailbox must be accessible from the same session. @param session the session @param num the message number @param mb the destination mailbox @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_move_message(mailsession * session, uint32_t num, char * mb); /* mailsession_get_messages_list returns the list of message numbers of the current mailbox. @param session the session @param result the list of message numbers will be stored in (* result), this structure have to be freed with mailmessage_list_free() @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_get_messages_list(mailsession * session, struct mailmessage_list ** result); /* mailsession_get_envelopes_list fills the parsed fields in the mailmessage structures of the mailmessage_list. @param session the session @param result this is the list of mailmessage structures @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_get_envelopes_list(mailsession * session, struct mailmessage_list * result); /* NOTE: some drivers does not implement this mailsession_remove_message removes the given message from the mailbox. The message is permanently deleted. @param session the session @param num is the message number @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_remove_message(mailsession * session, uint32_t num); /* NOTE: this function is not implemented in most drivers mailsession_search_message returns a list of message numbers that corresponds to the given criteria. @param session the session @param charset is the charset to use (it can be NULL) @param key is the list of criteria @param result the search result is stored in (* result), this structure have to be freed with mail_search_result_free() @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ #if 0 int mailsession_search_messages(mailsession * session, char * charset, struct mail_search_key * key, struct mail_search_result ** result); #endif /* mailsession_get_message returns a mailmessage structure that corresponds to the given message number. * WARNING * mailsession_get_message_by_uid() should be used instead. @param session the session @param num the message number @param result the allocated mailmessage structure will be stored in (* result), this structure have to be freed with mailmessage_free() @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_get_message(mailsession * session, uint32_t num, mailmessage ** result); /* mailsession_get_message_by_uid returns a mailmessage structure that corresponds to the given message unique identifier. This is currently implemented only for cached drivers. * WARNING * That will deprecates the use of mailsession_get_message() @param session the session @param uid the message unique identifier @param result the allocated mailmessage structure will be stored in (* result), this structure have to be freed with mailmessage_free() @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned on error */ int mailsession_get_message_by_uid(mailsession * session, const char * uid, mailmessage ** result); #ifdef __cplusplus } #endif #endif diff --git a/kmicromail/libetpan/include/libetpan/maildriver_types.h b/kmicromail/libetpan/include/libetpan/maildriver_types.h index 3ff9440..9eab4d6 100644 --- a/kmicromail/libetpan/include/libetpan/maildriver_types.h +++ b/kmicromail/libetpan/include/libetpan/maildriver_types.h @@ -1,793 +1,795 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #ifndef MAILDRIVER_TYPES_H #define MAILDRIVER_TYPES_H #include <inttypes.h> #include <sys/types.h> #include <libetpan/mailstream.h> #include <libetpan/mailimf.h> #include <libetpan/mailmime.h> #include <libetpan/carray.h> #include <libetpan/mailthread_types.h> #include <libetpan/maildriver_errors.h> #ifdef __cplusplus extern "C" { #endif typedef struct mailsession_driver mailsession_driver; typedef struct mailsession mailsession; typedef struct mailmessage_driver mailmessage_driver; typedef struct mailmessage mailmessage; /* mailmessage_list is a list of mailmessage - tab is an array of mailmessage structures */ struct mailmessage_list { carray * msg_tab; /* elements are (mailmessage *) */ }; struct mailmessage_list * mailmessage_list_new(carray * msg_tab); void mailmessage_list_free(struct mailmessage_list * env_list); /* mail_list is a list of mailbox names - list is a list of mailbox names */ struct mail_list { clist * mb_list; /* elements are (char *) */ }; struct mail_list * mail_list_new(clist * mb_list); void mail_list_free(struct mail_list * resp); /* This is a flag value. Flags can be combined with OR operation */ enum { MAIL_FLAG_NEW = 1 << 0, MAIL_FLAG_SEEN = 1 << 1, MAIL_FLAG_FLAGGED = 1 << 2, MAIL_FLAG_DELETED = 1 << 3, MAIL_FLAG_ANSWERED = 1 << 4, MAIL_FLAG_FORWARDED = 1 << 5, MAIL_FLAG_CANCELLED = 1 << 6, }; /* mail_flags is the value of a flag related to a message. - flags is the standard flags value - extension is a list of unknown flags for libEtPan! */ struct mail_flags { uint32_t fl_flags; clist * fl_extension; /* elements are (char *) */ }; struct mail_flags * mail_flags_new(uint32_t fl_flags, clist * fl_ext); void mail_flags_free(struct mail_flags * flags); /* This function creates a flag for a new message */ struct mail_flags * mail_flags_new_empty(void); /* mailimf_date_time_comp compares two dates */ int32_t mailimf_date_time_comp(struct mailimf_date_time * date1, struct mailimf_date_time * date2); /* this is type type of the search criteria */ enum { MAIL_SEARCH_KEY_ALL, /* all messages correspond */ MAIL_SEARCH_KEY_ANSWERED, /* messages with flag \Answered */ MAIL_SEARCH_KEY_BCC, /* messages which Bcc field contains a given string */ MAIL_SEARCH_KEY_BEFORE, /* messages which internal date is earlier than the specified date */ MAIL_SEARCH_KEY_BODY, /* message that contains the given string (in header and text parts) */ MAIL_SEARCH_KEY_CC, /* messages whose Cc field contains the given string */ MAIL_SEARCH_KEY_DELETED, /* messages with the flag \Deleted */ MAIL_SEARCH_KEY_FLAGGED, /* messages with the flag \Flagged */ MAIL_SEARCH_KEY_FROM, /* messages whose From field contains the given string */ MAIL_SEARCH_KEY_NEW, /* messages with the flag \Recent and not the \Seen flag */ MAIL_SEARCH_KEY_OLD, /* messages that do not have the \Recent flag set */ MAIL_SEARCH_KEY_ON, /* messages whose internal date is the specified date */ MAIL_SEARCH_KEY_RECENT, /* messages with the flag \Recent */ MAIL_SEARCH_KEY_SEEN, /* messages with the flag \Seen */ MAIL_SEARCH_KEY_SINCE, /* messages whose internal date is later than specified date */ MAIL_SEARCH_KEY_SUBJECT, /* messages whose Subject field contains the given string */ MAIL_SEARCH_KEY_TEXT, /* messages whose text part contains the given string */ MAIL_SEARCH_KEY_TO, /* messages whose To field contains the given string */ MAIL_SEARCH_KEY_UNANSWERED, /* messages with no flag \Answered */ MAIL_SEARCH_KEY_UNDELETED, /* messages with no flag \Deleted */ MAIL_SEARCH_KEY_UNFLAGGED, /* messages with no flag \Flagged */ MAIL_SEARCH_KEY_UNSEEN, /* messages with no flag \Seen */ MAIL_SEARCH_KEY_HEADER, /* messages whose given field contains the given string */ MAIL_SEARCH_KEY_LARGER, /* messages whose size is larger then the given size */ MAIL_SEARCH_KEY_NOT, /* not operation of the condition */ MAIL_SEARCH_KEY_OR, /* or operation between two conditions */ MAIL_SEARCH_KEY_SMALLER, /* messages whose size is smaller than the given size */ MAIL_SEARCH_KEY_MULTIPLE /* the boolean operator between the conditions is AND */ }; /* mail_search_key is the condition on the messages to return - type is the type of the condition - bcc is the text to search in the Bcc field when type is MAIL_SEARCH_KEY_BCC, should be allocated with malloc() - before is a date when type is MAIL_SEARCH_KEY_BEFORE - body is the text to search in the message when type is MAIL_SEARCH_KEY_BODY, should be allocated with malloc() - cc is the text to search in the Cc field when type is MAIL_SEARCH_KEY_CC, should be allocated with malloc() - from is the text to search in the From field when type is MAIL_SEARCH_KEY_FROM, should be allocated with malloc() - on is a date when type is MAIL_SEARCH_KEY_ON - since is a date when type is MAIL_SEARCH_KEY_SINCE - subject is the text to search in the Subject field when type is MAILIMAP_SEARCH_KEY_SUBJECT, should be allocated with malloc() - text is the text to search in the text part of the message when type is MAILIMAP_SEARCH_KEY_TEXT, should be allocated with malloc() - to is the text to search in the To field when type is MAILIMAP_SEARCH_KEY_TO, should be allocated with malloc() - header_name is the header name when type is MAILIMAP_SEARCH_KEY_HEADER, should be allocated with malloc() - header_value is the text to search in the given header when type is MAILIMAP_SEARCH_KEY_HEADER, should be allocated with malloc() - larger is a size when type is MAILIMAP_SEARCH_KEY_LARGER - not is a condition when type is MAILIMAP_SEARCH_KEY_NOT - or1 is a condition when type is MAILIMAP_SEARCH_KEY_OR - or2 is a condition when type is MAILIMAP_SEARCH_KEY_OR - sentbefore is a date when type is MAILIMAP_SEARCH_KEY_SENTBEFORE - senton is a date when type is MAILIMAP_SEARCH_KEY_SENTON - sentsince is a date when type is MAILIMAP_SEARCH_KEY_SENTSINCE - smaller is a size when type is MAILIMAP_SEARCH_KEY_SMALLER - multiple is a set of message when type is MAILIMAP_SEARCH_KEY_MULTIPLE */ #if 0 struct mail_search_key { int sk_type; union { char * sk_bcc; struct mailimf_date_time * sk_before; char * sk_body; char * sk_cc; char * sk_from; struct mailimf_date_time * sk_on; struct mailimf_date_time * sk_since; char * sk_subject; char * sk_text; char * sk_to; char * sk_header_name; char * sk_header_value; size_t sk_larger; struct mail_search_key * sk_not; struct mail_search_key * sk_or1; struct mail_search_key * sk_or2; size_t sk_smaller; clist * sk_multiple; /* list of (struct mailimap_search_key *) */ } sk_data; }; struct mail_search_key * mail_search_key_new(int sk_type, char * sk_bcc, struct mailimf_date_time * sk_before, char * sk_body, char * sk_cc, char * sk_from, struct mailimf_date_time * sk_on, struct mailimf_date_time * sk_since, char * sk_subject, char * sk_text, char * sk_to, char * sk_header_name, char * sk_header_value, size_t sk_larger, struct mail_search_key * sk_not, struct mail_search_key * sk_or1, struct mail_search_key * sk_or2, size_t sk_smaller, clist * sk_multiple); void mail_search_key_free(struct mail_search_key * key); #endif /* mail_search_result is a list of message numbers that is returned by the mailsession_search_messages function() */ #if 0 struct mail_search_result { clist * sr_list; /* list of (uint32_t *) */ }; struct mail_search_result * mail_search_result_new(clist * sr_list); void mail_search_result_free(struct mail_search_result * search_result); #endif /* There is three kinds of identities : - storage - folders - session A storage (struct mailstorage) represents whether a server or a main path, A storage can be an IMAP server, the root path of a MH or a mbox file. Folders (struct mailfolder) are the mailboxes we can choose in the server or as sub-folder of the main path. Folders for IMAP are the IMAP mailboxes, for MH this is one of the folder of the MH storage, for mbox, there is only one folder, the mbox file content; A mail session (struct mailsession) is whether a connection to a server or a path that is open. It is the abstraction lower folders and storage. It allow us to send commands. We have a session driver for mail session for each kind of storage. From a session, we can get a message (struct mailmessage) to read. We have a message driver for each kind of storage. */ /* maildriver is the driver structure for mail sessions - name is the name of the driver - initialize() is the function that will initializes a data structure specific to the driver, it returns a value that will be stored in the field data of the session. The field data of the session is the state of the session, the internal data structure used by the driver. It is called when creating the mailsession structure with mailsession_new(). - uninitialize() frees the structure created with initialize() - parameters() implements functions specific to the given mail access - connect_stream() connects a stream to the session - connect_path() notify a main path to the session - starttls() changes the current stream to a TLS stream - login() notifies the user and the password to authenticate to the session - logout() exits the session and closes the stream - noop() does no operation on the session, but it can be used to poll for the status of the connection. - build_folder_name() will return an allocated string with that contains the complete path of the folder to create - create_folder() creates the folder that corresponds to the given name - delete_folder() deletes the folder that corresponds to the given name - rename_folder() change the name of the folder - check_folder() makes a checkpoint of the session - examine_folder() selects a mailbox as readonly - select_folder() selects a mailbox - expunge_folder() deletes all messages marked \Deleted - status_folder() queries the status of the folder (number of messages, number of recent messages, number of unseen messages) - messages_number() queries the number of messages in the folder - recent_number() queries the number of recent messages in the folder - unseen_number() queries the number of unseen messages in the folder - list_folders() returns the list of all sub-mailboxes of the given mailbox - lsub_folders() returns the list of subscribed sub-mailboxes of the given mailbox - subscribe_folder() subscribes to the given mailbox - unsubscribe_folder() unsubscribes to the given mailbox - append_message() adds a RFC 2822 message to the current given mailbox - copy_message() copies a message whose number is given to a given mailbox. The mailbox must be accessible from the same session. - move_message() copies a message whose number is given to a given mailbox. The mailbox must be accessible from the same session. - get_messages_list() returns the list of message numbers of the current mailbox. - get_envelopes_list() fills the parsed fields in the mailmessage structures of the mailmessage_list. - remove_message() removes the given message from the mailbox. The message is permanently deleted. - search_message() returns a list of message numbers that corresponds to the given criteria. - get_message returns a mailmessage structure that corresponds to the given message number. - get_message_by_uid returns a mailmessage structure that corresponds to the given message unique identifier. * mandatory functions are the following : - connect_stream() of connect_path() - logout() - get_messages_list() - get_envelopes_list() * we advise you to implement these functions : - select_folder() (in case a session can access several folders) - noop() (to check if the server is responding) - check_folder() (to make a checkpoint of the session) - status_folder(), messages_number(), recent_number(), unseen_number() (to get stat of the folder) - append_message() (but can't be done in the case of POP3 at least) - login() in a case of an authenticated driver. - starttls() in a case of a stream driver, if the procotol supports STARTTLS. - get_message_by_uid() so that the application can remember the message by UID and build its own list of messages. * drivers' specific : Everything that is specific to the driver will be implemented in this function : - parameters() */ struct mailsession_driver { char * sess_name; int (* sess_initialize)(mailsession * session); void (* sess_uninitialize)(mailsession * session); int (* sess_parameters)(mailsession * session, int id, void * value); int (* sess_connect_stream)(mailsession * session, mailstream * s); int (* sess_connect_path)(mailsession * session, char * path); int (* sess_starttls)(mailsession * session); int (* sess_login)(mailsession * session, char * userid, char * password); int (* sess_logout)(mailsession * session); int (* sess_noop)(mailsession * session); /* folders operations */ int (* sess_build_folder_name)(mailsession * session, char * mb, char * name, char ** result); int (* sess_create_folder)(mailsession * session, char * mb); int (* sess_delete_folder)(mailsession * session, char * mb); int (* sess_rename_folder)(mailsession * session, char * mb, char * new_name); int (* sess_check_folder)(mailsession * session); int (* sess_examine_folder)(mailsession * session, char * mb); int (* sess_select_folder)(mailsession * session, char * mb); int (* sess_expunge_folder)(mailsession * session); int (* sess_status_folder)(mailsession * session, char * mb, uint32_t * result_num, uint32_t * result_recent, uint32_t * result_unseen); int (* sess_messages_number)(mailsession * session, char * mb, uint32_t * result); int (* sess_recent_number)(mailsession * session, char * mb, uint32_t * result); int (* sess_unseen_number)(mailsession * session, char * mb, uint32_t * result); int (* sess_list_folders)(mailsession * session, char * mb, struct mail_list ** result); int (* sess_lsub_folders)(mailsession * session, char * mb, struct mail_list ** result); int (* sess_subscribe_folder)(mailsession * session, char * mb); int (* sess_unsubscribe_folder)(mailsession * session, char * mb); /* messages operations */ int (* sess_append_message)(mailsession * session, char * message, size_t size); + int (* sess_append_message_flags)(mailsession * session, + char * message, size_t size, struct mail_flags * flags); int (* sess_copy_message)(mailsession * session, uint32_t num, char * mb); int (* sess_move_message)(mailsession * session, uint32_t num, char * mb); int (* sess_get_message)(mailsession * session, uint32_t num, mailmessage ** result); int (* sess_get_message_by_uid)(mailsession * session, const char * uid, mailmessage ** result); int (* sess_get_messages_list)(mailsession * session, struct mailmessage_list ** result); int (* sess_get_envelopes_list)(mailsession * session, struct mailmessage_list * env_list); int (* sess_remove_message)(mailsession * session, uint32_t num); #if 0 int (* sess_search_messages)(mailsession * session, char * charset, struct mail_search_key * key, struct mail_search_result ** result); #endif }; /* session is the data structure for a mail session. - data is the internal data structure used by the driver It is called when initializing the mailsession structure. - driver is the driver used for the session */ struct mailsession { void * sess_data; mailsession_driver * sess_driver; }; /* mailmessage_driver is the driver structure to get information from messages. - name is the name of the driver - initialize() is the function that will initializes a data structure specific to the driver, it returns a value that will be stored in the field data of the mailsession. The field data of the session is the state of the session, the internal data structure used by the driver. It is called when initializing the mailmessage structure with mailmessage_init(). - uninitialize() frees the structure created with initialize(). It will be called by mailmessage_free(). - flush() will free from memory all temporary structures of the message (for example, the MIME structure of the message). - fetch_result_free() will free all strings resulted by fetch() or any fetch_xxx() functions that returns a string. - fetch() returns the content of the message (headers and text). - fetch_header() returns the content of the headers. - fetch_body() returns the message text (message content without headers) - fetch_size() returns the size of the message content. - get_bodystructure() returns the MIME structure of the message. - fetch_section() returns the content of a given MIME part - fetch_section_header() returns the header of the message contained by the given MIME part. - fetch_section_mime() returns the MIME headers of the given MIME part. - fetch_section_body() returns the text (if this is a message, this is the message content without headers) of the given MIME part. - fetch_envelope() returns a mailimf_fields structure, with a list of fields chosen by the driver. - get_flags() returns a the flags related to the message. When you want to get flags of a message, you have to make sure to call get_flags() at least once before using directly message->flags. */ #define LIBETPAN_MAIL_MESSAGE_CHECK struct mailmessage_driver { char * msg_name; int (* msg_initialize)(mailmessage * msg_info); void (* msg_uninitialize)(mailmessage * msg_info); void (* msg_flush)(mailmessage * msg_info); void (* msg_check)(mailmessage * msg_info); void (* msg_fetch_result_free)(mailmessage * msg_info, char * msg); int (* msg_fetch)(mailmessage * msg_info, char ** result, size_t * result_len); int (* msg_fetch_header)(mailmessage * msg_info, char ** result, size_t * result_len); int (* msg_fetch_body)(mailmessage * msg_info, char ** result, size_t * result_len); int (* msg_fetch_size)(mailmessage * msg_info, size_t * result); int (* msg_get_bodystructure)(mailmessage * msg_info, struct mailmime ** result); int (* msg_fetch_section)(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len); int (* msg_fetch_section_header)(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len); int (* msg_fetch_section_mime)(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len); int (* msg_fetch_section_body)(mailmessage * msg_info, struct mailmime * mime, char ** result, size_t * result_len); int (* msg_fetch_envelope)(mailmessage * msg_info, struct mailimf_fields ** result); int (* msg_get_flags)(mailmessage * msg_info, struct mail_flags ** result); }; /* mailmessage is a data structure to get information from messages - session is the session linked to the given message, it can be NULL - driver is the message driver - index is the message number - uid, when it is not NULL, it means that the folder the folder has persistant message numbers, the string is the unique message number in the folder. uid should be implemented if possible. for drivers where we cannot generate real uid, a suggestion is "AAAA-IIII" where AAAA is some random session number and IIII the content of index field. - size, when it is not 0, is the size of the message content. - fields, when it is not NULL, are the header fields of the message. - flags, when it is not NULL, are the flags related to the message. - single_fields, when resolved != 0, is filled with the data of fields. - mime, when it is not NULL - cached is != 0 when the header fields were read from the cache. - data is data specific to the driver, this is internal data structure, some state of the message. */ struct mailmessage { mailsession * msg_session; mailmessage_driver * msg_driver; uint32_t msg_index; char * msg_uid; size_t msg_size; struct mailimf_fields * msg_fields; struct mail_flags * msg_flags; int msg_resolved; struct mailimf_single_fields msg_single_fields; struct mailmime * msg_mime; /* internal data */ int msg_cached; void * msg_data; /* msg_folder field : used to reference the mailfolder, this is a workaround due to the problem with initial conception, where folder notion did not exist. */ void * msg_folder; /* user data */ void * msg_user_data; }; /* mailmessage_tree is a node in the messages tree (thread) - parent is the parent of the message, it is NULL if the message is the root of the message tree. - date is the date of the message in number of second elapsed since 00:00:00 on January 1, 1970, Coordinated Universal Time (UTC). - msg is the message structure that is stored referenced by the node. is msg is NULL, this is a dummy node. - children is an array that contains all the children of the node. children are mailmessage_tree structures. - is_reply is != 0 when the message is a reply or a forward - base_subject is the extracted subject of the message. - index is the message number. */ struct mailmessage_tree { struct mailmessage_tree * node_parent; char * node_msgid; time_t node_date; mailmessage * node_msg; carray * node_children; /* array of (struct mailmessage_tree *) */ /* private, used for threading */ int node_is_reply; char * node_base_subject; }; struct mailmessage_tree * mailmessage_tree_new(char * node_msgid, time_t node_date, mailmessage * node_msg); void mailmessage_tree_free(struct mailmessage_tree * tree); /* mailmessage_tree_free_recursive if you want to release memory of the given tree and all the sub-trees, you can use this function. */ void mailmessage_tree_free_recursive(struct mailmessage_tree * tree); struct generic_message_t { int (* msg_prefetch)(mailmessage * msg_info); void (* msg_prefetch_free)(struct generic_message_t * msg); int msg_fetched; char * msg_message; size_t msg_length; void * msg_data; }; const char * maildriver_strerror(int err); #ifdef __cplusplus } #endif #endif diff --git a/kmicromail/libetpan/include/libetpan/mailfolder.h b/kmicromail/libetpan/include/libetpan/mailfolder.h index 3ecad23..ff53470 100644 --- a/kmicromail/libetpan/include/libetpan/mailfolder.h +++ b/kmicromail/libetpan/include/libetpan/mailfolder.h @@ -1,32 +1,35 @@ #ifndef MAILFOLDER_H #define MAILFOLDER_H #include "mailstorage_types.h" int mailfolder_noop(struct mailfolder * folder); int mailfolder_check(struct mailfolder * folder); int mailfolder_expunge(struct mailfolder * folder); int mailfolder_status(struct mailfolder * folder, uint32_t * result_messages, uint32_t * result_recent, uint32_t * result_unseen); int mailfolder_append_message(struct mailfolder * folder, char * message, size_t size); +int mailfolder_append_message_flags(struct mailfolder * folder, + char * message, size_t size, struct mail_flags * flags); + int mailfolder_get_messages_list(struct mailfolder * folder, struct mailmessage_list ** result); int mailfolder_get_envelopes_list(struct mailfolder * folder, struct mailmessage_list * result); int mailfolder_get_message(struct mailfolder * folder, uint32_t num, mailmessage ** result); int mailfolder_get_message_by_uid(struct mailfolder * folder, const char * uid, mailmessage ** result); #endif diff --git a/kmicromail/libetpan/include/libetpan/mailmbox.h b/kmicromail/libetpan/include/libetpan/mailmbox.h index 8be086c..0427f1f 100644 --- a/kmicromail/libetpan/include/libetpan/mailmbox.h +++ b/kmicromail/libetpan/include/libetpan/mailmbox.h @@ -1,140 +1,144 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #ifndef MAILMBOX_H #define MAILMBOX_H #ifdef __cplusplus extern "C" { #endif #include <libetpan/mailmbox_types.h> int mailmbox_append_message_list(struct mailmbox_folder * folder, carray * append_tab); int mailmbox_append_message(struct mailmbox_folder * folder, const char * data, size_t len); +int +mailmbox_append_message_uid(struct mailmbox_folder * folder, + const char * data, size_t len, unsigned int * puid); + int mailmbox_fetch_msg(struct mailmbox_folder * folder, uint32_t num, char ** result, size_t * result_len); int mailmbox_fetch_msg_headers(struct mailmbox_folder * folder, uint32_t num, char ** result, size_t * result_len); void mailmbox_fetch_result_free(char * msg); int mailmbox_copy_msg_list(struct mailmbox_folder * dest_folder, struct mailmbox_folder * src_folder, carray * tab); int mailmbox_copy_msg(struct mailmbox_folder * dest_folder, struct mailmbox_folder * src_folder, uint32_t uid); int mailmbox_expunge(struct mailmbox_folder * folder); int mailmbox_delete_msg(struct mailmbox_folder * folder, uint32_t uid); int mailmbox_init(const char * filename, int force_readonly, int force_no_uid, uint32_t default_written_uid, struct mailmbox_folder ** result_folder); void mailmbox_done(struct mailmbox_folder * folder); /* low-level access primitives */ int mailmbox_write_lock(struct mailmbox_folder * folder); int mailmbox_write_unlock(struct mailmbox_folder * folder); int mailmbox_read_lock(struct mailmbox_folder * folder); int mailmbox_read_unlock(struct mailmbox_folder * folder); /* memory map */ int mailmbox_map(struct mailmbox_folder * folder); void mailmbox_unmap(struct mailmbox_folder * folder); void mailmbox_sync(struct mailmbox_folder * folder); /* open & close file */ int mailmbox_open(struct mailmbox_folder * folder); void mailmbox_close(struct mailmbox_folder * folder); /* validate cache */ int mailmbox_validate_write_lock(struct mailmbox_folder * folder); int mailmbox_validate_read_lock(struct mailmbox_folder * folder); /* fetch message */ int mailmbox_fetch_msg_no_lock(struct mailmbox_folder * folder, uint32_t num, char ** result, size_t * result_len); int mailmbox_fetch_msg_headers_no_lock(struct mailmbox_folder * folder, uint32_t num, char ** result, size_t * result_len); /* append message */ int mailmbox_append_message_list_no_lock(struct mailmbox_folder * folder, carray * append_tab); int mailmbox_expunge_no_lock(struct mailmbox_folder * folder); #ifdef __cplusplus } #endif #endif diff --git a/kmicromail/libetpan/include/libetpan/mailmbox_types.h b/kmicromail/libetpan/include/libetpan/mailmbox_types.h index dd6758c..bd6ee30 100644 --- a/kmicromail/libetpan/include/libetpan/mailmbox_types.h +++ b/kmicromail/libetpan/include/libetpan/mailmbox_types.h @@ -1,142 +1,143 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #ifndef MAILMBOX_TYPES_H #define MAILMBOX_TYPES_H #ifdef __cplusplus extern "C" { #endif #include <sys/types.h> #include <libetpan/libetpan-config.h> #include <libetpan/mailimf.h> #include <libetpan/carray.h> #include <libetpan/chash.h> enum { MAILMBOX_NO_ERROR = 0, MAILMBOX_ERROR_PARSE, MAILMBOX_ERROR_INVAL, MAILMBOX_ERROR_FILE_NOT_FOUND, MAILMBOX_ERROR_MEMORY, MAILMBOX_ERROR_TEMPORARY_FILE, MAILMBOX_ERROR_FILE, MAILMBOX_ERROR_MSG_NOT_FOUND, MAILMBOX_ERROR_READONLY, }; struct mailmbox_folder { char mb_filename[PATH_MAX]; time_t mb_mtime; int mb_fd; int mb_read_only; int mb_no_uid; int mb_changed; unsigned int mb_deleted_count; char * mb_mapping; size_t mb_mapping_size; uint32_t mb_written_uid; uint32_t mb_max_uid; chash * mb_hash; carray * mb_tab; }; struct mailmbox_folder * mailmbox_folder_new(const char * mb_filename); void mailmbox_folder_free(struct mailmbox_folder * folder); struct mailmbox_msg_info { unsigned int msg_index; uint32_t msg_uid; int msg_written_uid; int msg_deleted; size_t msg_start; size_t msg_start_len; size_t msg_headers; size_t msg_headers_len; size_t msg_body; size_t msg_body_len; size_t msg_size; size_t msg_padding; }; int mailmbox_msg_info_update(struct mailmbox_folder * folder, size_t msg_start, size_t msg_start_len, size_t msg_headers, size_t msg_headers_len, size_t msg_body, size_t msg_body_len, size_t msg_size, size_t msg_padding, uint32_t msg_uid); struct mailmbox_msg_info * mailmbox_msg_info_new(size_t msg_start, size_t msg_start_len, size_t msg_headers, size_t msg_headers_len, size_t msg_body, size_t msg_body_len, size_t msg_size, size_t msg_padding, uint32_t msg_uid); void mailmbox_msg_info_free(struct mailmbox_msg_info * info); struct mailmbox_append_info { const char * ai_message; size_t ai_size; + unsigned int ai_uid; }; struct mailmbox_append_info * mailmbox_append_info_new(const char * ai_message, size_t ai_size); void mailmbox_append_info_free(struct mailmbox_append_info * info); #ifdef __cplusplus } #endif #endif diff --git a/kmicromail/libetpan/include/libetpan/mailmh.h b/kmicromail/libetpan/include/libetpan/mailmh.h index 40432cb..00199b8 100644 --- a/kmicromail/libetpan/include/libetpan/mailmh.h +++ b/kmicromail/libetpan/include/libetpan/mailmh.h @@ -1,143 +1,150 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #ifndef MAILMH_H #define MAILMH_H #ifdef __cplusplus extern "C" { #endif #include <sys/types.h> #include <inttypes.h> #include <libetpan/carray.h> #include <libetpan/cinthash.h> #include <libetpan/chash.h> enum { MAILMH_NO_ERROR = 0, MAILMH_ERROR_FOLDER, MAILMH_ERROR_MEMORY, MAILMH_ERROR_FILE, MAILMH_ERROR_COULD_NOT_ALLOC_MSG, MAILMH_ERROR_RENAME, MAILMH_ERROR_MSG_NOT_FOUND, }; struct mailmh { struct mailmh_folder * mh_main; }; struct mailmh_msg_info { unsigned int msg_array_index; uint32_t msg_index; size_t msg_size; time_t msg_mtime; }; struct mailmh_folder { char * fl_filename; unsigned int fl_array_index; char * fl_name; time_t fl_mtime; struct mailmh_folder * fl_parent; uint32_t fl_max_index; carray * fl_msgs_tab; #if 0 cinthash_t * fl_msgs_hash; #endif chash * fl_msgs_hash; carray * fl_subfolders_tab; chash * fl_subfolders_hash; }; struct mailmh * mailmh_new(const char * foldername); void mailmh_free(struct mailmh * f); struct mailmh_msg_info * mailmh_msg_info_new(uint32_t index, size_t size, time_t mtime); void mailmh_msg_info_free(struct mailmh_msg_info * msg_info); struct mailmh_folder * mailmh_folder_new(struct mailmh_folder * parent, const char * name); void mailmh_folder_free(struct mailmh_folder * folder); int mailmh_folder_add_subfolder(struct mailmh_folder * parent, const char * name); struct mailmh_folder * mailmh_folder_find(struct mailmh_folder * root, const char * filename); int mailmh_folder_remove_subfolder(struct mailmh_folder * folder); int mailmh_folder_rename_subfolder(struct mailmh_folder * src_folder, struct mailmh_folder * dst_folder, const char * new_name); int mailmh_folder_get_message_filename(struct mailmh_folder * folder, uint32_t index, char ** result); int mailmh_folder_get_message_fd(struct mailmh_folder * folder, uint32_t index, int flags, int * result); int mailmh_folder_get_message_size(struct mailmh_folder * folder, uint32_t index, size_t * result); +int mailmh_folder_add_message_uid(struct mailmh_folder * folder, + const char * message, size_t size, + uint32_t * pindex); + int mailmh_folder_add_message(struct mailmh_folder * folder, const char * message, size_t size); +int mailmh_folder_add_message_file_uid(struct mailmh_folder * folder, + int fd, uint32_t * pindex); + int mailmh_folder_add_message_file(struct mailmh_folder * folder, int fd); int mailmh_folder_remove_message(struct mailmh_folder * folder, uint32_t index); int mailmh_folder_move_message(struct mailmh_folder * dest_folder, struct mailmh_folder * src_folder, uint32_t index); int mailmh_folder_update(struct mailmh_folder * folder); unsigned int mailmh_folder_get_message_number(struct mailmh_folder * folder); #ifdef __cplusplus } #endif #endif diff --git a/kmicromail/libetpan/include/libetpan/mailstorage.h b/kmicromail/libetpan/include/libetpan/mailstorage.h index d56aef1..4c57883 100644 --- a/kmicromail/libetpan/include/libetpan/mailstorage.h +++ b/kmicromail/libetpan/include/libetpan/mailstorage.h @@ -1,98 +1,99 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #ifndef MAIL_STORAGE_H #define MAIL_STORAGE_H #include <libetpan/maildriver_types.h> #include <libetpan/mailstorage_types.h> #ifdef __cplusplus extern "C" { #endif /* storage */ /* mailstorage_new This function creates an empty storage. This storage have to be initialized. The "driver" and "data" fields should be initialized. @param id is the name of the storage. It can be NULL. The given parameter is no more needed when the creation is finished. The given string is duplicated. @return The mail storage is returned. */ struct mailstorage * mailstorage_new(char * sto_id); void mailstorage_free(struct mailstorage * storage); /* session will be initialized on success. */ int mailstorage_connect(struct mailstorage * storage); void mailstorage_disconnect(struct mailstorage * storage); +int mailstorage_noop(struct mailstorage * storage); + /* folder */ struct mailfolder * mailfolder_new(struct mailstorage * fld_storage, char * fld_pathname, char * fld_virtual_name); void mailfolder_free(struct mailfolder * folder); int mailfolder_add_child(struct mailfolder * parent, struct mailfolder * child); int mailfolder_detach_parent(struct mailfolder * folder); int mailfolder_connect(struct mailfolder * folder); void mailfolder_disconnect(struct mailfolder * folder); - #ifdef __cplusplus } #endif #endif diff --git a/kmicromail/libetpan/maildir/maildir.c b/kmicromail/libetpan/maildir/maildir.c index 320ef81..0e038b1 100644 --- a/kmicromail/libetpan/maildir/maildir.c +++ b/kmicromail/libetpan/maildir/maildir.c @@ -1,710 +1,729 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001 - 2003 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "maildir.h" #include <string.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <sys/types.h> #include <dirent.h> #include <time.h> #include <sys/stat.h> #include <sys/mman.h> #ifdef LIBETPAN_SYSTEM_BASENAME #include <libgen.h> #endif /* We suppose the maildir mailbox remains on one unique filesystem. */ struct maildir * maildir_new(const char * path) { struct maildir * md; md = malloc(sizeof(* md)); if (md == NULL) goto err; md->mdir_counter = 0; md->mdir_mtime_new = (time_t) -1; md->mdir_mtime_cur = (time_t) -1; md->mdir_pid = getpid(); gethostname(md->mdir_hostname, sizeof(md->mdir_hostname)); strncpy(md->mdir_path, path, sizeof(md->mdir_path)); md->mdir_path[PATH_MAX - 1] = '\0'; md->mdir_msg_list = carray_new(128); if (md->mdir_msg_list == NULL) goto free; md->mdir_msg_hash = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYNONE); if (md->mdir_msg_hash == NULL) goto free_msg_list; return md; free_msg_list: carray_free(md->mdir_msg_list); free: free(md); err: return NULL; } static void maildir_flush(struct maildir * md, int msg_new); void maildir_free(struct maildir * md) { maildir_flush(md, 0); maildir_flush(md, 1); chash_free(md->mdir_msg_hash); carray_free(md->mdir_msg_list); free(md); } #define MAX_TRY_ALLOC 32 static char * maildir_get_new_message_filename(struct maildir * md, char * tmpfile) { char filename[PATH_MAX]; char basename[PATH_MAX]; int k; time_t now; now = time(NULL); k = 0; while (k < MAX_TRY_ALLOC) { snprintf(basename, sizeof(basename), "%lu.%u_%u.%s", (unsigned long) now, md->mdir_pid, md->mdir_counter, md->mdir_hostname); snprintf(filename, sizeof(filename), "%s/tmp/%s", md->mdir_path, basename); if (link(tmpfile, filename) == 0) { char * dup_filename; dup_filename = strdup(filename); if (dup_filename == NULL) { unlink(filename); return NULL; } unlink(tmpfile); md->mdir_counter ++; return dup_filename; } md->mdir_counter ++; k ++; } return NULL; } static void msg_free(struct maildir_msg * msg) { free(msg->msg_uid); free(msg->msg_filename); free(msg); } /* msg_new() filename is given without path */ static struct maildir_msg * msg_new(char * filename, int new_msg) { struct maildir_msg * msg; char * p; int flags; size_t uid_len; char * begin_uid; /* name of file : xxx-xxx_xxx-xxx:2,SRFT */ msg = malloc(sizeof(* msg)); if (msg == NULL) goto err; msg->msg_filename = strdup(filename); if (msg->msg_filename == NULL) goto free; begin_uid = filename; uid_len = strlen(begin_uid); flags = 0; p = strstr(filename, ":2,"); if (p != NULL) { uid_len = p - begin_uid; p += 3; /* parse flags */ while (* p != '\0') { switch (* p) { case 'S': flags |= MAILDIR_FLAG_SEEN; break; case 'R': flags |= MAILDIR_FLAG_REPLIED; break; case 'F': flags |= MAILDIR_FLAG_FLAGGED; break; case 'T': flags |= MAILDIR_FLAG_TRASHED; break; } p ++; } } if (new_msg) flags |= MAILDIR_FLAG_NEW; msg->msg_flags = flags; msg->msg_uid = malloc(uid_len + 1); if (msg->msg_uid == NULL) goto free_filename; strncpy(msg->msg_uid, begin_uid, uid_len); msg->msg_uid[uid_len] = '\0'; return msg; free_filename: free(msg->msg_filename); free: free(msg); err: return NULL; } static void maildir_flush(struct maildir * md, int msg_new) { unsigned int i; i = 0; while (i < carray_count(md->mdir_msg_list)) { struct maildir_msg * msg; int delete; msg = carray_get(md->mdir_msg_list, i); if (msg_new) { delete = 0; if ((msg->msg_flags & MAILDIR_FLAG_NEW) != 0) delete = 1; } else { delete = 1; if ((msg->msg_flags & MAILDIR_FLAG_NEW) != 0) delete = 0; } if (delete) { chashdatum key; key.data = msg->msg_uid; key.len = strlen(msg->msg_uid); chash_delete(md->mdir_msg_hash, &key, NULL); carray_delete(md->mdir_msg_list, i); msg_free(msg); } else { i ++; } } } static int add_message(struct maildir * md, char * filename, int is_new) { struct maildir_msg * msg; chashdatum key; chashdatum value; unsigned int i; int res; int r; msg = msg_new(filename, is_new); if (msg == NULL) { res = MAILDIR_ERROR_MEMORY; goto err; } r = carray_add(md->mdir_msg_list, msg, &i); if (r < 0) { res = MAILDIR_ERROR_MEMORY; goto free_msg; } key.data = msg->msg_uid; key.len = strlen(msg->msg_uid); value.data = msg; value.len = 0; r = chash_set(md->mdir_msg_hash, &key, &value, NULL); if (r < 0) { res = MAILDIR_ERROR_MEMORY; goto delete; } return MAILDIR_NO_ERROR; delete: carray_delete(md->mdir_msg_list, i); free_msg: msg_free(msg); err: return res; } static int add_directory(struct maildir * md, char * path, int is_new) { DIR * d; struct dirent * entry; int res; int r; char filename[PATH_MAX]; d = opendir(path); if (d == NULL) { res = MAILDIR_ERROR_DIRECTORY; goto err; } while ((entry = readdir(d)) != NULL) { struct stat stat_info; snprintf(filename, sizeof(filename), "%s/%s", path, entry->d_name); r = stat(filename, &stat_info); if (r < 0) continue; if (S_ISDIR(stat_info.st_mode)) continue; r = add_message(md, entry->d_name, is_new); if (r != MAILDIR_NO_ERROR) { /* ignore errors */ } } closedir(d); return MAILDIR_NO_ERROR; err: return res; } int maildir_update(struct maildir * md) { struct stat stat_info; char path_new[PATH_MAX]; char path_cur[PATH_MAX]; int r; int res; snprintf(path_new, sizeof(path_new), "%s/new", md->mdir_path); snprintf(path_cur, sizeof(path_cur), "%s/cur", md->mdir_path); /* did new/ changed ? */ r = stat(path_new, &stat_info); if (r < 0) { res = MAILDIR_ERROR_DIRECTORY; goto free; } if (md->mdir_mtime_new != stat_info.st_mtime) { md->mdir_mtime_new = stat_info.st_mtime; maildir_flush(md, 1); /* messages in new */ r = add_directory(md, path_new, 1); if (r != MAILDIR_NO_ERROR) { res = r; goto free; } } /* did cur/ changed ? */ r = stat(path_cur, &stat_info); if (r < 0) { res = MAILDIR_ERROR_DIRECTORY; goto free; } if (md->mdir_mtime_cur != stat_info.st_mtime) { md->mdir_mtime_cur = stat_info.st_mtime; maildir_flush(md, 0); /* messages in cur */ r = add_directory(md, path_cur, 0); if (r != MAILDIR_NO_ERROR) { res = r; goto free; } } return MAILDIR_NO_ERROR; free: maildir_flush(md, 0); maildir_flush(md, 1); md->mdir_mtime_cur = (time_t) -1; md->mdir_mtime_new = (time_t) -1; return res; } #ifndef LIBETPAN_SYSTEM_BASENAME static char * libetpan_basename(char * filename) { char * next; char * p; p = filename; next = strchr(p, '/'); while (next != NULL) { p = next; next = strchr(p + 1, '/'); } if (p == filename) return filename; else return p + 1; } #else #define libetpan_basename(a) basename(a) #endif -int maildir_message_add(struct maildir * md, - const char * message, size_t size) +int maildir_message_add_uid(struct maildir * md, + const char * message, size_t size, + char * uid, size_t max_uid_len) { char path_new[PATH_MAX]; char tmpname[PATH_MAX]; int fd; int r; char * mapping; char * delivery_tmp_name; char * delivery_tmp_basename; char delivery_new_name[PATH_MAX]; char * delivery_new_basename; int res; struct stat stat_info; r = maildir_update(md); if (r != MAILDIR_NO_ERROR) { res = r; goto err; } /* write to tmp/ with a classic temporary file */ - snprintf(tmpname, sizeof(tmpname), "%s/tmp/etpan-maildir-XXXXXX", md->mdir_path); + snprintf(tmpname, sizeof(tmpname), "%s/tmp/etpan-maildir-XXXXXX", + md->mdir_path); fd = mkstemp(tmpname); if (fd < 0) { res = MAILDIR_ERROR_FILE; goto err; } r = ftruncate(fd, size); if (r < 0) { res = MAILDIR_ERROR_FILE; goto close; } mapping = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (mapping == MAP_FAILED) { res = MAILDIR_ERROR_FILE; goto close; } memcpy(mapping, message, size); msync(mapping, size, MS_SYNC); munmap(mapping, size); close(fd); /* write to tmp/ with maildir standard name */ delivery_tmp_name = maildir_get_new_message_filename(md, tmpname); if (delivery_tmp_name == NULL) { res = MAILDIR_ERROR_FILE; goto unlink; } /* write to new/ with maildir standard name */ strncpy(tmpname, delivery_tmp_name, sizeof(tmpname)); tmpname[sizeof(tmpname) - 1] = '\0'; delivery_tmp_basename = libetpan_basename(tmpname); snprintf(delivery_new_name, sizeof(delivery_new_name), "%s/new/%s", md->mdir_path, delivery_tmp_basename); r = link(delivery_tmp_name, delivery_new_name); if (r < 0) { res = MAILDIR_ERROR_FILE; goto unlink_tmp; } snprintf(path_new, sizeof(path_new), "%s/new", md->mdir_path); r = stat(path_new, &stat_info); if (r < 0) { unlink(delivery_new_name); res = MAILDIR_ERROR_FILE; goto unlink_tmp; } md->mdir_mtime_new = stat_info.st_mtime; delivery_new_basename = libetpan_basename(delivery_new_name); r = add_message(md, delivery_new_basename, 1); if (r != MAILDIR_NO_ERROR) { unlink(delivery_new_name); res = MAILDIR_ERROR_FILE; goto unlink_tmp; } + if (uid != NULL) + strncpy(uid, delivery_new_basename, max_uid_len); + unlink(delivery_tmp_name); free(delivery_tmp_name); return MAILDIR_NO_ERROR; unlink_tmp: unlink(delivery_tmp_name); free(delivery_tmp_name); goto err; close: close(fd); unlink: unlink(tmpname); err: return res; } -int maildir_message_add_file(struct maildir * md, int fd) +int maildir_message_add(struct maildir * md, + const char * message, size_t size) +{ + return maildir_message_add_uid(md, message, size, + NULL, 0); +} + +int maildir_message_add_file_uid(struct maildir * md, int fd, + char * uid, size_t max_uid_len) { char * message; struct stat buf; int r; if (fstat(fd, &buf) == -1) return MAILDIR_ERROR_FILE; message = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (message == MAP_FAILED) return MAILDIR_ERROR_FILE; - r = maildir_message_add(md, message, buf.st_size); + r = maildir_message_add_uid(md, message, buf.st_size, uid, max_uid_len); munmap(message, buf.st_size); return r; } +int maildir_message_add_file(struct maildir * md, int fd) +{ + return maildir_message_add_file_uid(md, fd, + NULL, 0); +} + char * maildir_message_get(struct maildir * md, const char * uid) { chashdatum key; chashdatum value; char filename[PATH_MAX]; char * dup_filename; struct maildir_msg * msg; char * dir; int r; key.data = (void *) uid; key.len = strlen(uid); r = chash_get(md->mdir_msg_hash, &key, &value); if (r < 0) return NULL; msg = value.data; if ((msg->msg_flags & MAILDIR_FLAG_NEW) != 0) dir = "new"; else dir = "cur"; snprintf(filename, sizeof(filename), "%s/%s/%s", md->mdir_path, dir, msg->msg_filename); dup_filename = strdup(filename); if (dup_filename == NULL) return NULL; return dup_filename; } int maildir_message_remove(struct maildir * md, const char * uid) { chashdatum key; chashdatum value; char filename[PATH_MAX]; struct maildir_msg * msg; char * dir; int r; int res; key.data = (void *) uid; key.len = strlen(uid); r = chash_get(md->mdir_msg_hash, &key, &value); if (r < 0) { res = MAILDIR_ERROR_NOT_FOUND; goto err; } msg = value.data; if ((msg->msg_flags & MAILDIR_FLAG_NEW) != 0) dir = "new"; else dir = "cur"; snprintf(filename, sizeof(filename), "%s/%s/%s", md->mdir_path, dir, msg->msg_filename); r = unlink(filename); if (r < 0) { res = MAILDIR_ERROR_FILE; goto err; } return MAILDIR_NO_ERROR; err: return res; } int maildir_message_change_flags(struct maildir * md, const char * uid, int new_flags) { chashdatum key; chashdatum value; char filename[PATH_MAX]; struct maildir_msg * msg; char * dir; int r; char new_filename[PATH_MAX]; char flag_str[5]; size_t i; int res; key.data = (void *) uid; key.len = strlen(uid); r = chash_get(md->mdir_msg_hash, &key, &value); if (r < 0) { res = MAILDIR_ERROR_NOT_FOUND; goto err; } msg = value.data; if ((msg->msg_flags & MAILDIR_FLAG_NEW) != 0) dir = "new"; else dir = "cur"; snprintf(filename, sizeof(filename), "%s/%s/%s", md->mdir_path, dir, msg->msg_filename); if ((new_flags & MAILDIR_FLAG_NEW) != 0) dir = "new"; else dir = "cur"; i = 0; if ((new_flags & MAILDIR_FLAG_SEEN) != 0) { flag_str[i] = 'S'; i ++; } if ((new_flags & MAILDIR_FLAG_REPLIED) != 0) { flag_str[i] = 'R'; i ++; } if ((new_flags & MAILDIR_FLAG_FLAGGED) != 0) { flag_str[i] = 'F'; i ++; } if ((new_flags & MAILDIR_FLAG_TRASHED) != 0) { flag_str[i] = 'T'; i ++; } flag_str[i] = 0; if (flag_str[0] == '\0') snprintf(new_filename, sizeof(new_filename), "%s/%s/%s", md->mdir_path, dir, msg->msg_uid); else snprintf(new_filename, sizeof(new_filename), "%s/%s/%s:2,%s", md->mdir_path, dir, msg->msg_uid, flag_str); if (strcmp(filename, new_filename) == 0) return MAILDIR_NO_ERROR; r = link(filename, new_filename); if (r < 0) { res = MAILDIR_ERROR_FILE; goto err; } unlink(filename); return MAILDIR_NO_ERROR; err: return res; } diff --git a/kmicromail/libetpan/maildir/maildir.h b/kmicromail/libetpan/maildir/maildir.h index b782484..268dda1 100644 --- a/kmicromail/libetpan/maildir/maildir.h +++ b/kmicromail/libetpan/maildir/maildir.h @@ -1,60 +1,67 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001 - 2003 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #ifndef MAILDIR_H #define MAILDIR_H #include <libetpan/maildir_types.h> struct maildir * maildir_new(const char * path); void maildir_free(struct maildir * md); int maildir_update(struct maildir * md); +int maildir_message_add_uid(struct maildir * md, + const char * message, size_t size, + char * uid, size_t max_uid_len); + int maildir_message_add(struct maildir * md, const char * message, size_t size); +int maildir_message_add_file_uid(struct maildir * md, int fd, + char * uid, size_t max_uid_len); + int maildir_message_add_file(struct maildir * md, int fd); char * maildir_message_get(struct maildir * md, const char * uid); int maildir_message_remove(struct maildir * md, const char * uid); int maildir_message_change_flags(struct maildir * md, const char * uid, int new_flags); #endif diff --git a/kmicromail/libetpan/mbox/mailmbox.c b/kmicromail/libetpan/mbox/mailmbox.c index 280c313..b3fce02 100644 --- a/kmicromail/libetpan/mbox/mailmbox.c +++ b/kmicromail/libetpan/mbox/mailmbox.c @@ -1,1424 +1,1439 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "mailmbox.h" #include <sys/file.h> #include <sys/stat.h> #include <unistd.h> #include <sys/mman.h> #include <fcntl.h> #include <time.h> #include <sys/types.h> #include <unistd.h> #include <string.h> #include <ctype.h> #include <stdlib.h> #include <stdio.h> #include "libetpan-config.h" #include "mmapstring.h" #include "mailmbox_parse.h" #include "maillock.h" /* http://www.qmail.org/qmail-manual-html/man5/mbox.html RFC 2076 */ #define TMPDIR "/tmp" /* mbox is a file with a corresponding filename */ #define UID_HEADER "X-LibEtPan-UID:" #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif int mailmbox_write_lock(struct mailmbox_folder * folder) { int r; if (folder->mb_read_only) return MAILMBOX_ERROR_READONLY; r = maillock_write_lock(folder->mb_filename, folder->mb_fd); if (r == 0) return MAILMBOX_NO_ERROR; else return MAILMBOX_ERROR_FILE; } int mailmbox_write_unlock(struct mailmbox_folder * folder) { int r; r = maillock_write_unlock(folder->mb_filename, folder->mb_fd); if (r == 0) return MAILMBOX_NO_ERROR; else return MAILMBOX_ERROR_FILE; } int mailmbox_read_lock(struct mailmbox_folder * folder) { int r; r = maillock_read_lock(folder->mb_filename, folder->mb_fd); if (r == 0) return MAILMBOX_NO_ERROR; else return MAILMBOX_ERROR_FILE; } int mailmbox_read_unlock(struct mailmbox_folder * folder) { int r; r = maillock_read_unlock(folder->mb_filename, folder->mb_fd); if (r == 0) return MAILMBOX_NO_ERROR; else return MAILMBOX_ERROR_FILE; } /* map the file into memory. the file must be locked. */ int mailmbox_map(struct mailmbox_folder * folder) { char * str; struct stat buf; int res; int r; r = stat(folder->mb_filename, &buf); if (r < 0) { res = MAILMBOX_ERROR_FILE; goto err; } if (folder->mb_read_only) str = (char *) mmap(0, buf.st_size, PROT_READ, MAP_PRIVATE, folder->mb_fd, 0); else str = (char *) mmap(0, buf.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, folder->mb_fd, 0); if (str == MAP_FAILED) { res = MAILMBOX_ERROR_FILE; goto err; } folder->mb_mapping = str; folder->mb_mapping_size = buf.st_size; return MAILMBOX_NO_ERROR; err: return res; } /* unmap the file */ void mailmbox_unmap(struct mailmbox_folder * folder) { munmap(folder->mb_mapping, folder->mb_mapping_size); folder->mb_mapping = NULL; folder->mb_mapping_size = 0; } void mailmbox_sync(struct mailmbox_folder * folder) { msync(folder->mb_mapping, folder->mb_mapping_size, MS_SYNC); } void mailmbox_timestamp(struct mailmbox_folder * folder) { int r; struct stat buf; r = stat(folder->mb_filename, &buf); if (r < 0) folder->mb_mtime = (time_t) -1; else folder->mb_mtime = buf.st_mtime; } /* open the file */ int mailmbox_open(struct mailmbox_folder * folder) { int fd; int read_only; + fd = -1; + read_only = TRUE; + if (!folder->mb_read_only) { read_only = FALSE; fd = open(folder->mb_filename, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); } if (folder->mb_read_only || (fd < 0)) { read_only = TRUE; fd = open(folder->mb_filename, O_RDONLY); if (fd < 0) return MAILMBOX_ERROR_FILE_NOT_FOUND; } folder->mb_fd = fd; folder->mb_read_only = read_only; return MAILMBOX_NO_ERROR; } /* close the file */ void mailmbox_close(struct mailmbox_folder * folder) { close(folder->mb_fd); folder->mb_fd = -1; } static int mailmbox_validate_lock(struct mailmbox_folder * folder, int (* custom_lock)(struct mailmbox_folder *), int (* custom_unlock)(struct mailmbox_folder *)) { struct stat buf; int res; int r; r = stat(folder->mb_filename, &buf); if (r < 0) { buf.st_mtime = (time_t) -1; } if ((buf.st_mtime != folder->mb_mtime) || ((size_t) buf.st_size != folder->mb_mapping_size)) { int r; mailmbox_unmap(folder); mailmbox_close(folder); r = mailmbox_open(folder); if (r != MAILMBOX_NO_ERROR) { res = r; goto err; } r = custom_lock(folder); if (r != MAILMBOX_NO_ERROR) { res = r; goto err; } r = mailmbox_map(folder); if (r != MAILMBOX_NO_ERROR) { res = r; goto err_unlock; } r = mailmbox_parse(folder); if (r != MAILMBOX_NO_ERROR) { res = r; goto err_unlock; } folder->mb_mtime = buf.st_mtime; return MAILMBOX_NO_ERROR; } else { r = custom_lock(folder); if (r != MAILMBOX_NO_ERROR) { res = r; goto err; } } return MAILMBOX_NO_ERROR; err_unlock: custom_unlock(folder); err: return res; } int mailmbox_validate_write_lock(struct mailmbox_folder * folder) { return mailmbox_validate_lock(folder, mailmbox_write_lock, mailmbox_write_unlock); } int mailmbox_validate_read_lock(struct mailmbox_folder * folder) { return mailmbox_validate_lock(folder, mailmbox_read_lock, mailmbox_read_unlock); } /* ********************************************************************** */ /* append messages */ #define MAX_FROM_LINE_SIZE 256 static inline size_t get_line(const char * line, size_t length, const char ** pnext_line, size_t * pcount) { size_t count; count = 0; while (1) { if (length == 0) break; if (* line == '\r') { line ++; count ++; length --; if (length > 0) { if (* line == '\n') { line ++; count ++; length --; break; } } } else if (* line == '\n') { line ++; count ++; length --; break; } else { line ++; length --; count ++; } } * pnext_line = line; * pcount = count; return count; } /* TODO : should strip \r\n if any see also in write_fixed_line */ static inline size_t get_fixed_line_size(const char * line, size_t length, const char ** pnext_line, size_t * pcount, size_t * pfixed_count) { size_t count; const char * next_line; size_t fixed_count; if (!get_line(line, length, &next_line, &count)) return 0; fixed_count = count; if (count >= 5) { if (line[0] == 'F') { if (strncmp(line, "From ", 5) == 0) fixed_count ++; } } * pnext_line = next_line; * pcount = count; * pfixed_count = fixed_count; return count; } static size_t get_fixed_message_size(const char * message, size_t size, uint32_t uid, int force_no_uid) { size_t fixed_size; size_t cur_token; size_t left; const char * next; const char * cur; int end; int r; uint32_t tmp_uid; cur_token = 0; fixed_size = 0; /* headers */ end = FALSE; while (!end) { size_t begin; int ignore; ignore = FALSE; begin = cur_token; if (cur_token + strlen(UID_HEADER) <= size) { if (message[cur_token] == 'X') { if (strncasecmp(message + cur_token, UID_HEADER, strlen(UID_HEADER)) == 0) { ignore = TRUE; } } } r = mailimf_ignore_field_parse(message, size, &cur_token); switch (r) { case MAILIMF_NO_ERROR: if (!ignore) fixed_size += cur_token - begin; break; case MAILIMF_ERROR_PARSE: default: end = TRUE; break; } } if (!force_no_uid) { /* UID header */ fixed_size += strlen(UID_HEADER " \r\n"); tmp_uid = uid; while (tmp_uid >= 10) { tmp_uid /= 10; fixed_size ++; } fixed_size ++; } /* body */ left = size - cur_token; next = message + cur_token; while (left > 0) { size_t count; size_t fixed_count; cur = next; if (!get_fixed_line_size(cur, left, &next, &count, &fixed_count)) break; fixed_size += fixed_count; left -= count; } return fixed_size; } static inline char * write_fixed_line(char * str, const char * line, size_t length, const char ** pnext_line, size_t * pcount) { size_t count; const char * next_line; if (!get_line(line, length, &next_line, &count)) return str; if (count >= 5) { if (line[0] == 'F') { if (strncmp(line, "From ", 5) == 0) { * str = '>'; str ++; } } } memcpy(str, line, count); * pnext_line = next_line; * pcount = count; str += count; return str; } static char * write_fixed_message(char * str, const char * message, size_t size, uint32_t uid, int force_no_uid) { size_t fixed_size; size_t cur_token; size_t left; int end; int r; const char * cur_src; size_t numlen; cur_token = 0; fixed_size = 0; /* headers */ end = FALSE; while (!end) { size_t begin; int ignore; ignore = FALSE; begin = cur_token; if (cur_token + strlen(UID_HEADER) <= size) { if (message[cur_token] == 'X') { if (strncasecmp(message + cur_token, UID_HEADER, strlen(UID_HEADER)) == 0) { ignore = TRUE; } } } r = mailimf_ignore_field_parse(message, size, &cur_token); switch (r) { case MAILIMF_NO_ERROR: if (!ignore) { memcpy(str, message + begin, cur_token - begin); str += cur_token - begin; } break; case MAILIMF_ERROR_PARSE: default: end = TRUE; break; } } if (!force_no_uid) { /* UID header */ memcpy(str, UID_HEADER " ", strlen(UID_HEADER " ")); str += strlen(UID_HEADER " "); numlen = snprintf(str, 20, "%i\r\n", uid); str += numlen; } /* body */ cur_src = message + cur_token; left = size - cur_token; while (left > 0) { size_t count; const char * next; str = write_fixed_line(str, cur_src, left, &next, &count); cur_src = next; left -= count; } return str; } #define DEFAULT_FROM_LINE "From - Wed Jun 30 21:49:08 1993\n" int mailmbox_append_message_list_no_lock(struct mailmbox_folder * folder, carray * append_tab) { size_t extra_size; int r; char from_line[MAX_FROM_LINE_SIZE] = DEFAULT_FROM_LINE; struct tm time_info; time_t date; int res; size_t old_size; char * str; unsigned int i; size_t from_size; size_t maxuid; size_t left; size_t crlf_count; if (folder->mb_read_only) { res = MAILMBOX_ERROR_READONLY; goto err; } date = time(NULL); from_size = strlen(DEFAULT_FROM_LINE); if (localtime_r(&date, &time_info) != NULL) from_size = strftime(from_line, MAX_FROM_LINE_SIZE, "From - %c\n", &time_info); maxuid = /* */ folder->mb_max_uid; extra_size = 0; for(i = 0 ; i < carray_count(append_tab) ; i ++) { struct mailmbox_append_info * info; info = carray_get(append_tab, i); extra_size += from_size; extra_size += get_fixed_message_size(info->ai_message, info->ai_size, folder->mb_max_uid + i + 1, folder->mb_no_uid); extra_size += 2; /* CR LF */ + + info->ai_uid = folder->mb_max_uid + i + 1; } left = folder->mb_mapping_size; crlf_count = 0; while (left >= 1) { if (folder->mb_mapping[left - 1] == '\n') { crlf_count ++; left --; } else if (folder->mb_mapping[left - 1] == '\r') { left --; } else break; if (crlf_count == 2) break; } old_size = folder->mb_mapping_size; mailmbox_unmap(folder); if (old_size != 0) { if (crlf_count != 2) extra_size += (2 - crlf_count) * 2; } r = ftruncate(folder->mb_fd, extra_size + old_size); if (r < 0) { mailmbox_map(folder); res = MAILMBOX_ERROR_FILE; goto err; } r = mailmbox_map(folder); if (r < 0) { ftruncate(folder->mb_fd, old_size); return MAILMBOX_ERROR_FILE; } str = folder->mb_mapping + old_size; if (old_size != 0) { for(i = 0 ; i < 2 - crlf_count ; i ++) { * str = '\r'; str ++; * str = '\n'; str ++; } } for(i = 0 ; i < carray_count(append_tab) ; i ++) { struct mailmbox_append_info * info; info = carray_get(append_tab, i); memcpy(str, from_line, from_size); str += strlen(from_line); str = write_fixed_message(str, info->ai_message, info->ai_size, folder->mb_max_uid + i + 1, folder->mb_no_uid); * str = '\r'; str ++; * str = '\n'; str ++; } folder->mb_max_uid += carray_count(append_tab); return MAILMBOX_NO_ERROR; err: return res; } int mailmbox_append_message_list(struct mailmbox_folder * folder, carray * append_tab) { int r; int res; size_t cur_token; r = mailmbox_validate_write_lock(folder); if (r != MAILMBOX_NO_ERROR) { res = r; goto err; } r = mailmbox_expunge_no_lock(folder); if (r != MAILMBOX_NO_ERROR) { res = r; goto unlock; } cur_token = folder->mb_mapping_size; r = mailmbox_append_message_list_no_lock(folder, append_tab); if (r != MAILMBOX_NO_ERROR) { res = r; goto unlock; } mailmbox_sync(folder); r = mailmbox_parse_additionnal(folder, &cur_token); if (r != MAILMBOX_NO_ERROR) { res = r; goto unlock; } mailmbox_timestamp(folder); mailmbox_write_unlock(folder); return MAILMBOX_NO_ERROR; unlock: mailmbox_write_unlock(folder); err: return res; } int -mailmbox_append_message(struct mailmbox_folder * folder, - const char * data, size_t len) +mailmbox_append_message_uid(struct mailmbox_folder * folder, + const char * data, size_t len, unsigned int * puid) { carray * tab; struct mailmbox_append_info * append_info; int res; int r; tab = carray_new(1); if (tab == NULL) { res = MAILMBOX_ERROR_MEMORY; goto err; } append_info = mailmbox_append_info_new(data, len); if (append_info == NULL) { res = MAILMBOX_ERROR_MEMORY; goto free_list; } r = carray_add(tab, append_info, NULL); if (r < 0) { res = MAILMBOX_ERROR_MEMORY; goto free_append_info; } r = mailmbox_append_message_list(folder, tab); + if (puid != NULL) + * puid = append_info->ai_uid; + mailmbox_append_info_free(append_info); carray_free(tab); return r; free_append_info: mailmbox_append_info_free(append_info); free_list: carray_free(tab); err: return res; } +int +mailmbox_append_message(struct mailmbox_folder * folder, + const char * data, size_t len) +{ + return mailmbox_append_message_uid(folder, data, len, NULL); +} + /* ********************************************************************** */ int mailmbox_fetch_msg_no_lock(struct mailmbox_folder * folder, uint32_t num, char ** result, size_t * result_len) { struct mailmbox_msg_info * info; int res; chashdatum key; chashdatum data; int r; key.data = # key.len = sizeof(num); r = chash_get(folder->mb_hash, &key, &data); if (r < 0) { res = MAILMBOX_ERROR_MSG_NOT_FOUND; goto err; } info = data.data; if (info->msg_deleted) { res = MAILMBOX_ERROR_MSG_NOT_FOUND; goto err; } * result = folder->mb_mapping + info->msg_headers; * result_len = info->msg_size - info->msg_start_len; return MAILMBOX_NO_ERROR; err: return res; } int mailmbox_fetch_msg_headers_no_lock(struct mailmbox_folder * folder, uint32_t num, char ** result, size_t * result_len) { struct mailmbox_msg_info * info; int res; chashdatum key; chashdatum data; int r; key.data = # key.len = sizeof(num); r = chash_get(folder->mb_hash, &key, &data); if (r < 0) { res = MAILMBOX_ERROR_MSG_NOT_FOUND; goto err; } info = data.data; if (info->msg_deleted) { res = MAILMBOX_ERROR_MSG_NOT_FOUND; goto err; } * result = folder->mb_mapping + info->msg_headers; * result_len = info->msg_headers_len; return MAILMBOX_NO_ERROR; err: return res; } int mailmbox_fetch_msg(struct mailmbox_folder * folder, uint32_t num, char ** result, size_t * result_len) { MMAPString * mmapstr; int res; char * data; size_t len; int r; size_t fixed_size; char * end; r = mailmbox_validate_read_lock(folder); if (r != MAILMBOX_NO_ERROR) { res = r; goto err; } r = mailmbox_fetch_msg_no_lock(folder, num, &data, &len); if (r != MAILMBOX_NO_ERROR) { res = r; goto unlock; } /* size with no uid */ fixed_size = get_fixed_message_size(data, len, 0, 1 /* force no uid */); #if 0 mmapstr = mmap_string_new_len(data, fixed_size); if (mmapstr == NULL) { res = MAILMBOX_ERROR_MEMORY; goto unlock; } #endif mmapstr = mmap_string_sized_new(fixed_size); if (mmapstr == NULL) { res = MAILMBOX_ERROR_MEMORY; goto unlock; } end = write_fixed_message(mmapstr->str, data, len, 0, 1 /* force no uid */); * end = '\0'; mmapstr->len = fixed_size; r = mmap_string_ref(mmapstr); if (r < 0) { mmap_string_free(mmapstr); res = MAILMBOX_ERROR_MEMORY; goto unlock; } * result = mmapstr->str; * result_len = mmapstr->len; mailmbox_read_unlock(folder); return MAILMBOX_NO_ERROR; unlock: mailmbox_read_unlock(folder); err: return res; } int mailmbox_fetch_msg_headers(struct mailmbox_folder * folder, uint32_t num, char ** result, size_t * result_len) { MMAPString * mmapstr; int res; char * data; size_t len; int r; size_t fixed_size; char * end; r = mailmbox_validate_read_lock(folder); if (r != MAILMBOX_NO_ERROR) { res = r; goto err; } r = mailmbox_fetch_msg_headers_no_lock(folder, num, &data, &len); if (r != MAILMBOX_NO_ERROR) { res = r; goto unlock; } #if 0 mmapstr = mmap_string_new_len(data, len); if (mmapstr == NULL) { res = MAILMBOX_ERROR_MEMORY; goto unlock; } #endif /* size with no uid */ fixed_size = get_fixed_message_size(data, len, 0, 1 /* force no uid */); mmapstr = mmap_string_sized_new(fixed_size); if (mmapstr == NULL) { res = MAILMBOX_ERROR_MEMORY; goto unlock; } end = write_fixed_message(mmapstr->str, data, len, 0, 1 /* force no uid */); * end = '\0'; mmapstr->len = fixed_size; r = mmap_string_ref(mmapstr); if (r < 0) { mmap_string_free(mmapstr); res = MAILMBOX_ERROR_MEMORY; goto unlock; } * result = mmapstr->str; * result_len = mmapstr->len; mailmbox_read_unlock(folder); return MAILMBOX_NO_ERROR; unlock: mailmbox_read_unlock(folder); err: return res; } void mailmbox_fetch_result_free(char * msg) { mmap_string_unref(msg); } int mailmbox_copy_msg_list(struct mailmbox_folder * dest_folder, struct mailmbox_folder * src_folder, carray * tab) { int r; int res; carray * append_tab; unsigned int i; r = mailmbox_validate_read_lock(src_folder); if (r != MAILMBOX_NO_ERROR) { res = r; goto err; } append_tab = carray_new(carray_count(tab)); if (append_tab == NULL) { res = MAILMBOX_ERROR_MEMORY; goto src_unlock; } for(i = 0 ; i < carray_count(tab) ; i ++) { struct mailmbox_append_info * append_info; char * data; size_t len; uint32_t uid; uid = * ((uint32_t *) carray_get(tab, i)); r = mailmbox_fetch_msg_no_lock(src_folder, uid, &data, &len); if (r != MAILMBOX_NO_ERROR) { res = r; goto free_list; } append_info = mailmbox_append_info_new(data, len); if (append_info == NULL) { res = MAILMBOX_ERROR_MEMORY; goto free_list; } r = carray_add(append_tab, append_info, NULL); if (r < 0) { mailmbox_append_info_free(append_info); res = MAILMBOX_ERROR_MEMORY; goto free_list; } } r = mailmbox_append_message_list(dest_folder, append_tab); if (r != MAILMBOX_NO_ERROR) { res = r; goto src_unlock; } for(i = 0 ; i < carray_count(append_tab) ; i ++) { struct mailmbox_append_info * append_info; append_info = carray_get(append_tab, i); mailmbox_append_info_free(append_info); } carray_free(append_tab); mailmbox_read_unlock(src_folder); return MAILMBOX_NO_ERROR; free_list: for(i = 0 ; i < carray_count(append_tab) ; i ++) { struct mailmbox_append_info * append_info; append_info = carray_get(append_tab, i); mailmbox_append_info_free(append_info); } carray_free(append_tab); src_unlock: mailmbox_read_unlock(src_folder); err: return res; } int mailmbox_copy_msg(struct mailmbox_folder * dest_folder, struct mailmbox_folder * src_folder, uint32_t uid) { carray * tab; int res; uint32_t * puid; int r; tab = carray_new(1); if (tab == NULL) { res = MAILMBOX_ERROR_MEMORY; goto err; } puid = malloc(sizeof(* puid)); if (puid == NULL) { res = MAILMBOX_ERROR_MEMORY; goto free_array; } * puid = uid; r = mailmbox_copy_msg_list(dest_folder, src_folder, tab); res = r; free(puid); free_array: carray_free(tab); err: return res; } static int mailmbox_expunge_to_file_no_lock(char * dest_filename, int dest_fd, struct mailmbox_folder * folder, size_t * result_size) { int r; int res; unsigned long i; size_t cur_offset; char * dest; size_t size; size = 0; for(i = 0 ; i < carray_count(folder->mb_tab) ; i ++) { struct mailmbox_msg_info * info; info = carray_get(folder->mb_tab, i); if (!info->msg_deleted) { size += info->msg_size + info->msg_padding; if (!folder->mb_no_uid) { if (!info->msg_written_uid) { uint32_t uid; size += strlen(UID_HEADER " \r\n"); uid = info->msg_uid; while (uid >= 10) { uid /= 10; size ++; } size ++; } } } } r = ftruncate(dest_fd, size); if (r < 0) { res = MAILMBOX_ERROR_FILE; goto err; } dest = (char *) mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, dest_fd, 0); if (dest == MAP_FAILED) { res = MAILMBOX_ERROR_FILE; goto err; } cur_offset = 0; for(i = 0 ; i < carray_count(folder->mb_tab) ; i ++) { struct mailmbox_msg_info * info; info = carray_get(folder->mb_tab, i); if (!info->msg_deleted) { memcpy(dest + cur_offset, folder->mb_mapping + info->msg_start, info->msg_headers_len + info->msg_start_len); cur_offset += info->msg_headers_len + info->msg_start_len; if (!folder->mb_no_uid) { if (!info->msg_written_uid) { size_t numlen; memcpy(dest + cur_offset, UID_HEADER " ", strlen(UID_HEADER " ")); cur_offset += strlen(UID_HEADER " "); numlen = snprintf(dest + cur_offset, size - cur_offset, "%i\r\n", info->msg_uid); cur_offset += numlen; } } memcpy(dest + cur_offset, folder->mb_mapping + info->msg_headers + info->msg_headers_len, info->msg_size - (info->msg_start_len + info->msg_headers_len) + info->msg_padding); cur_offset += info->msg_size - (info->msg_start_len + info->msg_headers_len) + info->msg_padding; } } fflush(stdout); msync(dest, size, MS_SYNC); munmap(dest, size); * result_size = size; return MAILMBOX_NO_ERROR; err: return res; } int mailmbox_expunge_no_lock(struct mailmbox_folder * folder) { char tmpfile[PATH_MAX]; int r; int res; int dest_fd; size_t size; if (folder->mb_read_only) return MAILMBOX_ERROR_READONLY; if (((folder->mb_written_uid >= folder->mb_max_uid) || folder->mb_no_uid) && (!folder->mb_changed)) { /* no need to expunge */ return MAILMBOX_NO_ERROR; } snprintf(tmpfile, PATH_MAX, "%sXXXXXX", folder->mb_filename); dest_fd = mkstemp(tmpfile); if (dest_fd < 0) { res = MAILMBOX_ERROR_FILE; goto unlink; } r = mailmbox_expunge_to_file_no_lock(tmpfile, dest_fd, folder, &size); if (r != MAILMBOX_NO_ERROR) { res = r; goto unlink; } close(dest_fd); r = rename(tmpfile, folder->mb_filename); if (r < 0) { res = r; goto err; } mailmbox_unmap(folder); mailmbox_close(folder); r = mailmbox_open(folder); if (r != MAILMBOX_NO_ERROR) { res = r; goto err; } r = mailmbox_map(folder); if (r != MAILMBOX_NO_ERROR) { res = r; goto err; } r = mailmbox_parse(folder); if (r != MAILMBOX_NO_ERROR) { res = r; goto err; } mailmbox_timestamp(folder); folder->mb_changed = FALSE; folder->mb_deleted_count = 0; return MAILMBOX_NO_ERROR; unlink: close(dest_fd); unlink(tmpfile); err: return res; } int mailmbox_expunge(struct mailmbox_folder * folder) { int r; int res; r = mailmbox_validate_write_lock(folder); if (r != MAILMBOX_NO_ERROR) { res = r; goto err; } r = mailmbox_expunge_no_lock(folder); res = r; mailmbox_write_unlock(folder); err: return res; } int mailmbox_delete_msg(struct mailmbox_folder * folder, uint32_t uid) { struct mailmbox_msg_info * info; int res; chashdatum key; chashdatum data; int r; if (folder->mb_read_only) { res = MAILMBOX_ERROR_READONLY; goto err; } key.data = &uid; key.len = sizeof(uid); r = chash_get(folder->mb_hash, &key, &data); if (r < 0) { res = MAILMBOX_ERROR_MSG_NOT_FOUND; goto err; } info = data.data; if (info->msg_deleted) { res = MAILMBOX_ERROR_MSG_NOT_FOUND; goto err; } info->msg_deleted = TRUE; folder->mb_changed = TRUE; folder->mb_deleted_count ++; return MAILMBOX_NO_ERROR; err: return res; } /* INIT of MBOX - open file - map the file - lock the file - parse memory - unlock the file */ int mailmbox_init(const char * filename, int force_readonly, int force_no_uid, uint32_t default_written_uid, struct mailmbox_folder ** result_folder) { struct mailmbox_folder * folder; int r; int res; folder = mailmbox_folder_new(filename); if (folder == NULL) { res = MAILMBOX_ERROR_MEMORY; goto err; } folder->mb_no_uid = force_no_uid; folder->mb_read_only = force_readonly; folder->mb_written_uid = default_written_uid; folder->mb_changed = FALSE; folder->mb_deleted_count = 0; r = mailmbox_open(folder); if (r != MAILMBOX_NO_ERROR) { res = r; goto free; } r = mailmbox_map(folder); if (r != MAILMBOX_NO_ERROR) { res = r; goto close; } r = mailmbox_validate_read_lock(folder); if (r != MAILMBOX_NO_ERROR) { res = r; goto unmap; } mailmbox_read_unlock(folder); * result_folder = folder; return MAILMBOX_NO_ERROR; unmap: mailmbox_unmap(folder); close: mailmbox_close(folder); free: mailmbox_folder_free(folder); err: return res; } /* when MBOX is DONE - check for changes - unmap the file - close file */ void mailmbox_done(struct mailmbox_folder * folder) { if (!folder->mb_read_only) mailmbox_expunge(folder); mailmbox_unmap(folder); mailmbox_close(folder); mailmbox_folder_free(folder); } diff --git a/kmicromail/libetpan/mbox/mailmbox.h b/kmicromail/libetpan/mbox/mailmbox.h index 8be086c..0427f1f 100644 --- a/kmicromail/libetpan/mbox/mailmbox.h +++ b/kmicromail/libetpan/mbox/mailmbox.h @@ -1,140 +1,144 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #ifndef MAILMBOX_H #define MAILMBOX_H #ifdef __cplusplus extern "C" { #endif #include <libetpan/mailmbox_types.h> int mailmbox_append_message_list(struct mailmbox_folder * folder, carray * append_tab); int mailmbox_append_message(struct mailmbox_folder * folder, const char * data, size_t len); +int +mailmbox_append_message_uid(struct mailmbox_folder * folder, + const char * data, size_t len, unsigned int * puid); + int mailmbox_fetch_msg(struct mailmbox_folder * folder, uint32_t num, char ** result, size_t * result_len); int mailmbox_fetch_msg_headers(struct mailmbox_folder * folder, uint32_t num, char ** result, size_t * result_len); void mailmbox_fetch_result_free(char * msg); int mailmbox_copy_msg_list(struct mailmbox_folder * dest_folder, struct mailmbox_folder * src_folder, carray * tab); int mailmbox_copy_msg(struct mailmbox_folder * dest_folder, struct mailmbox_folder * src_folder, uint32_t uid); int mailmbox_expunge(struct mailmbox_folder * folder); int mailmbox_delete_msg(struct mailmbox_folder * folder, uint32_t uid); int mailmbox_init(const char * filename, int force_readonly, int force_no_uid, uint32_t default_written_uid, struct mailmbox_folder ** result_folder); void mailmbox_done(struct mailmbox_folder * folder); /* low-level access primitives */ int mailmbox_write_lock(struct mailmbox_folder * folder); int mailmbox_write_unlock(struct mailmbox_folder * folder); int mailmbox_read_lock(struct mailmbox_folder * folder); int mailmbox_read_unlock(struct mailmbox_folder * folder); /* memory map */ int mailmbox_map(struct mailmbox_folder * folder); void mailmbox_unmap(struct mailmbox_folder * folder); void mailmbox_sync(struct mailmbox_folder * folder); /* open & close file */ int mailmbox_open(struct mailmbox_folder * folder); void mailmbox_close(struct mailmbox_folder * folder); /* validate cache */ int mailmbox_validate_write_lock(struct mailmbox_folder * folder); int mailmbox_validate_read_lock(struct mailmbox_folder * folder); /* fetch message */ int mailmbox_fetch_msg_no_lock(struct mailmbox_folder * folder, uint32_t num, char ** result, size_t * result_len); int mailmbox_fetch_msg_headers_no_lock(struct mailmbox_folder * folder, uint32_t num, char ** result, size_t * result_len); /* append message */ int mailmbox_append_message_list_no_lock(struct mailmbox_folder * folder, carray * append_tab); int mailmbox_expunge_no_lock(struct mailmbox_folder * folder); #ifdef __cplusplus } #endif #endif diff --git a/kmicromail/libetpan/mbox/mailmbox_types.c b/kmicromail/libetpan/mbox/mailmbox_types.c index 1986182..4e3e521 100644 --- a/kmicromail/libetpan/mbox/mailmbox_types.c +++ b/kmicromail/libetpan/mbox/mailmbox_types.c @@ -1,250 +1,251 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "mailmbox_types.h" #include <string.h> #include <stdlib.h> #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif /* *********************************************************************** */ int mailmbox_msg_info_update(struct mailmbox_folder * folder, size_t msg_start, size_t msg_start_len, size_t msg_headers, size_t msg_headers_len, size_t msg_body, size_t msg_body_len, size_t msg_size, size_t msg_padding, uint32_t msg_uid) { struct mailmbox_msg_info * info; int res; chashdatum key; chashdatum data; int r; key.data = &msg_uid; key.len = sizeof(msg_uid); r = chash_get(folder->mb_hash, &key, &data); if (r < 0) { unsigned int index; info = mailmbox_msg_info_new(msg_start, msg_start_len, msg_headers, msg_headers_len, msg_body, msg_body_len, msg_size, msg_padding, msg_uid); if (info == NULL) { res = MAILMBOX_ERROR_MEMORY; goto err; } r = carray_add(folder->mb_tab, info, &index); if (r < 0) { mailmbox_msg_info_free(info); res = MAILMBOX_ERROR_MEMORY; goto err; } if (msg_uid != 0) { chashdatum key; chashdatum data; key.data = &msg_uid; key.len = sizeof(msg_uid); data.data = info; data.len = 0; r = chash_set(folder->mb_hash, &key, &data, NULL); if (r < 0) { mailmbox_msg_info_free(info); carray_delete(folder->mb_tab, index); res = MAILMBOX_ERROR_MEMORY; goto err; } } info->msg_index = index; } else { info = data.data; info->msg_start = msg_start; info->msg_start_len = msg_start_len; info->msg_headers = msg_headers; info->msg_headers_len = msg_headers_len; info->msg_body = msg_body; info->msg_body_len = msg_body_len; info->msg_size = msg_size; info->msg_padding = msg_padding; } return MAILMBOX_NO_ERROR; err: return res; } struct mailmbox_msg_info * mailmbox_msg_info_new(size_t msg_start, size_t msg_start_len, size_t msg_headers, size_t msg_headers_len, size_t msg_body, size_t msg_body_len, size_t msg_size, size_t msg_padding, uint32_t msg_uid) { struct mailmbox_msg_info * info; info = malloc(sizeof(* info)); if (info == NULL) return NULL; info->msg_index = 0; info->msg_uid = msg_uid; if (msg_uid != 0) info->msg_written_uid = TRUE; else info->msg_written_uid = FALSE; info->msg_deleted = FALSE; info->msg_start = msg_start; info->msg_start_len = msg_start_len; info->msg_headers = msg_headers; info->msg_headers_len = msg_headers_len; info->msg_body = msg_body; info->msg_body_len = msg_body_len; info->msg_size = msg_size; info->msg_padding = msg_padding; return info; } void mailmbox_msg_info_free(struct mailmbox_msg_info * info) { free(info); } /* append info */ struct mailmbox_append_info * mailmbox_append_info_new(const char * ai_message, size_t ai_size) { struct mailmbox_append_info * info; info = malloc(sizeof(* info)); if (info == NULL) return NULL; info->ai_message = ai_message; info->ai_size = ai_size; + info->ai_uid = 0; return info; } void mailmbox_append_info_free(struct mailmbox_append_info * info) { free(info); } struct mailmbox_folder * mailmbox_folder_new(const char * mb_filename) { struct mailmbox_folder * folder; folder = malloc(sizeof(* folder)); if (folder == NULL) goto err; strncpy(folder->mb_filename, mb_filename, PATH_MAX); folder->mb_mtime = (time_t) -1; folder->mb_fd = -1; folder->mb_read_only = TRUE; folder->mb_no_uid = TRUE; folder->mb_changed = FALSE; folder->mb_deleted_count = 0; folder->mb_mapping = NULL; folder->mb_mapping_size = 0; folder->mb_written_uid = 0; folder->mb_max_uid = 0; folder->mb_hash = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY); if (folder->mb_hash == NULL) goto free; folder->mb_tab = carray_new(128); if (folder->mb_tab == NULL) goto free_hash; return folder; free_hash: chash_free(folder->mb_hash); free: free(folder); err: return NULL; } void mailmbox_folder_free(struct mailmbox_folder * folder) { unsigned int i; for(i = 0 ; i < carray_count(folder->mb_tab) ; i++) { struct mailmbox_msg_info * info; info = carray_get(folder->mb_tab, i); if (info != NULL) mailmbox_msg_info_free(info); } carray_free(folder->mb_tab); chash_free(folder->mb_hash); free(folder); } diff --git a/kmicromail/libetpan/mbox/mailmbox_types.h b/kmicromail/libetpan/mbox/mailmbox_types.h index dd6758c..bd6ee30 100644 --- a/kmicromail/libetpan/mbox/mailmbox_types.h +++ b/kmicromail/libetpan/mbox/mailmbox_types.h @@ -1,142 +1,143 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #ifndef MAILMBOX_TYPES_H #define MAILMBOX_TYPES_H #ifdef __cplusplus extern "C" { #endif #include <sys/types.h> #include <libetpan/libetpan-config.h> #include <libetpan/mailimf.h> #include <libetpan/carray.h> #include <libetpan/chash.h> enum { MAILMBOX_NO_ERROR = 0, MAILMBOX_ERROR_PARSE, MAILMBOX_ERROR_INVAL, MAILMBOX_ERROR_FILE_NOT_FOUND, MAILMBOX_ERROR_MEMORY, MAILMBOX_ERROR_TEMPORARY_FILE, MAILMBOX_ERROR_FILE, MAILMBOX_ERROR_MSG_NOT_FOUND, MAILMBOX_ERROR_READONLY, }; struct mailmbox_folder { char mb_filename[PATH_MAX]; time_t mb_mtime; int mb_fd; int mb_read_only; int mb_no_uid; int mb_changed; unsigned int mb_deleted_count; char * mb_mapping; size_t mb_mapping_size; uint32_t mb_written_uid; uint32_t mb_max_uid; chash * mb_hash; carray * mb_tab; }; struct mailmbox_folder * mailmbox_folder_new(const char * mb_filename); void mailmbox_folder_free(struct mailmbox_folder * folder); struct mailmbox_msg_info { unsigned int msg_index; uint32_t msg_uid; int msg_written_uid; int msg_deleted; size_t msg_start; size_t msg_start_len; size_t msg_headers; size_t msg_headers_len; size_t msg_body; size_t msg_body_len; size_t msg_size; size_t msg_padding; }; int mailmbox_msg_info_update(struct mailmbox_folder * folder, size_t msg_start, size_t msg_start_len, size_t msg_headers, size_t msg_headers_len, size_t msg_body, size_t msg_body_len, size_t msg_size, size_t msg_padding, uint32_t msg_uid); struct mailmbox_msg_info * mailmbox_msg_info_new(size_t msg_start, size_t msg_start_len, size_t msg_headers, size_t msg_headers_len, size_t msg_body, size_t msg_body_len, size_t msg_size, size_t msg_padding, uint32_t msg_uid); void mailmbox_msg_info_free(struct mailmbox_msg_info * info); struct mailmbox_append_info { const char * ai_message; size_t ai_size; + unsigned int ai_uid; }; struct mailmbox_append_info * mailmbox_append_info_new(const char * ai_message, size_t ai_size); void mailmbox_append_info_free(struct mailmbox_append_info * info); #ifdef __cplusplus } #endif #endif diff --git a/kmicromail/libetpan/mh/mailmh.c b/kmicromail/libetpan/mh/mailmh.c index d6ff950..119f217 100644 --- a/kmicromail/libetpan/mh/mailmh.c +++ b/kmicromail/libetpan/mh/mailmh.c @@ -1,965 +1,981 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "mailmh.h" /* perfs : /net/home/dinh/Mail/inbox/sylpheed 686 2724 /net/home/dinh/Mail/inbox/sylpheed bart:~/LibEtPan/libetpan/tests> time ./mhtest >/dev/null real 0m0.385s user 0m0.270s sys 0m0.110s */ #include <dirent.h> #include <sys/stat.h> #include <errno.h> #include <unistd.h> #include <sys/mman.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include "libetpan-config.h" struct mailmh * mailmh_new(const char * foldername) { struct mailmh * f; f = malloc(sizeof(*f)); if (f == NULL) return NULL; f->mh_main = mailmh_folder_new(NULL, foldername); if (f->mh_main == NULL) { free(f); return NULL; } return f; } void mailmh_free(struct mailmh * f) { mailmh_folder_free(f->mh_main); free(f); } struct mailmh_msg_info * mailmh_msg_info_new(uint32_t index, size_t size, time_t mtime) { struct mailmh_msg_info * msg_info; msg_info = malloc(sizeof(* msg_info)); if (msg_info == NULL) return NULL; msg_info->msg_index = index; msg_info->msg_size = size; msg_info->msg_mtime = mtime; msg_info->msg_array_index = 0; return msg_info; } void mailmh_msg_info_free(struct mailmh_msg_info * msg_info) { free(msg_info); } struct mailmh_folder * mailmh_folder_new(struct mailmh_folder * parent, const char * name) { char * filename; char * parent_filename; struct mailmh_folder * folder; folder = malloc(sizeof(* folder)); if (folder == NULL) goto err; if (parent == NULL) { filename = strdup(name); if (filename == NULL) goto free_folder; } else { parent_filename = parent->fl_filename; filename = malloc(strlen(parent_filename) + strlen(name) + 2); if (filename == NULL) goto free_folder; strcpy(filename, parent_filename); strcat(filename, MAIL_DIR_SEPARATOR_S); strcat(filename, name); } folder->fl_filename = filename; folder->fl_name = strdup(name); if (folder->fl_name == NULL) goto free_filename; folder->fl_msgs_tab = carray_new(128); if (folder->fl_msgs_tab == NULL) goto free_name; #if 0 folder->fl_msgs_hash = cinthash_new(128); if (folder->fl_msgs_hash == NULL) goto free_msgs_tab; #endif folder->fl_msgs_hash = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY); if (folder->fl_msgs_hash == NULL) goto free_msgs_tab; folder->fl_subfolders_tab = carray_new(128); if (folder->fl_subfolders_tab == NULL) goto free_msgs_hash; folder->fl_subfolders_hash = chash_new(128, CHASH_COPYNONE); if (folder->fl_subfolders_hash == NULL) goto free_subfolders_tab; folder->fl_mtime = 0; folder->fl_parent = parent; folder->fl_max_index = 0; return folder; free_subfolders_tab: carray_free(folder->fl_subfolders_tab); free_msgs_hash: #if 0 cinthash_free(folder->fl_msgs_hash); #endif chash_free(folder->fl_msgs_hash); free_msgs_tab: carray_free(folder->fl_msgs_tab); free_name: free(folder->fl_name); free_filename: free(folder->fl_filename); free_folder: free(folder); err: return NULL; } void mailmh_folder_free(struct mailmh_folder * folder) { unsigned int i; for(i = 0 ; i < carray_count(folder->fl_subfolders_tab) ; i++) { struct mailmh_folder * subfolder; subfolder = carray_get(folder->fl_subfolders_tab, i); if (subfolder != NULL) mailmh_folder_free(subfolder); } carray_free(folder->fl_subfolders_tab); chash_free(folder->fl_subfolders_hash); for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i++) { struct mailmh_msg_info * msg_info; msg_info = carray_get(folder->fl_msgs_tab, i); if (msg_info != NULL) mailmh_msg_info_free(msg_info); } carray_free(folder->fl_msgs_tab); chash_free(folder->fl_msgs_hash); #if 0 cinthash_free(folder->fl_msgs_hash); #endif free(folder->fl_filename); free(folder->fl_name); free(folder); } struct mailmh_folder * mailmh_folder_find(struct mailmh_folder * root, const char * filename) { int r; char pathname[PATH_MAX]; char * p; chashdatum key; chashdatum data; struct mailmh_folder * folder; char * start; if (strcmp(root->fl_filename, filename) == 0) return root; #if 0 r = mailmh_folder_update(root); if (r != MAILMH_NO_ERROR) return NULL; #endif #if 0 for(i = 0 ; i < root->fl_subfolders_tab->len ; i++) { struct mailmh_folder * subfolder; subfolder = carray_get(root->fl_subfolders_tab, i); if (subfolder != NULL) if (strncmp(subfolder->fl_filename, filename, strlen(subfolder->fl_filename)) == 0) return mailmh_folder_find(subfolder, filename); } #endif strncpy(pathname, filename, PATH_MAX); pathname[PATH_MAX - 1] = 0; start = pathname + strlen(root->fl_filename) + 1; p = strchr(start, MAIL_DIR_SEPARATOR); if (p != NULL) { * p = 0; root = mailmh_folder_find(root, pathname); if (root != NULL) { folder = mailmh_folder_find(root, filename); if (folder == NULL) return NULL; return folder; } return NULL; } else { key.data = pathname; key.len = strlen(pathname); r = chash_get(root->fl_subfolders_hash, &key, &data); if (r < 0) return NULL; return data.data; } } int mailmh_folder_update(struct mailmh_folder * folder) { DIR * d; struct dirent * ent; struct stat buf; char * mh_seq; char filename[PATH_MAX]; int res; int r; uint32_t max_index; #if 0 int add_folder; #endif unsigned int i; if (stat(folder->fl_filename, &buf) == -1) { res = MAILMH_ERROR_FOLDER; goto err; } if (folder->fl_mtime == buf.st_mtime) { res = MAILMH_NO_ERROR; goto err; } folder->fl_mtime = buf.st_mtime; d = opendir(folder->fl_filename); if (d == NULL) { res = MAILMH_ERROR_FOLDER; goto err; } max_index = 0; #if 0 if (folder->fl_subfolders_tab->len == 0) add_folder = 1; else add_folder = 0; #endif /* clear the message list */ for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i ++) { struct mailmh_msg_info * msg_info; chashdatum key; msg_info = carray_get(folder->fl_msgs_tab, i); if (msg_info == NULL) continue; #if 0 cinthash_remove(folder->fl_msgs_hash, msg_info->msg_index); #endif key.data = &msg_info->msg_index; key.len = sizeof(msg_info->msg_index); chash_delete(folder->fl_msgs_hash, &key, NULL); mailmh_msg_info_free(msg_info); } carray_set_size(folder->fl_msgs_tab, 0); do { uint32_t index; ent = readdir(d); if (ent != NULL) { snprintf(filename, PATH_MAX, "%s%c%s", folder->fl_filename, MAIL_DIR_SEPARATOR, ent->d_name); if (stat(filename, &buf) == -1) continue; if (S_ISREG(buf.st_mode)) { index = strtoul(ent->d_name, NULL, 10); if (index != 0) { struct mailmh_msg_info * msg_info; unsigned int array_index; chashdatum key; chashdatum data; msg_info = mailmh_msg_info_new(index, buf.st_size, buf.st_mtime); if (msg_info == NULL) { res = MAILMH_ERROR_MEMORY; goto closedir; } r = carray_add(folder->fl_msgs_tab, msg_info, &array_index); if (r < 0) { mailmh_msg_info_free(msg_info); res = MAILMH_ERROR_MEMORY; goto closedir; } msg_info->msg_array_index = array_index; if (index > max_index) max_index = index; #if 0 r = cinthash_add(folder->fl_msgs_hash, msg_info->msg_index, msg_info); #endif key.data = &msg_info->msg_index; key.len = sizeof(msg_info->msg_index); data.data = msg_info; data.len = 0; r = chash_set(folder->fl_msgs_hash, &key, &data, NULL); if (r < 0) { carray_delete_fast(folder->fl_msgs_tab, msg_info->msg_array_index); mailmh_msg_info_free(msg_info); res = MAILMH_ERROR_MEMORY; goto closedir; } } } else if (S_ISDIR(buf.st_mode)) { struct mailmh_folder * subfolder; unsigned int array_index; chashdatum key; chashdatum data; if (ent->d_name[0] == '.') { if (ent->d_name[1] == 0) continue; if ((ent->d_name[1] == '.') && (ent->d_name[2] == 0)) continue; } key.data = ent->d_name; key.len = strlen(ent->d_name); r = chash_get(folder->fl_subfolders_hash, &key, &data); if (r < 0) { subfolder = mailmh_folder_new(folder, ent->d_name); if (subfolder == NULL) { res = MAILMH_ERROR_MEMORY; goto closedir; } r = carray_add(folder->fl_subfolders_tab, subfolder, &array_index); if (r < 0) { mailmh_folder_free(subfolder); res = MAILMH_ERROR_MEMORY; goto closedir; } subfolder->fl_array_index = array_index; key.data = subfolder->fl_filename; key.len = strlen(subfolder->fl_filename); data.data = subfolder; data.len = 0; r = chash_set(folder->fl_subfolders_hash, &key, &data, NULL); if (r < 0) { carray_delete_fast(folder->fl_subfolders_tab, subfolder->fl_array_index); mailmh_folder_free(subfolder); res = MAILMH_ERROR_MEMORY; goto closedir; } } } } } while (ent != NULL); folder->fl_max_index = max_index; mh_seq = malloc(strlen(folder->fl_filename) + 2 + sizeof(".mh_sequences")); if (mh_seq == NULL) { res = MAILMH_ERROR_MEMORY; goto closedir; } strcpy(mh_seq, folder->fl_filename); strcat(mh_seq, MAIL_DIR_SEPARATOR_S); strcat(mh_seq, ".mh_sequences"); if (stat(mh_seq, &buf) == -1) { int fd; fd = creat(mh_seq, S_IRUSR | S_IWUSR); if (fd != -1) close(fd); } free(mh_seq); closedir(d); return MAILMH_NO_ERROR; closedir: closedir(d); err: return res; } int mailmh_folder_add_subfolder(struct mailmh_folder * parent, const char * name) { char * foldername; int r; struct mailmh_folder * folder; unsigned int array_index; chashdatum key; chashdatum data; foldername = malloc(strlen(parent->fl_filename) + strlen(name) + 2); if (foldername == NULL) return MAILMH_ERROR_MEMORY; strcpy(foldername, parent->fl_filename); strcat(foldername, MAIL_DIR_SEPARATOR_S); strcat(foldername, name); r = mkdir(foldername, 0700); free(foldername); if (r < 0) return MAILMH_ERROR_FOLDER; folder = mailmh_folder_new(parent, name); if (folder == NULL) return MAILMH_ERROR_MEMORY; r = carray_add(parent->fl_subfolders_tab, folder, &array_index); if (r < 0) { mailmh_folder_free(folder); return MAILMH_ERROR_MEMORY; } folder->fl_array_index = array_index; key.data = folder->fl_filename; key.len = strlen(folder->fl_filename); data.data = folder; data.len = 0; r = chash_set(parent->fl_subfolders_hash, &key, &data, NULL); if (r < 0) { carray_delete_fast(folder->fl_subfolders_tab, folder->fl_array_index); mailmh_folder_free(folder); return MAILMH_ERROR_MEMORY; } return MAILMH_NO_ERROR; } int mailmh_folder_remove_subfolder(struct mailmh_folder * folder) { struct mailmh_folder * parent; chashdatum key; chashdatum data; int r; parent = folder->fl_parent; key.data = folder->fl_filename; key.len = strlen(folder->fl_filename); r = chash_get(parent->fl_subfolders_hash, &key, &data); if (r < 0) return MAILMH_ERROR_FOLDER; chash_delete(parent->fl_subfolders_hash, &key, NULL); carray_delete_fast(parent->fl_subfolders_tab, folder->fl_array_index); mailmh_folder_free(folder); return MAILMH_NO_ERROR; } int mailmh_folder_rename_subfolder(struct mailmh_folder * src_folder, struct mailmh_folder * dst_folder, const char * new_name) { int r; struct mailmh_folder * folder; struct mailmh_folder * parent; char * new_foldername; parent = src_folder->fl_parent; if (parent == NULL) return MAILMH_ERROR_RENAME; new_foldername = malloc(strlen(dst_folder->fl_filename) + 2 + strlen(new_name)); if (new_foldername == NULL) return MAILMH_ERROR_MEMORY; strcpy(new_foldername, dst_folder->fl_filename); strcat(new_foldername, MAIL_DIR_SEPARATOR_S); strcat(new_foldername, new_name); r = rename(src_folder->fl_filename, new_foldername); free(new_foldername); if (r < 0) return MAILMH_ERROR_RENAME; r = mailmh_folder_remove_subfolder(src_folder); if (r != MAILMH_NO_ERROR) return r; folder = mailmh_folder_new(dst_folder, new_name); if (folder == NULL) return MAILMH_ERROR_MEMORY; r = carray_add(parent->fl_subfolders_tab, folder, NULL); if (r < 0) { mailmh_folder_free(folder); return MAILMH_ERROR_MEMORY; } return MAILMH_NO_ERROR; } #define MAX_TRY_ALLOC 32 /* initial file MUST be in the same directory */ static int mailmh_folder_alloc_msg(struct mailmh_folder * folder, char * filename, uint32_t * result) { uint32_t max; uint32_t k; char * new_filename; size_t len; len = strlen(folder->fl_filename) + 20; new_filename = malloc(len); if (new_filename == NULL) return MAILMH_ERROR_MEMORY; max = folder->fl_max_index + 1; k = 0; while (k < MAX_TRY_ALLOC) { snprintf(new_filename, len, "%s%c%lu", folder->fl_filename, MAIL_DIR_SEPARATOR, (unsigned long) (max + k)); if (link(filename, new_filename) == 0) { int r; free(new_filename); unlink(filename); if (k > MAX_TRY_ALLOC / 2) { r = mailmh_folder_update(folder); /* ignore errors */ } * result = max + k; folder->fl_max_index = max + k; return MAILMH_NO_ERROR; } else if (errno == EXDEV) { free(filename); return MAILMH_ERROR_FOLDER; } k ++; } free(new_filename); return MAILMH_ERROR_FOLDER; } int mailmh_folder_get_message_filename(struct mailmh_folder * folder, uint32_t index, char ** result) { char * filename; int len; #if 0 r = mailmh_folder_update(folder); if (r != MAILMH_NO_ERROR) return r; #endif len = strlen(folder->fl_filename) + 20; filename = malloc(len); if (filename == NULL) return MAILMH_ERROR_MEMORY; snprintf(filename, len, "%s%c%lu", folder->fl_filename, MAIL_DIR_SEPARATOR, (unsigned long) index); * result = filename; return MAILMH_NO_ERROR;; } int mailmh_folder_get_message_fd(struct mailmh_folder * folder, uint32_t index, int flags, int * result) { char * filename; int fd; int r; #if 0 r = mailmh_folder_update(folder); if (r != MAILMH_NO_ERROR) return r; #endif r = mailmh_folder_get_message_filename(folder, index, &filename); if (r != MAILMH_NO_ERROR) return r; fd = open(filename, flags); free(filename); if (fd == -1) return MAILMH_ERROR_MSG_NOT_FOUND; * result = fd; return MAILMH_NO_ERROR; } int mailmh_folder_get_message_size(struct mailmh_folder * folder, uint32_t index, size_t * result) { int r; char * filename; struct stat buf; r = mailmh_folder_get_message_filename(folder, index, &filename); if (r != MAILMH_NO_ERROR) return r; r = stat(filename, &buf); free(filename); if (r < 0) return MAILMH_ERROR_FILE; * result = buf.st_size; return MAILMH_NO_ERROR; } -int mailmh_folder_add_message(struct mailmh_folder * folder, - const char * message, size_t size) +int mailmh_folder_add_message_uid(struct mailmh_folder * folder, + const char * message, size_t size, + uint32_t * pindex) { char * tmpname; int fd; size_t namesize; size_t left; ssize_t res; struct mailmh_msg_info * msg_info; uint32_t index; int error; int r; unsigned int array_index; struct stat buf; chashdatum key; chashdatum data; #if 0 r = mailmh_folder_update(folder); if (r != MAILMH_NO_ERROR) { error = r; goto err; } #endif namesize = strlen(folder->fl_filename) + 20; tmpname = malloc(namesize); snprintf(tmpname, namesize, "%s%ctmpXXXXXX", folder->fl_filename, MAIL_DIR_SEPARATOR); fd = mkstemp(tmpname); if (fd < 0) { error = MAILMH_ERROR_FILE; goto free; } left = size; while (left > 0) { res = write(fd, message, left); if (res == -1) { close(fd); error = MAILMH_ERROR_FILE; goto free; } left -= res; } close(fd); r = stat(tmpname, &buf); if (r < 0) { error = MAILMH_ERROR_FILE; goto free; } r = mailmh_folder_alloc_msg(folder, tmpname, &index); if (r != MAILMH_NO_ERROR) { unlink(tmpname); error = MAILMH_ERROR_COULD_NOT_ALLOC_MSG; goto free; } free(tmpname); msg_info = mailmh_msg_info_new(index, size, buf.st_mtime); if (msg_info == NULL) { mailmh_folder_remove_message(folder, index); error = MAILMH_ERROR_MEMORY; goto err; } r = carray_add(folder->fl_msgs_tab, msg_info, &array_index); if (r < 0) { mailmh_folder_remove_message(folder, index); mailmh_msg_info_free(msg_info); error = MAILMH_ERROR_MEMORY; goto err; } msg_info->msg_array_index = array_index; #if 0 r = cinthash_add(folder->fl_msgs_hash, index, msg_info); #endif key.data = &index; key.len = sizeof(index); data.data = msg_info; data.len = 0; + if (pindex != NULL) + * pindex = index; + r = chash_set(folder->fl_msgs_hash, &key, &data, NULL); if (r < 0) { carray_delete_fast(folder->fl_msgs_tab, msg_info->msg_array_index); mailmh_msg_info_free(msg_info); error = MAILMH_ERROR_MEMORY; goto err; } return MAILMH_NO_ERROR; free: free(tmpname); err: return error; } -int mailmh_folder_add_message_file(struct mailmh_folder * folder, - int fd) +int mailmh_folder_add_message(struct mailmh_folder * folder, + const char * message, size_t size) +{ + return mailmh_folder_add_message_uid(folder, message, size, NULL); +} + +int mailmh_folder_add_message_file_uid(struct mailmh_folder * folder, + int fd, uint32_t * pindex) { char * message; struct stat buf; int r; #if 0 r = mailmh_folder_update(folder); if (r != MAILMH_NO_ERROR) return r; #endif if (fstat(fd, &buf) == -1) return MAILMH_ERROR_FILE; message = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (message == MAP_FAILED) return MAILMH_ERROR_FILE; - r = mailmh_folder_add_message(folder, message, buf.st_size); + r = mailmh_folder_add_message_uid(folder, message, buf.st_size, pindex); munmap(message, buf.st_size); return r; } +int mailmh_folder_add_message_file(struct mailmh_folder * folder, + int fd) +{ + return mailmh_folder_add_message_file_uid(folder, fd, NULL); +} + int mailmh_folder_remove_message(struct mailmh_folder * folder, uint32_t index) { char * filename; struct mailmh_msg_info * msg_info; int res; int r; chashdatum key; chashdatum data; #if 0 r = mailmh_folder_update(folder); if (r != MAILMH_NO_ERROR) { res = r; goto err; } #endif r = mailmh_folder_get_message_filename(folder, index, &filename); if (filename == NULL) { res = r; goto err; } if (unlink(filename) == -1) { res = MAILMH_ERROR_FILE; goto free; } key.data = &index; key.len = sizeof(index); r = chash_get(folder->fl_msgs_hash, &key, &data); #if 0 msg_info = cinthash_find(folder->fl_msgs_hash, index); #endif if (r == 0) { msg_info = data.data; carray_delete_fast(folder->fl_msgs_tab, msg_info->msg_array_index); #if 0 cinthash_remove(folder->fl_msgs_hash, index); #endif chash_delete(folder->fl_msgs_hash, &key, NULL); } return MAILMH_NO_ERROR; free: free(filename); err: return res; } int mailmh_folder_move_message(struct mailmh_folder * dest_folder, struct mailmh_folder * src_folder, uint32_t index) { int fd; char * filename; int r; #if 0 r = mailmh_folder_update(dest_folder); if (r != MAILMH_NO_ERROR) return r; r = mailmh_folder_update(src_folder); if (r != MAILMH_NO_ERROR) return r; #endif /* move on the same filesystem */ r = mailmh_folder_get_message_filename(src_folder, index, &filename); if (r != MAILMH_NO_ERROR) return r; r = mailmh_folder_alloc_msg(dest_folder, filename, &index); free(filename); if (r == MAILMH_NO_ERROR) return MAILMH_NO_ERROR; /* move on the different filesystems */ r = mailmh_folder_get_message_fd(src_folder, index, O_RDONLY, &fd); if (r != MAILMH_NO_ERROR) return r; r = mailmh_folder_add_message_file(dest_folder, fd); if (r != MAILMH_NO_ERROR) { close(fd); return r; } close(fd); r = mailmh_folder_remove_message(src_folder, index); return MAILMH_NO_ERROR; } unsigned int mailmh_folder_get_message_number(struct mailmh_folder * folder) { unsigned int i; unsigned int count; count = 0; for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i ++) if (carray_get(folder->fl_msgs_tab, i) != NULL) count ++; return count; } diff --git a/kmicromail/libetpan/mh/mailmh.h b/kmicromail/libetpan/mh/mailmh.h index 40432cb..00199b8 100644 --- a/kmicromail/libetpan/mh/mailmh.h +++ b/kmicromail/libetpan/mh/mailmh.h @@ -1,143 +1,150 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #ifndef MAILMH_H #define MAILMH_H #ifdef __cplusplus extern "C" { #endif #include <sys/types.h> #include <inttypes.h> #include <libetpan/carray.h> #include <libetpan/cinthash.h> #include <libetpan/chash.h> enum { MAILMH_NO_ERROR = 0, MAILMH_ERROR_FOLDER, MAILMH_ERROR_MEMORY, MAILMH_ERROR_FILE, MAILMH_ERROR_COULD_NOT_ALLOC_MSG, MAILMH_ERROR_RENAME, MAILMH_ERROR_MSG_NOT_FOUND, }; struct mailmh { struct mailmh_folder * mh_main; }; struct mailmh_msg_info { unsigned int msg_array_index; uint32_t msg_index; size_t msg_size; time_t msg_mtime; }; struct mailmh_folder { char * fl_filename; unsigned int fl_array_index; char * fl_name; time_t fl_mtime; struct mailmh_folder * fl_parent; uint32_t fl_max_index; carray * fl_msgs_tab; #if 0 cinthash_t * fl_msgs_hash; #endif chash * fl_msgs_hash; carray * fl_subfolders_tab; chash * fl_subfolders_hash; }; struct mailmh * mailmh_new(const char * foldername); void mailmh_free(struct mailmh * f); struct mailmh_msg_info * mailmh_msg_info_new(uint32_t index, size_t size, time_t mtime); void mailmh_msg_info_free(struct mailmh_msg_info * msg_info); struct mailmh_folder * mailmh_folder_new(struct mailmh_folder * parent, const char * name); void mailmh_folder_free(struct mailmh_folder * folder); int mailmh_folder_add_subfolder(struct mailmh_folder * parent, const char * name); struct mailmh_folder * mailmh_folder_find(struct mailmh_folder * root, const char * filename); int mailmh_folder_remove_subfolder(struct mailmh_folder * folder); int mailmh_folder_rename_subfolder(struct mailmh_folder * src_folder, struct mailmh_folder * dst_folder, const char * new_name); int mailmh_folder_get_message_filename(struct mailmh_folder * folder, uint32_t index, char ** result); int mailmh_folder_get_message_fd(struct mailmh_folder * folder, uint32_t index, int flags, int * result); int mailmh_folder_get_message_size(struct mailmh_folder * folder, uint32_t index, size_t * result); +int mailmh_folder_add_message_uid(struct mailmh_folder * folder, + const char * message, size_t size, + uint32_t * pindex); + int mailmh_folder_add_message(struct mailmh_folder * folder, const char * message, size_t size); +int mailmh_folder_add_message_file_uid(struct mailmh_folder * folder, + int fd, uint32_t * pindex); + int mailmh_folder_add_message_file(struct mailmh_folder * folder, int fd); int mailmh_folder_remove_message(struct mailmh_folder * folder, uint32_t index); int mailmh_folder_move_message(struct mailmh_folder * dest_folder, struct mailmh_folder * src_folder, uint32_t index); int mailmh_folder_update(struct mailmh_folder * folder); unsigned int mailmh_folder_get_message_number(struct mailmh_folder * folder); #ifdef __cplusplus } #endif #endif diff --git a/kmicromail/libetpan/mime/mailmime_decode.c b/kmicromail/libetpan/mime/mailmime_decode.c index 3025dcb..e48ec19 100644 --- a/kmicromail/libetpan/mime/mailmime_decode.c +++ b/kmicromail/libetpan/mime/mailmime_decode.c @@ -1,533 +1,543 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ /* RFC 2047 : MIME (Multipurpose Internet Mail Extensions) Part Three: Message Header Extensions for Non-ASCII Text */ #include "mailmime_decode.h" #include <ctype.h> #include <unistd.h> #include <sys/mman.h> #include <string.h> #include <stdlib.h> #include "mailmime_content.h" #include "charconv.h" #include "mmapstring.h" #include "mailimf.h" #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif static int mailmime_charset_parse(const char * message, size_t length, size_t * index, char ** charset); enum { MAILMIME_ENCODING_B, MAILMIME_ENCODING_Q }; static int mailmime_encoding_parse(const char * message, size_t length, size_t * index, int * result); static int mailmime_etoken_parse(const char * message, size_t length, size_t * index, char ** result); static int mailmime_non_encoded_word_parse(const char * message, size_t length, size_t * index, char ** result); static int mailmime_encoded_word_parse(const char * message, size_t length, size_t * index, struct mailmime_encoded_word ** result); enum { TYPE_ERROR, TYPE_WORD, TYPE_ENCODED_WORD, }; int mailmime_encoded_phrase_parse(const char * default_fromcode, const char * message, size_t length, size_t * index, const char * tocode, char ** result) { MMAPString * gphrase; struct mailmime_encoded_word * word; int first; size_t cur_token; int r; int res; char * str; char * wordutf8; int type; cur_token = * index; gphrase = mmap_string_new(""); if (gphrase == NULL) { res = MAILIMF_ERROR_MEMORY; goto err; } first = TRUE; type = TYPE_ERROR; /* XXX - removes a gcc warning */ while (1) { r = mailmime_encoded_word_parse(message, length, &cur_token, &word); if (r == MAILIMF_NO_ERROR) { if (!first) { if (type != TYPE_ENCODED_WORD) { if (mmap_string_append_c(gphrase, ' ') == NULL) { mailmime_encoded_word_free(word); res = MAILIMF_ERROR_MEMORY; goto free; } } } type = TYPE_ENCODED_WORD; wordutf8 = NULL; r = charconv(tocode, word->wd_charset, word->wd_text, strlen(word->wd_text), &wordutf8); switch (r) { case MAIL_CHARCONV_ERROR_MEMORY: mailmime_encoded_word_free(word); res = MAILIMF_ERROR_MEMORY; goto free; case MAIL_CHARCONV_ERROR_UNKNOWN_CHARSET: case MAIL_CHARCONV_ERROR_CONV: mailmime_encoded_word_free(word); res = MAILIMF_ERROR_PARSE; goto free; } if (wordutf8 != NULL) { if (mmap_string_append(gphrase, wordutf8) == NULL) { mailmime_encoded_word_free(word); free(wordutf8); res = MAILIMF_ERROR_MEMORY; goto free; } free(wordutf8); } mailmime_encoded_word_free(word); first = FALSE; } else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto free; } if (r == MAILIMF_ERROR_PARSE) { char * raw_word; r = mailmime_non_encoded_word_parse(message, length, &cur_token, &raw_word); if (r == MAILIMF_NO_ERROR) { if (!first) { if (mmap_string_append_c(gphrase, ' ') == NULL) { free(raw_word); res = MAILIMF_ERROR_MEMORY; goto free; } } type = TYPE_WORD; wordutf8 = NULL; r = charconv(tocode, default_fromcode, raw_word, strlen(raw_word), &wordutf8); - if (wordutf8 != NULL) { - if (mmap_string_append(gphrase, wordutf8) == NULL) { - free(wordutf8); + switch (r) { + case MAIL_CHARCONV_ERROR_MEMORY: free(raw_word); res = MAILIMF_ERROR_MEMORY; goto free; + + case MAIL_CHARCONV_ERROR_UNKNOWN_CHARSET: + case MAIL_CHARCONV_ERROR_CONV: + free(raw_word); + res = MAILIMF_ERROR_PARSE; + goto free; } + if (mmap_string_append(gphrase, wordutf8) == NULL) { free(wordutf8); + free(raw_word); + res = MAILIMF_ERROR_MEMORY; + goto free; } + free(raw_word); first = FALSE; } else if (r == MAILIMF_ERROR_PARSE) { break; } else { res = r; goto free; } } } if (first) { res = MAILIMF_ERROR_PARSE; goto free; } str = strdup(gphrase->str); if (str == NULL) { res = MAILIMF_ERROR_MEMORY; goto free; } mmap_string_free(gphrase); * result = str; * index = cur_token; return MAILIMF_NO_ERROR; free: mmap_string_free(gphrase); err: return res; } static int mailmime_non_encoded_word_parse(const char * message, size_t length, size_t * index, char ** result) { int end; size_t cur_token; int res; char * text; int r; size_t begin; cur_token = * index; r = mailimf_fws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { res = r; goto err; } begin = cur_token; end = FALSE; while (1) { if (cur_token >= length) break; switch (message[cur_token]) { case ' ': case '\t': case '\r': case '\n': end = TRUE; break; } if (end) break; cur_token ++; } if (cur_token - begin == 0) { res = MAILIMF_ERROR_PARSE; goto err; } text = malloc(cur_token - begin + 1); if (text == NULL) { res = MAILIMF_ERROR_MEMORY; goto err; } memcpy(text, message + begin, cur_token - begin); text[cur_token - begin] = '\0'; * index = cur_token; * result = text; return MAILIMF_NO_ERROR; err: return res; } static int mailmime_encoded_word_parse(const char * message, size_t length, size_t * index, struct mailmime_encoded_word ** result) { size_t cur_token; char * charset; int encoding; char * text; size_t end_encoding; char * decoded; size_t decoded_len; struct mailmime_encoded_word * ew; int r; int res; int opening_quote; int end; cur_token = * index; r = mailimf_fws_parse(message, length, &cur_token); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { res = r; goto err; } opening_quote = FALSE; r = mailimf_char_parse(message, length, &cur_token, '\"'); if (r == MAILIMF_NO_ERROR) { opening_quote = TRUE; } else if (r == MAILIMF_ERROR_PARSE) { /* do nothing */ } else { res = r; goto err; } r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "=?"); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailmime_charset_parse(message, length, &cur_token, &charset); if (r != MAILIMF_NO_ERROR) { res = r; goto err; } r = mailimf_char_parse(message, length, &cur_token, '?'); if (r != MAILIMF_NO_ERROR) { res = r; goto free_charset; } r = mailmime_encoding_parse(message, length, &cur_token, &encoding); if (r != MAILIMF_NO_ERROR) { res = r; goto free_charset; } r = mailimf_char_parse(message, length, &cur_token, '?'); if (r != MAILIMF_NO_ERROR) { res = r; goto free_charset; } end = FALSE; end_encoding = cur_token; while (1) { if (end_encoding >= length) break; switch (message[end_encoding]) { case '?': #if 0 case ' ': #endif end = TRUE; break; } if (end) break; end_encoding ++; } decoded_len = 0; decoded = NULL; switch (encoding) { case MAILMIME_ENCODING_B: r = mailmime_base64_body_parse(message, end_encoding, &cur_token, &decoded, &decoded_len); if (r != MAILIMF_NO_ERROR) { res = r; goto free_charset; } break; case MAILMIME_ENCODING_Q: r = mailmime_quoted_printable_body_parse(message, end_encoding, &cur_token, &decoded, &decoded_len, TRUE); if (r != MAILIMF_NO_ERROR) { res = r; goto free_charset; } break; } text = malloc(decoded_len + 1); if (text == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_charset; } if (decoded_len > 0) memcpy(text, decoded, decoded_len); text[decoded_len] = '\0'; mailmime_decoded_part_free(decoded); r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "?="); if (r != MAILIMF_NO_ERROR) { res = r; goto free_encoded_text; } if (opening_quote) { r = mailimf_char_parse(message, length, &cur_token, '\"'); if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { res = r; goto free_encoded_text; } } ew = mailmime_encoded_word_new(charset, text); if (ew == NULL) { res = MAILIMF_ERROR_MEMORY; goto free_encoded_text; } * result = ew; * index = cur_token; return MAILIMF_NO_ERROR; free_encoded_text: mailmime_encoded_text_free(text); free_charset: mailmime_charset_free(charset); err: return res; } static int mailmime_charset_parse(const char * message, size_t length, size_t * index, char ** charset) { return mailmime_etoken_parse(message, length, index, charset); } static int mailmime_encoding_parse(const char * message, size_t length, size_t * index, int * result) { size_t cur_token; int encoding; cur_token = * index; if (cur_token >= length) return MAILIMF_ERROR_PARSE; switch ((char) toupper((unsigned char) message[cur_token])) { case 'Q': encoding = MAILMIME_ENCODING_Q; break; case 'B': encoding = MAILMIME_ENCODING_B; break; default: return MAILIMF_ERROR_INVAL; } cur_token ++; * result = encoding; * index = cur_token; return MAILIMF_NO_ERROR; } int is_etoken_char(char ch) { unsigned char uch = ch; if (uch < 31) return FALSE; switch (uch) { case ' ': case '(': case ')': case '<': case '>': case '@': case ',': case ';': case ':': case '"': case '/': case '[': case ']': case '?': case '.': case '=': return FALSE; } return TRUE; } static int mailmime_etoken_parse(const char * message, size_t length, size_t * index, char ** result) { return mailimf_custom_string_parse(message, length, index, result, is_etoken_char); } diff --git a/kmicromail/libetpan/mime/mailmime_write.c b/kmicromail/libetpan/mime/mailmime_write.c index 5c3b1f7..208e3ba 100644 --- a/kmicromail/libetpan/mime/mailmime_write.c +++ b/kmicromail/libetpan/mime/mailmime_write.c @@ -1,1416 +1,1416 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "mailmime_write.h" #include <stdlib.h> #include <string.h> #include <time.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <sys/mman.h> #include "mailimf_write.h" #include "mailmime_content.h" #include "mailmime_types_helper.h" #define MAX_MAIL_COL 78 #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif static int mailmime_field_write(FILE * f, int * col, struct mailmime_field * field); static int mailmime_id_write(FILE * f, int * col, char * id); static int mailmime_description_write(FILE * f, int * col, char * descr); static int mailmime_version_write(FILE * f, int * col, uint32_t version); static int mailmime_encoding_write(FILE * f, int * col, struct mailmime_mechanism * encoding); static int mailmime_language_write(FILE * f, int * col, struct mailmime_language * language); static int mailmime_disposition_write(FILE * f, int * col, struct mailmime_disposition * disposition); static int mailmime_disposition_param_write(FILE * f, int * col, struct mailmime_disposition_parm * param); static int mailmime_parameter_write(FILE * f, int * col, struct mailmime_parameter * param); /* static int mailmime_content_write(FILE * f, int * col, struct mailmime_content * content); */ static int mailmime_type_write(FILE * f, int * col, struct mailmime_type * type); static int mailmime_discrete_type_write(FILE * f, int * col, struct mailmime_discrete_type * discrete_type); static int mailmime_composite_type_write(FILE * f, int * col, struct mailmime_composite_type * composite_type); static int mailmime_sub_write(FILE * f, int * col, struct mailmime * build_info); /* ***** */ int mailmime_fields_write(FILE * f, int * col, struct mailmime_fields * fields) { int r; clistiter * cur; for(cur = clist_begin(fields->fld_list) ; cur != NULL ; cur = clist_next(cur)) { struct mailmime_field * field; field = cur->data; r = mailmime_field_write(f, col, field); if (r != MAILIMF_NO_ERROR) return r; } return MAILIMF_NO_ERROR; } static int mailmime_field_write(FILE * f, int * col, struct mailmime_field * field) { int r; switch (field->fld_type) { case MAILMIME_FIELD_TYPE: r = mailmime_content_write(f, col, field->fld_data.fld_content); break; case MAILMIME_FIELD_TRANSFER_ENCODING: r = mailmime_encoding_write(f, col, field->fld_data.fld_encoding); break; case MAILMIME_FIELD_ID: r = mailmime_id_write(f, col, field->fld_data.fld_id); break; case MAILMIME_FIELD_DESCRIPTION: r = mailmime_description_write(f, col, field->fld_data.fld_description); break; case MAILMIME_FIELD_VERSION: r = mailmime_version_write(f, col, field->fld_data.fld_version); break; case MAILMIME_FIELD_DISPOSITION: r = mailmime_disposition_write(f, col, field->fld_data.fld_disposition); break; case MAILMIME_FIELD_LANGUAGE: r = mailmime_language_write(f, col, field->fld_data.fld_language); break; default: r = MAILIMF_ERROR_INVAL; break; } if (r != MAILIMF_NO_ERROR) return r; return MAILIMF_NO_ERROR; } static int mailmime_id_write(FILE * f, int * col, char * id) { int r; r = mailimf_string_write(f, col, "Content-ID: ", 12); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_string_write(f, col, "<", 1); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_string_write(f, col, id, strlen(id)); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_string_write(f, col, ">", 1); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_string_write(f, col, "\r\n", 2); if (r != MAILIMF_NO_ERROR) return r; #if 0 * col = 0; #endif return MAILIMF_NO_ERROR; } static int mailmime_description_write(FILE * f, int * col, char * descr) { int r; r = mailimf_string_write(f, col, "Content-Description: ", 21); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_string_write(f, col, descr, strlen(descr)); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_string_write(f, col, "\r\n", 2); if (r != MAILIMF_NO_ERROR) return r; #if 0 * col = 0; #endif return MAILIMF_NO_ERROR; } static int mailmime_version_write(FILE * f, int * col, uint32_t version) { int r; char versionstr[40]; r = mailimf_string_write(f, col, "MIME-Version: ", 14); if (r != MAILIMF_NO_ERROR) return r; snprintf(versionstr, 40, "%i.%i", version >> 16, version & 0xFFFF); r = mailimf_string_write(f, col, versionstr, strlen(versionstr)); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_string_write(f, col, "\r\n", 2); if (r != MAILIMF_NO_ERROR) return r; #if 0 * col = 0; #endif return MAILIMF_NO_ERROR; } static int mailmime_encoding_write(FILE * f, int * col, struct mailmime_mechanism * encoding) { int r; r = mailimf_string_write(f, col, "Content-Transfer-Encoding: ", 27); if (r != MAILIMF_NO_ERROR) return r; switch (encoding->enc_type) { case MAILMIME_MECHANISM_7BIT: r = mailimf_string_write(f, col, "7bit", 4); break; case MAILMIME_MECHANISM_8BIT: r = mailimf_string_write(f, col, "8bit", 4); break; case MAILMIME_MECHANISM_BINARY: r = mailimf_string_write(f, col, "binary", 6); break; case MAILMIME_MECHANISM_QUOTED_PRINTABLE: r = mailimf_string_write(f, col, "quoted-printable", 16); break; case MAILMIME_MECHANISM_BASE64: r = mailimf_string_write(f, col, "base64", 6); break; case MAILMIME_MECHANISM_TOKEN: r = mailimf_string_write(f, col, encoding->enc_token, strlen(encoding->enc_token)); break; default: r = MAILIMF_ERROR_INVAL; break; } if (r != MAILIMF_NO_ERROR) return r; r = mailimf_string_write(f, col, "\r\n", 2); if (r != MAILIMF_NO_ERROR) return r; #if 0 * col = 0; #endif return MAILIMF_NO_ERROR; } static int mailmime_language_write(FILE * f, int * col, struct mailmime_language * language) { int r; clistiter * cur; int first; r = mailimf_string_write(f, col, "Content-Language: ", 18); if (r != MAILIMF_NO_ERROR) return r; first = TRUE; for(cur = clist_begin(language->lg_list) ; cur != NULL ; cur = clist_next(cur)) { char * lang; size_t len; lang = clist_content(cur); len = strlen(lang); if (!first) { r = mailimf_string_write(f, col, ", ", 2); if (r != MAILIMF_NO_ERROR) return r; } else { first = FALSE; } if (* col > 1) { if (* col + len > MAX_MAIL_COL) { r = mailimf_string_write(f, col, "\r\n ", 3); if (r != MAILIMF_NO_ERROR) return r; #if 0 * col = 1; #endif } } r = mailimf_string_write(f, col, lang, len); if (r != MAILIMF_NO_ERROR) return r; } r = mailimf_string_write(f, col, "\r\n", 2); if (r != MAILIMF_NO_ERROR) return r; #if 0 * col = 0; #endif return MAILIMF_NO_ERROR; } static int mailmime_disposition_write(FILE * f, int * col, struct mailmime_disposition * disposition) { struct mailmime_disposition_type * dsp_type; int r; clistiter * cur; dsp_type = disposition->dsp_type; r = mailimf_string_write(f, col, "Content-Disposition: ", 21); if (r != MAILIMF_NO_ERROR) return r; switch (dsp_type->dsp_type) { case MAILMIME_DISPOSITION_TYPE_INLINE: r = mailimf_string_write(f, col, "inline", 6); break; case MAILMIME_DISPOSITION_TYPE_ATTACHMENT: r = mailimf_string_write(f, col, "attachment", 10); break; case MAILMIME_DISPOSITION_TYPE_EXTENSION: r = mailimf_string_write(f, col, dsp_type->dsp_extension, strlen(dsp_type->dsp_extension)); break; default: r = MAILIMF_ERROR_INVAL; break; } if (r != MAILIMF_NO_ERROR) return r; for(cur = clist_begin(disposition->dsp_parms) ; cur != NULL ; cur = clist_next(cur)) { struct mailmime_disposition_parm * param; param = cur->data; r = mailimf_string_write(f, col, "; ", 2); if (r != MAILIMF_NO_ERROR) return r; r = mailmime_disposition_param_write(f, col, param); if (r != MAILIMF_NO_ERROR) return r; } r = mailimf_string_write(f, col, "\r\n", 2); if (r != MAILIMF_NO_ERROR) return r; return MAILIMF_NO_ERROR; } static int mailmime_disposition_param_write(FILE * f, int * col, struct mailmime_disposition_parm * param) { size_t len; char sizestr[20]; int r; switch (param->pa_type) { case MAILMIME_DISPOSITION_PARM_FILENAME: len = strlen("filename=") + strlen(param->pa_data.pa_filename); break; case MAILMIME_DISPOSITION_PARM_CREATION_DATE: len = strlen("creation-date=") + strlen(param->pa_data.pa_creation_date); break; case MAILMIME_DISPOSITION_PARM_MODIFICATION_DATE: len = strlen("modification-date=") + strlen(param->pa_data.pa_modification_date); break; case MAILMIME_DISPOSITION_PARM_READ_DATE: len = strlen("read-date=") + strlen(param->pa_data.pa_read_date); break; case MAILMIME_DISPOSITION_PARM_SIZE: - snprintf(sizestr, 20, "%u", param->pa_data.pa_size); + snprintf(sizestr, 20, "%lu", (unsigned long) param->pa_data.pa_size); len = strlen("size=") + strlen(sizestr); break; case MAILMIME_DISPOSITION_PARM_PARAMETER: len = strlen(param->pa_data.pa_parameter->pa_name) + 1 + strlen(param->pa_data.pa_parameter->pa_value); break; default: return MAILIMF_ERROR_INVAL; } if (* col > 1) { if (* col + len > MAX_MAIL_COL) { r = mailimf_string_write(f, col, "\r\n ", 3); if (r != MAILIMF_NO_ERROR) return r; #if 0 * col = 1; #endif } } switch (param->pa_type) { case MAILMIME_DISPOSITION_PARM_FILENAME: r = mailimf_string_write(f, col, "filename=", 9); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_quoted_string_write(f, col, param->pa_data.pa_filename, strlen(param->pa_data.pa_filename)); if (r != MAILIMF_NO_ERROR) return r; break; case MAILMIME_DISPOSITION_PARM_CREATION_DATE: r = mailimf_string_write(f, col, "creation-date=", 14); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_quoted_string_write(f, col, param->pa_data.pa_creation_date, strlen(param->pa_data.pa_creation_date)); if (r != MAILIMF_NO_ERROR) return r; break; case MAILMIME_DISPOSITION_PARM_MODIFICATION_DATE: r = mailimf_string_write(f, col, "modification-date=", 18); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_quoted_string_write(f, col, param->pa_data.pa_modification_date, strlen(param->pa_data.pa_modification_date)); if (r != MAILIMF_NO_ERROR) return r; break; case MAILMIME_DISPOSITION_PARM_READ_DATE: r = mailimf_string_write(f, col, "read-date=", 10); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_quoted_string_write(f, col, param->pa_data.pa_read_date, strlen(param->pa_data.pa_read_date)); if (r != MAILIMF_NO_ERROR) return r; break; case MAILMIME_DISPOSITION_PARM_SIZE: r = mailimf_string_write(f, col, "size=", 5); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_string_write(f, col, sizestr, strlen(sizestr)); if (r != MAILIMF_NO_ERROR) return r; break; case MAILMIME_DISPOSITION_PARM_PARAMETER: r = mailmime_parameter_write(f, col, param->pa_data.pa_parameter); if (r != MAILIMF_NO_ERROR) return r; break; } return MAILIMF_NO_ERROR; } static int mailmime_parameter_write(FILE * f, int * col, struct mailmime_parameter * param) { int r; r = mailimf_string_write(f, col, param->pa_name, strlen(param->pa_name)); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_string_write(f, col, "=", 1); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_quoted_string_write(f, col, param->pa_value, strlen(param->pa_value)); if (r != MAILIMF_NO_ERROR) return r; return MAILIMF_NO_ERROR; } int mailmime_content_type_write(FILE * f, int * col, struct mailmime_content * content) { clistiter * cur; size_t len; int r; r = mailmime_type_write(f, col, content->ct_type); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_string_write(f, col, "/", 1); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_string_write(f, col, content->ct_subtype, strlen(content->ct_subtype)); if (r != MAILIMF_NO_ERROR) return r; if (content->ct_parameters != NULL) { for(cur = clist_begin(content->ct_parameters) ; cur != NULL ; cur = clist_next(cur)) { struct mailmime_parameter * param; param = cur->data; r = mailimf_string_write(f, col, "; ", 2); if (r != MAILIMF_NO_ERROR) return r; len = strlen(param->pa_name) + 1 + strlen(param->pa_value); if (* col > 1) { if (* col + len > MAX_MAIL_COL) { r = mailimf_string_write(f, col, "\r\n ", 3); if (r != MAILIMF_NO_ERROR) return r; #if 0 * col = 1; #endif } } r = mailmime_parameter_write(f, col, param); if (r != MAILIMF_NO_ERROR) return r; } } return MAILIMF_NO_ERROR; } int mailmime_content_write(FILE * f, int * col, struct mailmime_content * content) { int r; r = mailimf_string_write(f, col, "Content-Type: ", 14); if (r != MAILIMF_NO_ERROR) return r; r = mailmime_content_type_write(f, col, content); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_string_write(f, col, "\r\n", 2); if (r != MAILIMF_NO_ERROR) return r; return MAILIMF_NO_ERROR; } static int mailmime_type_write(FILE * f, int * col, struct mailmime_type * type) { int r; switch (type->tp_type) { case MAILMIME_TYPE_DISCRETE_TYPE: r = mailmime_discrete_type_write(f, col, type->tp_data.tp_discrete_type); break; case MAILMIME_TYPE_COMPOSITE_TYPE: r = mailmime_composite_type_write(f, col, type->tp_data.tp_composite_type); break; default: r = MAILIMF_ERROR_INVAL; break; } if (r != MAILIMF_NO_ERROR) return r; return MAILIMF_NO_ERROR; } static int mailmime_discrete_type_write(FILE * f, int * col, struct mailmime_discrete_type * discrete_type) { int r; switch (discrete_type->dt_type) { case MAILMIME_DISCRETE_TYPE_TEXT: r = mailimf_string_write(f, col, "text", 4); break; case MAILMIME_DISCRETE_TYPE_IMAGE: r = mailimf_string_write(f, col, "image", 5); break; case MAILMIME_DISCRETE_TYPE_AUDIO: r = mailimf_string_write(f, col, "audio", 5); break; case MAILMIME_DISCRETE_TYPE_VIDEO: r = mailimf_string_write(f, col, "video", 5); break; case MAILMIME_DISCRETE_TYPE_APPLICATION: r = mailimf_string_write(f, col, "application", 11); break; case MAILMIME_DISCRETE_TYPE_EXTENSION: r = mailimf_string_write(f, col, discrete_type->dt_extension, strlen(discrete_type->dt_extension)); break; default: r = MAILIMF_ERROR_INVAL; break; } if (r != MAILIMF_NO_ERROR) return r; return MAILIMF_NO_ERROR; } static int mailmime_composite_type_write(FILE * f, int * col, struct mailmime_composite_type * composite_type) { int r; switch (composite_type->ct_type) { case MAILMIME_COMPOSITE_TYPE_MESSAGE: r = mailimf_string_write(f, col, "message", 7); break; case MAILMIME_COMPOSITE_TYPE_MULTIPART: r = mailimf_string_write(f, col, "multipart", 9); break; case MAILMIME_COMPOSITE_TYPE_EXTENSION: r = mailimf_string_write(f, col, composite_type->ct_token, strlen(composite_type->ct_token)); break; default: r = MAILIMF_ERROR_INVAL; break; } if (r != MAILIMF_NO_ERROR) return r; return MAILIMF_NO_ERROR; } /* ****************************************************************** */ /* message */ /* static int mailmime_data_write(FILE * f, int * col, struct mailmime_data * data, int is_text); */ static int mailmime_text_content_write(FILE * f, int * col, int encoding, int istext, const char * text, size_t size); /* static int mailmime_base64_write(FILE * f, int * col, char * text, size_t size); static int mailmime_quoted_printable_write(FILE * f, int * col, int istext, char * text, size_t size); */ static int mailmime_part_write(FILE * f, int * col, struct mailmime * build_info) { clistiter * cur; int first; int r; char * boundary; int istext; istext = TRUE; boundary = NULL; if (build_info->mm_content_type != NULL) { if (build_info->mm_type == MAILMIME_MULTIPLE) { boundary = mailmime_extract_boundary(build_info->mm_content_type); if (boundary == NULL) return MAILIMF_ERROR_INVAL; } if (build_info->mm_content_type->ct_type->tp_type == MAILMIME_TYPE_DISCRETE_TYPE) { if (build_info->mm_content_type->ct_type->tp_data.tp_discrete_type->dt_type != MAILMIME_DISCRETE_TYPE_TEXT) istext = FALSE; } } switch (build_info->mm_type) { case MAILMIME_SINGLE: /* 1-part body */ if (build_info->mm_data.mm_single != NULL) { r = mailmime_data_write(f, col, build_info->mm_data.mm_single, istext); if (r != MAILIMF_NO_ERROR) return r; } break; case MAILMIME_MULTIPLE: /* multi-part */ /* preamble */ if (build_info->mm_data.mm_multipart.mm_preamble != NULL) { r = mailmime_data_write(f, col, build_info->mm_data.mm_multipart.mm_preamble, TRUE); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_string_write(f, col, "\r\n", 2); if (r != MAILIMF_NO_ERROR) return r; #if 0 * col = 0; #endif } /* sub-parts */ first = TRUE; for(cur = clist_begin(build_info->mm_data.mm_multipart.mm_mp_list) ; cur != NULL ; cur = clist_next(cur)) { struct mailmime * subpart; subpart = cur->data; if (!first) { r = mailimf_string_write(f, col, "\r\n", 2); if (r != MAILIMF_NO_ERROR) return r; #if 0 * col = 0; #endif } else { first = FALSE; } r = mailimf_string_write(f, col, "--", 2); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_string_write(f, col, boundary, strlen(boundary)); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_string_write(f, col, "\r\n", 2); if (r != MAILIMF_NO_ERROR) return r; #if 0 * col = 0; #endif r = mailmime_sub_write(f, col, subpart); if (r != MAILIMF_NO_ERROR) return r; } r = mailimf_string_write(f, col, "\r\n", 2); if (r != MAILIMF_NO_ERROR) return r; #if 0 * col = 0; #endif r = mailimf_string_write(f, col, "--", 2); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_string_write(f, col, boundary, strlen(boundary)); if (r != MAILIMF_NO_ERROR) return r; r = mailimf_string_write(f, col, "--", 2); if (r != MAILIMF_NO_ERROR) return r; /* epilogue */ r = mailimf_string_write(f, col, "\r\n", 2); if (r != MAILIMF_NO_ERROR) return r; #if 0 * col = 0; #endif if (build_info->mm_data.mm_multipart.mm_epilogue != NULL) { r = mailmime_data_write(f, col, build_info->mm_data.mm_multipart.mm_epilogue, TRUE); if (r != MAILIMF_NO_ERROR) return r; } break; case MAILMIME_MESSAGE: if (build_info->mm_data.mm_message.mm_fields != NULL) { r = mailimf_fields_write(f, col, build_info->mm_data.mm_message.mm_fields); if (r != MAILIMF_NO_ERROR) return r; } if (build_info->mm_mime_fields != NULL) { r = mailmime_fields_write(f, col, build_info->mm_mime_fields); if (r != MAILIMF_NO_ERROR) return r; } /* encapsuled message */ if (build_info->mm_data.mm_message.mm_msg_mime != NULL) { r = mailmime_sub_write(f, col, build_info->mm_data.mm_message.mm_msg_mime); if (r != MAILIMF_NO_ERROR) return r; } break; } return MAILIMF_NO_ERROR; } static int mailmime_sub_write(FILE * f, int * col, struct mailmime * build_info) { int r; #if 0 * col = 0; #endif /* MIME field - Content-Type */ if (build_info->mm_content_type != NULL) { r = mailmime_content_write(f, col, build_info->mm_content_type); if (r != MAILIMF_NO_ERROR) return r; } /* other MIME fields */ if (build_info->mm_type != MAILMIME_MESSAGE) { if (build_info->mm_mime_fields != NULL) { r = mailmime_fields_write(f, col, build_info->mm_mime_fields); if (r != MAILIMF_NO_ERROR) return r; } } r = mailimf_string_write(f, col, "\r\n", 2); if (r != MAILIMF_NO_ERROR) return r; #if 0 * col = 0; #endif return mailmime_part_write(f, col, build_info); } int mailmime_write(FILE * f, int * col, struct mailmime * build_info) { if (build_info->mm_parent != NULL) return mailmime_sub_write(f, col, build_info); else return mailmime_part_write(f, col, build_info); } int mailmime_data_write(FILE * f, int * col, struct mailmime_data * data, int istext) { int fd; int r; char * text; struct stat buf; int res; switch (data->dt_type) { case MAILMIME_DATA_TEXT: if (data->dt_encoded) { r = mailimf_string_write(f, col, data->dt_data.dt_text.dt_data, data->dt_data.dt_text.dt_length); if (r != MAILIMF_NO_ERROR) return r; } else { r = mailmime_text_content_write(f, col, data->dt_encoding, istext, data->dt_data.dt_text.dt_data, data->dt_data.dt_text.dt_length); if (r != MAILIMF_NO_ERROR) return r; } break; case MAILMIME_DATA_FILE: fd = open(data->dt_data.dt_filename, O_RDONLY); if (fd < 0) { res = MAILIMF_ERROR_FILE; goto err; } r = fstat(fd, &buf); if (r < 0) { res = MAILIMF_ERROR_FILE; goto close; } if (buf.st_size != 0) { text = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); if (text == NULL) { res = MAILIMF_ERROR_FILE; goto close; } if (data->dt_encoded) { r = mailimf_string_write(f, col, text, buf.st_size); if (r != MAILIMF_NO_ERROR) { res = r; goto unmap; } } else { r = mailmime_text_content_write(f, col, data->dt_encoding, istext, text, buf.st_size); if (r != MAILIMF_NO_ERROR) { res = r; goto unmap; } } munmap(text, buf.st_size); } close(fd); if (r != MAILIMF_NO_ERROR) return r; break; unmap: munmap(text, buf.st_size); close: close(fd); err: return res; } return MAILIMF_NO_ERROR; } static int mailmime_text_content_write(FILE * f, int * col, int encoding, int istext, const char * text, size_t size) { switch (encoding) { case MAILMIME_MECHANISM_QUOTED_PRINTABLE: return mailmime_quoted_printable_write(f, col, istext, text, size); break; case MAILMIME_MECHANISM_BASE64: return mailmime_base64_write(f, col, text, size); break; case MAILMIME_MECHANISM_7BIT: case MAILMIME_MECHANISM_8BIT: case MAILMIME_MECHANISM_BINARY: default: return mailimf_string_write(f, col, text, size); } } static const char base64_encoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; #define BASE64_MAX_COL 76 int mailmime_base64_write(FILE * f, int * col, const char * text, size_t size) { int a; int b; int c; size_t remains; const char * p; size_t count; char ogroup[4]; int r; remains = size; p = text; while (remains > 0) { switch (remains) { case 1: a = (unsigned char) p[0]; b = 0; c = 0; count = 1; break; case 2: a = (unsigned char) p[0]; b = (unsigned char) p[1]; c = 0; count = 2; break; default: a = (unsigned char) p[0]; b = (unsigned char) p[1]; c = (unsigned char) p[2]; count = 3; break; } ogroup[0]= base64_encoding[a >> 2]; ogroup[1]= base64_encoding[((a & 3) << 4) | (b >> 4)]; ogroup[2]= base64_encoding[((b & 0xF) << 2) | (c >> 6)]; ogroup[3]= base64_encoding[c & 0x3F]; switch (count) { case 1: ogroup[2]= '='; ogroup[3]= '='; break; case 2: ogroup[3]= '='; break; } if (* col + 4 > BASE64_MAX_COL) { r = mailimf_string_write(f, col, "\r\n", 2); if (r != MAILIMF_NO_ERROR) return r; #if 0 * col = 0; #endif } r = mailimf_string_write(f, col, ogroup, 4); if (r != MAILIMF_NO_ERROR) return r; remains -= count; p += count; } r = mailimf_string_write(f, col, "\r\n", 2); return MAILIMF_NO_ERROR; } #if 0 #define MAX_WRITE_SIZE 512 #endif enum { STATE_INIT, STATE_CR, STATE_SPACE, STATE_SPACE_CR, }; #if 0 static inline int write_try_buf(FILE * f, int * col, char ** pstart, size_t * plen) { int r; if (* plen >= MAX_WRITE_SIZE) { r = mailimf_string_write(f, col, * pstart, * plen); if (r != MAILIMF_NO_ERROR) return r; * plen = 0; } return MAILIMF_NO_ERROR; } #endif static inline int write_remaining(FILE * f, int * col, const char ** pstart, size_t * plen) { int r; if (* plen > 0) { r = mailimf_string_write(f, col, * pstart, * plen); if (r != MAILIMF_NO_ERROR) return r; * plen = 0; } return MAILIMF_NO_ERROR; } #define QP_MAX_COL 72 int mailmime_quoted_printable_write(FILE * f, int * col, int istext, const char * text, size_t size) { size_t i; const char * start; size_t len; char hexstr[6]; int r; int state; start = text; len = 0; state = STATE_INIT; i = 0; while (i < size) { unsigned char ch; if (* col + len > QP_MAX_COL) { r = write_remaining(f, col, &start, &len); if (r != MAILIMF_NO_ERROR) return r; start = text + i; r = mailimf_string_write(f, col, "=\r\n", 3); if (r != MAILIMF_NO_ERROR) return r; } ch = text[i]; switch (state) { case STATE_INIT: switch (ch) { case ' ': case '\t': state = STATE_SPACE; break; case '\r': state = STATE_CR; break; case '!': case '"': case '#': case '$': case '@': case '[': case '\\': case ']': case '^': case '`': case '{': case '|': case '}': case '~': case '=': case '?': case '_': case 'F': /* there is no more 'From' at the beginning of a line */ r = write_remaining(f, col, &start, &len); if (r != MAILIMF_NO_ERROR) return r; start = text + i + 1; snprintf(hexstr, 6, "=%02X", ch); r = mailimf_string_write(f, col, hexstr, 3); if (r != MAILIMF_NO_ERROR) return r; break; default: if (istext && (ch == '\n')) { r = write_remaining(f, col, &start, &len); if (r != MAILIMF_NO_ERROR) return r; start = text + i + 1; r = mailimf_string_write(f, col, "\r\n", 2); if (r != MAILIMF_NO_ERROR) return r; break; } else { if (((ch >= 33) && (ch <= 60)) || ((ch >= 62) && (ch <= 126))) { len ++; } else { r = write_remaining(f, col, &start, &len); if (r != MAILIMF_NO_ERROR) return r; start = text + i + 1; snprintf(hexstr, 6, "=%02X", ch); r = mailimf_string_write(f, col, hexstr, 3); if (r != MAILIMF_NO_ERROR) return r; } } break; } i ++; break; case STATE_CR: switch (ch) { case '\n': r = write_remaining(f, col, &start, &len); if (r != MAILIMF_NO_ERROR) return r; start = text + i + 1; r = mailimf_string_write(f, col, "\r\n", 2); if (r != MAILIMF_NO_ERROR) return r; i ++; state = STATE_INIT; break; default: r = write_remaining(f, col, &start, &len); if (r != MAILIMF_NO_ERROR) return r; start = text + i; snprintf(hexstr, 6, "=%02X", '\r'); r = mailimf_string_write(f, col, hexstr, 3); if (r != MAILIMF_NO_ERROR) return r; state = STATE_INIT; break; } break; case STATE_SPACE: switch (ch) { case '\r': state = STATE_SPACE_CR; i ++; break; case '\n': r = write_remaining(f, col, &start, &len); if (r != MAILIMF_NO_ERROR) return r; start = text + i + 1; snprintf(hexstr, 6, "=%02X\r\n", text[i - 1]); r = mailimf_string_write(f, col, hexstr, strlen(hexstr)); if (r != MAILIMF_NO_ERROR) return r; state = STATE_INIT; i ++; break; case ' ': case '\t': len ++; i ++; break; default: #if 0 len += 2; state = STATE_INIT; i ++; #endif len ++; state = STATE_INIT; break; } break; case STATE_SPACE_CR: switch (ch) { case '\n': r = write_remaining(f, col, &start, &len); if (r != MAILIMF_NO_ERROR) return r; start = text + i + 1; snprintf(hexstr, 6, "=%02X\r\n", text[i - 2]); r = mailimf_string_write(f, col, hexstr, strlen(hexstr)); if (r != MAILIMF_NO_ERROR) return r; state = STATE_INIT; i ++; break; default: r = write_remaining(f, col, &start, &len); if (r != MAILIMF_NO_ERROR) return r; start = text + i + 1; snprintf(hexstr, 6, "%c=%02X", text[i - 2], '\r'); r = mailimf_string_write(f, col, hexstr, strlen(hexstr)); if (r != MAILIMF_NO_ERROR) return r; state = STATE_INIT; break; } break; } } return MAILIMF_NO_ERROR; } diff --git a/kmicromail/libetpan/smtp/mailsmtp.c b/kmicromail/libetpan/smtp/mailsmtp.c index b3be432..3ab1d11 100644 --- a/kmicromail/libetpan/smtp/mailsmtp.c +++ b/kmicromail/libetpan/smtp/mailsmtp.c @@ -1,982 +1,984 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa, * All rights reserved. * * SMTP AUTH support by Juergen Graf * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "mailsmtp.h" #include "connect.h" #include "md5.h" #include "base64.h" #include "mail.h" #include <netinet/in.h> #include <string.h> #include <stdlib.h> #include <unistd.h> #include <stdio.h> /* RFC 2821 : SMTP RFC 1891 : SMTP Service Extension for Delivery Status Notifications RFC 1428 : Transition of Internet Mail from Just-Send-8 to 8bit-SMTP/MIME RFC 1652 : SMTP Service Extension for 8bit-MIMEtransport RFC 1845 : SMTP Service Extension for Checkpoint/Restart RFC 1846 : SMTP 521 Reply Code RFC 1870 : SMTP Service Extension for Message Size Declaration RFC 1985 : SMTP Service Extension for Remote Message Queue Starting RFC 2034 : SMTP Service Extension for Returning Enhanced Error Codes RFC 2442 : The Batch SMTP Media Type RFC 2487 : SMTP Service Extension for Secure SMTP over TLS RFC 2505 : Anti-Spam Recommendations for SMTP MTAs RFC 2554 : SMTP Service Extension for Authentication RFC 2645 : ON-DEMAND MAIL RELAY (ODMR) SMTP with Dynamic IP Addresses RFC 2852 : Deliver By SMTP Service Extension RFC 2920 : SMTP Service Extension for Command Pipelining RFC 3030 : SMTP Service Extensions for Transmission of Large and Binary MIME Messages */ #define SMTP_STATUS_CONTINUE 0x1000 mailsmtp * mailsmtp_new(size_t progr_rate, progress_function * progr_fun) { mailsmtp * session; session = malloc(sizeof(* session)); if (session == NULL) goto err; session->stream = NULL; session->progr_rate = progr_rate; session->progr_fun = progr_fun; session->response = NULL; session->line_buffer = mmap_string_new(""); if (session->line_buffer == NULL) goto free_session; session->response_buffer = mmap_string_new(""); if (session->response_buffer == NULL) goto free_line_buffer; session->esmtp = 0; session->auth = MAILSMTP_AUTH_NOT_CHECKED; return session; free_line_buffer: mmap_string_free(session->line_buffer); free_session: free(session); err: return NULL; } void mailsmtp_free(mailsmtp * session) { if (session->stream) mailsmtp_quit(session); mmap_string_free(session->line_buffer); mmap_string_free(session->response_buffer); free(session); } static int send_command(mailsmtp * f, char * command); static int read_response(mailsmtp * session); /* smtp operations */ int mailsmtp_connect(mailsmtp * session, mailstream * s) { int code; session->stream = s; code = read_response(session); switch (code) { case 220: return MAILSMTP_NO_ERROR; case 554: session->stream = NULL; mailstream_close(s); return MAILSMTP_ERROR_SERVICE_NOT_AVAILABLE; default: session->stream = NULL; mailstream_close(s); return MAILSMTP_ERROR_UNEXPECTED_CODE; } } #define SMTP_STRING_SIZE 513 int mailsmtp_quit(mailsmtp * session) { char command[SMTP_STRING_SIZE]; int r; snprintf(command, SMTP_STRING_SIZE, "QUIT\r\n"); r = send_command(session, command); if (r == -1) return MAILSMTP_ERROR_STREAM; r = read_response(session); if (r == 0) return MAILSMTP_ERROR_STREAM; mailstream_close(session->stream); session->stream = NULL; return MAILSMTP_NO_ERROR; } #define HOSTNAME_SIZE 256 int mailsmtp_helo(mailsmtp * session) { int r; char hostname[HOSTNAME_SIZE]; char command[SMTP_STRING_SIZE]; r = gethostname(hostname, HOSTNAME_SIZE); if (r < 0) return MAILSMTP_ERROR_HOSTNAME; snprintf(command, SMTP_STRING_SIZE, "HELO %s\r\n", hostname); r = send_command(session, command); if (r == -1) return MAILSMTP_ERROR_STREAM; r = read_response(session); switch (r) { case 250: + session->esmtp = 0; + session->auth = MAILSMTP_AUTH_NOT_CHECKED; return MAILSMTP_NO_ERROR; case 504: return MAILSMTP_ERROR_NOT_IMPLEMENTED; case 550: return MAILSMTP_ERROR_ACTION_NOT_TAKEN; case 0: return MAILSMTP_ERROR_STREAM; default: return MAILSMTP_ERROR_UNEXPECTED_CODE; } } int mailsmtp_mail(mailsmtp * session, const char * from) { int r; char command[SMTP_STRING_SIZE]; snprintf(command, SMTP_STRING_SIZE, "MAIL FROM:<%s>\r\n", from); r = send_command(session, command); if (r == -1) return MAILSMTP_ERROR_STREAM; r = read_response(session); switch (r) { case 250: return MAILSMTP_NO_ERROR; case 552: return MAILSMTP_ERROR_EXCEED_STORAGE_ALLOCATION; case 451: return MAILSMTP_ERROR_IN_PROCESSING; case 452: return MAILSMTP_ERROR_INSUFFICIENT_SYSTEM_STORAGE; case 550: return MAILSMTP_ERROR_MAILBOX_UNAVAILABLE; case 553: return MAILSMTP_ERROR_MAILBOX_NAME_NOT_ALLOWED; case 503: return MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND; case 0: return MAILSMTP_ERROR_STREAM; default: return MAILSMTP_ERROR_UNEXPECTED_CODE; } } int mailsmtp_rcpt(mailsmtp * session, const char * to) { return mailesmtp_rcpt(session, to, 0, NULL); } int mailsmtp_data(mailsmtp * session) { int r; char command[SMTP_STRING_SIZE]; snprintf(command, SMTP_STRING_SIZE, "DATA\r\n"); r = send_command(session, command); if (r == -1) return MAILSMTP_ERROR_STREAM; r = read_response(session); switch (r) { case 354: return MAILSMTP_NO_ERROR; case 451: return MAILSMTP_ERROR_IN_PROCESSING; case 554: return MAILSMTP_ERROR_TRANSACTION_FAILED; case 503: return MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND; default: return MAILSMTP_ERROR_UNEXPECTED_CODE; } } static int send_data(mailsmtp * session, const char * message, size_t size); int mailsmtp_data_message(mailsmtp * session, const char * message, size_t size) { int r; r = send_data(session, message, size); if (r == -1) return MAILSMTP_ERROR_STREAM; r = read_response(session); switch(r) { case 250: return MAILSMTP_NO_ERROR; case 552: return MAILSMTP_ERROR_EXCEED_STORAGE_ALLOCATION; case 554: return MAILSMTP_ERROR_TRANSACTION_FAILED; case 451: return MAILSMTP_ERROR_IN_PROCESSING; case 452: return MAILSMTP_ERROR_INSUFFICIENT_SYSTEM_STORAGE; case 0: return MAILSMTP_ERROR_STREAM; default: return MAILSMTP_ERROR_UNEXPECTED_CODE; } } /* esmtp operations */ /** * called during mailesmtp_ehlo * checks EHLO answer for server extensions and sets flags * in session->esmtp * checks AUTH methods in session->response and sets flags * in session->auth */ #define isdelim(x) ((x) == ' ' || (x) == '\r' || (x) == '\n' || (x) == '\0') int mailesmtp_parse_ehlo(mailsmtp * session) { char * response; /* restore data */ session->esmtp = MAILSMTP_ESMTP; session->auth = MAILSMTP_AUTH_CHECKED; response = session->response; /* ESMTP supported extensions : DSN EXPN 8BITMIME SIZE [<n>] ETRN STARTTLS AUTH <mechanisms...> */ while (response != NULL) { if (!strncasecmp(response, "EXPN", 4) && isdelim(response[4])) session->esmtp |= MAILSMTP_ESMTP_EXPN; else if (!strncasecmp(response, "ETRN", 4) && isdelim(response[4])) session->esmtp |= MAILSMTP_ESMTP_ETRN; else if (!strncasecmp(response, "DSN", 3) && isdelim(response[3])) session->esmtp |= MAILSMTP_ESMTP_DSN; else if (!strncasecmp(response, "8BITMIME", 8) && isdelim(response[8])) session->esmtp |= MAILSMTP_ESMTP_8BITMIME; else if (!strncasecmp(response, "STARTTLS", 8) && isdelim(response[8])) session->esmtp |= MAILSMTP_ESMTP_STARTTLS; else if (!strncasecmp(response, "SIZE", 4) && isdelim(response[4])) { session->esmtp |= MAILSMTP_ESMTP_SIZE; /* TODO: grab optionnal max size */ } else if (!strncasecmp(response, "AUTH ", 5)) { response += 5; /* remove "AUTH " */ while (response[0] != '\n' && response[0] != '\0') { while (response[0] == ' ') response++; if (strncasecmp(response, "LOGIN", 5) == 0) { session->auth |= MAILSMTP_AUTH_LOGIN; response += 5; } else if (strncasecmp(response, "CRAM-MD5", 8) == 0) { session->auth |= MAILSMTP_AUTH_CRAM_MD5; response += 8; } else if (strncasecmp(response, "PLAIN", 5) == 0) { session->auth |= MAILSMTP_AUTH_PLAIN; response += 5; } else { /* unknown auth method - jump to next word or eol */ while (!isdelim(response[0]) || response[0] == '\r') response++; } } } response = strpbrk(response, "\n"); if (response != NULL) response++; } return MAILSMTP_NO_ERROR; } int mailesmtp_ehlo(mailsmtp * session) { int r; char hostname[HOSTNAME_SIZE]; char command[SMTP_STRING_SIZE]; r = gethostname(hostname, HOSTNAME_SIZE); if (r != 0) return MAILSMTP_ERROR_HOSTNAME; snprintf(command, SMTP_STRING_SIZE, "EHLO %s\r\n", hostname); r = send_command(session, command); if (r == -1) return MAILSMTP_ERROR_STREAM; r = read_response(session); switch (r) { case 250: return mailesmtp_parse_ehlo(session); case 504: return MAILSMTP_ERROR_NOT_IMPLEMENTED; case 550: return MAILSMTP_ERROR_ACTION_NOT_TAKEN; case 0: return MAILSMTP_ERROR_STREAM; default: return MAILSMTP_ERROR_UNEXPECTED_CODE; } } /* if return_full is TRUE, the entire message is returned on error envid can be NULL */ int mailesmtp_mail(mailsmtp * session, const char * from, int return_full, const char * envid) { int r; char command[SMTP_STRING_SIZE]; char *body = ""; #if notyet /* TODO: figure out a way for the user to explicity enable this or not */ if (session->esmtp & MAILSMTP_ESMTP_8BITMIME) body = " BODY=8BITMIME"; #endif if (session->esmtp & MAILSMTP_ESMTP_DSN) { if (envid) snprintf(command, SMTP_STRING_SIZE, "MAIL FROM:<%s> RET=%s ENVID=%s%s\r\n", from, return_full ? "FULL" : "HDRS", envid, body); else snprintf(command, SMTP_STRING_SIZE, "MAIL FROM:<%s> RET=%s%s\r\n", from, return_full ? "FULL" : "HDRS", body); } else snprintf(command, SMTP_STRING_SIZE, "MAIL FROM:<%s>%s\r\n", from, body); r = send_command(session, command); if (r == -1) return MAILSMTP_ERROR_STREAM; r = read_response(session); switch (r) { case 250: return MAILSMTP_NO_ERROR; case 552: return MAILSMTP_ERROR_EXCEED_STORAGE_ALLOCATION; case 451: return MAILSMTP_ERROR_IN_PROCESSING; case 452: return MAILSMTP_ERROR_INSUFFICIENT_SYSTEM_STORAGE; case 550: return MAILSMTP_ERROR_MAILBOX_UNAVAILABLE; case 553: return MAILSMTP_ERROR_MAILBOX_NAME_NOT_ALLOWED; case 503: return MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND; case 0: return MAILSMTP_ERROR_STREAM; default: return MAILSMTP_ERROR_UNEXPECTED_CODE; } } int mailesmtp_rcpt(mailsmtp * session, const char * to, int notify, const char * orcpt) { int r; char command[SMTP_STRING_SIZE]; char notify_str[30] = ""; char notify_info_str[30] = ""; if (notify != 0 && session->esmtp & MAILSMTP_ESMTP_DSN) { if (notify & MAILSMTP_DSN_NOTIFY_SUCCESS) strcat(notify_info_str, ",SUCCESS"); if (notify & MAILSMTP_DSN_NOTIFY_FAILURE) strcat(notify_info_str, ",FAILURE"); if (notify & MAILSMTP_DSN_NOTIFY_DELAY) strcat(notify_info_str, ",DELAY"); if (notify & MAILSMTP_DSN_NOTIFY_NEVER) strcpy(notify_info_str, ",NEVER"); notify_info_str[0] = '='; strcpy(notify_str, " NOTIFY"); strcat(notify_str, notify_info_str); } if (orcpt && session->esmtp & MAILSMTP_ESMTP_DSN) snprintf(command, SMTP_STRING_SIZE, "RCPT TO:<%s>%s ORCPT=%s\r\n", to, notify_str, orcpt); else snprintf(command, SMTP_STRING_SIZE, "RCPT TO:<%s>%s\r\n", to, notify_str); r = send_command(session, command); if (r == -1) return MAILSMTP_ERROR_STREAM; r = read_response(session); switch (r) { case 250: return MAILSMTP_NO_ERROR; case 251: /* not local user, will be forwarded */ return MAILSMTP_NO_ERROR; case 550: case 450: return MAILSMTP_ERROR_MAILBOX_UNAVAILABLE; case 551: return MAILSMTP_ERROR_USER_NOT_LOCAL; case 552: return MAILSMTP_ERROR_EXCEED_STORAGE_ALLOCATION; case 553: return MAILSMTP_ERROR_MAILBOX_NAME_NOT_ALLOWED; case 451: return MAILSMTP_ERROR_IN_PROCESSING; case 452: return MAILSMTP_ERROR_INSUFFICIENT_SYSTEM_STORAGE; case 503: return MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND; case 0: return MAILSMTP_ERROR_STREAM; default: return MAILSMTP_ERROR_UNEXPECTED_CODE; } } int auth_map_errors(int err) { switch (err) { case 235: return MAILSMTP_NO_ERROR; /* AUTH successfull */ case 334: return MAILSMTP_NO_ERROR; /* AUTH in progress */ case 432: return MAILSMTP_ERROR_AUTH_TRANSITION_NEEDED; case 454: return MAILSMTP_ERROR_AUTH_TEMPORARY_FAILTURE; case 504: return MAILSMTP_ERROR_AUTH_NOT_SUPPORTED; case 530: return MAILSMTP_ERROR_AUTH_REQUIRED; case 534: return MAILSMTP_ERROR_AUTH_TOO_WEAK; case 538: return MAILSMTP_ERROR_AUTH_ENCRYPTION_REQUIRED; default: /* opportunistic approach ;) */ return MAILSMTP_NO_ERROR; } } static int mailsmtp_auth_login(mailsmtp * session, const char * user, const char * pass) { int err; char command[SMTP_STRING_SIZE]; char * user64, * pass64; user64 = NULL; pass64 = NULL; user64 = encode_base64(user, strlen(user)); if (user64 == NULL) { err = MAILSMTP_ERROR_MEMORY; goto err_free; } pass64 = encode_base64(pass, strlen(pass)); if (pass64 == NULL) { err = MAILSMTP_ERROR_MEMORY; goto err_free; } snprintf(command, SMTP_STRING_SIZE, "%s\r\n", user64); err = send_command(session, command); if (err == -1) { err = MAILSMTP_ERROR_STREAM; goto err_free; } err = read_response(session); err = auth_map_errors(err); if (err != MAILSMTP_NO_ERROR) goto err_free; snprintf(command, SMTP_STRING_SIZE, "%s\r\n", pass64); err = send_command(session, command); if (err == -1) { err = MAILSMTP_ERROR_STREAM; goto err_free; } err = read_response(session); err = auth_map_errors(err); err_free: free(user64); free(pass64); return err; } static int mailsmtp_auth_plain(mailsmtp * session, const char * user, const char * pass) { int err, len; char command[SMTP_STRING_SIZE]; char * plain, * plain64; len = strlen(user) + strlen(pass) + 3; plain = (char *) malloc(len); if (plain == NULL) { err = MAILSMTP_ERROR_MEMORY; goto err; } snprintf(plain, len, "%c%s%c%s", '\0', user, '\0', pass); plain64 = encode_base64(plain, len - 1); snprintf(command, SMTP_STRING_SIZE, "%s\r\n", plain64); err = send_command(session, command); if (err == -1) { err = MAILSMTP_ERROR_STREAM; goto err_free; } err = read_response(session); err = auth_map_errors(err); err_free: free(plain64); free(plain); err: return err; } static char * convert_hex(unsigned char *in, int len) { static char hex[] = "0123456789abcdef"; char * out; int i; out = (char *) malloc(len * 2 + 1); if (out == NULL) return NULL; for (i = 0; i < len; i++) { out[i * 2] = hex[in[i] >> 4]; out[i * 2 + 1] = hex[in[i] & 15]; } out[i*2] = 0; return out; } static char * hash_md5(const char * sec_key, const char * data, int len) { char key[65], digest[24]; char * hash_hex; int sec_len, i; sec_len = strlen(sec_key); if (sec_len < 64) { memcpy(key, sec_key, sec_len); for (i = sec_len; i < 64; i++) { key[i] = 0; } } else { memcpy(key, sec_key, 64); } hmac_md5(data, len, key, 64, digest); hash_hex = convert_hex(digest, 16); return hash_hex; } static int mailsmtp_auth_cram_md5(mailsmtp * session, const char * user, const char * pass) { int err; char command[SMTP_STRING_SIZE]; char *response, *auth_hex, *auth; response = decode_base64(session->response, strlen(session->response)); if (response == NULL) return MAILSMTP_ERROR_MEMORY; auth_hex = hash_md5(pass, response, strlen(response)); if (auth_hex == NULL) { err = MAILSMTP_ERROR_MEMORY; goto err_free_response; } snprintf(command, SMTP_STRING_SIZE, "%s %s", user, auth_hex); auth = encode_base64(command, strlen(command)); if (auth == NULL) { err = MAILSMTP_ERROR_MEMORY; goto err_free_auth_hex; } snprintf(command, SMTP_STRING_SIZE, "%s\r\n", auth); err = send_command(session, command); if (err == -1) { err = MAILSMTP_ERROR_STREAM; goto err_free; } err = read_response(session); err = auth_map_errors(err); err_free: free(auth); err_free_auth_hex: free(auth_hex); err_free_response: free(response); return err; } int mailsmtp_auth_type(mailsmtp * session, const char * user, const char * pass, int type) { int err; char command[SMTP_STRING_SIZE]; if (session->auth == MAILSMTP_AUTH_NOT_CHECKED) return MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND; if ( !(session->auth & type) ) return MAILSMTP_ERROR_AUTH_NOT_SUPPORTED; switch (type) { case MAILSMTP_AUTH_LOGIN: snprintf(command, SMTP_STRING_SIZE, "AUTH LOGIN\r\n"); break; case MAILSMTP_AUTH_PLAIN: snprintf(command, SMTP_STRING_SIZE, "AUTH PLAIN\r\n"); break; case MAILSMTP_AUTH_CRAM_MD5: snprintf(command, SMTP_STRING_SIZE, "AUTH CRAM-MD5\r\n"); break; default: return MAILSMTP_ERROR_NOT_IMPLEMENTED; } err = send_command(session, command); if (err == -1) return MAILSMTP_ERROR_STREAM; err = read_response(session); err = auth_map_errors(err); if (err != MAILSMTP_NO_ERROR) return err; switch (type) { case MAILSMTP_AUTH_LOGIN: return mailsmtp_auth_login(session, user, pass); case MAILSMTP_AUTH_PLAIN: return mailsmtp_auth_plain(session, user, pass); case MAILSMTP_AUTH_CRAM_MD5: return mailsmtp_auth_cram_md5(session, user, pass); default: return MAILSMTP_ERROR_NOT_IMPLEMENTED; } } int mailsmtp_auth(mailsmtp * session, const char * user, const char * pass) { if (session->auth == MAILSMTP_AUTH_NOT_CHECKED) return MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND; if (session->auth & MAILSMTP_AUTH_CRAM_MD5) { return mailsmtp_auth_type(session, user, pass, MAILSMTP_AUTH_CRAM_MD5); } else if (session->auth & MAILSMTP_AUTH_PLAIN) { return mailsmtp_auth_type(session, user, pass, MAILSMTP_AUTH_PLAIN); } else if (session->auth & MAILSMTP_AUTH_LOGIN) { return mailsmtp_auth_type(session, user, pass, MAILSMTP_AUTH_LOGIN); } else { return MAILSMTP_ERROR_AUTH_NOT_SUPPORTED; } } /* TODO: add mailesmtp_etrn, mailssmtp_expn */ int mailesmtp_starttls(mailsmtp * session) { int r; if (!(session->esmtp & MAILSMTP_ESMTP_STARTTLS)) return MAILSMTP_ERROR_STARTTLS_NOT_SUPPORTED; r = send_command(session, "STARTTLS\r\n"); if (r == -1) return MAILSMTP_ERROR_STREAM; r = read_response(session); switch (r) { case 220: return MAILSMTP_NO_ERROR; case 454: return MAILSMTP_ERROR_STARTTLS_TEMPORARY_FAILURE; default: return MAILSMTP_ERROR_UNEXPECTED_CODE; } } static int parse_response(mailsmtp * session, char * response) { char * message; int code; int cont = 0; code = strtol(response, &message, 10); if (* message == ' ') mmap_string_append(session->response_buffer, message + 1); else if (* message == '-') { cont = SMTP_STATUS_CONTINUE; mmap_string_append(session->response_buffer, message + 1); } else mmap_string_append(session->response_buffer, message); return code | cont; } static char * read_line(mailsmtp * session) { return mailstream_read_line_remove_eol(session->stream, session->line_buffer); } static int read_response(mailsmtp * session) { char * line; int code; mmap_string_assign(session->response_buffer, ""); do { line = read_line(session); if (line != NULL) { code = parse_response(session, line); mmap_string_append_c(session->response_buffer, '\n'); } else code = 0; } while ((code & SMTP_STATUS_CONTINUE) != 0); session->response = session->response_buffer->str; return code; } static int send_command(mailsmtp * f, char * command) { ssize_t r; r = mailstream_write(f->stream, command, strlen(command)); if (r == -1) return -1; r = mailstream_flush(f->stream); if (r == -1) return -1; return 0; } static int send_data(mailsmtp * session, const char * message, size_t size) { if (mailstream_send_data(session->stream, message, size, session->progr_rate, session->progr_fun) == -1) return -1; if (mailstream_flush(session->stream) == -1) return -1; return 0; } const char * mailsmtp_strerror(int errnum) { switch (errnum) { case MAILSMTP_NO_ERROR: return "No error"; case MAILSMTP_ERROR_UNEXPECTED_CODE: return "Unexpected error code"; case MAILSMTP_ERROR_SERVICE_NOT_AVAILABLE: return "Service not available"; case MAILSMTP_ERROR_STREAM: return "Stream error"; case MAILSMTP_ERROR_HOSTNAME: return "gethostname() failed"; case MAILSMTP_ERROR_NOT_IMPLEMENTED: return "Not implemented"; case MAILSMTP_ERROR_ACTION_NOT_TAKEN: return "Error, action not taken"; case MAILSMTP_ERROR_EXCEED_STORAGE_ALLOCATION: return "Data exceeds storage allocation"; case MAILSMTP_ERROR_IN_PROCESSING: return "Error in processing"; case MAILSMTP_ERROR_INSUFFICIENT_SYSTEM_STORAGE: return "Insufficient system storage"; case MAILSMTP_ERROR_MAILBOX_UNAVAILABLE: return "Mailbox unavailable"; case MAILSMTP_ERROR_MAILBOX_NAME_NOT_ALLOWED: return "Mailbox name not allowed"; case MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND: return "Bad command sequence"; case MAILSMTP_ERROR_USER_NOT_LOCAL: return "User not local"; case MAILSMTP_ERROR_TRANSACTION_FAILED: return "Transaction failed"; case MAILSMTP_ERROR_MEMORY: return "Memory error"; case MAILSMTP_ERROR_CONNECTION_REFUSED: return "Connection refused"; case MAILSMTP_ERROR_STARTTLS_TEMPORARY_FAILURE: return "TLS not available on server for temporary reason"; case MAILSMTP_ERROR_STARTTLS_NOT_SUPPORTED: return "TLS not supported by server"; default: return "Unknown error code"; } } diff --git a/kmicromail/libetpan/smtp/mailsmtp_helper.c b/kmicromail/libetpan/smtp/mailsmtp_helper.c index 32d6564..7995377 100644 --- a/kmicromail/libetpan/smtp/mailsmtp_helper.c +++ b/kmicromail/libetpan/smtp/mailsmtp_helper.c @@ -1,232 +1,228 @@ /* * libEtPan! -- a mail stuff library * * Copyright (C) 2001, 2002 - DINH Viet Hoa * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the libEtPan! project nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * $Id$ */ #include "mailsmtp.h" #include <string.h> #include <stdlib.h> #include "mail.h" int mailsmtp_init(mailsmtp * session) { int r; - session->esmtp = 0; + r = mailesmtp_ehlo(session); - if (r == MAILSMTP_NO_ERROR) { - // session->esmtp = TRUE; + if (r == MAILSMTP_NO_ERROR) return MAILSMTP_NO_ERROR; - } r = mailsmtp_helo(session); - /* if (r == MAILSMTP_NO_ERROR) { */ -/* session->esmtp = FALSE; */ -/* return MAILSMTP_NO_ERROR; */ -/* } */ + if (r == MAILSMTP_NO_ERROR) + return MAILSMTP_NO_ERROR; return r; } int mailesmtp_send(mailsmtp * session, const char * from, int return_full, const char * envid, clist * addresses, const char * message, size_t size) { int r; clistiter * l; if (!session->esmtp) return mailsmtp_send(session, from, addresses, message, size); r = mailesmtp_mail(session, from, return_full, envid); if (r != MAILSMTP_NO_ERROR) return r; for(l = clist_begin(addresses) ; l != NULL; l = clist_next(l)) { struct esmtp_address * addr; addr = clist_content(l); r = mailesmtp_rcpt(session, addr->address, addr->notify, addr->orcpt); if (r != MAILSMTP_NO_ERROR) return r; } r = mailsmtp_data(session); if (r != MAILSMTP_NO_ERROR) return r; r = mailsmtp_data_message(session, message, size); if (r != MAILSMTP_NO_ERROR) return r; return MAILSMTP_NO_ERROR; } int mailsmtp_send(mailsmtp * session, const char * from, clist * addresses, const char * message, size_t size) { int r; clistiter * l; r = mailsmtp_mail(session, from); if (r != MAILSMTP_NO_ERROR) return r; for(l = clist_begin(addresses) ; l != NULL; l = clist_next(l)) { struct esmtp_address * addr; addr = clist_content(l); r = mailsmtp_rcpt(session, addr->address); if (r != MAILSMTP_NO_ERROR) return r; } r = mailsmtp_data(session); if (r != MAILSMTP_NO_ERROR) return r; r = mailsmtp_data_message(session, message, size); if (r != MAILSMTP_NO_ERROR) return r; return MAILSMTP_NO_ERROR; } /* esmtp addresses and smtp addresses */ static struct esmtp_address * esmtp_address_new(char * addr, int notify, char * orcpt) { struct esmtp_address * esmtpa; esmtpa = malloc(sizeof(* esmtpa)); if (esmtpa == NULL) return NULL; esmtpa->address = strdup(addr); if (esmtpa->address == NULL) { free(esmtpa); return NULL; } if (orcpt != NULL) { esmtpa->orcpt = strdup(orcpt); if (esmtpa->orcpt == NULL) { free(esmtpa->address); free(esmtpa); return NULL; } } else esmtpa->orcpt = NULL; esmtpa->notify = notify; return esmtpa; } static void esmtp_address_free(struct esmtp_address * addr) { if (addr->orcpt) free(addr->orcpt); if (addr->address) free(addr->address); free(addr); } clist * esmtp_address_list_new() { return clist_new(); } void esmtp_address_list_free(clist * l) { clist_foreach(l, (clist_func) esmtp_address_free, NULL); clist_free(l); } int esmtp_address_list_add(clist * list, char * address, int notify, char * orcpt) { struct esmtp_address * esmtpa; int r; esmtpa = esmtp_address_new(address, notify, orcpt); if (esmtpa == NULL) return -1; r = clist_append(list, esmtpa); if (r < 0) { esmtp_address_free(esmtpa); return -1; } return 0; } clist * smtp_address_list_new() { return esmtp_address_list_new(); } int smtp_address_list_add(clist * list, char * address) { return esmtp_address_list_add(list, address, 0, NULL); } void smtp_address_list_free(clist * l) { esmtp_address_list_free(l); } diff --git a/kmicromail/libmailwrapper/abstractmail.cpp b/kmicromail/libmailwrapper/abstractmail.cpp index 3998abd..3b0ca1f 100644 --- a/kmicromail/libmailwrapper/abstractmail.cpp +++ b/kmicromail/libmailwrapper/abstractmail.cpp @@ -1,187 +1,237 @@ // CHANGED 2004-09-31 Lutz Rogowski #include "abstractmail.h" #include "imapwrapper.h" #include "pop3wrapper.h" #include "nntpwrapper.h" #include "mhwrapper.h" #include "mailtypes.h" +#include <qprogressbar.h> +#include <qapplication.h> #include <kdecore/kstandarddirs.h> #include <qfile.h> #include <qtextstream.h> #include <stdlib.h> #include <libetpan/mailmime_content.h> #include <libetpan/mailmime.h> using namespace Opie::Core; AbstractMail* AbstractMail::getWrapper(IMAPaccount *a) { return new IMAPwrapper(a); } AbstractMail* AbstractMail::getWrapper(POP3account *a) { return new POP3wrapper(a); } AbstractMail* AbstractMail::getWrapper(NNTPaccount *a) { return new NNTPwrapper(a); } AbstractMail* AbstractMail::getWrapper(const QString&a,const QString&name) { return new MHwrapper(a,name); } AbstractMail* AbstractMail::getWrapper(Account*a) { if (!a) return 0; switch (a->getType()) { case MAILLIB::A_IMAP: return new IMAPwrapper((IMAPaccount*)a); break; case MAILLIB::A_POP3: return new POP3wrapper((POP3account*)a); break; case MAILLIB::A_NNTP: return new NNTPwrapper((NNTPaccount*)a); break; default: return 0; } } encodedString* AbstractMail::decode_String(const encodedString*text,const QString&enc) { // odebug << "Decode string start" << oendl; char*result_text; size_t index = 0; /* reset for recursive use! */ size_t target_length = 0; result_text = 0; int mimetype = MAILMIME_MECHANISM_7BIT; if (enc.lower()=="quoted-printable") { mimetype = MAILMIME_MECHANISM_QUOTED_PRINTABLE; } else if (enc.lower()=="base64") { mimetype = MAILMIME_MECHANISM_BASE64; } else if (enc.lower()=="8bit") { mimetype = MAILMIME_MECHANISM_8BIT; } else if (enc.lower()=="binary") { mimetype = MAILMIME_MECHANISM_BINARY; } int err = mailmime_part_parse(text->Content(),text->Length(),&index,mimetype, &result_text,&target_length); encodedString* result = new encodedString(); if (err == MAILIMF_NO_ERROR) { result->setContent(result_text,target_length); } //odebug << "Decode string finished" << oendl; return result; } QString AbstractMail::convert_String(const char*text) { //size_t index = 0; char*res = 0; int err = MAILIMF_NO_ERROR; QString result(text); /* due a bug in libetpan it isn't usable this moment */ /* int err = mailmime_encoded_phrase_parse("iso-8859-1", text, strlen(text),&index, "iso-8859-1",&res);*/ //odebug << "Input: " << text << "" << oendl; if (err == MAILIMF_NO_ERROR && res && strlen(res)) { // result = QString(res); // odebug << "Res: " << res << ", length: " << strlen(res) << "" << oendl; } if (res) free(res); return result; } /* cp & paste from launcher */ QString AbstractMail::gen_attachment_id() { QFile file( "/proc/sys/kernel/random/uuid" ); if (!file.open(IO_ReadOnly ) ) return QString::null; QTextStream stream(&file); return "{" + stream.read().stripWhiteSpace() + "}"; } int AbstractMail::createMbox(const QString&,const FolderP&,const QString& ,bool) { return 0; } QString AbstractMail::defaultLocalfolder() { // QString f = getenv( "HOME" ); QString f = locateLocal( "data", "kmicromail/localmail"); // f += "/Applications/opiemail/localmail"; return f; } QString AbstractMail::draftFolder() { return QString("Drafts"); } /* temporary - will be removed when implemented in all classes */ void AbstractMail::deleteMails(const QString &,const QValueList<Opie::Core::OSmartPointer<RecMail> > &) { } void AbstractMail::deleteMailList(const QValueList<RecMailP>&target) { - qDebug("AbstractMail::deleteMailList:: Please reimplement! "); - + //qDebug("AbstractMail::deleteMailList:: Please reimplement! "); + // this is currently re-implemented in pop3wrapper and imapwrapper + int iii = 0; + int count = target.count(); + QProgressBar bar( count,0 ); + bar.setCaption (("Removing mails - close to abort!") ); + int w = 300; + if ( QApplication::desktop()->width() < 320 ) + w = 220; + int h = bar.sizeHint().height() ; + int dw = QApplication::desktop()->width(); + int dh = QApplication::desktop()->height(); + bar.setGeometry( (dw-w)/2, (dh - h )/2 ,w,h ); + bar.show(); + int modulo = (count/10)+1; + int incCounter = 0; + while (iii < count ) { + if ( ! bar.isVisible() ) + return ; + if ( incCounter % modulo == 0 ) + bar.setProgress( incCounter ); + ++incCounter; + qApp->processEvents(); + RecMailP mail = (*target.at( iii )); + deleteMail(mail); + ++iii; + } } void AbstractMail::mvcpAllMails(const FolderP&fromFolder, const QString&targetFolder,AbstractMail*targetWrapper,bool moveit, int maxSizeInKb) { QValueList<RecMailP> t; listMessages(fromFolder->getName(),t, maxSizeInKb); mvcpMailList( t,targetFolder,targetWrapper,moveit); } void AbstractMail::mvcpMailList(const QValueList<RecMailP>& t, const QString&targetFolder,AbstractMail*targetWrapper,bool moveit) { - encodedString*st = 0; int iii = 0; int count = t.count(); + if ( count == 0 ) + return; + + QProgressBar bar( count,0 ); + bar.setCaption (("Copying mails - close to abort!") ); + int w = 300; + if ( QApplication::desktop()->width() < 320 ) + w = 220; + int h = bar.sizeHint().height() ; + int dw = QApplication::desktop()->width(); + int dh = QApplication::desktop()->height(); + bar.setGeometry( (dw-w)/2, (dh - h )/2 ,w,h ); + bar.show(); + int modulo = (count/10)+1; + int incCounter = 0; while (iii < count ) { + if ( ! bar.isVisible() ) + return ; + if ( incCounter % modulo == 0 ) + bar.setProgress( incCounter ); + ++incCounter; + bar.raise(); + qApp->processEvents(); + //qDebug("copy "); RecMailP r = (*t.at( iii )); st = fetchRawBody(r); if (st) { targetWrapper->storeMessage(st->Content(),st->Length(),targetFolder); delete st; } ++iii; } + bar.hide(); if (moveit) { deleteMailList( t ); //deleteAllMail(fromFolder); } } void AbstractMail::mvcpMail(const RecMailP&mail,const QString&targetFolder,AbstractMail*targetWrapper,bool moveit) { encodedString*st = 0; st = fetchRawBody(mail); if (st) { targetWrapper->storeMessage(st->Content(),st->Length(),targetFolder); delete st; } if (moveit) { deleteMail(mail); } } diff --git a/kmicromail/libmailwrapper/imapwrapper.cpp b/kmicromail/libmailwrapper/imapwrapper.cpp index bb8bbfc..11d3343 100644 --- a/kmicromail/libmailwrapper/imapwrapper.cpp +++ b/kmicromail/libmailwrapper/imapwrapper.cpp @@ -1,1230 +1,1260 @@ // CHANGED 2004-09-31 Lutz Rogowski #include <stdlib.h> #include <libetpan/libetpan.h> #include <qpe/global.h> #include <qapplication.h> #include "imapwrapper.h" #include "mailtypes.h" #include "logindialog.h" +#include <qprogressbar.h> using namespace Opie::Core; IMAPwrapper::IMAPwrapper( IMAPaccount *a ) : AbstractMail() { account = a; m_imap = 0; m_Lastmbox = ""; } IMAPwrapper::~IMAPwrapper() { logout(); } /* to avoid to often select statements in loops etc. we trust that we are logged in and connection is established!*/ int IMAPwrapper::selectMbox(const QString&mbox) { if (mbox == m_Lastmbox) { return MAILIMAP_NO_ERROR; } int err = mailimap_select( m_imap, (char*)mbox.latin1()); if ( err != MAILIMAP_NO_ERROR ) { m_Lastmbox = ""; return err; } m_Lastmbox = mbox; return err; } void IMAPwrapper::imap_progress( size_t current, size_t maximum ) { qApp->processEvents(); qDebug("imap progress %d of %d ",current,maximum ); } bool IMAPwrapper::start_tls(bool force_tls) { int err; bool try_tls; mailimap_capability_data * cap_data = 0; err = mailimap_capability(m_imap,&cap_data); if (err != MAILIMAP_NO_ERROR) { Global::statusMessage("error getting capabilities!"); return false; } clistiter * cur; for(cur = clist_begin(cap_data->cap_list) ; cur != NULL;cur = clist_next(cur)) { struct mailimap_capability * cap; cap = (struct mailimap_capability *)clist_content(cur); if (cap->cap_type == MAILIMAP_CAPABILITY_NAME) { if (strcasecmp(cap->cap_data.cap_name, "STARTTLS") == 0) { try_tls = true; break; } } } if (cap_data) { mailimap_capability_data_free(cap_data); } if (try_tls) { err = mailimap_starttls(m_imap); if (err != MAILIMAP_NO_ERROR && force_tls) { Global::statusMessage(tr("Server has no TLS support!")); try_tls = false; } else { mailstream_low * low; mailstream_low * new_low; low = mailstream_get_low(m_imap->imap_stream); if (!low) { try_tls = false; } else { int fd = mailstream_low_get_fd(low); if (fd > -1 && (new_low = mailstream_low_ssl_open(fd))!=0) { mailstream_low_free(low); mailstream_set_low(m_imap->imap_stream, new_low); } else { try_tls = false; } } } } return try_tls; } void IMAPwrapper::login() { const char *server, *user, *pass; uint16_t port; int err = MAILIMAP_NO_ERROR; if (account->getOffline()) return; /* we are connected this moment */ /* TODO: setup a timer holding the line or if connection closed - delete the value */ if (m_imap) { err = mailimap_noop(m_imap); if (err!=MAILIMAP_NO_ERROR) { logout(); } else { mailstream_flush(m_imap->imap_stream); return; } } server = account->getServer().latin1(); port = account->getPort().toUInt(); if ( account->getUser().isEmpty() || account->getPassword().isEmpty() ) { LoginDialog login( account->getUser(), account->getPassword(), NULL, 0, true ); login.show(); if ( QDialog::Accepted == login.exec() ) { // ok user = login.getUser().latin1(); pass = login.getPassword().latin1(); } else { // cancel return; } } else { user = account->getUser().latin1(); pass = account->getPassword().latin1(); } m_imap = mailimap_new( 20, &imap_progress ); /* connect */ bool ssl = false; bool try_tls = false; bool force_tls = false; if ( account->ConnectionType() == 2 ) { ssl = true; } if (account->ConnectionType()==1) { force_tls = true; } if ( ssl ) { qDebug("using ssl "); err = mailimap_ssl_connect( m_imap, (char*)server, port ); } else { err = mailimap_socket_connect( m_imap, (char*)server, port ); } if ( err != MAILIMAP_NO_ERROR && err != MAILIMAP_NO_ERROR_AUTHENTICATED && err != MAILIMAP_NO_ERROR_NON_AUTHENTICATED ) { QString failure = ""; if (err == MAILIMAP_ERROR_CONNECTION_REFUSED) { failure="Connection refused"; } else { failure="Unknown failure"; } Global::statusMessage(tr("error connecting imap server: %1").arg(failure)); mailimap_free( m_imap ); m_imap = 0; return; } if (!ssl) { try_tls = start_tls(force_tls); } bool ok = true; if (force_tls && !try_tls) { Global::statusMessage(tr("Server has no TLS support!")); ok = false; } /* login */ if (ok) { err = mailimap_login_simple( m_imap, (char*)user, (char*)pass ); if ( err != MAILIMAP_NO_ERROR ) { Global::statusMessage(tr("error logging in imap server: %1").arg(m_imap->imap_response)); ok = false; } } if (!ok) { err = mailimap_close( m_imap ); mailimap_free( m_imap ); m_imap = 0; } } void IMAPwrapper::logout() { int err = MAILIMAP_NO_ERROR; if (!m_imap) return; err = mailimap_logout( m_imap ); err = mailimap_close( m_imap ); mailimap_free( m_imap ); m_imap = 0; m_Lastmbox = ""; } void IMAPwrapper::listMessages(const QString&mailbox,QValueList<Opie::Core::OSmartPointer<RecMail> > &target , int maxSizeInKb) { int err = MAILIMAP_NO_ERROR; clist *result = 0; clistcell *current; mailimap_fetch_type *fetchType = 0; mailimap_set *set = 0; login(); if (!m_imap) { return; } /* select mailbox READONLY for operations */ err = selectMbox(mailbox); if ( err != MAILIMAP_NO_ERROR ) { return; } int last = m_imap->imap_selection_info->sel_exists; if (last == 0) { Global::statusMessage(tr("Mailbox has no mails")); return; } else { } /* the range has to start at 1!!! not with 0!!!! */ set = mailimap_set_new_interval( 1, last ); fetchType = mailimap_fetch_type_new_fetch_att_list_empty(); mailimap_fetch_type_new_fetch_att_list_add(fetchType,mailimap_fetch_att_new_envelope()); mailimap_fetch_type_new_fetch_att_list_add(fetchType,mailimap_fetch_att_new_flags()); mailimap_fetch_type_new_fetch_att_list_add(fetchType,mailimap_fetch_att_new_internaldate()); mailimap_fetch_type_new_fetch_att_list_add(fetchType,mailimap_fetch_att_new_rfc822_size()); err = mailimap_fetch( m_imap, set, fetchType, &result ); mailimap_set_free( set ); mailimap_fetch_type_free( fetchType ); QString date,subject,from; if ( err == MAILIMAP_NO_ERROR ) { mailimap_msg_att * msg_att; int i = 0; for (current = clist_begin(result); current != 0; current=clist_next(current)) { ++i; msg_att = (mailimap_msg_att*)current->data; RecMail*m = parse_list_result(msg_att); if (m) { if ( maxSizeInKb == 0 || m->Msgsize()<=maxSizeInKb*1024 ) { m->setNumber(i); m->setMbox(mailbox); m->setWrapper(this); target.append(m); } } } Global::statusMessage(tr("Mailbox has %1 mails").arg(target.count())); } else { Global::statusMessage(tr("Error fetching headers: %1").arg(m_imap->imap_response)); } if (result) mailimap_fetch_list_free(result); } QValueList<Opie::Core::OSmartPointer<Folder> >* IMAPwrapper::listFolders() { const char *path, *mask; int err = MAILIMAP_NO_ERROR; clist *result = 0; clistcell *current = 0; clistcell*cur_flag = 0; mailimap_mbx_list_flags*bflags = 0; QValueList<FolderP>* folders = new QValueList<FolderP>(); login(); if (!m_imap) { return folders; } /* * First we have to check for INBOX 'cause it sometimes it's not inside the path. * We must not forget to filter them out in next loop! * it seems like ugly code. and yes - it is ugly code. but the best way. */ QString temp; mask = "INBOX" ; mailimap_mailbox_list *list; err = mailimap_list( m_imap, (char*)"", (char*)mask, &result ); QString del; bool selectable = true; bool no_inferiors = false; if ( err == MAILIMAP_NO_ERROR ) { current = result->first; for ( int i = result->count; i > 0; i-- ) { list = (mailimap_mailbox_list *) current->data; // it is better use the deep copy mechanism of qt itself // instead of using strdup! temp = list->mb_name; del = list->mb_delimiter; current = current->next; if ( (bflags = list->mb_flag) ) { selectable = !(bflags->mbf_type==MAILIMAP_MBX_LIST_FLAGS_SFLAG&& bflags->mbf_sflag==MAILIMAP_MBX_LIST_SFLAG_NOSELECT); for(cur_flag=clist_begin(bflags->mbf_oflags);cur_flag;cur_flag=clist_next(cur_flag)) { if ( ((mailimap_mbx_list_oflag*)cur_flag->data)->of_type==MAILIMAP_MBX_LIST_OFLAG_NOINFERIORS) { no_inferiors = true; } } } folders->append( new IMAPFolder(temp,del,selectable,no_inferiors,account->getPrefix())); } } else { qDebug("error fetching folders: "); } mailimap_list_result_free( result ); /* * second stage - get the other then inbox folders */ mask = "*" ; path = account->getPrefix().latin1(); if (!path) path = ""; err = mailimap_list( m_imap, (char*)path, (char*)mask, &result ); if ( err == MAILIMAP_NO_ERROR ) { current = result->first; for ( current=clist_begin(result);current!=NULL;current=clist_next(current)) { no_inferiors = false; list = (mailimap_mailbox_list *) current->data; // it is better use the deep copy mechanism of qt itself // instead of using strdup! temp = list->mb_name; if (temp.lower()=="inbox") continue; if (temp.lower()==account->getPrefix().lower()) continue; if ( (bflags = list->mb_flag) ) { selectable = !(bflags->mbf_type==MAILIMAP_MBX_LIST_FLAGS_SFLAG&& bflags->mbf_sflag==MAILIMAP_MBX_LIST_SFLAG_NOSELECT); for(cur_flag=clist_begin(bflags->mbf_oflags);cur_flag;cur_flag=clist_next(cur_flag)) { if ( ((mailimap_mbx_list_oflag*)cur_flag->data)->of_type==MAILIMAP_MBX_LIST_OFLAG_NOINFERIORS) { no_inferiors = true; } } } del = list->mb_delimiter; folders->append(new IMAPFolder(temp,del,selectable,no_inferiors,account->getPrefix())); } } else { qDebug("error fetching folders "); } if (result) mailimap_list_result_free( result ); return folders; } RecMail*IMAPwrapper::parse_list_result(mailimap_msg_att* m_att) { RecMail * m = 0; mailimap_msg_att_item *item=0; clistcell *current,*c,*cf; mailimap_msg_att_dynamic*flist; mailimap_flag_fetch*cflag; int size; QBitArray mFlags(7); QStringList addresslist; if (!m_att) { return m; } m = new RecMail(); for (c = clist_begin(m_att->att_list); c!=NULL;c=clist_next(c) ) { current = c; size = 0; item = (mailimap_msg_att_item*)current->data; if (item->att_type!=MAILIMAP_MSG_ATT_ITEM_STATIC) { flist = (mailimap_msg_att_dynamic*)item->att_data.att_dyn; if (!flist->att_list) { continue; } cf = flist->att_list->first; for (cf = clist_begin(flist->att_list); cf!=NULL; cf = clist_next(cf)) { cflag = (mailimap_flag_fetch*)cf->data; if (cflag->fl_type==MAILIMAP_FLAG_FETCH_OTHER && cflag->fl_flag!=0) { switch (cflag->fl_flag->fl_type) { case MAILIMAP_FLAG_ANSWERED: /* \Answered flag */ mFlags.setBit(FLAG_ANSWERED); break; case MAILIMAP_FLAG_FLAGGED: /* \Flagged flag */ mFlags.setBit(FLAG_FLAGGED); break; case MAILIMAP_FLAG_DELETED: /* \Deleted flag */ mFlags.setBit(FLAG_DELETED); break; case MAILIMAP_FLAG_SEEN: /* \Seen flag */ mFlags.setBit(FLAG_SEEN); break; case MAILIMAP_FLAG_DRAFT: /* \Draft flag */ mFlags.setBit(FLAG_DRAFT); break; case MAILIMAP_FLAG_KEYWORD: /* keyword flag */ break; case MAILIMAP_FLAG_EXTENSION: /* \extension flag */ break; default: break; } } else if (cflag->fl_type==MAILIMAP_FLAG_FETCH_RECENT) { mFlags.setBit(FLAG_RECENT); } } continue; } if (item->att_data.att_static->att_type==MAILIMAP_MSG_ATT_ENVELOPE) { mailimap_envelope * head = item->att_data.att_static->att_data.att_env; m->setDate(head->env_date); m->setSubject(convert_String((const char*)head->env_subject)); //m->setSubject(head->env_subject); if (head->env_from!=NULL) { addresslist = address_list_to_stringlist(head->env_from->frm_list); if (addresslist.count()) { m->setFrom(addresslist.first()); } } if (head->env_to!=NULL) { addresslist = address_list_to_stringlist(head->env_to->to_list); m->setTo(addresslist); } if (head->env_cc!=NULL) { addresslist = address_list_to_stringlist(head->env_cc->cc_list); m->setCC(addresslist); } if (head->env_bcc!=NULL) { addresslist = address_list_to_stringlist(head->env_bcc->bcc_list); m->setBcc(addresslist); } /* reply to address, eg. email. */ if (head->env_reply_to!=NULL) { addresslist = address_list_to_stringlist(head->env_reply_to->rt_list); if (addresslist.count()) { m->setReplyto(addresslist.first()); } } if (head->env_in_reply_to!=NULL) { QString h(head->env_in_reply_to); while (h.length()>0 && h[0]=='<') { h.remove(0,1); } while (h.length()>0 && h[h.length()-1]=='>') { h.remove(h.length()-1,1); } if (h.length()>0) { m->setInreply(QStringList(h)); } } if (head->env_message_id) { m->setMsgid(QString(head->env_message_id)); } } else if (item->att_data.att_static->att_type==MAILIMAP_MSG_ATT_INTERNALDATE) { #if 0 mailimap_date_time*d = item->att_data.att_static->att_data.att_internal_date; QDateTime da(QDate(d->dt_year,d->dt_month,d->dt_day),QTime(d->dt_hour,d->dt_min,d->dt_sec)); //odebug << "" << d->dt_year << " " << d->dt_month << " " << d->dt_day << " - " << d->dt_hour << " " << d->dt_min << " " << d->dt_sec << "" << oendl; //odebug << da.toString() << oendl; #endif } else if (item->att_data.att_static->att_type==MAILIMAP_MSG_ATT_RFC822_SIZE) { size = item->att_data.att_static->att_data.att_rfc822_size; } } /* msg is already deleted */ if (mFlags.testBit(FLAG_DELETED) && m) { delete m; m = 0; } if (m) { m->setFlags(mFlags); m->setMsgsize(size); } return m; } RecBodyP IMAPwrapper::fetchBody(const RecMailP&mail) { RecBodyP body = new RecBody(); const char *mb; int err = MAILIMAP_NO_ERROR; clist *result = 0; clistcell *current; mailimap_fetch_att *fetchAtt = 0; mailimap_fetch_type *fetchType = 0; mailimap_set *set = 0; mailimap_body*body_desc = 0; mb = mail->getMbox().latin1(); login(); if (!m_imap) { return body; } err = selectMbox(mail->getMbox()); if ( err != MAILIMAP_NO_ERROR ) { return body; } /* the range has to start at 1!!! not with 0!!!! */ set = mailimap_set_new_interval( mail->getNumber(),mail->getNumber() ); fetchAtt = mailimap_fetch_att_new_bodystructure(); fetchType = mailimap_fetch_type_new_fetch_att(fetchAtt); err = mailimap_fetch( m_imap, set, fetchType, &result ); mailimap_set_free( set ); mailimap_fetch_type_free( fetchType ); if (err == MAILIMAP_NO_ERROR && (current=clist_begin(result)) ) { mailimap_msg_att * msg_att; msg_att = (mailimap_msg_att*)current->data; mailimap_msg_att_item*item = (mailimap_msg_att_item*)msg_att->att_list->first->data; QValueList<int> path; body_desc = item->att_data.att_static->att_data.att_body; traverseBody(mail,body_desc,body,0,path); } else { //odebug << "error fetching body: " << m_imap->imap_response << "" << oendl; } if (result) mailimap_fetch_list_free(result); return body; } QStringList IMAPwrapper::address_list_to_stringlist(clist*list) { QStringList l; QString from; bool named_from; clistcell *current = NULL; mailimap_address * current_address=NULL; if (!list) { return l; } unsigned int count = 0; for (current=clist_begin(list);current!= NULL;current=clist_next(current)) { from = ""; named_from = false; current_address=(mailimap_address*)current->data; if (current_address->ad_personal_name){ from+=convert_String((const char*)current_address->ad_personal_name); from+=" "; named_from = true; } if (named_from && (current_address->ad_mailbox_name || current_address->ad_host_name)) { from+="<"; } if (current_address->ad_mailbox_name) { from+=QString(current_address->ad_mailbox_name); from+="@"; } if (current_address->ad_host_name) { from+=QString(current_address->ad_host_name); } if (named_from && (current_address->ad_mailbox_name || current_address->ad_host_name)) { from+=">"; } l.append(QString(from)); if (++count > 99) { break; } } return l; } encodedString*IMAPwrapper::fetchRawPart(const RecMailP&mail,const QValueList<int>&path,bool internal_call) { encodedString*res=new encodedString; int err; mailimap_fetch_type *fetchType; mailimap_set *set; clistcell*current,*cur; mailimap_section_part * section_part = 0; mailimap_section_spec * section_spec = 0; mailimap_section * section = 0; mailimap_fetch_att * fetch_att = 0; login(); if (!m_imap) { return res; } if (!internal_call) { err = selectMbox(mail->getMbox()); if ( err != MAILIMAP_NO_ERROR ) { return res; } } set = mailimap_set_new_single(mail->getNumber()); clist*id_list = 0; /* if path == empty then its a request for the whole rfc822 mail and generates a "fetch <id> (body[])" statement on imap server */ if (path.count()>0 ) { id_list = clist_new(); for (unsigned j=0; j < path.count();++j) { uint32_t * p_id = (uint32_t *)malloc(sizeof(*p_id)); *p_id = path[j]; clist_append(id_list,p_id); } section_part = mailimap_section_part_new(id_list); section_spec = mailimap_section_spec_new(MAILIMAP_SECTION_SPEC_SECTION_PART, NULL, section_part, NULL); } section = mailimap_section_new(section_spec); fetch_att = mailimap_fetch_att_new_body_section(section); fetchType = mailimap_fetch_type_new_fetch_att(fetch_att); clist*result = 0; err = mailimap_fetch( m_imap, set, fetchType, &result ); mailimap_set_free( set ); mailimap_fetch_type_free( fetchType ); if (err == MAILIMAP_NO_ERROR && (current=clist_begin(result)) ) { mailimap_msg_att * msg_att; msg_att = (mailimap_msg_att*)current->data; mailimap_msg_att_item*msg_att_item; for(cur = clist_begin(msg_att->att_list) ; cur != NULL ; cur = clist_next(cur)) { msg_att_item = (mailimap_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) { char*text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part; /* detach - we take over the content */ msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = 0L; res->setContent(text,msg_att_item->att_data.att_static->att_data.att_body_section->sec_length); } } } } else { ;//odebug << "error fetching text: " << m_imap->imap_response << "" << oendl; } if (result) mailimap_fetch_list_free(result); return res; } /* current_recursion is for recursive calls. current_count means the position inside the internal loop! */ void IMAPwrapper::traverseBody(const RecMailP&mail,mailimap_body*body,RecBodyP&target_body, int current_recursion,QValueList<int>recList,int current_count) { if (!body || current_recursion>=10) { return; } switch (body->bd_type) { case MAILIMAP_BODY_1PART: { QValueList<int>countlist = recList; countlist.append(current_count); RecPartP currentPart = new RecPart(); mailimap_body_type_1part*part1 = body->bd_data.bd_body_1part; QString id(""); currentPart->setPositionlist(countlist); for (unsigned int j = 0; j < countlist.count();++j) { id+=(j>0?" ":""); id+=QString("%1").arg(countlist[j]); } //odebug << "ID = " << id.latin1() << "" << oendl; currentPart->setIdentifier(id); fillSinglePart(currentPart,part1); /* important: Check for is NULL 'cause a body can be empty! And we put it only into the mail if it is the FIRST part */ if (part1->bd_type==MAILIMAP_BODY_TYPE_1PART_TEXT && target_body->Bodytext().isNull() && countlist[0]==1) { QString body_text = fetchTextPart(mail,countlist,true,currentPart->Encoding()); target_body->setDescription(currentPart); target_body->setBodytext(body_text); if (countlist.count()>1) { target_body->addPart(currentPart); } } else { target_body->addPart(currentPart); } if (part1->bd_type==MAILIMAP_BODY_TYPE_1PART_MSG) { traverseBody(mail,part1->bd_data.bd_type_msg->bd_body,target_body,current_recursion+1,countlist); } } break; case MAILIMAP_BODY_MPART: { QValueList<int>countlist = recList; clistcell*current=0; mailimap_body*current_body=0; unsigned int ccount = 1; mailimap_body_type_mpart*mailDescription = body->bd_data.bd_body_mpart; for (current=clist_begin(mailDescription->bd_list);current!=0;current=clist_next(current)) { current_body = (mailimap_body*)current->data; if (current_body->bd_type==MAILIMAP_BODY_MPART) { RecPartP targetPart = new RecPart(); targetPart->setType("multipart"); fillMultiPart(targetPart,mailDescription); countlist.append(current_count); targetPart->setPositionlist(countlist); target_body->addPart(targetPart); QString id(""); for (unsigned int j = 0; j < countlist.count();++j) { id+=(j>0?" ":""); id+=QString("%1").arg(countlist[j]); } // odebug << "ID(mpart) = " << id.latin1() << "" << oendl; } traverseBody(mail,current_body,target_body,current_recursion+1,countlist,ccount); if (current_body->bd_type==MAILIMAP_BODY_MPART) { countlist = recList; } ++ccount; } } break; default: break; } } void IMAPwrapper::fillSinglePart(RecPartP&target_part,mailimap_body_type_1part*Description) { if (!Description) { return; } switch (Description->bd_type) { case MAILIMAP_BODY_TYPE_1PART_TEXT: target_part->setType("text"); fillSingleTextPart(target_part,Description->bd_data.bd_type_text); break; case MAILIMAP_BODY_TYPE_1PART_BASIC: fillSingleBasicPart(target_part,Description->bd_data.bd_type_basic); break; case MAILIMAP_BODY_TYPE_1PART_MSG: target_part->setType("message"); fillSingleMsgPart(target_part,Description->bd_data.bd_type_msg); break; default: break; } } void IMAPwrapper::fillSingleTextPart(RecPartP&target_part,mailimap_body_type_text*which) { if (!which) { return; } QString sub; sub = which->bd_media_text; //odebug << "Type= text/" << which->bd_media_text << "" << oendl; target_part->setSubtype(sub.lower()); target_part->setLines(which->bd_lines); fillBodyFields(target_part,which->bd_fields); } void IMAPwrapper::fillSingleMsgPart(RecPartP&target_part,mailimap_body_type_msg*which) { if (!which) { return; } target_part->setSubtype("rfc822"); //odebug << "Message part" << oendl; /* we set this type to text/plain */ target_part->setLines(which->bd_lines); fillBodyFields(target_part,which->bd_fields); } void IMAPwrapper::fillMultiPart(RecPartP&target_part,mailimap_body_type_mpart*which) { if (!which) return; QString sub = which->bd_media_subtype; target_part->setSubtype(sub.lower()); if (which->bd_ext_mpart && which->bd_ext_mpart->bd_parameter && which->bd_ext_mpart->bd_parameter->pa_list) { clistcell*cur = 0; mailimap_single_body_fld_param*param=0; for (cur = clist_begin(which->bd_ext_mpart->bd_parameter->pa_list);cur!=NULL;cur=clist_next(cur)) { param = (mailimap_single_body_fld_param*)cur->data; if (param) { target_part->addParameter(QString(param->pa_name).lower(),QString(param->pa_value)); } } } } void IMAPwrapper::fillSingleBasicPart(RecPartP&target_part,mailimap_body_type_basic*which) { if (!which) { return; } QString type,sub; switch (which->bd_media_basic->med_type) { case MAILIMAP_MEDIA_BASIC_APPLICATION: type = "application"; break; case MAILIMAP_MEDIA_BASIC_AUDIO: type = "audio"; break; case MAILIMAP_MEDIA_BASIC_IMAGE: type = "image"; break; case MAILIMAP_MEDIA_BASIC_MESSAGE: type = "message"; break; case MAILIMAP_MEDIA_BASIC_VIDEO: type = "video"; break; case MAILIMAP_MEDIA_BASIC_OTHER: default: if (which->bd_media_basic->med_basic_type) { type = which->bd_media_basic->med_basic_type; } else { type = ""; } break; } if (which->bd_media_basic->med_subtype) { sub = which->bd_media_basic->med_subtype; } else { sub = ""; } // odebug << "Type = " << type.latin1() << "/" << sub.latin1() << "" << oendl; target_part->setType(type.lower()); target_part->setSubtype(sub.lower()); fillBodyFields(target_part,which->bd_fields); } void IMAPwrapper::fillBodyFields(RecPartP&target_part,mailimap_body_fields*which) { if (!which) return; if (which->bd_parameter && which->bd_parameter->pa_list && which->bd_parameter->pa_list->count>0) { clistcell*cur; mailimap_single_body_fld_param*param=0; for (cur = clist_begin(which->bd_parameter->pa_list);cur!=NULL;cur=clist_next(cur)) { param = (mailimap_single_body_fld_param*)cur->data; if (param) { target_part->addParameter(QString(param->pa_name).lower(),QString(param->pa_value)); } } } mailimap_body_fld_enc*enc = which->bd_encoding; QString encoding(""); switch (enc->enc_type) { case MAILIMAP_BODY_FLD_ENC_7BIT: encoding = "7bit"; break; case MAILIMAP_BODY_FLD_ENC_8BIT: encoding = "8bit"; break; case MAILIMAP_BODY_FLD_ENC_BINARY: encoding="binary"; break; case MAILIMAP_BODY_FLD_ENC_BASE64: encoding="base64"; break; case MAILIMAP_BODY_FLD_ENC_QUOTED_PRINTABLE: encoding="quoted-printable"; break; case MAILIMAP_BODY_FLD_ENC_OTHER: default: if (enc->enc_value) { char*t=enc->enc_value; encoding=QString(enc->enc_value); enc->enc_value=0L; free(t); } } if (which->bd_description) { target_part->setDescription(QString(which->bd_description)); } target_part->setEncoding(encoding); target_part->setSize(which->bd_size); } void IMAPwrapper::deleteMailList(const QValueList<RecMailP>&target) { + //#if 0 mailimap_flag_list*flist; mailimap_set *set; mailimap_store_att_flags * store_flags; int err; login(); + //#endif if (!m_imap) { return; } int iii = 0; int count = target.count(); - qDebug("imap remove count %d ", count); + // qDebug("imap remove count %d ", count); + + QProgressBar bar( count,0 ); + bar.setCaption (("Removing mails - close to abort!") ); + int w = 300; + if ( QApplication::desktop()->width() < 320 ) + w = 220; + int h = bar.sizeHint().height() ; + int dw = QApplication::desktop()->width(); + int dh = QApplication::desktop()->height(); + bar.setGeometry( (dw-w)/2, (dh - h )/2 ,w,h ); + bar.show(); + int modulo = (count/10)+1; + int incCounter = 0; + while (iii < count ) { - qDebug("IMAP remove %d ", iii); + if ( ! bar.isVisible() ) + return ; + if ( incCounter % modulo == 0 ) + bar.setProgress( incCounter ); + ++incCounter; + qApp->processEvents(); RecMailP mail = (*target.at( iii )); - + //#if 0 + //qDebug("IMAP remove %d %d ", iii, mail->getNumber() ); err = selectMbox(mail->getMbox()); if ( err != MAILIMAP_NO_ERROR ) { return; } flist = mailimap_flag_list_new_empty(); mailimap_flag_list_add(flist,mailimap_flag_new_deleted()); store_flags = mailimap_store_att_flags_new_set_flags(flist); set = mailimap_set_new_single(mail->getNumber()); err = mailimap_store(m_imap,set,store_flags); mailimap_set_free( set ); mailimap_store_att_flags_free(store_flags); if (err != MAILIMAP_NO_ERROR) { // odebug << "error deleting mail: " << m_imap->imap_response << "" << oendl; return; } // odebug << "deleting mail: " << m_imap->imap_response << "" << oendl; /* should we realy do that at this moment? */ + // err = mailimap_expunge(m_imap); + //if (err != MAILIMAP_NO_ERROR) { + // Global::statusMessage(tr("Error deleting mails: %s").arg(m_imap->imap_response)); + // } + //#endif + //deleteMail( mail); + ++iii; + } + //qDebug("Deleting imap mails... "); err = mailimap_expunge(m_imap); if (err != MAILIMAP_NO_ERROR) { - Global::statusMessage(tr("error deleting mail: %s").arg(m_imap->imap_response)); - } - ++iii; + Global::statusMessage(tr("Error deleting mails: %s").arg(m_imap->imap_response)); } } void IMAPwrapper::deleteMail(const RecMailP&mail) { mailimap_flag_list*flist; mailimap_set *set; mailimap_store_att_flags * store_flags; int err; login(); if (!m_imap) { return; } err = selectMbox(mail->getMbox()); if ( err != MAILIMAP_NO_ERROR ) { return; } flist = mailimap_flag_list_new_empty(); mailimap_flag_list_add(flist,mailimap_flag_new_deleted()); store_flags = mailimap_store_att_flags_new_set_flags(flist); set = mailimap_set_new_single(mail->getNumber()); err = mailimap_store(m_imap,set,store_flags); mailimap_set_free( set ); mailimap_store_att_flags_free(store_flags); if (err != MAILIMAP_NO_ERROR) { // odebug << "error deleting mail: " << m_imap->imap_response << "" << oendl; return; } // odebug << "deleting mail: " << m_imap->imap_response << "" << oendl; /* should we realy do that at this moment? */ err = mailimap_expunge(m_imap); if (err != MAILIMAP_NO_ERROR) { Global::statusMessage(tr("error deleting mail: %s").arg(m_imap->imap_response)); } - qDebug("IMAPwrapper::deleteMail "); + //qDebug("IMAPwrapper::deleteMail 2"); } void IMAPwrapper::answeredMail(const RecMailP&mail) { mailimap_flag_list*flist; mailimap_set *set; mailimap_store_att_flags * store_flags; int err; login(); if (!m_imap) { return; } err = selectMbox(mail->getMbox()); if ( err != MAILIMAP_NO_ERROR ) { return; } flist = mailimap_flag_list_new_empty(); mailimap_flag_list_add(flist,mailimap_flag_new_answered()); store_flags = mailimap_store_att_flags_new_add_flags(flist); set = mailimap_set_new_single(mail->getNumber()); err = mailimap_store(m_imap,set,store_flags); mailimap_set_free( set ); mailimap_store_att_flags_free(store_flags); if (err != MAILIMAP_NO_ERROR) { // odebug << "error marking mail: " << m_imap->imap_response << "" << oendl; return; } } QString IMAPwrapper::fetchTextPart(const RecMailP&mail,const QValueList<int>&path,bool internal_call,const QString&enc) { QString body(""); encodedString*res = fetchRawPart(mail,path,internal_call); encodedString*r = decode_String(res,enc); delete res; if (r) { if (r->Length()>0) { body = r->Content(); } delete r; } return body; } QString IMAPwrapper::fetchTextPart(const RecMailP&mail,const RecPartP&part) { return fetchTextPart(mail,part->Positionlist(),false,part->Encoding()); } encodedString* IMAPwrapper::fetchDecodedPart(const RecMailP&mail,const RecPartP&part) { encodedString*res = fetchRawPart(mail,part->Positionlist(),false); encodedString*r = decode_String(res,part->Encoding()); delete res; return r; } encodedString* IMAPwrapper::fetchRawPart(const RecMailP&mail,const RecPartP&part) { return fetchRawPart(mail,part->Positionlist(),false); } int IMAPwrapper::deleteAllMail(const FolderP&folder) { login(); if (!m_imap) { return 0; } mailimap_flag_list*flist; mailimap_set *set; mailimap_store_att_flags * store_flags; int err = selectMbox(folder->getName()); if ( err != MAILIMAP_NO_ERROR ) { return 0; } int last = m_imap->imap_selection_info->sel_exists; if (last == 0) { Global::statusMessage(tr("Mailbox has no mails!")); return 0; } flist = mailimap_flag_list_new_empty(); mailimap_flag_list_add(flist,mailimap_flag_new_deleted()); store_flags = mailimap_store_att_flags_new_set_flags(flist); set = mailimap_set_new_interval( 1, last ); err = mailimap_store(m_imap,set,store_flags); mailimap_set_free( set ); mailimap_store_att_flags_free(store_flags); if (err != MAILIMAP_NO_ERROR) { Global::statusMessage(tr("error deleting mail: %s").arg(m_imap->imap_response)); return 0; } // odebug << "deleting mail: " << m_imap->imap_response << "" << oendl; /* should we realy do that at this moment? */ err = mailimap_expunge(m_imap); if (err != MAILIMAP_NO_ERROR) { Global::statusMessage(tr("error deleting mail: %s").arg(m_imap->imap_response)); return 0; } // odebug << "Delete successfull " << m_imap->imap_response << "" << oendl; return 1; } int IMAPwrapper::createMbox(const QString&folder,const FolderP&parentfolder,const QString& delemiter,bool getsubfolder) { if (folder.length()==0) return 0; login(); if (!m_imap) {return 0;} QString pre = account->getPrefix(); if (delemiter.length()>0 && pre.findRev(delemiter)!=pre.length()-1) { pre+=delemiter; } if (parentfolder) { pre += parentfolder->getDisplayName()+delemiter; } pre+=folder; if (getsubfolder) { if (delemiter.length()>0) { pre+=delemiter; } else { Global::statusMessage(tr("Cannot create folder %1 for holding subfolders").arg(pre)); return 0; } } // odebug << "Creating " << pre.latin1() << "" << oendl; int res = mailimap_create(m_imap,pre.latin1()); if (res != MAILIMAP_NO_ERROR) { Global::statusMessage(tr("%1").arg(m_imap->imap_response)); return 0; } return 1; } int IMAPwrapper::deleteMbox(const FolderP&folder) { if (!folder) return 0; login(); if (!m_imap) {return 0;} int res = mailimap_delete(m_imap,folder->getName()); if (res != MAILIMAP_NO_ERROR) { Global::statusMessage(tr("%1").arg(m_imap->imap_response)); return 0; } return 1; } void IMAPwrapper::statusFolder(folderStat&target_stat,const QString & mailbox) { mailimap_status_att_list * att_list =0; mailimap_mailbox_data_status * status=0; clistiter * cur = 0; int r = 0; target_stat.message_count = 0; target_stat.message_unseen = 0; target_stat.message_recent = 0; login(); if (!m_imap) { return; } att_list = mailimap_status_att_list_new_empty(); if (!att_list) return; r = mailimap_status_att_list_add(att_list, MAILIMAP_STATUS_ATT_MESSAGES); r = mailimap_status_att_list_add(att_list, MAILIMAP_STATUS_ATT_RECENT); r = mailimap_status_att_list_add(att_list, MAILIMAP_STATUS_ATT_UNSEEN); r = mailimap_status(m_imap, mailbox.latin1(), att_list, &status); if (r==MAILIMAP_NO_ERROR&&status->st_info_list!=0) { for (cur = clist_begin(status->st_info_list); cur != NULL ; cur = clist_next(cur)) { mailimap_status_info * status_info; status_info = (mailimap_status_info *)clist_content(cur); switch (status_info->st_att) { case MAILIMAP_STATUS_ATT_MESSAGES: target_stat.message_count = status_info->st_value; break; case MAILIMAP_STATUS_ATT_RECENT: target_stat.message_recent = status_info->st_value; break; case MAILIMAP_STATUS_ATT_UNSEEN: target_stat.message_unseen = status_info->st_value; break; } } } else { // odebug << "Error retrieving status" << oendl; } if (status) mailimap_mailbox_data_status_free(status); if (att_list) mailimap_status_att_list_free(att_list); } void IMAPwrapper::storeMessage(const char*msg,size_t length, const QString&folder) { login(); if (!m_imap) return; if (!msg) return; int r = mailimap_append(m_imap,(char*)folder.latin1(),0,0,msg,length); if (r != MAILIMAP_NO_ERROR) { Global::statusMessage("Error storing mail!"); } } MAILLIB::ATYPE IMAPwrapper::getType()const { return account->getType(); } const QString&IMAPwrapper::getName()const { // odebug << "Get name: " << account->getAccountName().latin1() << "" << oendl; return account->getAccountName(); } encodedString* IMAPwrapper::fetchRawBody(const RecMailP&mail) { // dummy QValueList<int> path; return fetchRawPart(mail,path,false); } void IMAPwrapper::mvcpAllMails(const FolderP&fromFolder, const QString&targetFolder,AbstractMail*targetWrapper,bool moveit, int maxSizeInKb) { if (targetWrapper != this || maxSizeInKb > 0 ) { AbstractMail::mvcpAllMails(fromFolder,targetFolder,targetWrapper,moveit, maxSizeInKb); qDebug("IMAPwrapper::mvcpAllMails::Using generic"); // odebug << "Using generic" << oendl; return; } mailimap_set *set = 0; login(); if (!m_imap) { return; } int err = selectMbox(fromFolder->getName()); if ( err != MAILIMAP_NO_ERROR ) { return; } int last = m_imap->imap_selection_info->sel_exists; set = mailimap_set_new_interval( 1, last ); err = mailimap_copy(m_imap,set,targetFolder.latin1()); mailimap_set_free( set ); if ( err != MAILIMAP_NO_ERROR ) { - QString error_msg = tr("error copy mails: %1").arg(m_imap->imap_response); + QString error_msg = tr("Error copy mails: %1").arg(m_imap->imap_response); Global::statusMessage(error_msg); // odebug << error_msg << oendl; return; } if (moveit) { deleteAllMail(fromFolder); } } void IMAPwrapper::mvcpMail(const RecMailP&mail,const QString&targetFolder,AbstractMail*targetWrapper,bool moveit) { if (targetWrapper != this) { // odebug << "Using generic" << oendl; AbstractMail::mvcpMail(mail,targetFolder,targetWrapper,moveit); return; } mailimap_set *set = 0; login(); if (!m_imap) { return; } int err = selectMbox(mail->getMbox()); if ( err != MAILIMAP_NO_ERROR ) { return; } set = mailimap_set_new_single(mail->getNumber()); err = mailimap_copy(m_imap,set,targetFolder.latin1()); mailimap_set_free( set ); if ( err != MAILIMAP_NO_ERROR ) { QString error_msg = tr("error copy mail: %1").arg(m_imap->imap_response); Global::statusMessage(error_msg); // odebug << error_msg << oendl; return; } if (moveit) { deleteMail(mail); } } diff --git a/kmicromail/libmailwrapper/pop3wrapper.cpp b/kmicromail/libmailwrapper/pop3wrapper.cpp index 7a84b30..0e6612c 100644 --- a/kmicromail/libmailwrapper/pop3wrapper.cpp +++ b/kmicromail/libmailwrapper/pop3wrapper.cpp @@ -1,282 +1,321 @@ // CHANGED 2004-09-31 Lutz Rogowski #include <stdlib.h> #include "pop3wrapper.h" #include "mailtypes.h" #include "logindialog.h" #include <libetpan/libetpan.h> #include <qpe/global.h> #include <qfile.h> +#include <qprogressbar.h> +#include <qapplication.h> /* we don't fetch messages larger than 5 MB */ #define HARD_MSG_SIZE_LIMIT 5242880 using namespace Opie::Core; POP3wrapper::POP3wrapper( POP3account *a ) : Genericwrapper() { account = a; m_pop3 = NULL; msgTempName = a->getFileName()+"_msg_cache"; last_msg_id = 0; } POP3wrapper::~POP3wrapper() { logout(); QFile msg_cache(msgTempName); if (msg_cache.exists()) { msg_cache.remove(); } } void POP3wrapper::pop3_progress( size_t current, size_t maximum ) { ; // odebug << "POP3: " << current << " of " << maximum << "" << oendl; } RecBodyP POP3wrapper::fetchBody( const RecMailP &mail ) { int err = MAILPOP3_NO_ERROR; char *message = 0; size_t length = 0; RecBodyP body = new RecBody(); login(); if ( !m_pop3 ) { return body; } mailmessage * mailmsg; if (mail->Msgsize()>HARD_MSG_SIZE_LIMIT) { ; // odebug << "Message to large: " << mail->Msgsize() << "" << oendl; return body; } QFile msg_cache(msgTempName); cleanMimeCache(); if (mail->getNumber()!=last_msg_id) { if (msg_cache.exists()) { msg_cache.remove(); } msg_cache.open(IO_ReadWrite|IO_Truncate); last_msg_id = mail->getNumber(); err = mailsession_get_message(m_pop3->sto_session, mail->getNumber(), &mailmsg); err = mailmessage_fetch(mailmsg,&message,&length); msg_cache.writeBlock(message,length); } else { QString msg=""; msg_cache.open(IO_ReadOnly); message = new char[4096]; memset(message,0,4096); while (msg_cache.readBlock(message,4095)>0) { msg+=message; memset(message,0,4096); } delete message; message = (char*)malloc(msg.length()+1*sizeof(char)); memset(message,0,msg.length()+1); memcpy(message,msg.latin1(),msg.length()); /* transform to libetpan stuff */ mailmsg = mailmessage_new(); mailmessage_init(mailmsg, NULL, data_message_driver, 0, strlen(message)); generic_message_t * msg_data; msg_data = (generic_message_t *)mailmsg->msg_data; msg_data->msg_fetched = 1; msg_data->msg_message = message; msg_data->msg_length = strlen(message); } body = parseMail(mailmsg); /* clean up */ if (mailmsg) mailmessage_free(mailmsg); if (message) free(message); return body; } void POP3wrapper::listMessages(const QString &, QValueList<Opie::Core::OSmartPointer<RecMail> > &target, int maxSizeInKb ) { login(); if (!m_pop3) return; uint32_t res_messages,res_recent,res_unseen; mailsession_status_folder(m_pop3->sto_session,"INBOX",&res_messages,&res_recent,&res_unseen); parseList(target,m_pop3->sto_session,"INBOX", false, maxSizeInKb); Global::statusMessage( tr("Mailbox contains %1 mail(s)").arg(res_messages)); } void POP3wrapper::login() { if (account->getOffline()) return; /* we'll hold the line */ if ( m_pop3 != NULL ) return; const char *server, *user, *pass; uint16_t port; int err = MAILPOP3_NO_ERROR; server = account->getServer().latin1(); port = account->getPort().toUInt(); if ( account->getUser().isEmpty() || account->getPassword().isEmpty() ) { LoginDialog login( account->getUser(), account->getPassword(), NULL, 0, true ); login.show(); if ( QDialog::Accepted == login.exec() ) { // ok user = login.getUser().latin1(); pass = login.getPassword().latin1(); } else { // cancel ; // odebug << "POP3: Login canceled" << oendl; return; } } else { user = account->getUser().latin1(); pass = account->getPassword().latin1(); } // bool ssl = account->getSSL(); m_pop3=mailstorage_new(NULL); int conntypeset = account->ConnectionType(); int conntype = 0; if ( conntypeset == 3 ) { conntype = CONNECTION_TYPE_COMMAND; } else if ( conntypeset == 2 ) { conntype = CONNECTION_TYPE_TLS; } else if ( conntypeset == 1 ) { conntype = CONNECTION_TYPE_STARTTLS; } else if ( conntypeset == 0 ) { conntype = CONNECTION_TYPE_TRY_STARTTLS; } //(ssl?CONNECTION_TYPE_TLS:CONNECTION_TYPE_PLAIN); pop3_mailstorage_init(m_pop3,(char*)server, port, NULL, conntype, POP3_AUTH_TYPE_PLAIN, (char*)user,(char*)pass,0,0,0); err = mailstorage_connect(m_pop3); if (err != MAIL_NO_ERROR) { ; // odebug << QString( "FEHLERNUMMER %1" ).arg( err ) << oendl; Global::statusMessage(tr("Error initializing folder")); mailstorage_free(m_pop3); m_pop3 = 0; } else { mailsession * session = m_pop3->sto_session; mailpop3 * mail = ( ( pop3_session_state_data * )session->sess_data )->pop3_session; if (mail) { mail->pop3_progr_fun = &pop3_progress; } } } void POP3wrapper::logout() { if ( m_pop3 == NULL ) return; mailstorage_free(m_pop3); m_pop3 = 0; } QValueList<Opie::Core::OSmartPointer<Folder> >* POP3wrapper::listFolders() { QValueList<Opie::Core::OSmartPointer<Folder> >* folders = new QValueList<FolderP>(); FolderP inb=new Folder("INBOX","/"); folders->append(inb); return folders; } -void POP3wrapper::deleteMailList(QValueList<RecMailP>&target) +void POP3wrapper::deleteMailList(const QValueList<RecMailP>&target) { login(); if (!m_pop3) return; int iii = 0; int count = target.count(); + QProgressBar bar( count,0 ); + bar.setCaption (("Removing mails - close to abort!") ); + int w = 300; + if ( QApplication::desktop()->width() < 320 ) + w = 220; + int h = bar.sizeHint().height() ; + int dw = QApplication::desktop()->width(); + int dh = QApplication::desktop()->height(); + bar.setGeometry( (dw-w)/2, (dh - h )/2 ,w,h ); + bar.show(); + int modulo = (count/10)+1; + int incCounter = 0; while (iii < count ) { + if ( ! bar.isVisible() ) + return ; + if ( incCounter % modulo == 0 ) + bar.setProgress( incCounter ); + ++incCounter; + qApp->processEvents(); + //qDebug("delete "); RecMailP mail = (*target.at( iii )); int err = mailsession_remove_message(m_pop3->sto_session,mail->getNumber()); if (err != MAIL_NO_ERROR) { - Global::statusMessage(tr("error deleting mail")); + Global::statusMessage(tr("Error deleting mail")); } ++iii; } } void POP3wrapper::deleteMail(const RecMailP&mail) { login(); if (!m_pop3) return; int err = mailsession_remove_message(m_pop3->sto_session,mail->getNumber()); if (err != MAIL_NO_ERROR) { Global::statusMessage(tr("error deleting mail")); } } void POP3wrapper::answeredMail(const RecMailP&) {} int POP3wrapper::deleteAllMail(const FolderP&) { login(); if (!m_pop3) return 0; int res = 1; uint32_t result = 0; int err = mailsession_messages_number(m_pop3->sto_session,NULL,&result); if (err != MAIL_NO_ERROR) { Global::statusMessage(tr("Error getting folder info")); return 0; } + QProgressBar bar( result,0 ); + bar.setCaption (("Deleting mails - close to abort!") ); + int w = 300; + if ( QApplication::desktop()->width() < 320 ) + w = 220; + int h = bar.sizeHint().height() ; + int dw = QApplication::desktop()->width(); + int dh = QApplication::desktop()->height(); + bar.setGeometry( (dw-w)/2, (dh - h )/2 ,w,h ); + bar.show(); + int modulo = (result/10)+1; + int incCounter = 0; for (unsigned int i = 0; i < result; ++i) { + if ( ! bar.isVisible() ) + return 0; + if ( incCounter % modulo == 0 ) + bar.setProgress( incCounter ); + ++incCounter; + qApp->processEvents(); err = mailsession_remove_message(m_pop3->sto_session,i+1); if (err != MAIL_NO_ERROR) { Global::statusMessage(tr("Error deleting mail %1").arg(i+1)); res=0; } break; } return res; } void POP3wrapper::statusFolder(folderStat&target_stat,const QString&) { login(); target_stat.message_count = 0; target_stat.message_unseen = 0; target_stat.message_recent = 0; if (!m_pop3) return; int r = mailsession_status_folder(m_pop3->sto_session,0,&target_stat.message_count, &target_stat.message_recent,&target_stat.message_unseen); if (r != MAIL_NO_ERROR) { ; // odebug << "error getting folter status." << oendl; } } encodedString* POP3wrapper::fetchRawBody(const RecMailP&mail) { char*target=0; size_t length=0; encodedString*res = 0; mailmessage * mailmsg = 0; int err = mailsession_get_message(m_pop3->sto_session, mail->getNumber(), &mailmsg); err = mailmessage_fetch(mailmsg,&target,&length); if (mailmsg) mailmessage_free(mailmsg); if (target) { res = new encodedString(target,length); } return res; } MAILLIB::ATYPE POP3wrapper::getType()const { return account->getType(); } const QString&POP3wrapper::getName()const{ return account->getAccountName(); } diff --git a/kmicromail/libmailwrapper/pop3wrapper.h b/kmicromail/libmailwrapper/pop3wrapper.h index ee754a4..7c70942 100644 --- a/kmicromail/libmailwrapper/pop3wrapper.h +++ b/kmicromail/libmailwrapper/pop3wrapper.h @@ -1,44 +1,44 @@ // CHANGED 2004-09-31 Lutz Rogowski #ifndef __POP3WRAPPER #define __POP3WRAPPER #include "mailwrapper.h" #include "genericwrapper.h" #include <qstring.h> class encodedString; struct mailstorage; struct mailfolder; class POP3wrapper : public Genericwrapper { Q_OBJECT public: POP3wrapper( POP3account *a ); virtual ~POP3wrapper(); /* mailbox will be ignored */ virtual void listMessages(const QString & mailbox, QValueList<Opie::Core::OSmartPointer<RecMail> > &target, int maxSizeInKb = 0 ); virtual QValueList<Opie::Core::OSmartPointer<Folder> >* listFolders(); /* mailbox will be ignored */ virtual void statusFolder(folderStat&target_stat,const QString & mailbox="INBOX"); virtual void deleteMail(const RecMailP&mail); + virtual void deleteMailList(const QValueList<RecMailP>&target); virtual void answeredMail(const RecMailP&mail); - virtual void deleteMailList(QValueList<RecMailP>&target); virtual int deleteAllMail(const Opie::Core::OSmartPointer<Folder>&); virtual RecBodyP fetchBody( const RecMailP &mail ); virtual encodedString* fetchRawBody(const RecMailP&mail); virtual void logout(); virtual MAILLIB::ATYPE getType()const; virtual const QString&getName()const; static void pop3_progress( size_t current, size_t maximum ); protected: void login(); POP3account *account; mailstorage*m_pop3; }; #endif diff --git a/kmicromail/opiemail.cpp b/kmicromail/opiemail.cpp index 3fbdcec..251f15a 100644 --- a/kmicromail/opiemail.cpp +++ b/kmicromail/opiemail.cpp @@ -1,408 +1,421 @@ // CHANGED 2004-09-31 Lutz Rogowski // CHANGED 2004-08-06 Lutz Rogowski #include "settingsdialog.h" #include "opiemail.h" #include "editaccounts.h" #include "composemail.h" #include "mailistviewitem.h" #include "viewmail.h" #include "selectstore.h" #include "selectsmtp.h" #include <qmessagebox.h> #include <qpe/qpeapplication.h> #include <libmailwrapper/smtpwrapper.h> #include <libmailwrapper/mailtypes.h> #include <libmailwrapper/abstractmail.h> /* OPIE */ //#include <qpe/resource.h> -#include <qpe/qpeapplication.h> +//#include <qpe/qpeapplication.h> /* QT */ using namespace Opie::Core; OpieMail::OpieMail( QWidget *parent, const char *name, WFlags flags ) : MainWindow( parent, name) //, WStyle_ContextHelp ) { settings = new Settings(); folderView->populate( settings->getAccounts() ); } OpieMail::~OpieMail() { if (settings) delete settings; } void OpieMail::appMessage(const QCString &msg, const QByteArray &data) { } #include <stdlib.h> void OpieMail::message(const QCString &msg, const QByteArray &data) { // copied from old mail2 static int ii = 0; // block second call if ( ii < 2 ) { ++ii; if ( ii > 1 ) { qDebug("qcop call blocked "); return; } } //qDebug("KM:appMessage %d *%s* %x", ii, msg.data(), this); if (msg == "writeMail(QString,QString)") { QDataStream stream(data,IO_ReadOnly); QString name, email; stream >> name >> email; // removing the whitespaces at beginning and end is needed! slotwriteMail(name.stripWhiteSpace(),email.stripWhiteSpace()); } else if (msg == "newMail()") { slotComposeMail(); } else if (msg == "newMail(QString)") { QDataStream stream(data,IO_ReadOnly); QString nameemail; stream >> nameemail; // the format is // NAME <EMAIL>:SUBJECT //qDebug("message %s ", nameemail.latin1()); slotwriteMail2( nameemail ); } } void OpieMail::slotwriteMail2(const QString& namemail ) { // qDebug("OpieMail::slotwriteMail2 "); qApp->processEvents(); ComposeMail compose( settings, this, 0, true ); if ( !namemail.isEmpty() ) { QString to = namemail; if ( namemail.find( " <") > 1 ) { to = "\"" +to.replace( QRegExp( " <"), "\" <") ; } else if ( namemail.find( "<") > 1 ) { to = "\"" +to.replace( QRegExp( "<"), "\" <") ; } int sub = to.find( ">:"); if ( sub > 0 ) { compose.setTo( to.left(sub+1) ); compose.setSubject( to.mid(sub+2) ); } else compose.setTo( to ); } compose.slotAdjustColumns(); compose.showMaximized(); compose.exec(); //qDebug("retttich "); } void OpieMail::slotwriteMail(const QString&name,const QString&email) { // qDebug("OpieMail::slotwriteMail "); ComposeMail compose( settings, this, 0, true , WStyle_ContextHelp ); if (!email.isEmpty()) { if (!name.isEmpty()) { compose.setTo("\"" + name + "\"" + " " + "<"+ email + ">"); } else { compose.setTo(email); } } compose.slotAdjustColumns(); compose.showMaximized(); compose.exec(); } void OpieMail::slotComposeMail() { slotwriteMail2( QString () ); //slotwriteMail(0l,0l); } void OpieMail::slotSendQueued() { SMTPaccount *smtp = 0; QList<Account> list = settings->getAccounts(); QList<SMTPaccount> smtpList; smtpList.setAutoDelete(false); Account *it; for ( it = list.first(); it; it = list.next() ) { if ( it->getType() == MAILLIB::A_SMTP ) { smtp = static_cast<SMTPaccount *>(it); smtpList.append(smtp); } } if (smtpList.count()==0) { QMessageBox::information(0,tr("Info"),tr("Define a smtp account first!\n")); return; } if (smtpList.count()==1) { smtp = smtpList.at(0); } else { smtp = 0; selectsmtp selsmtp; selsmtp.setSelectionlist(&smtpList); selsmtp.showMaximized(); if ( selsmtp.exec() == QDialog::Accepted ) { smtp = selsmtp.selected_smtp(); } } if (smtp) { SMTPwrapper * wrap = new SMTPwrapper(smtp); if ( wrap->flushOutbox() ) { QMessageBox::information(0,tr("Info"),tr("Mail queue flushed")); } delete wrap; } } void OpieMail::slotSearchMails() { qDebug("OpieMail::slotSearchMails():not implemented "); } void OpieMail::slotEditSettings() { SettingsDialog settingsDialog( this, 0, true, WStyle_ContextHelp ); settingsDialog.showMaximized(); settingsDialog.exec(); } void OpieMail::slotEditAccounts() { EditAccounts eaDialog( settings, this, 0, true, WStyle_ContextHelp ); eaDialog.slotAdjustColumns(); eaDialog.showMaximized(); eaDialog.exec(); if ( settings ) delete settings; settings = new Settings(); folderView->populate( settings->getAccounts() ); } void OpieMail::displayMail() { QListViewItem*item = mailView->currentItem(); if (!item) return; RecMailP mail = ((MailListViewItem*)item)->data(); RecBodyP body = folderView->fetchBody(mail); ViewMail readMail( this,"", Qt::WType_Modal | WStyle_ContextHelp ); readMail.setBody( body ); readMail.setMail( mail ); readMail.showMaximized(); readMail.exec(); if ( readMail.deleted ) { folderView->refreshCurrent(); } else { ( (MailListViewItem*)item )->setPixmap( 0, QPixmap() ); } } void OpieMail::slotDeleteMail() { if (!mailView->currentItem()) return; RecMailP mail = ((MailListViewItem*)mailView->currentItem() )->data(); if ( QMessageBox::warning(this, tr("Delete Mail"), QString( tr("<p>Do you really want to delete this mail? <br><br>" ) + mail->getFrom() + " - " + mail->getSubject() ) , QMessageBox::Yes, QMessageBox::No ) == QMessageBox::Yes ) { mail->Wrapper()->deleteMail( mail ); folderView->refreshCurrent(); } } void OpieMail::slotDeleteAllMail() { - if (!mailView->currentItem()) return; - RecMailP mail = ((MailListViewItem*)mailView->currentItem() )->data(); + + QValueList<RecMailP> t; if ( QMessageBox::warning(this, tr("Delete All Mails"), tr("Do you really want to delete\nall selected mails?" ) , QMessageBox::Yes, QMessageBox::No ) == QMessageBox::Yes ) { MailListViewItem* item = (MailListViewItem*)mailView->firstChild (); while ( item ) { if ( item->isSelected() ) { - RecMailP mail = item->data(); - mail->Wrapper()->deleteMail( mail ); + t.append( item->data() ); } item = (MailListViewItem*)item->nextSibling(); } - folderView->refreshCurrent(); } + else + return; + if ( t.count() == 0 ) + return; + RecMailP mail = t.first(); + mail->Wrapper()->deleteMailList(t); + folderView->refreshCurrent(); + + } void OpieMail::clearSelection() { mailView->clearSelection(); } void OpieMail::mailHold(int button, QListViewItem *item,const QPoint&,int ) { if (!mailView->currentItem()) return; MAILLIB::ATYPE mailtype = ((MailListViewItem*)mailView->currentItem() )->wrapperType(); /* just the RIGHT button - or hold on pda */ if (button!=2) {return;} if (!item) return; QPopupMenu *m = new QPopupMenu(0); if (m) { if (mailtype==MAILLIB::A_NNTP) { m->insertItem(tr("Read this posting"),this,SLOT(displayMail())); // m->insertItem(tr("Copy this posting"),this,SLOT(slotMoveCopyMail())); } else { if (folderView->currentisDraft()) { m->insertItem(tr("Edit this mail"),this,SLOT(reEditMail())); } m->insertItem(tr("Read this mail"),this,SLOT(displayMail())); - m->insertItem(tr("Copy/Move this mail"),this,SLOT(slotMoveCopyMail())); + m->insertItem(tr("Move/Copy this mail"),this,SLOT(slotMoveCopyMail())); m->insertItem(tr("Delete this mail"),this,SLOT(slotDeleteMail())); m->insertSeparator(); - m->insertItem(tr("Copy/Move all selected mail"),this,SLOT(slotMoveCopyAllMail())); + m->insertItem(tr("Move/Copy all selected mail"),this,SLOT(slotMoveCopyAllMail())); m->insertItem(tr("Delete all selected mails"),this,SLOT(slotDeleteAllMail())); m->insertItem(tr("Clear selection"),this,SLOT(clearSelection())); } m->setFocus(); m->exec( QPoint( QCursor::pos().x(), QCursor::pos().y()) ); delete m; } } void OpieMail::slotShowFolders( bool show ) { if ( show && folderView->isHidden() ) { folderView->show(); } else if ( !show && !folderView->isHidden() ) { folderView->hide(); } } void OpieMail::refreshMailView(const QValueList<RecMailP>&list) { MailListViewItem*item = 0; mailView->clear(); QValueList<RecMailP>::ConstIterator it; for (it = list.begin(); it != list.end();++it) { item = new MailListViewItem(mailView,item); item->storeData((*it)); item->showEntry(); } } void OpieMail::mailLeftClicked( QListViewItem *item ) { mailView->clearSelection(); /* just LEFT button - or tap with stylus on pda */ //if (button!=1) return; if (!item) return; if (folderView->currentisDraft()) { reEditMail(); } else { displayMail(); } } void OpieMail::slotMoveCopyMail() { if (!mailView->currentItem()) return; RecMailP mail = ((MailListViewItem*)mailView->currentItem() )->data(); AbstractMail*targetMail = 0; QString targetFolder = ""; Selectstore sels; folderView->setupFolderselect(&sels); if (!sels.exec()) return; targetMail = sels.currentMail(); targetFolder = sels.currentFolder(); if ( (mail->Wrapper()==targetMail && mail->getMbox()==targetFolder) || targetFolder.isEmpty()) { return; } if (sels.newFolder() && !targetMail->createMbox(targetFolder)) { QMessageBox::critical(0,tr("Error creating new Folder"), tr("<center>Error while creating<br>new folder - breaking.</center>")); return; } + sels.hide(); + qApp->processEvents(); + // qDebug("hiding sels "); mail->Wrapper()->mvcpMail(mail,targetFolder,targetMail,sels.moveMails()); folderView->refreshCurrent(); } void OpieMail::slotMoveCopyAllMail() { if (!mailView->currentItem()) return; QValueList<RecMailP> t; - if ( QMessageBox::warning(this, tr("Copy/Move all selected mails"), tr("Do you really want to copy/move\nall selected mails?" ) , QMessageBox::Yes, QMessageBox::No ) == QMessageBox::Yes ) + // if ( QMessageBox::warning(this, tr("Move/Copy all selected mails"), tr("Do you really want to copy/move\nall selected mails?" ) , QMessageBox::Yes, QMessageBox::No ) == QMessageBox::Yes ) { MailListViewItem* item = (MailListViewItem*)mailView->firstChild (); while ( item ) { if ( item->isSelected() ) { t.append( item->data() ); } item = (MailListViewItem*)item->nextSibling(); } } - else - return; + // else + // return; if ( t.count() == 0 ) return; RecMailP mail = t.first(); AbstractMail*targetMail = 0; QString targetFolder = ""; Selectstore sels; folderView->setupFolderselect(&sels); if (!sels.exec()) return; targetMail = sels.currentMail(); targetFolder = sels.currentFolder(); if ( (mail->Wrapper()==targetMail && mail->getMbox()==targetFolder) || targetFolder.isEmpty()) { return; } if (sels.newFolder() && !targetMail->createMbox(targetFolder)) { QMessageBox::critical(0,tr("Error creating new Folder"), tr("<center>Error while creating<br>new folder - breaking.</center>")); return; } + sels.hide(); + qApp->processEvents(); + //qDebug("hiding sels "); mail->Wrapper()->mvcpMailList(t,targetFolder,targetMail,sels.moveMails()); folderView->refreshCurrent(); } void OpieMail::reEditMail() { if (!mailView->currentItem()) return; ComposeMail compose( settings, this, 0, true , WStyle_ContextHelp ); compose.reEditMail(((MailListViewItem*)mailView->currentItem() )->data()); compose.slotAdjustColumns(); compose.showMaximized(); compose.exec(); } |