123 files changed, 40299 insertions, 0 deletions
diff --git a/libetpan/src/driver/TODO b/libetpan/src/driver/TODO new file mode 100644 index 0000000..4ba2c46 --- a/dev/null +++ b/libetpan/src/driver/TODO @@ -0,0 +1,9 @@ +- get_message_list() will disconnect and reconnect POP3 box +- add UID to non-cached drivers, help clients to recognize messages +- move IMAP UID cache to non-cached driver +- fix message size (put it in cache) +- XXX : fetch body in nntp do not use generic_fetch_body +- add flags prototype to add or remove flags +- cache bodystructures +- search is not implemented +- list of folder new implementation diff --git a/libetpan/src/driver/implementation/data-message/data_message_driver.c b/libetpan/src/driver/implementation/data-message/data_message_driver.c new file mode 100644 index 0000000..fbdffcd --- a/dev/null +++ b/libetpan/src/driver/implementation/data-message/data_message_driver.c @@ -0,0 +1,119 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "data_message_driver.h" + +#include "mailmessage.h" +#include "mailmessage_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 fetch_size(mailmessage * msg, size_t * result) +{ + struct generic_message_t * msg_data; + + msg_data = msg->msg_data; + * result = msg_data->msg_length; + + return MAIL_NO_ERROR; +} + + +static mailmessage_driver local_data_message_driver = { + .msg_name = "data", + + .msg_initialize = mailmessage_generic_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 = mailmessage_generic_fetch_header, + .msg_fetch_body = mailmessage_generic_fetch_body, + .msg_fetch_size = 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 * data_message_driver = &local_data_message_driver; + + + +mailmessage * data_message_init(char * data, size_t len) +{ + struct generic_message_t * msg_data; + mailmessage * msg; + int r; + + msg = mailmessage_new(); + if (msg == NULL) + goto err; + + r = mailmessage_init(msg, NULL, data_message_driver, 0, len); + if (r < 0) + goto free; + + msg_data = msg->msg_data; + msg_data->msg_fetched = 1; + msg_data->msg_message = data; + msg_data->msg_length = len; + + return msg; + + free: + mailmessage_free(msg); + err: + return NULL; +} + +void data_message_detach_mime(mailmessage * msg) +{ + msg->msg_mime = NULL; +} diff --git a/libetpan/src/driver/implementation/data-message/data_message_driver.h b/libetpan/src/driver/implementation/data-message/data_message_driver.h new file mode 100644 index 0000000..b6569c2 --- a/dev/null +++ b/libetpan/src/driver/implementation/data-message/data_message_driver.h @@ -0,0 +1,50 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef DATA_MESSAGE_DRIVER_H + +#define DATA_MESSAGE_DRIVER_H + +#include <libetpan/mailmessage.h> + +#define LIBETPAN_DATA_MESSAGE + +extern mailmessage_driver * data_message_driver; + +mailmessage * data_message_init(char * data, size_t len); + +void data_message_detach_mime(mailmessage * msg); + +#endif diff --git a/libetpan/src/driver/implementation/db/dbdriver.c b/libetpan/src/driver/implementation/db/dbdriver.c new file mode 100644 index 0000000..e374e64 --- a/dev/null +++ b/libetpan/src/driver/implementation/db/dbdriver.c @@ -0,0 +1,1134 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "dbdriver.h" +#include "imfcache.h" +#include "generic_cache.h" +#include "libetpan-config.h" +#include "dbdriver_message.h" +#include "mail_cache_db.h" +#include <string.h> +#include <stdlib.h> +#include "mailmessage.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(mailsession * session, + uint32_t num, mailmessage ** result); + +static int get_message_by_uid(mailsession * session, + const char * uid, mailmessage ** result); + +static mailsession_driver local_db_session_driver = { + .sess_name = "db", + + .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, + + .sess_get_message = get_message, + .sess_get_message_by_uid = get_message_by_uid, +}; + +mailsession_driver * db_session_driver = &local_db_session_driver; + +static inline struct db_session_state_data * get_data(mailsession * session) +{ + return session->sess_data; +} + +static int flags_store_process(mailsession * session) +{ + unsigned int i; + MMAPString * mmapstr; + int r; + int res; + struct mail_cache_db * maildb; + struct db_session_state_data * data; + struct mail_flags_store * flags_store; + + data = get_data(session); + + flags_store = data->db_flags_store; + + if (carray_count(flags_store->fls_tab) == 0) + return MAIL_NO_ERROR; + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + r = mail_cache_db_open_lock(data->db_filename, &maildb); + if (r < 0) { + res = MAIL_ERROR_FILE; + goto free_mmapstr; + } + + for(i = 0 ; i < carray_count(flags_store->fls_tab) ; i ++) { + mailmessage * msg; + char key[PATH_MAX]; + + msg = carray_get(flags_store->fls_tab, i); + + snprintf(key, sizeof(key), "%lu-flags", (unsigned long) msg->msg_index); + + r = generic_cache_flags_write(maildb, mmapstr, + key, msg->msg_flags); + } + + mail_flags_store_clear(flags_store); + + mail_cache_db_close_unlock(data->db_filename, maildb); + mmap_string_free(mmapstr); + + return MAIL_NO_ERROR; + + free_mmapstr: + mmap_string_free(mmapstr); + err: + return res; +} + +static int db_get_next_validity(struct mail_cache_db * maildb, + uint32_t * p_validity) +{ + int r; + char key_value[PATH_MAX]; + uint32_t validity; + void * serialized; + size_t serialized_len; + int res; + MMAPString * mmapstr; + size_t cur_token; + + mmapstr = mmap_string_new_len(serialized, serialized_len); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + snprintf(key_value, sizeof(key_value), "next-validity"); + + r = mail_cache_db_get(maildb, key_value, strlen(key_value), + &serialized, &serialized_len); + + if (r >= 0) { + size_t cur_token; + + cur_token = 0; + r = mailimf_cache_int_read(mmapstr, &cur_token, &validity); + if (r < 0) + validity = 0; + } + else { + validity = 0; + } + + mmap_string_set_size(mmapstr, 0); + cur_token = 0; + r = mailimf_cache_int_write(mmapstr, &cur_token, validity + 1); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_mmapstr; + } + + r = mail_cache_db_put(maildb, key_value, strlen(key_value), + mmapstr->str, mmapstr->len); + if (r < 0) { + res = MAIL_ERROR_FILE; + goto free_mmapstr; + } + + mmap_string_free(mmapstr); + + * p_validity = validity; + + return MAIL_NO_ERROR; + + free_mmapstr: + mmap_string_free(mmapstr); + err: + return res; +} + +static int db_get_next_msg_number(struct mail_cache_db * maildb, + uint32_t * p_num) +{ + int r; + char key_value[PATH_MAX]; + uint32_t num; + void * serialized; + size_t serialized_len; + int res; + MMAPString * mmapstr; + size_t cur_token; + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + snprintf(key_value, sizeof(key_value), "next-msg"); + + r = mail_cache_db_get(maildb, key_value, strlen(key_value), + &serialized, &serialized_len); + + if (r >= 0) { + size_t cur_token; + + if (mmap_string_append_len(mmapstr, serialized, serialized_len) == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + cur_token = 0; + r = mailimf_cache_int_read(mmapstr, &cur_token, &num); + if (r < 0) + num = 1; + } + else { + num = 1; + } + + mmap_string_set_size(mmapstr, 0); + cur_token = 0; + r = mailimf_cache_int_write(mmapstr, &cur_token, num + 1); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_mmapstr; + } + + r = mail_cache_db_put(maildb, key_value, strlen(key_value), + mmapstr->str, mmapstr->len); + if (r < 0) { + res = MAIL_ERROR_FILE; + goto free_mmapstr; + } + + mmap_string_free(mmapstr); + + * p_num = num; + + return MAIL_NO_ERROR; + + free_mmapstr: + mmap_string_free(mmapstr); + err: + return res; +} + +static int db_set_message_list(struct mail_cache_db * maildb, + carray * msglist) +{ + MMAPString * mmapstr; + char key_value[PATH_MAX]; + int r; + unsigned int i; + size_t cur_token; + int res; + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + cur_token = 0; + for(i = 0 ; i < carray_count(msglist) ; i ++) { + uint32_t * msg; + + msg = carray_get(msglist, i); + r = mailimf_cache_int_write(mmapstr, &cur_token, * msg); + if (r != MAIL_NO_ERROR) { + res = r; + goto free_mmapstr; + } + } + + snprintf(key_value, sizeof(key_value), "message-list"); + r = mail_cache_db_put(maildb, key_value, strlen(key_value), + mmapstr->str, mmapstr->len); + if (r < 0) { + res = MAIL_ERROR_FILE; + goto err; + } + + mmap_string_free(mmapstr); + + return MAIL_NO_ERROR; + + free_mmapstr: + mmap_string_free(mmapstr); + err: + return res; +} + +static int db_get_message_list(struct mail_cache_db * maildb, + carray ** p_msglist) +{ + carray * msglist; + void * serialized; + size_t serialized_len; + int r; + char key_value[PATH_MAX]; + int res; + unsigned int i; + + msglist = carray_new(16); + if (msglist == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + snprintf(key_value, sizeof(key_value), "message-list"); + r = mail_cache_db_get(maildb, key_value, strlen(key_value), + &serialized, &serialized_len); + if (r >= 0) { + MMAPString * mmapstr; + size_t cur_token; + + /* collect message list */ + + mmapstr = mmap_string_new_len(serialized, serialized_len); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_msglist; + } + + cur_token = 0; + do { + uint32_t num; + uint32_t * msg; + + r = mailimf_cache_int_read(mmapstr, &cur_token, &num); + if (r != MAIL_NO_ERROR) + break; + + msg = malloc(sizeof(* msg)); + if (msg == NULL) { + res = MAIL_ERROR_MEMORY; + mmap_string_free(mmapstr); + goto free_msglist; + } + * msg = num; + + r = carray_add(msglist, msg, NULL); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + free(msg); + mmap_string_free(mmapstr); + goto free_msglist; + } + } while (1); + + mmap_string_free(mmapstr); + } + + * p_msglist = msglist; + + return MAIL_NO_ERROR; + + free_msglist: + for(i = 0 ; i < carray_count(msglist) ; i ++) { + uint32_t * msg; + + msg = carray_get(msglist, i); + free(msg); + } + carray_free(msglist); + err: + return res; +} + +static int initialize(mailsession * session) +{ + struct db_session_state_data * data; + + data = malloc(sizeof(* data)); + if (data == NULL) + goto err; + + data->db_filename[0] = '\0'; + + data->db_flags_store = mail_flags_store_new(); + if (data->db_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 db_session_state_data * data; + + data = get_data(session); + + flags_store_process(session); + + mail_flags_store_free(data->db_flags_store); + + free(data); + + session->sess_data = NULL; +} + +static int connect_path(mailsession * session, char * path) +{ + struct db_session_state_data * data; + + data = get_data(session); + + strncpy(data->db_filename, path, sizeof(data->db_filename)); + + return MAIL_NO_ERROR; +} + +static int logout(mailsession * session) +{ + return MAIL_NO_ERROR; +} + +static int expunge_folder(mailsession * session) +{ + int r; + char key_value[PATH_MAX]; + struct mail_cache_db * maildb; + carray * msglist; + unsigned int i; + struct db_session_state_data * data; + int res; + chash * msg_table; + MMAPString * mmapstr; + + data = get_data(session); + + flags_store_process(session); + + r = mail_cache_db_open_lock(data->db_filename, &maildb); + if (r < 0) { + res = MAIL_ERROR_FILE; + goto err; + } + + r = db_get_message_list(maildb, &msglist); + if (r != MAIL_NO_ERROR) { + res = r; + goto close_db; + } + + msg_table = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY); + if (msg_table == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_msglist; + } + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_msgtable; + } + + i = 0; + while (i < carray_count(msglist)) { + uint32_t num; + uint32_t * msg; + chashdatum key; + chashdatum value; + struct mail_flags * flags; + int deleted; + + msg = carray_get(msglist, i); + num = * msg; + + deleted = 0; + snprintf(key_value, sizeof(key_value), "%lu-flags", + (unsigned long) num); + r = generic_cache_flags_read(maildb, mmapstr, key_value, &flags); + if (r == MAIL_NO_ERROR) { + if ((flags->fl_flags & MAIL_FLAG_DELETED) != 0) + deleted = 1; + } + + if (!deleted) { + snprintf(key_value, sizeof(key_value), "%lu", (unsigned long) num); + key.data = key_value; + key.len = strlen(key_value); + chash_set(msg_table, &key, &value, NULL); + + snprintf(key_value, sizeof(key_value), "%lu-envelope", + (unsigned long) num); + key.data = key_value; + key.len = strlen(key_value); + chash_set(msg_table, &key, &value, NULL); + + snprintf(key_value, sizeof(key_value), "%lu-flags", + (unsigned long) num); + key.data = key_value; + key.len = strlen(key_value); + chash_set(msg_table, &key, &value, NULL); + + i ++; + } + else { + free(msg); + carray_delete(msglist, i); + } + } + + mmap_string_free(mmapstr); + + r = mail_cache_db_clean_up(maildb, msg_table); + + chash_free(msg_table); + + r = db_set_message_list(maildb, msglist); + + for(i = 0 ; i < carray_count(msglist) ; i ++) { + uint32_t * msg; + + msg = carray_get(msglist, i); + free(msg); + } + carray_free(msglist); + + mail_cache_db_close_unlock(data->db_filename, maildb); + + return MAIL_NO_ERROR; + + free_msgtable: + chash_free(msg_table); + free_msglist: + for(i = 0 ; i < carray_count(msglist) ; i ++) { + uint32_t * msg; + + msg = carray_get(msglist, i); + free(msg); + } + close_db: + mail_cache_db_close_unlock(data->db_filename, maildb); + err: + return res; +} + +static int status_folder(mailsession * session, char * mb, + uint32_t * result_messages, uint32_t * result_recent, + uint32_t * result_unseen) +{ + struct mail_cache_db * maildb; + char key_value[PATH_MAX]; + MMAPString * mmapstr; + uint32_t messages; + uint32_t recent; + uint32_t unseen; + struct db_session_state_data * data; + int r; + int res; + carray * msglist; + unsigned int i; + + data = get_data(session); + + flags_store_process(session); + + r = mail_cache_db_open_lock(data->db_filename, &maildb); + if (r < 0) { + res = MAIL_ERROR_FILE; + goto err; + } + + r = db_get_message_list(maildb, &msglist); + if (r != MAIL_NO_ERROR) { + res = r; + goto close_db; + } + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_list; + } + + messages = 0; + recent = 0; + unseen = 0; + for(i = 0 ; i < carray_count(msglist) ; i ++) { + uint32_t num; + uint32_t * msg; + int r; + struct mail_flags * flags; + + msg = carray_get(msglist, i); + num = * msg; + free(msg); + carray_set(msglist, i, NULL); + + messages ++; + + snprintf(key_value, sizeof(key_value), "%lu-flags", (unsigned long) num); + + r = generic_cache_flags_read(maildb, mmapstr, key_value, &flags); + if (r == MAIL_NO_ERROR) { + 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); + + carray_free(msglist); + + mail_cache_db_close_unlock(data->db_filename, maildb); + + * result_messages = messages; + * result_unseen = unseen; + * result_recent = recent; + + return MAIL_NO_ERROR; + + free_list: + for(i = 0 ; i < carray_count(msglist) ; i ++) { + uint32_t * msg; + + msg = carray_get(msglist, i); + if (msg != NULL) + free(msg); + } + carray_free(msglist); + close_db: + mail_cache_db_close_unlock(data->db_filename, maildb); + err: + return res; +} + +static int recent_number(mailsession * session, char * mb, + uint32_t * result) +{ + uint32_t dummy_messages; + uint32_t dummy_unseen; + + return status_folder(session, mb, + &dummy_messages, result, &dummy_unseen); +} + +static int unseen_number(mailsession * session, char * mb, + uint32_t * result) +{ + uint32_t dummy_messages; + uint32_t dummy_recent; + + return status_folder(session, mb, + &dummy_messages, &dummy_recent, result); +} + +static int messages_number(mailsession * session, char * mb, + uint32_t * result) +{ + uint32_t dummy_unseen; + uint32_t dummy_recent; + + return status_folder(session, mb, + result, &dummy_recent, &dummy_unseen); +} + +static int append_message(mailsession * session, + char * message, size_t size) +{ + return append_message_flags(session, message, size, NULL); +} + +static int append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags) +{ + carray * msglist; + unsigned int i; + uint32_t * msg; + uint32_t num; + char key_value[PATH_MAX]; + MMAPString * mmapstr; + struct mail_cache_db * maildb; + struct db_session_state_data * data; + size_t cur_token; + struct mailimf_fields * fields; + int r; + int res; + + data = get_data(session); + + r = mail_cache_db_open_lock(data->db_filename, &maildb); + if (r < 0) { + res = MAIL_ERROR_FILE; + goto err; + } + + r = db_get_next_msg_number(maildb, &num); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + r = db_get_message_list(maildb, &msglist); + if (r != MAIL_NO_ERROR) { + res = r; + goto close_db; + } + + msg = malloc(sizeof(* msg)); + if (msg == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_msglist; + } + + * msg = num; + + r = carray_add(msglist, msg, NULL); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + free(msg); + goto free_msglist; + } + + r = db_set_message_list(maildb, msglist); + if (r != MAIL_NO_ERROR) { + res = r; + goto free_msglist; + } + + /* free msglist */ + + for(i = 0 ; i < carray_count(msglist) ; i ++) { + uint32_t * msg; + + msg = carray_get(msglist, i); + free(msg); + } + carray_free(msglist); + + snprintf(key_value, sizeof(key_value), "%lu", (unsigned long) num); + + r = mail_cache_db_put(maildb, key_value, strlen(key_value), + message, size); + if (r < 0) { + res = MAIL_ERROR_FILE; + goto close_db; + } + + /* write envelope */ + + cur_token = 0; + r = mailimf_envelope_fields_parse(message, size, &cur_token, &fields); + if (r != MAILIMF_NO_ERROR) { + res = MAIL_ERROR_PARSE; + goto close_db; + } + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto close_db; + } + + cur_token = 0; + r = mailimf_cache_fields_write(mmapstr, &cur_token, fields); + if (r != MAIL_NO_ERROR) { + res = r; + mmap_string_free(mmapstr); + goto close_db; + } + + snprintf(key_value, sizeof(key_value), "%lu-envelope", (unsigned long) num); + + r = mail_cache_db_put(maildb, key_value, strlen(key_value), + mmapstr->str, mmapstr->len); + + mmap_string_free(mmapstr); + + mailimf_fields_free(fields); + + /* write flags */ + + if (flags != NULL) { + snprintf(key_value, sizeof(key_value), "%lu-flags", (unsigned long) num); + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto close_db; + } + + r = generic_cache_flags_write(maildb, mmapstr, + key_value, flags); + + mmap_string_free(mmapstr); + + if (r != MAIL_NO_ERROR) { + res = MAIL_ERROR_FILE; + goto close_db; + } + } + + mail_cache_db_close_unlock(data->db_filename, maildb); + + return MAIL_NO_ERROR; + + free_msglist: + for(i = 0 ; i < carray_count(msglist) ; i ++) { + uint32_t * msg; + + msg = carray_get(msglist, i); + free(msg); + } + carray_free(msglist); + close_db: + mail_cache_db_close_unlock(data->db_filename, maildb); + err: + return res; +} + +static int get_messages_list(mailsession * session, + struct mailmessage_list ** result) +{ + int r; + char key[PATH_MAX]; + struct mail_cache_db * maildb; + struct db_session_state_data * data; + int res; + carray * msglist; + unsigned int i; + carray * msgtab; + struct mailmessage_list * driver_msglist; + + data = get_data(session); + + r = mail_cache_db_open_lock(data->db_filename, &maildb); + if (r < 0) { + res = MAIL_ERROR_FILE; + goto err; + } + + r = db_get_message_list(maildb, &msglist); + if (r != MAIL_NO_ERROR) { + res = r; + goto close_db; + } + + msgtab = carray_new(16); + if (msgtab == NULL) { + res = MAIL_ERROR_MEMORY; + goto close_db; + } + + for(i = 0 ; i < carray_count(msglist) ; i ++) { + uint32_t msg_num; + uint32_t * pmsg_num; + mailmessage * msg; + size_t size; + + pmsg_num = carray_get(msglist, i); + msg_num = * pmsg_num; + free(pmsg_num); + carray_set(msglist, i, NULL); + + snprintf(key, sizeof(key), "%lu", (unsigned long) msg_num); + r = mail_cache_db_get_size(maildb, key, strlen(key), &size); + if (r < 0) { + continue; + } + + msg = mailmessage_new(); + if (msg == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_list; + } + + r = mailmessage_init(msg, session, db_message_driver, + msg_num, size); + if (r != MAIL_NO_ERROR) { + mailmessage_free(msg); + res = r; + goto free_list; + } + + r = carray_add(msgtab, msg, NULL); + if (r < 0) { + mailmessage_free(msg); + res = MAIL_ERROR_MEMORY; + goto free_list; + } + } + carray_free(msglist); + + driver_msglist = mailmessage_list_new(msgtab); + if (driver_msglist == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_list; + } + + mail_cache_db_close_unlock(data->db_filename, maildb); + + * result = driver_msglist; + + return MAIL_NO_ERROR; + + free_list: + for(i = 0 ; i < carray_count(msgtab) ; i ++) { + mailmessage * msg; + + msg = carray_get(msgtab, i); + mailmessage_free(msg); + } + carray_free(msgtab); + + for(i = 0 ; i < carray_count(msglist) ; i ++) { + uint32_t * msg; + + msg = carray_get(msglist, i); + if (msg != NULL) + free(msg); + } + carray_free(msglist); + close_db: + mail_cache_db_close_unlock(data->db_filename, maildb); + err: + return res; +} + +static int get_envelopes_list(mailsession * session, + struct mailmessage_list * env_list) +{ + unsigned int i; + char key[PATH_MAX]; + int r; + struct mail_cache_db * maildb; + int res; + struct db_session_state_data * data; + MMAPString * mmapstr; + + data = get_data(session); + + flags_store_process(session); + + r = mail_cache_db_open_lock(data->db_filename, &maildb); + if (r < 0) { + res = MAIL_ERROR_FILE; + goto err; + } + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto close_db; + } + + 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) { + snprintf(key, sizeof(key), "%lu-envelope", + (unsigned long) msg->msg_index); + + r = generic_cache_fields_read(maildb, mmapstr, + key, &msg->msg_fields); + } + + if (msg->msg_flags == NULL) { + snprintf(key, sizeof(key), "%lu-flags", + (unsigned long) msg->msg_index); + + r = generic_cache_flags_read(maildb, mmapstr, + key, &msg->msg_flags); + } + } + + mmap_string_free(mmapstr); + + mail_cache_db_close_unlock(data->db_filename, maildb); + + return MAIL_NO_ERROR; + + close_db: + mail_cache_db_close_unlock(data->db_filename, maildb); + err: + return res; +} + +static int check_folder(mailsession * session) +{ + flags_store_process(session); + + return MAIL_NO_ERROR; +} + +static int get_message(mailsession * session, + uint32_t num, mailmessage ** result) +{ + mailmessage * msg; + int r; + size_t size; + char key[PATH_MAX]; + struct db_session_state_data * data; + struct mail_cache_db * maildb; + int res; + + data = get_data(session); + + r = mail_cache_db_open_lock(data->db_filename, &maildb); + if (r < 0) { + res = MAIL_ERROR_FILE; + goto err; + } + + msg = mailmessage_new(); + if (msg == NULL) { + res = MAIL_ERROR_MEMORY; + goto close_db; + } + + size = 0; + snprintf(key, sizeof(key), "%lu", (unsigned long) num); + r = mail_cache_db_get_size(maildb, key, strlen(key), &size); + /* ignore error */ + + r = mailmessage_init(msg, session, db_message_driver, + num, size); + if (r != MAIL_NO_ERROR) { + mailmessage_free(msg); + res = r; + goto close_db; + } + + mail_cache_db_close_unlock(data->db_filename, maildb); + + return MAIL_NO_ERROR; + + close_db: + mail_cache_db_close_unlock(data->db_filename, maildb); + err: + return res; +} + +static int get_message_by_uid(mailsession * session, + const char * uid, mailmessage ** result) +{ + uint32_t msg_num; + + msg_num = strtoul(uid, NULL, 10); + + return get_message(session, msg_num, result); +} diff --git a/libetpan/src/driver/implementation/db/dbdriver.h b/libetpan/src/driver/implementation/db/dbdriver.h new file mode 100644 index 0000000..1c2a96d --- a/dev/null +++ b/libetpan/src/driver/implementation/db/dbdriver.h @@ -0,0 +1,53 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef DBDRIVER_H + +#define DBDRIVER_H + +#include <libetpan/dbdriver_message.h> +#include <libetpan/dbdriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailsession_driver * db_session_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/db/dbdriver_message.c b/libetpan/src/driver/implementation/db/dbdriver_message.c new file mode 100644 index 0000000..70e9dca --- a/dev/null +++ b/libetpan/src/driver/implementation/db/dbdriver_message.c @@ -0,0 +1,308 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "dbdriver_message.h" +#include "dbdriver.h" +#include "mail_cache_db.h" + +#include "mailmessage_tools.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 fetch_envelope(mailmessage * msg_info, + struct mailimf_fields ** result); + +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_db_message_driver = { + .msg_name = "db", + + .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 = fetch_envelope, + + .msg_get_flags = get_flags, +}; + +mailmessage_driver * db_message_driver = &local_db_message_driver; + +struct db_msg_data { + MMAPString * msg_content; +}; + +static inline struct db_session_state_data * +get_session_data(mailmessage * msg) +{ + return msg->msg_session->sess_data; +} + +static int prefetch(mailmessage * msg_info) +{ + struct generic_message_t * msg; + int res; + struct db_msg_data * data; + struct db_session_state_data * sess_data; + MMAPString * msg_content; + struct mail_cache_db * maildb; + int r; + char key[PATH_MAX]; + void * msg_data; + size_t msg_data_len; + + sess_data = get_session_data(msg_info); + + r = mail_cache_db_open_lock(sess_data->db_filename, &maildb); + if (r < 0) { + res = MAIL_ERROR_FILE; + goto err; + } + + snprintf(key, sizeof(key), "%lu", (unsigned long) msg_info->msg_index); + r = mail_cache_db_get(maildb, key, strlen(key), &msg_data, &msg_data_len); + if (r < 0) { + res = MAIL_ERROR_MSG_NOT_FOUND; + goto close_db; + } + + msg_content = mmap_string_new_len(msg_data, msg_data_len); + if (msg_content == NULL) { + res = MAIL_ERROR_MEMORY; + goto close_db; + } + + data = malloc(sizeof(* data)); + if (data == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_mmapstr; + } + + data->msg_content = msg_content; + + msg = msg_info->msg_data; + + msg->msg_data = data; + msg->msg_message = msg_content->str; + msg->msg_length = msg_content->len; + + mail_cache_db_close_unlock(sess_data->db_filename, maildb); + + return MAIL_NO_ERROR; + + free_mmapstr: + mmap_string_free(msg_content); + close_db: + mail_cache_db_close_unlock(sess_data->db_filename, maildb); + err: + return res; +} + +static void prefetch_free(struct generic_message_t * msg) +{ + if (msg->msg_message != NULL) { + struct db_msg_data * data; + + data = msg->msg_data; + mmap_string_free(data->msg_content); + data->msg_content = NULL; + free(data); + msg->msg_message = NULL; + } +} + +static int initialize(mailmessage * msg_info) +{ + struct generic_message_t * msg; + int r; + char key[PATH_MAX]; + + snprintf(key, sizeof(key), "%lu", (unsigned long) msg_info->msg_index); + msg_info->msg_uid = strdup(key); + if (msg_info->msg_uid == NULL) + return MAIL_ERROR_MEMORY; + + 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)->db_flags_store, + msg_info); + /* ignore errors */ + } +} + +static int fetch_envelope(mailmessage * msg_info, + struct mailimf_fields ** result) +{ + char key[PATH_MAX]; + int r; + struct db_session_state_data * sess_data; + struct mail_cache_db * maildb; + int res; + struct mailimf_fields * fields; + MMAPString * mmapstr; + + sess_data = get_session_data(msg_info); + + r = mail_cache_db_open_lock(sess_data->db_filename, &maildb); + if (r < 0) { + res = MAIL_ERROR_FILE; + goto err; + } + + snprintf(key, sizeof(key), "%lu-envelope", + (unsigned long) msg_info->msg_index); + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto close_db; + } + + r = generic_cache_fields_read(maildb, mmapstr, + key, &fields); + + mmap_string_free(mmapstr); + + if (r != MAIL_NO_ERROR) { + res = MAIL_ERROR_MSG_NOT_FOUND; + goto close_db; + } + + mail_cache_db_close_unlock(sess_data->db_filename, maildb); + + * result = fields; + + return MAIL_NO_ERROR; + + close_db: + mail_cache_db_close_unlock(sess_data->db_filename, maildb); + err: + return res; +} + +static int get_flags(mailmessage * msg_info, + struct mail_flags ** result) +{ + char key[PATH_MAX]; + int r; + struct db_session_state_data * sess_data; + struct mail_cache_db * maildb; + int res; + MMAPString * mmapstr; + + sess_data = get_session_data(msg_info); + + r = mail_cache_db_open_lock(sess_data->db_filename, &maildb); + if (r < 0) { + res = MAIL_ERROR_FILE; + goto err; + } + + snprintf(key, sizeof(key), "%lu-flags", (unsigned long) msg_info->msg_index); + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto close_db; + } + + r = generic_cache_flags_read(maildb, mmapstr, + key, &msg_info->msg_flags); + + mmap_string_free(mmapstr); + + if (r != MAIL_NO_ERROR) { + msg_info->msg_flags = mail_flags_new_empty(); + if (msg_info->msg_flags == NULL) { + res = MAIL_ERROR_MEMORY; + goto close_db; + } + } + + mail_cache_db_close_unlock(sess_data->db_filename, maildb); + + * result = msg_info->msg_flags; + + return MAIL_NO_ERROR; + + close_db: + mail_cache_db_close_unlock(sess_data->db_filename, maildb); + err: + return res; +} + diff --git a/libetpan/src/driver/implementation/db/dbdriver_message.h b/libetpan/src/driver/implementation/db/dbdriver_message.h new file mode 100644 index 0000000..f634775 --- a/dev/null +++ b/libetpan/src/driver/implementation/db/dbdriver_message.h @@ -0,0 +1,52 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef DBDRIVER_MESSAGE_H + +#define DBDRIVER_MESSAGE_H + +#include <libetpan/dbdriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailmessage_driver * db_message_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/db/dbdriver_types.h b/libetpan/src/driver/implementation/db/dbdriver_types.h new file mode 100644 index 0000000..052e3db --- a/dev/null +++ b/libetpan/src/driver/implementation/db/dbdriver_types.h @@ -0,0 +1,71 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef DBDRIVER_TYPES_H + +#define DBDRIVER_TYPES_H + +#include <libetpan/libetpan-config.h> + +#include <libetpan/maildriver_types.h> +#include <libetpan/generic_cache_types.h> +#include <libetpan/mailstorage_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct db_session_state_data { + char db_filename[PATH_MAX]; + struct mail_flags_store * db_flags_store; +}; + +/* db storage */ + +/* + db_mailstorage is the state data specific to the db storage. + + - pathname is the path of the db storage. +*/ + +struct db_mailstorage { + char * db_pathname; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/db/dbstorage.c b/libetpan/src/driver/implementation/db/dbstorage.c new file mode 100644 index 0000000..c4be63c --- a/dev/null +++ b/libetpan/src/driver/implementation/db/dbstorage.c @@ -0,0 +1,144 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "dbstorage.h" +#include "mailstorage.h" + +#include "mail.h" +#include "mailmessage.h" +#include "dbdriver.h" +#include "maildriver.h" + +#include <stdlib.h> +#include <string.h> + +/* db storage */ + +static int db_mailstorage_connect(struct mailstorage * storage); +static int +db_mailstorage_get_folder_session(struct mailstorage * storage, + char * pathname, mailsession ** result); +static void db_mailstorage_uninitialize(struct mailstorage * storage); + +static mailstorage_driver db_mailstorage_driver = { + .sto_name = "db", + .sto_connect = db_mailstorage_connect, + .sto_get_folder_session = db_mailstorage_get_folder_session, + .sto_uninitialize = db_mailstorage_uninitialize, +}; + +int db_mailstorage_init(struct mailstorage * storage, + char * db_pathname) +{ + struct db_mailstorage * db_storage; + + db_storage = malloc(sizeof(* db_storage)); + if (db_storage == NULL) + goto err; + + db_storage->db_pathname = strdup(db_pathname); + if (db_storage->db_pathname == NULL) + goto free; + + storage->sto_data = db_storage; + storage->sto_driver = &db_mailstorage_driver; + + return MAIL_NO_ERROR; + + free: + free(db_storage); + err: + return MAIL_ERROR_MEMORY; +} + +static void db_mailstorage_uninitialize(struct mailstorage * storage) +{ + struct db_mailstorage * db_storage; + + db_storage = storage->sto_data; + free(db_storage->db_pathname); + free(db_storage); + + storage->sto_data = NULL; +} + +static int db_mailstorage_connect(struct mailstorage * storage) +{ + struct db_mailstorage * db_storage; + mailsession_driver * driver; + int r; + int res; + mailsession * session; + + db_storage = storage->sto_data; + + driver = db_session_driver; + + session = mailsession_new(driver); + if (session == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + r = mailsession_connect_path(session, db_storage->db_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 +db_mailstorage_get_folder_session(struct mailstorage * storage, + char * pathname, mailsession ** result) +{ + * result = storage->sto_session; + + return MAIL_NO_ERROR; +} + diff --git a/libetpan/src/driver/implementation/db/dbstorage.h b/libetpan/src/driver/implementation/db/dbstorage.h new file mode 100644 index 0000000..5fa9659 --- a/dev/null +++ b/libetpan/src/driver/implementation/db/dbstorage.h @@ -0,0 +1,61 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef DBSTORAGE_H + +#define DBSTORAGE_H + +#include <libetpan/dbdriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + db_mailstorage_init is the constructor for a DB storage. + + @param storage this is the storage to initialize. + + @param pathname is the directory that contains the mailbox. +*/ + +int db_mailstorage_init(struct mailstorage * storage, + char * db_pathname); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/hotmail/hotmailstorage.c b/libetpan/src/driver/implementation/hotmail/hotmailstorage.c new file mode 100644 index 0000000..0d1503b --- a/dev/null +++ b/libetpan/src/driver/implementation/hotmail/hotmailstorage.c @@ -0,0 +1,62 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "hotmailstorage.h" + +#include "pop3storage.h" +#include "pop3driver_types.h" + +/* + hotway is a gateway from hotmail to POP3 + + http://hotwayd.sourceforge.net/ +*/ + +static char hotway_command[512] = "/usr/bin/hotwayd"; + +int hotmail_mailstorage_init(struct mailstorage * storage, + char * hotmail_login, char * hotmail_password, + int hotmail_cached, char * hotmail_cache_directory, + char * hotmail_flags_directory) +{ + return pop3_mailstorage_init(storage, + "hotmail.dummy", 0, + hotway_command, + CONNECTION_TYPE_COMMAND, POP3_AUTH_TYPE_PLAIN, + hotmail_login, hotmail_password, + hotmail_cached, hotmail_cache_directory, + hotmail_flags_directory); +} + diff --git a/libetpan/src/driver/implementation/hotmail/hotmailstorage.h b/libetpan/src/driver/implementation/hotmail/hotmailstorage.h new file mode 100644 index 0000000..05d6385 --- a/dev/null +++ b/libetpan/src/driver/implementation/hotmail/hotmailstorage.h @@ -0,0 +1,56 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef HOTMAILSTORAGE_H + +#define HOTMAILSTORAGE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "mailstorage_types.h" + +int hotmail_mailstorage_init(struct mailstorage * storage, + char * hotmail_login, char * hotmail_password, + int hotmail_cached, char * hotmail_cache_directory, + char * hotmail_flags_directory); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/libetpan/src/driver/implementation/imap/imapdriver.c b/libetpan/src/driver/implementation/imap/imapdriver.c new file mode 100644 index 0000000..815e077 --- a/dev/null +++ b/libetpan/src/driver/implementation/imap/imapdriver.c @@ -0,0 +1,1226 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "imapdriver.h" + +#include "mail.h" +#include "imapdriver_tools.h" +#include "mailmessage.h" +#include "imapdriver_message.h" +#include "imapdriver_types.h" +#include "maildriver.h" +#include "maildriver_tools.h" +#include "generic_cache.h" + +#include <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); +} + + + +#define IMAP_SET_MAX_COUNT 100 + +static int +imapdriver_get_envelopes_list(mailsession * session, + struct mailmessage_list * env_list) +{ + struct mailimap_set * set; + struct mailimap_fetch_att * fetch_att; + struct mailimap_fetch_type * fetch_type; + int res; + clist * fetch_result; + int r; + uint32_t exists; + clist * msg_list; + clistiter * set_iter; + + if (get_imap_session(session)->imap_selection_info == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + imap_flags_store_process(get_imap_session(session), + get_data(session)->imap_flags_store); + + exists = get_imap_session(session)->imap_selection_info->sel_exists; + + if (exists == 0) + return MAIL_NO_ERROR; + + fetch_type = mailimap_fetch_type_new_fetch_att_list_empty(); + if (fetch_type == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + fetch_att = mailimap_fetch_att_new_uid(); + if (fetch_att == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_type; + } + + r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); + if (r != MAILIMAP_NO_ERROR) { + mailimap_fetch_att_free(fetch_att); + res = MAIL_ERROR_MEMORY; + goto free_fetch_type; + } + + fetch_att = mailimap_fetch_att_new_flags(); + if (fetch_att == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_type; + } + + r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); + if (r != MAILIMAP_NO_ERROR) { + mailimap_fetch_att_free(fetch_att); + res = MAIL_ERROR_MEMORY; + goto free_fetch_type; + } + + r = imap_add_envelope_fetch_att(fetch_type); + if (r != MAIL_NO_ERROR) { + res = r; + goto free_fetch_type; + } + + r = maildriver_env_list_to_msg_list(env_list, &msg_list); + if (r != MAIL_NO_ERROR) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_type; + } + + if (clist_begin(msg_list) == NULL) { + /* no need to fetch envelopes */ + + mailimap_fetch_type_free(fetch_type); + clist_free(msg_list); + return MAIL_NO_ERROR; + } + + r = msg_list_to_imap_set(msg_list, &set); + if (r != MAIL_NO_ERROR) { + clist_foreach(msg_list, (clist_func) free, NULL); + clist_free(msg_list); + res = MAIL_ERROR_MEMORY; + goto free_fetch_type; + } + clist_foreach(msg_list, (clist_func) free, NULL); + clist_free(msg_list); + + set_iter = clist_begin(set->set_list); + while (set_iter != NULL) { + struct mailimap_set * subset; + unsigned int count; + + subset = mailimap_set_new_empty(); + if (subset == NULL) { + res = MAIL_ERROR_MEMORY; + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); + res = MAIL_ERROR_MEMORY; + goto err; + } + + count = 0; + while (count < IMAP_SET_MAX_COUNT) { + struct mailimap_set_item * item; + + item = clist_content(set_iter); + set_iter = clist_delete(set->set_list, set_iter); + + r = mailimap_set_add(subset, item); + if (r != MAILIMAP_NO_ERROR) { + mailimap_set_item_free(item); + mailimap_set_free(subset); + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); + res = MAIL_ERROR_MEMORY; + goto err; + } + + count ++; + + if (set_iter == NULL) + break; + } + + r = mailimap_uid_fetch(get_imap_session(session), subset, + fetch_type, &fetch_result); + + mailimap_set_free(subset); + + switch (r) { + case MAILIMAP_NO_ERROR: + break; + default: + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); + return imap_error_to_mail_error(r); + } + + if (clist_begin(fetch_result) == NULL) { + res = MAIL_ERROR_FETCH; + goto err; + } + + r = imap_fetch_result_to_envelop_list(fetch_result, env_list); + mailimap_fetch_list_free(fetch_result); + + if (r != MAIL_NO_ERROR) { + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); + res = MAIL_ERROR_MEMORY; + goto err; + } + } + +#if 0 + r = mailimap_uid_fetch(get_imap_session(session), set, + fetch_type, &fetch_result); +#endif + + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); +#if 0 + switch (r) { + case MAILIMAP_NO_ERROR: + break; + default: + return imap_error_to_mail_error(r); + } + + r = imap_fetch_result_to_envelop_list(fetch_result, env_list); + mailimap_fetch_list_free(fetch_result); + + if (r != MAIL_NO_ERROR) { + res = MAIL_ERROR_MEMORY; + goto err; + } +#endif + + return MAIL_NO_ERROR; + + free_fetch_type: + mailimap_fetch_type_free(fetch_type); + err: + return res; +} + + +#if 0 +static int imapdriver_search_messages(mailsession * session, char * charset, + struct mail_search_key * key, + struct mail_search_result ** result) +{ + struct mailimap_search_key * imap_key; + int r; + clist * imap_result; + clist * result_list; + struct mail_search_result * search_result; + clistiter * cur; + + r = mail_search_to_imap_search(key, &imap_key); + if (r != MAIL_NO_ERROR) + return MAIL_ERROR_MEMORY; + + r = mailimap_uid_search(get_imap_session(session), charset, imap_key, + &imap_result); + + mailimap_search_key_free(imap_key); + + switch (r) { + case MAILIMAP_NO_ERROR: + break; + default: + return imap_error_to_mail_error(r); + } + + result_list = clist_new(); + if (result_list == NULL) + return MAIL_ERROR_MEMORY; + + for(cur = clist_begin(imap_result) ; cur != NULL ; cur = clist_next(cur)) { + uint32_t val = * (uint32_t *) clist_content(cur); + uint32_t * new; + + new = malloc(sizeof(* new)); + if (new == NULL) { + goto free_imap_result; + } + + * new = val; + + r = clist_append(result_list, new); + if (r != 0) { + free(new); + goto free_imap_result; + } + } + + search_result = mail_search_result_new(result_list); + if (search_result == NULL) + goto free_imap_result; + + mailimap_search_result_free(imap_result); + + * result = search_result; + + return MAIL_NO_ERROR; + + free_imap_result: + mailimap_search_result_free(imap_result); + return MAIL_ERROR_MEMORY; +} +#endif + +static int imapdriver_starttls(mailsession * session) +{ + mailimap * imap; + int r; + struct mailimap_capability_data * cap_data; + clistiter * cur; + int starttls; + int fd; + mailstream_low * low; + mailstream_low * new_low; + int capability_available; + + imap = get_imap_session(session); + + capability_available = FALSE; + if (imap->imap_connection_info != NULL) + if (imap->imap_connection_info->imap_capability != NULL) { + capability_available = TRUE; + cap_data = imap->imap_connection_info->imap_capability; + } + + if (!capability_available) { + r = mailimap_capability(imap, &cap_data); + switch (r) { + case MAILIMAP_NO_ERROR: + break; + default: + return imap_error_to_mail_error(r); + } + } + + starttls = FALSE; + for(cur = clist_begin(cap_data->cap_list) ; cur != NULL ; + cur = clist_next(cur)) { + struct mailimap_capability * cap; + + cap = clist_content(cur); + + if (cap->cap_type == MAILIMAP_CAPABILITY_NAME) + if (strcasecmp(cap->cap_data.cap_name, "STARTTLS") == 0) { + starttls = TRUE; + break; + } + } + + if (!capability_available) + mailimap_capability_data_free(cap_data); + + if (!starttls) + return MAIL_ERROR_NO_TLS; + + r = mailimap_starttls(imap); + + switch (r) { + case MAILIMAP_NO_ERROR: + break; + default: + return imap_error_to_mail_error(r); + } + + low = mailstream_get_low(imap->imap_stream); + fd = mailstream_low_get_fd(low); + if (fd == -1) + return MAIL_ERROR_STREAM; + + new_low = mailstream_low_ssl_open(fd); + if (new_low == NULL) + return MAIL_ERROR_STREAM; + + mailstream_low_free(low); + mailstream_set_low(imap->imap_stream, new_low); + + return MAIL_NO_ERROR; +} + +static int imapdriver_get_message(mailsession * session, + uint32_t num, mailmessage ** result) +{ + mailmessage * msg_info; + int r; + + msg_info = mailmessage_new(); + if (msg_info == NULL) + return MAIL_ERROR_MEMORY; + + r = mailmessage_init(msg_info, session, imap_message_driver, num, 0); + if (r != MAIL_NO_ERROR) { + mailmessage_free(msg_info); + return r; + } + + * result = msg_info; + + return MAIL_NO_ERROR; +} + +/* Retrieve a message by UID + + libEtPan! uid format for IMAP is "UIDVALIDITY-UID" + where UIDVALIDITY and UID are decimal representation of + respectively uidvalidity and uid numbers. + + Return value: + MAIL_ERROR_INVAL if uid is NULL or has an incorrect format. + MAIL_ERROR_MSG_NOT_FOUND if uidvalidity has changed or uid was not found + MAIL_NO_ERROR if message was found. Result is in result +*/ + +static int imapdriver_get_message_by_uid(mailsession * session, + const char * uid, + mailmessage ** result) +{ + uint32_t uidvalidity; + uint32_t num; + char * p1, * p2; + mailimap * imap; + + if (uid == NULL) + return MAIL_ERROR_INVAL; + + uidvalidity = strtoul(uid, &p1, 10); + if (p1 == uid || * p1 != '-') + return MAIL_ERROR_INVAL; + + p1++; + num = strtoul(p1, &p2, 10); + if (p2 == p1 || * p2 != '\0') + return MAIL_ERROR_INVAL; + + imap = get_imap_session(session); + if (imap->imap_selection_info->sel_uidvalidity != uidvalidity) + return MAIL_ERROR_MSG_NOT_FOUND; + + return imapdriver_get_message(session, num, result); +} diff --git a/libetpan/src/driver/implementation/imap/imapdriver.h b/libetpan/src/driver/implementation/imap/imapdriver.h new file mode 100644 index 0000000..cbc0c51 --- a/dev/null +++ b/libetpan/src/driver/implementation/imap/imapdriver.h @@ -0,0 +1,52 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef IMAPDRIVER_H + +#define IMAPDRIVER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <libetpan/imapdriver_types.h> + +extern mailsession_driver * imap_session_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/imap/imapdriver_cached.c b/libetpan/src/driver/implementation/imap/imapdriver_cached.c new file mode 100644 index 0000000..806b282 --- a/dev/null +++ b/libetpan/src/driver/implementation/imap/imapdriver_cached.c @@ -0,0 +1,1370 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "imapdriver_cached.h" + +#include "libetpan-config.h" + +#include <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) { + mailmessage * msg; + + msg = carray_get(env_list->msg_tab, i); + mailmessage_free(msg); + carray_delete(env_list->msg_tab, i); + } + else { + i ++; + } + } + + tab = carray_new(carray_count(env_list->msg_tab) + + carray_count(data->imap_uid_list)); + if (tab == NULL) { + res = MAIL_ERROR_MEMORY; + goto free; + } + carray_set_size(tab, + carray_count(env_list->msg_tab) + carray_count(data->imap_uid_list)); + + /* sort cached data before adding them to the list */ + qsort(carray_data(data->imap_uid_list), carray_count(data->imap_uid_list), + sizeof(* carray_data(data->imap_uid_list)), + (int (*)(const void *, const void *)) cmp_uid); + + /* adds cached UID */ + for(i = 0 ; i < carray_count(data->imap_uid_list) ; i ++) { + struct uid_cache_item * cache_item; + mailmessage * msg; + + cache_item = carray_get(data->imap_uid_list, i); + + msg = mailmessage_new(); + if (msg == NULL) { + res = MAIL_ERROR_MEMORY; + goto free; + } + + r = mailmessage_init(msg, session, imap_cached_message_driver, + cache_item->uid, cache_item->size); + if (r != MAIL_NO_ERROR) { + mailmessage_free(msg); + res = r; + goto free; + } + + carray_set(tab, i, msg); + } + + /* adds new elements */ + for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { + mailmessage * msg; + + msg = carray_get(env_list->msg_tab, i); + carray_set(tab, carray_count(data->imap_uid_list) + i, msg); + } + + /* replace list of messages in env_list */ + carray_free(env_list->msg_tab); + env_list->msg_tab = tab; + + r = update_uid_cache(session, env_list); + if (r != MAIL_NO_ERROR) { + res = r; + goto free; + } +#endif + + * result = env_list; + + return MAIL_NO_ERROR; + + free: + mailmessage_list_free(env_list); + err: + return res; +} + +#define IMAP_SET_MAX_COUNT 100 + +static int get_flags_list(mailsession * session, + struct mailmessage_list * env_list) +{ + struct mailimap_set * set; + struct mailimap_fetch_att * fetch_att; + struct mailimap_fetch_type * fetch_type; + int res; + clist * fetch_result; + int r; + clist * msg_list; +#if 0 + struct imap_session_state_data * data; +#endif + unsigned i; + unsigned dest; + clistiter * set_iter; + +#if 0 + data = session->data; +#endif + + fetch_type = mailimap_fetch_type_new_fetch_att_list_empty(); + if (fetch_type == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + fetch_att = mailimap_fetch_att_new_uid(); + if (fetch_att == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_type; + } + + r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); + if (r != MAILIMAP_NO_ERROR) { + mailimap_fetch_att_free(fetch_att); + res = MAIL_ERROR_MEMORY; + goto free_fetch_type; + } + + fetch_att = mailimap_fetch_att_new_flags(); + if (fetch_att == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_type; + } + + r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); + if (r != MAILIMAP_NO_ERROR) { + mailimap_fetch_att_free(fetch_att); + res = MAIL_ERROR_MEMORY; + goto free_fetch_type; + } + + r = maildriver_env_list_to_msg_list_no_flags(env_list, &msg_list); + if (r != MAIL_NO_ERROR) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_type; + } + + if (clist_begin(msg_list) == NULL) { + /* no need to fetch envelopes */ + + clist_free(msg_list); + mailimap_fetch_type_free(fetch_type); + return MAIL_NO_ERROR; + } + + r = msg_list_to_imap_set(msg_list, &set); + if (r != MAIL_NO_ERROR) { + clist_foreach(msg_list, (clist_func) free, NULL); + clist_free(msg_list); + res = MAIL_ERROR_MEMORY; + goto free_fetch_type; + } + clist_foreach(msg_list, (clist_func) free, NULL); + clist_free(msg_list); + + set_iter = clist_begin(set->set_list); + while (set_iter != NULL) { + struct mailimap_set * subset; + unsigned int count; + + subset = mailimap_set_new_empty(); + if (subset == NULL) { + res = MAIL_ERROR_MEMORY; + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); + res = MAIL_ERROR_MEMORY; + goto err; + } + + count = 0; + while (count < IMAP_SET_MAX_COUNT) { + struct mailimap_set_item * item; + + item = clist_content(set_iter); + set_iter = clist_delete(set->set_list, set_iter); + + r = mailimap_set_add(subset, item); + if (r != MAILIMAP_NO_ERROR) { + mailimap_set_item_free(item); + mailimap_set_free(subset); + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); + res = MAIL_ERROR_MEMORY; + goto err; + } + + count ++; + + if (set_iter == NULL) + break; + } + + r = mailimap_uid_fetch(get_imap_session(session), subset, + fetch_type, &fetch_result); + + mailimap_set_free(subset); + + switch (r) { + case MAILIMAP_NO_ERROR: + break; + default: + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); + return imap_error_to_mail_error(r); + } + + if (clist_begin(fetch_result) == NULL) { + res = MAIL_ERROR_FETCH; + goto err; + } + + r = imap_fetch_result_to_envelop_list(fetch_result, env_list); + mailimap_fetch_list_free(fetch_result); + + if (r != MAIL_NO_ERROR) { + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); + res = MAIL_ERROR_MEMORY; + goto err; + } + } + +#if 0 + r = mailimap_uid_fetch(get_imap_session(session), set, + fetch_type, &fetch_result); +#endif + + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); + +#if 0 + switch (r) { + case MAILIMAP_NO_ERROR: + break; + default: + return imap_error_to_mail_error(r); + } + + r = imap_fetch_result_to_envelop_list(fetch_result, env_list); + mailimap_fetch_list_free(fetch_result); + + if (r != MAIL_NO_ERROR) { + res = MAIL_ERROR_MEMORY; + goto err; + } +#endif + + /* remove messages that don't have flags */ + i = 0; + dest = 0; + while (i < carray_count(env_list->msg_tab)) { + mailmessage * msg; + + msg = carray_get(env_list->msg_tab, i); + if (msg->msg_flags != NULL) { + carray_set(env_list->msg_tab, dest, msg); + dest ++; + } + else { + mailmessage_free(msg); + } + i ++; + } + carray_set_size(env_list->msg_tab, dest); + + return MAIL_NO_ERROR; + + free_fetch_type: + mailimap_fetch_type_free(fetch_type); + err: + return res; +} + + +#define ENV_NAME "env.db" + +static void get_uid_from_filename(char * filename) +{ + char * p; + + p = strstr(filename, "-part"); + if (p != NULL) + * p = 0; + p = strstr(filename, "-envelope"); + if (p != NULL) + * p = 0; + p = strstr(filename, "-rfc822"); + if (p != NULL) + * p = 0; +} + +static int +imapdriver_cached_get_envelopes_list(mailsession * session, + struct mailmessage_list * env_list) +{ + int r; + int res; + uint32_t i; + struct imap_cached_session_state_data * data; + MMAPString * mmapstr; + struct mail_cache_db * cache_db; + char filename[PATH_MAX]; + + data = get_cached_data(session); + if (data->imap_quoted_mb == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + snprintf(filename, PATH_MAX, "%s/%s", data->imap_quoted_mb, ENV_NAME); + + r = mail_cache_db_open_lock(filename, &cache_db); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_mmapstr; + } + + /* fill with cached */ + + for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { + mailmessage * msg; + struct mailimf_fields * fields; + + msg = carray_get(env_list->msg_tab, i); + + if (msg->msg_fields == NULL) { + r = imapdriver_get_cached_envelope(cache_db, mmapstr, + session, msg, &fields); + if (r == MAIL_NO_ERROR) { + msg->msg_cached = TRUE; + msg->msg_fields = fields; + } + } + } + + mail_cache_db_close_unlock(filename, cache_db); + + r = mailsession_get_envelopes_list(get_ancestor(session), env_list); + + check_for_uid_cache(session); + + if (r != MAIL_NO_ERROR) { + res = r; + goto free_mmapstr; + } + + r = get_flags_list(session, env_list); + + if (r != MAIL_NO_ERROR) { + res = r; + goto free_mmapstr; + } + +#ifdef CACHE_MESSAGE_LIST + r = update_uid_cache(session, env_list); + if (r != MAIL_NO_ERROR) { + res = r; + goto free_mmapstr; + } +#endif + + /* must write cache */ + + r = mail_cache_db_open_lock(filename, &cache_db); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_mmapstr; + } + + for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { + mailmessage * msg; + + msg = carray_get(env_list->msg_tab, i); + + if (msg->msg_fields != NULL) { + if (!msg->msg_cached) { + r = imapdriver_write_cached_envelope(cache_db, mmapstr, + session, msg, msg->msg_fields); + } + } + } + + /* flush cache */ + + maildriver_cache_clean_up(cache_db, NULL, env_list); + + mail_cache_db_close_unlock(filename, cache_db); + mmap_string_free(mmapstr); + + /* remove cache files */ + + maildriver_message_cache_clean_up(data->imap_quoted_mb, env_list, + get_uid_from_filename); + + return MAIL_NO_ERROR; + + free_mmapstr: + mmap_string_free(mmapstr); + err: + return res; +} + +static int imapdriver_cached_remove_message(mailsession * session, + uint32_t num) +{ + int r; + + r = mailsession_remove_message(get_ancestor(session), num); + + check_for_uid_cache(session); + + return r; +} + +#if 0 +static int imapdriver_cached_search_messages(mailsession * session, + char * charset, + struct mail_search_key * key, + struct mail_search_result ** + result) +{ + int r; + + r = mailsession_search_messages(get_ancestor(session), charset, key, result); + + check_for_uid_cache(session); + + return r; +} +#endif + +static int imapdriver_cached_get_message(mailsession * session, + uint32_t num, mailmessage ** result) +{ + mailmessage * msg_info; + int r; + + msg_info = mailmessage_new(); + if (msg_info == NULL) + return MAIL_ERROR_MEMORY; + + r = mailmessage_init(msg_info, session, imap_cached_message_driver, num, 0); + if (r != MAIL_NO_ERROR) { + mailmessage_free(msg_info); + return r; + } + + * result = msg_info; + + return MAIL_NO_ERROR; +} + +/* Retrieve a message by UID + * libEtPan! uid format for IMAP is "UIDVALIDITY-UID" + * where UIDVALIDITY and UID are decimal representation of + * respectively uidvalidity and uid numbers. + * Return value: + * MAIL_ERROR_INVAL if uid is NULL or has an incorrect format. + * MAIL_ERROR_MSG_NOT_FOUND if uidvalidity has changed or uid was not found + * MAIL_NO_ERROR if message was found. Result is in result + */ +static int imapdriver_cached_get_message_by_uid(mailsession * session, + const char * uid, + mailmessage ** result) +{ + uint32_t uidvalidity; + uint32_t num; + char * p1, * p2; + mailimap *imap; + + if (uid == NULL) + return MAIL_ERROR_INVAL; + + uidvalidity = strtoul(uid, &p1, 10); + if (p1 == uid || * p1 != '-') + return MAIL_ERROR_INVAL; + + p1++; + num = strtoul(p1, &p2, 10); + if (p2 == p1 || * p2 != '\0') + return MAIL_ERROR_INVAL; + + imap = get_imap_session(session); + if (imap->imap_selection_info->sel_uidvalidity != uidvalidity) + return MAIL_ERROR_MSG_NOT_FOUND; + + return imapdriver_cached_get_message(session, num, result); +} diff --git a/libetpan/src/driver/implementation/imap/imapdriver_cached.h b/libetpan/src/driver/implementation/imap/imapdriver_cached.h new file mode 100644 index 0000000..c324f5e --- a/dev/null +++ b/libetpan/src/driver/implementation/imap/imapdriver_cached.h @@ -0,0 +1,52 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef IMAPDRIVER_CACHED_H + +#define IMAPDRIVER_CACHED_H + +#include <libetpan/imapdriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailsession_driver * imap_cached_session_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/imap/imapdriver_cached_message.c b/libetpan/src/driver/implementation/imap/imapdriver_cached_message.c new file mode 100644 index 0000000..34e1ca3 --- a/dev/null +++ b/libetpan/src/driver/implementation/imap/imapdriver_cached_message.c @@ -0,0 +1,664 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "imapdriver_cached_message.h" + +#include "imapdriver_tools.h" +#include "imapdriver_message.h" +#include "imapdriver_cached.h" +#include "imapdriver_types.h" +#include "imapdriver.h" +#include "mailmessage.h" +#include "generic_cache.h" +#include "mail_cache_db.h" + +#include <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:; +} + +static void generate_key_from_section(char * key, size_t size, + mailmessage * msg_info, + struct mailmime * mime, int type) +{ + char section_str[PATH_MAX]; + + generate_key_from_mime_section(section_str, PATH_MAX, mime); + + switch (type) { + case IMAP_SECTION_MESSAGE: + snprintf(key, size, "%s-%s", msg_info->msg_uid, section_str); + break; + case IMAP_SECTION_HEADER: + snprintf(key, size, "%s-%s-header", msg_info->msg_uid, section_str); + break; + case IMAP_SECTION_MIME: + snprintf(key, size, "%s-%s-mime", msg_info->msg_uid, section_str); + break; + case IMAP_SECTION_BODY: + snprintf(key, size, "%s-%s-text", msg_info->msg_uid, section_str); + break; + } +} + +static void generate_key_from_message(char * key, size_t size, + mailmessage * msg_info, + int type) +{ + switch (type) { + case MAILIMAP_MSG_ATT_RFC822: + snprintf(key, size, "%s-rfc822", msg_info->msg_uid); + break; + case MAILIMAP_MSG_ATT_RFC822_HEADER: + snprintf(key, size, "%s-rfc822-header", msg_info->msg_uid); + break; + case MAILIMAP_MSG_ATT_RFC822_TEXT: + snprintf(key, size, "%s-rfc822-text", msg_info->msg_uid); + break; + case MAILIMAP_MSG_ATT_ENVELOPE: + snprintf(key, size, "%s-envelope", msg_info->msg_uid); + break; + } +} + +static void build_cache_name(char * filename, size_t size, + mailmessage * msg, char * key) +{ + char * quoted_mb; + + quoted_mb = get_cached_session_data(msg)->imap_quoted_mb; + + snprintf(filename, size, "%s/%s", quoted_mb, key); +} + +static int imap_initialize(mailmessage * msg_info) +{ + mailmessage * ancestor; + int r; + char key[PATH_MAX]; + char * uid; + mailimap * imap; + + ancestor = mailmessage_new(); + if (ancestor == NULL) + return MAIL_ERROR_MEMORY; + + r = mailmessage_init(ancestor, get_ancestor_session(msg_info), + imap_message_driver, + msg_info->msg_index, 0); + if (r != MAIL_NO_ERROR) { + mailmessage_free(ancestor); + return r; + } + + imap = get_imap_session(msg_info); + + snprintf(key, PATH_MAX, "%u-%u", + imap->imap_selection_info->sel_uidvalidity, msg_info->msg_index); + uid = strdup(key); + if (uid == NULL) { + mailmessage_free(ancestor); + return MAIL_ERROR_MEMORY; + } + + msg_info->msg_data = ancestor; + msg_info->msg_uid = uid; + + return MAIL_NO_ERROR; +} + +static void imap_uninitialize(mailmessage * msg_info) +{ + mailmessage_free(get_ancestor(msg_info)); + msg_info->msg_data = NULL; +} + +static void imap_flush(mailmessage * msg_info) +{ + if (msg_info->msg_mime != NULL) { + mailmime_free(msg_info->msg_mime); + msg_info->msg_mime = NULL; + } +} + +static void imap_check(mailmessage * msg_info) +{ + get_ancestor(msg_info)->msg_flags = msg_info->msg_flags; + mailmessage_check(get_ancestor(msg_info)); + get_ancestor(msg_info)->msg_flags = NULL; +} + +static void imap_fetch_result_free(mailmessage * msg_info, + char * msg) +{ + mailmessage_fetch_result_free(get_ancestor(msg_info), msg); +} + +static int imap_fetch(mailmessage * msg_info, + char ** result, + size_t * result_len) +{ + char key[PATH_MAX]; + char filename[PATH_MAX]; + int r; + char * str; + size_t len; + + generate_key_from_message(key, PATH_MAX, + msg_info, MAILIMAP_MSG_ATT_RFC822); + + build_cache_name(filename, PATH_MAX, msg_info, key); + + r = generic_cache_read(filename, &str, &len); + if (r == MAIL_NO_ERROR) { + * result = str; + * result_len = len; + + return MAIL_NO_ERROR; + } + + r = mailmessage_fetch(get_ancestor(msg_info), + result, result_len); + if (r == MAIL_NO_ERROR) + generic_cache_store(filename, * result, strlen(* result)); + + return r; +} + +static int imap_fetch_header(mailmessage * msg_info, + char ** result, + size_t * result_len) +{ + char key[PATH_MAX]; + char filename[PATH_MAX]; + int r; + char * str; + size_t len; + + generate_key_from_message(key, PATH_MAX, + msg_info, MAILIMAP_MSG_ATT_RFC822_HEADER); + + build_cache_name(filename, PATH_MAX, msg_info, key); + + r = generic_cache_read(filename, &str, &len); + if (r == MAIL_NO_ERROR) { + * result = str; + * result_len = len; + + return MAIL_NO_ERROR; + } + + r = mailmessage_fetch_header(get_ancestor(msg_info), result, + result_len); + if (r == MAIL_NO_ERROR) + generic_cache_store(filename, * result, * result_len); + + return r; +} + +static int imap_fetch_body(mailmessage * msg_info, + char ** result, size_t * result_len) +{ + char key[PATH_MAX]; + char filename[PATH_MAX]; + int r; + char * str; + size_t len; + + generate_key_from_message(key, PATH_MAX, + msg_info, MAILIMAP_MSG_ATT_RFC822_TEXT); + + build_cache_name(filename, PATH_MAX, msg_info, key); + + r = generic_cache_read(filename, &str, &len); + if (r == MAIL_NO_ERROR) { + * result = str; + * result_len = len; + return MAIL_NO_ERROR; + } + + r = mailmessage_fetch_body(get_ancestor(msg_info), result, + result_len); + if (r == MAIL_NO_ERROR) + generic_cache_store(filename, * result, * result_len); + + return r; +} + +static int imap_fetch_size(mailmessage * msg_info, + size_t * result) +{ + return mailmessage_fetch_size(get_ancestor(msg_info), result); +} + +static int imap_get_bodystructure(mailmessage * msg_info, + struct mailmime ** result) +{ + int r; + + if (msg_info->msg_mime != NULL) { + * result = msg_info->msg_mime; + + return MAIL_NO_ERROR; + } + + r = mailmessage_get_bodystructure(get_ancestor(msg_info), + result); + if (r == MAIL_NO_ERROR) { + msg_info->msg_mime = get_ancestor(msg_info)->msg_mime; + get_ancestor(msg_info)->msg_mime = NULL; + } + + return r; +} + +static int imap_fetch_section(mailmessage * msg_info, + struct mailmime * mime, + char ** result, size_t * result_len) +{ + char key[PATH_MAX]; + char filename[PATH_MAX]; + int r; + char * str; + size_t len; + + generate_key_from_section(key, PATH_MAX, + msg_info, mime, IMAP_SECTION_MESSAGE); + + build_cache_name(filename, PATH_MAX, msg_info, key); + + r = generic_cache_read(filename, &str, &len); + if (r == MAIL_NO_ERROR) { + * result = str; + * result_len = len; + + return MAIL_NO_ERROR; + } + + r = mailmessage_fetch_section(get_ancestor(msg_info), + mime, result, result_len); + if (r == MAIL_NO_ERROR) + generic_cache_store(filename, * result, * result_len); + + return r; +} + +static int imap_fetch_section_header(mailmessage * msg_info, + struct mailmime * mime, + char ** result, + size_t * result_len) +{ + char key[PATH_MAX]; + char filename[PATH_MAX]; + int r; + char * str; + size_t len; + + generate_key_from_section(key, PATH_MAX, + msg_info, mime, IMAP_SECTION_HEADER); + + build_cache_name(filename, PATH_MAX, msg_info, key); + + r = generic_cache_read(filename, &str, &len); + if (r == MAIL_NO_ERROR) { + * result = str; + * result_len = len; + + return MAIL_NO_ERROR; + } + + r = mailmessage_fetch_section_header(get_ancestor(msg_info), + mime, result, result_len); + if (r == MAIL_NO_ERROR) + generic_cache_store(filename, * result, * result_len); + + return r; +} + +static int imap_fetch_section_mime(mailmessage * msg_info, + struct mailmime * mime, + char ** result, + size_t * result_len) +{ + char key[PATH_MAX]; + char filename[PATH_MAX]; + int r; + char * str; + size_t len; + + generate_key_from_section(key, PATH_MAX, + msg_info, mime, IMAP_SECTION_MIME); + + build_cache_name(filename, PATH_MAX, msg_info, key); + + r = generic_cache_read(filename, &str, &len); + if (r == MAIL_NO_ERROR) { + * result = str; + * result_len = len; + + return MAIL_NO_ERROR; + } + + r = mailmessage_fetch_section_mime(get_ancestor(msg_info), + mime, result, result_len); + if (r == MAIL_NO_ERROR) + generic_cache_store(filename, * result, * result_len); + + return r; +} + +static int imap_fetch_section_body(mailmessage * msg_info, + struct mailmime * mime, + char ** result, + size_t * result_len) +{ + char key[PATH_MAX]; + char filename[PATH_MAX]; + int r; + char * str; + size_t len; + + generate_key_from_section(key, PATH_MAX, + msg_info, mime, IMAP_SECTION_BODY); + + build_cache_name(filename, PATH_MAX, msg_info, key); + + r = generic_cache_read(filename, &str, &len); + if (r == MAIL_NO_ERROR) { + + * result = str; + * result_len = len; + + return MAIL_NO_ERROR; + } + + r = mailmessage_fetch_section_body(get_ancestor(msg_info), + mime, result, result_len); + if (r == MAIL_NO_ERROR) + generic_cache_store(filename, * result, * result_len); + + return r; +} + +static int imap_get_flags(mailmessage * msg_info, + struct mail_flags ** result) +{ + int r; + struct mail_flags * flags; + + if (msg_info->msg_flags != NULL) { + * result = msg_info->msg_flags; + return MAIL_NO_ERROR; + } + + r = mailmessage_get_flags(get_ancestor(msg_info), &flags); + if (r != MAIL_NO_ERROR) + return r; + + get_ancestor(msg_info)->msg_flags = NULL; + msg_info->msg_flags = flags; + * result = flags; + + return MAIL_NO_ERROR; +} + +#define ENV_NAME "env.db" + +static int imap_fetch_envelope(mailmessage * msg_info, + struct mailimf_fields ** result) +{ + struct mailimf_fields * fields; + int r; + struct mail_cache_db * cache_db; + MMAPString * mmapstr; + char filename[PATH_MAX]; + struct imap_cached_session_state_data * data; + int res; + + data = get_cached_session_data(msg_info); + if (data->imap_quoted_mb == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + snprintf(filename, PATH_MAX, "%s/%s", data->imap_quoted_mb, ENV_NAME); + + r = mail_cache_db_open_lock(filename, &cache_db); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto close_db; + } + + r = imapdriver_get_cached_envelope(cache_db, mmapstr, + msg_info->msg_session, msg_info, &fields); + + if ((r != MAIL_ERROR_CACHE_MISS) && (r != MAIL_NO_ERROR)) { + res = r; + goto close_db; + } + + r = mailmessage_fetch_envelope(get_ancestor(msg_info), &fields); + if (r != MAIL_NO_ERROR) { + res = r; + goto close_db; + } + + r = imapdriver_write_cached_envelope(cache_db, mmapstr, + msg_info->msg_session, msg_info, fields); + + * result = fields; + + mmap_string_free(mmapstr); + mail_cache_db_close_unlock(filename, cache_db); + + return MAIL_NO_ERROR; + + close_db: + mail_cache_db_close_unlock(filename, cache_db); + err: + return res; +} diff --git a/libetpan/src/driver/implementation/imap/imapdriver_cached_message.h b/libetpan/src/driver/implementation/imap/imapdriver_cached_message.h new file mode 100644 index 0000000..bf43311 --- a/dev/null +++ b/libetpan/src/driver/implementation/imap/imapdriver_cached_message.h @@ -0,0 +1,52 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef IMAPDRIVER_CACHED_MESSAGE_H + +#define IMAPDRIVER_CACHED_MESSAGE_H + +#include <libetpan/imapdriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailmessage_driver * imap_cached_message_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/imap/imapdriver_message.c b/libetpan/src/driver/implementation/imap/imapdriver_message.c new file mode 100644 index 0000000..42e645d --- a/dev/null +++ b/libetpan/src/driver/implementation/imap/imapdriver_message.c @@ -0,0 +1,1239 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "imapdriver_message.h" + +#include "imapdriver_tools.h" +#include "imapdriver.h" +#include "imapdriver_types.h" +#include "mailimap.h" +#include "maildriver_tools.h" +#include "generic_cache.h" + +#include <stdlib.h> +#include <string.h> + +static int imap_initialize(mailmessage * msg_info); + +static void imap_fetch_result_free(mailmessage * msg_info, + char * msg); + +static int imap_fetch(mailmessage * msg_info, + char ** result, + size_t * result_len); + +static int imap_fetch_header(mailmessage * msg_info, + char ** result, + size_t * result_len); + +static int imap_fetch_body(mailmessage * msg_info, + char ** result, size_t * result_len); + +static int imap_fetch_size(mailmessage * msg_info, + size_t * result); + +static int imap_get_bodystructure(mailmessage * msg_info, + struct mailmime ** result); + +static int imap_fetch_section(mailmessage * msg_info, + struct mailmime * mime, + char ** result, size_t * result_len); + +static int imap_fetch_section_header(mailmessage * msg_info, + struct mailmime * mime, + char ** result, + size_t * result_len); + +static int imap_fetch_section_mime(mailmessage * msg_info, + struct mailmime * mime, + char ** result, + size_t * result_len); + +static int imap_fetch_section_body(mailmessage * msg_info, + struct mailmime * mime, + char ** result, + size_t * result_len); + +static int imap_fetch_envelope(mailmessage * msg_info, + struct mailimf_fields ** result); + +static int imap_get_flags(mailmessage * msg_info, + struct mail_flags ** result); + +static void imap_flush(mailmessage * msg_info); + +static void imap_check(mailmessage * msg_info); + +static mailmessage_driver local_imap_message_driver = { + .msg_name = "imap", + + .msg_initialize = imap_initialize, + .msg_uninitialize = NULL, + + .msg_flush = imap_flush, + .msg_check = imap_check, + + .msg_fetch_result_free = imap_fetch_result_free, + + .msg_fetch = imap_fetch, + .msg_fetch_header = imap_fetch_header, + .msg_fetch_body = imap_fetch_body, + .msg_fetch_size = imap_fetch_size, + .msg_get_bodystructure = imap_get_bodystructure, + .msg_fetch_section = imap_fetch_section, + .msg_fetch_section_header = imap_fetch_section_header, + .msg_fetch_section_mime = imap_fetch_section_mime, + .msg_fetch_section_body = imap_fetch_section_body, + .msg_fetch_envelope = imap_fetch_envelope, + + .msg_get_flags = imap_get_flags, +}; + +mailmessage_driver * imap_message_driver = &local_imap_message_driver; + +static inline struct imap_session_state_data * +get_session_data(mailmessage * msg) +{ + return msg->msg_session->sess_data; +} + +static inline mailimap * get_imap_session(mailmessage * msg) +{ + return get_session_data(msg)->imap_session; +} + + + +static int imap_initialize(mailmessage * msg_info) +{ + char key[PATH_MAX]; + char * uid; + mailimap * imap; + + imap = get_imap_session(msg_info); + + snprintf(key, PATH_MAX, "%u-%u", + imap->imap_selection_info->sel_uidvalidity, msg_info->msg_index); + + uid = strdup(key); + if (uid == NULL) { + return MAIL_ERROR_MEMORY; + } + + msg_info->msg_uid = uid; + + return MAIL_NO_ERROR; +} + + +static void imap_fetch_result_free(mailmessage * msg_info, + char * msg) +{ + if (msg != NULL) { + if (mmap_string_unref(msg) != 0) + free(msg); + } +} + + +static void imap_flush(mailmessage * msg_info) +{ + if (msg_info->msg_mime != NULL) { + mailmime_free(msg_info->msg_mime); + msg_info->msg_mime = NULL; + } +} + +static void imap_check(mailmessage * msg_info) +{ + int r; + + if (msg_info->msg_flags != NULL) { + r = mail_flags_store_set(get_session_data(msg_info)->imap_flags_store, + msg_info); + /* ignore errors */ + } +} + +static int imap_fetch(mailmessage * msg_info, + char ** result, + size_t * result_len) +{ + int r; + struct mailimap_set * set; + struct mailimap_fetch_att * fetch_att; + struct mailimap_fetch_type * fetch_type; + clist * fetch_result; + struct mailimap_msg_att * msg_att; + struct mailimap_msg_att_item * msg_att_item; + char * text; + size_t text_length; + int res; + clistiter * cur; + struct mailimap_section * section; + + set = mailimap_set_new_single(msg_info->msg_index); + if (set == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + +#if 0 + fetch_att = mailimap_fetch_att_new_rfc822(); + if (fetch_att == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_set; + } + + fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att); + if (fetch_type == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_att; + } + + r = mailimap_uid_fetch(get_imap_session(msg_info->session), set, + fetch_type, &fetch_result); + + mailimap_fetch_type_free(fetch_type); +#endif + + section = mailimap_section_new(NULL); + if (section == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_set; + } + + fetch_att = mailimap_fetch_att_new_body_peek_section(section); + if (fetch_att == NULL) { + mailimap_section_free(section); + res = MAIL_ERROR_MEMORY; + goto free_set; + } + + fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att); + if (fetch_type == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_att; + } + + r = mailimap_uid_fetch(get_imap_session(msg_info), set, + fetch_type, &fetch_result); + + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); + + switch (r) { + case MAILIMAP_NO_ERROR: + break; + default: + return imap_error_to_mail_error(r); + } + + if (clist_begin(fetch_result) == NULL) { + mailimap_fetch_list_free(fetch_result); + return MAIL_ERROR_FETCH; + } + + msg_att = clist_begin(fetch_result)->data; + + text = NULL; + text_length = 0; + + for(cur = clist_begin(msg_att->att_list) ; cur != NULL ; + cur = clist_next(cur)) { + msg_att_item = clist_content(cur); + + if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) { +#if 0 + if (msg_att_item->msg_att_static->type == MAILIMAP_MSG_ATT_RFC822) { + text = msg_att_item->msg_att_static->rfc822; + msg_att_item->msg_att_static->rfc822 = NULL; + text_length = msg_att_item->msg_att_static->length; + } +#endif + if (msg_att_item->att_data.att_static->att_type == + MAILIMAP_MSG_ATT_BODY_SECTION) { + text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part; + /* detach */ + msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL; + text_length = + msg_att_item->att_data.att_static->att_data.att_body_section->sec_length; + } + } + } + + mailimap_fetch_list_free(fetch_result); + + if (text == NULL) + return MAIL_ERROR_FETCH; + + * result = text; + * result_len = text_length; + + return MAIL_NO_ERROR; + + free_fetch_att: + mailimap_fetch_att_free(fetch_att); + free_set: + mailimap_set_free(set); + err: + return res; +} + +static int imap_fetch_header(mailmessage * msg_info, + char ** result, + size_t * result_len) +{ + int r; + struct mailimap_set * set; + struct mailimap_fetch_att * fetch_att; + struct mailimap_fetch_type * fetch_type; + clist * fetch_result; + struct mailimap_msg_att * msg_att; + struct mailimap_msg_att_item * msg_att_item; + char * text; + size_t text_length; + int res; + clistiter * cur; + struct mailimap_section * section; + + set = mailimap_set_new_single(msg_info->msg_index); + if (set == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + +#if 0 + fetch_att = mailimap_fetch_att_new_rfc822_header(); + if (fetch_att == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_set; + } + + fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att); + if (fetch_type == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_att; + } + + r = mailimap_uid_fetch(get_imap_session(msg_info->session), + set, fetch_type, &fetch_result); + + mailimap_fetch_type_free(fetch_type); +#endif + + section = mailimap_section_new_header(); + if (section == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_set; + } + + fetch_att = mailimap_fetch_att_new_body_peek_section(section); + if (fetch_att == NULL) { + mailimap_section_free(section); + res = MAIL_ERROR_MEMORY; + goto free_set; + } + + fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att); + if (fetch_type == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_att; + } + + r = mailimap_uid_fetch(get_imap_session(msg_info), set, + fetch_type, &fetch_result); + + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); + + switch (r) { + case MAILIMAP_NO_ERROR: + break; + default: + return imap_error_to_mail_error(r); + } + + if (clist_begin(fetch_result) == NULL) { + mailimap_fetch_list_free(fetch_result); + return MAIL_ERROR_FETCH; + } + + msg_att = clist_begin(fetch_result)->data; + + text = NULL; + text_length = 0; + + for(cur = clist_begin(msg_att->att_list) ; cur != NULL ; + cur = clist_next(cur)) { + msg_att_item = clist_content(cur); + + if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) { +#if 0 + if (msg_att_item->msg_att_static->type == + MAILIMAP_MSG_ATT_RFC822_HEADER) { + text = msg_att_item->msg_att_static->rfc822_header; + msg_att_item->msg_att_static->rfc822_header = NULL; + text_length = msg_att_item->msg_att_static->length; + } +#endif + if (msg_att_item->att_data.att_static->att_type == + MAILIMAP_MSG_ATT_BODY_SECTION) { + text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part; + msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL; + text_length = + msg_att_item->att_data.att_static->att_data.att_body_section->sec_length; + } + } + } + + mailimap_fetch_list_free(fetch_result); + + if (text == NULL) + return MAIL_ERROR_FETCH; + + * result = text; + * result_len = text_length; + + return MAIL_NO_ERROR; + + free_fetch_att: + mailimap_fetch_att_free(fetch_att); + free_set: + mailimap_set_free(set); + err: + return res; +} + +static int imap_fetch_body(mailmessage * msg_info, + char ** result, size_t * result_len) +{ + int r; + struct mailimap_set * set; + struct mailimap_fetch_att * fetch_att; + struct mailimap_fetch_type * fetch_type; + clist * fetch_result; + struct mailimap_msg_att * msg_att; + struct mailimap_msg_att_item * msg_att_item; + char * text; + size_t text_length; + int res; + clistiter * cur; + struct mailimap_section * section; + + set = mailimap_set_new_single(msg_info->msg_index); + if (set == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + +#if 0 + fetch_att = mailimap_fetch_att_new_rfc822_text(); + if (fetch_att == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_set; + } + + fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att); + if (fetch_type == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_att; + } + + r = mailimap_uid_fetch(get_imap_session(msg_info->session), set, + fetch_type, &fetch_result); + + mailimap_fetch_type_free(fetch_type); +#endif + section = mailimap_section_new_text(); + if (section == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_set; + } + + fetch_att = mailimap_fetch_att_new_body_peek_section(section); + if (fetch_att == NULL) { + mailimap_section_free(section); + res = MAIL_ERROR_MEMORY; + goto free_set; + } + + fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att); + if (fetch_type == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_att; + } + + r = mailimap_uid_fetch(get_imap_session(msg_info), set, + fetch_type, &fetch_result); + + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); + + switch (r) { + case MAILIMAP_NO_ERROR: + break; + default: + return imap_error_to_mail_error(r); + } + + cur = clist_begin(fetch_result); + if (cur == NULL) { + mailimap_fetch_list_free(fetch_result); + return MAIL_ERROR_FETCH; + } + + msg_att = clist_content(cur); + + text = NULL; + text_length = 0; + + for(cur = clist_begin(msg_att->att_list) ; cur != NULL ; + cur = clist_next(cur)) { + msg_att_item = clist_content(cur); + + if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) { +#if 0 + if (msg_att_item->msg_att_static->type == + MAILIMAP_MSG_ATT_RFC822_TEXT) { + text = msg_att_item->msg_att_static->rfc822_text; + msg_att_item->msg_att_static->rfc822_text = NULL; + text_length = msg_att_item->msg_att_static->length; + } +#endif + if (msg_att_item->att_data.att_static->att_type == + MAILIMAP_MSG_ATT_BODY_SECTION) { + text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part; + msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL; + text_length = + msg_att_item->att_data.att_static->att_data.att_body_section->sec_length; + } + } + } + + mailimap_fetch_list_free(fetch_result); + + if (text == NULL) + return MAIL_ERROR_FETCH; + + * result = text; + * result_len = text_length; + + return MAIL_NO_ERROR; + + free_fetch_att: + mailimap_fetch_att_free(fetch_att); + free_set: + mailimap_set_free(set); + err: + return res; +} + +static int imap_fetch_size(mailmessage * msg_info, + size_t * result) +{ + int r; + struct mailimap_set * set; + struct mailimap_fetch_att * fetch_att; + struct mailimap_fetch_type * fetch_type; + clist * fetch_result; + struct mailimap_msg_att * msg_att; + struct mailimap_msg_att_item * msg_att_item; + size_t size; + int res; + clistiter * cur; + + set = mailimap_set_new_single(msg_info->msg_index); + if (set == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + fetch_att = mailimap_fetch_att_new_rfc822_size(); + if (fetch_att == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_set; + } + + fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att); + if (fetch_type == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_att; + } + + r = mailimap_uid_fetch(get_imap_session(msg_info), set, + fetch_type, &fetch_result); + + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); + + switch (r) { + case MAILIMAP_ERROR_BAD_STATE: + return MAIL_ERROR_BAD_STATE; + case MAILIMAP_ERROR_STREAM: + return MAIL_ERROR_STREAM; + case MAILIMAP_NO_ERROR: + break; + default: + return MAIL_ERROR_FETCH; + } + + if (clist_begin(fetch_result) == NULL) { + mailimap_fetch_list_free(fetch_result); + return MAIL_ERROR_FETCH; + } + + msg_att = clist_begin(fetch_result)->data; + + for(cur = clist_begin(msg_att->att_list) ; cur != NULL ; + cur = clist_next(cur)) { + msg_att_item = clist_content(cur); + + if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) { + + if (msg_att_item->att_data.att_static->att_type == + MAILIMAP_MSG_ATT_RFC822_SIZE) { + size = msg_att_item->att_data.att_static->att_data.att_rfc822_size; + + * result = size; + + mailimap_fetch_list_free(fetch_result); + return MAIL_NO_ERROR; + } + } + } + + mailimap_fetch_list_free(fetch_result); + + return MAIL_ERROR_FETCH; + + free_fetch_att: + mailimap_fetch_att_free(fetch_att); + free_set: + mailimap_set_free(set); + err: + return res; +} + +static int imap_get_bodystructure(mailmessage * msg_info, + struct mailmime ** result) +{ + int r; + struct mailimap_set * set; + struct mailimap_fetch_att * fetch_att; + struct mailimap_fetch_type * fetch_type; + clist * fetch_result; + struct mailimap_msg_att * msg_att; + struct mailimap_body * imap_body; + struct mailmime * body; + int res; + struct mailimf_fields * fields; + struct mailmime * new_body; + struct mailmime_content * content_message; + struct mailimap_envelope * envelope; + uint32_t uid; + char * references; + size_t ref_size; + clistiter * cur; + + if (msg_info->msg_mime != NULL) { + * result = msg_info->msg_mime; + + return MAIL_NO_ERROR; + } + + set = mailimap_set_new_single(msg_info->msg_index); + if (set == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + fetch_type = mailimap_fetch_type_new_fetch_att_list_empty(); + if (fetch_type == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_set; + } + + fetch_att = mailimap_fetch_att_new_uid(); + if (fetch_att == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_type; + } + + r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); + if (r != MAILIMAP_NO_ERROR) { + mailimap_fetch_att_free(fetch_att); + res = MAIL_ERROR_MEMORY; + goto free_fetch_type; + } + + fetch_att = mailimap_fetch_att_new_bodystructure(); + if (fetch_att == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_type; + } + + r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); + if (r != MAILIMAP_NO_ERROR) { + mailimap_fetch_att_free(fetch_att); + res = MAIL_ERROR_MEMORY; + goto free_fetch_type; + } + + r = imap_add_envelope_fetch_att(fetch_type); + if (r != MAIL_NO_ERROR) { + res = r; + goto free_fetch_type; + } + + + r = mailimap_uid_fetch(get_imap_session(msg_info), set, + fetch_type, &fetch_result); + + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); + + switch (r) { + case MAILIMAP_NO_ERROR: + break; + default: + return imap_error_to_mail_error(r); + } + + cur = clist_begin(fetch_result); + if (cur == NULL) { + mailimap_fetch_list_free(fetch_result); + return MAIL_ERROR_FETCH; + } + + msg_att = clist_content(cur); + + uid = 0; + references = NULL; + ref_size = 0; + imap_body = NULL; + envelope = NULL; + + r = imap_get_msg_att_info(msg_att, + &uid, &envelope, &references, &ref_size, NULL, &imap_body); + if (r != MAIL_NO_ERROR) { + mailimap_fetch_list_free(fetch_result); + res = r; + goto err; + } + + if (uid != msg_info->msg_index) { + mailimap_fetch_list_free(fetch_result); + res = MAIL_ERROR_MSG_NOT_FOUND; + goto err; + } + + if (imap_body == NULL) { + mailimap_fetch_list_free(fetch_result); + res = MAIL_ERROR_FETCH; + goto err; + } + + r = imap_body_to_body(imap_body, &body); + if (r != MAIL_NO_ERROR) { + mailimap_fetch_list_free(fetch_result); + res = r; + goto err; + } + + fields = NULL; + if (envelope != NULL) { + r = imap_env_to_fields(envelope, references, ref_size, &fields); + if (r != MAIL_NO_ERROR) { + mailmime_free(body); + mailimap_fetch_list_free(fetch_result); + res = r; + goto err; + } + } + + content_message = mailmime_get_content_message(); + if (content_message == NULL) { + if (fields != NULL) + mailimf_fields_free(fields); + mailmime_free(body); + mailimap_fetch_list_free(fetch_result); + res = MAIL_ERROR_MEMORY; + goto err; + } + + new_body = mailmime_new(MAILMIME_MESSAGE, NULL, + 0, NULL, content_message, + NULL, NULL, NULL, NULL, fields, body); + + if (new_body == NULL) { + mailmime_content_free(content_message); + if (fields != NULL) + mailimf_fields_free(fields); + mailmime_free(body); + mailimap_fetch_list_free(fetch_result); + res = MAIL_ERROR_MEMORY; + goto err; + } + msg_info->msg_mime = new_body; + + mailimap_fetch_list_free(fetch_result); + + * result = new_body; + + return MAIL_NO_ERROR; + + free_fetch_type: + mailimap_fetch_type_free(fetch_type); + free_set: + mailimap_set_free(set); + err: + return res; +} + +static int +fetch_imap(mailmessage * msg, + struct mailimap_fetch_type * fetch_type, + char ** result, size_t * result_len) +{ + int r; + struct mailimap_msg_att * msg_att; + struct mailimap_msg_att_item * msg_att_item; + clist * fetch_result; + struct mailimap_set * set; + char * text; + size_t text_length; + clistiter * cur; + + set = mailimap_set_new_single(msg->msg_index); + if (set == NULL) + return MAIL_ERROR_MEMORY; + + r = mailimap_uid_fetch(get_imap_session(msg), set, + fetch_type, &fetch_result); + + mailimap_set_free(set); + + switch (r) { + case MAILIMAP_NO_ERROR: + break; + default: + return imap_error_to_mail_error(r); + } + + if (clist_begin(fetch_result) == NULL) { + mailimap_fetch_list_free(fetch_result); + return MAIL_ERROR_FETCH; + } + + msg_att = clist_begin(fetch_result)->data; + + text = NULL; + text_length = 0; + + for(cur = clist_begin(msg_att->att_list) ; cur != NULL ; + cur = clist_next(cur)) { + msg_att_item = clist_content(cur); + + if (msg_att_item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) { + + if (msg_att_item->att_data.att_static->att_type == + MAILIMAP_MSG_ATT_BODY_SECTION) { + text = msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part; + msg_att_item->att_data.att_static->att_data.att_body_section->sec_body_part = NULL; + text_length = + msg_att_item->att_data.att_static->att_data.att_body_section->sec_length; + } + } + } + + mailimap_fetch_list_free(fetch_result); + + if (text == NULL) + return MAIL_ERROR_FETCH; + + * result = text; + * result_len = text_length; + + return MAIL_NO_ERROR; +} + + +static int imap_fetch_section(mailmessage * msg_info, + struct mailmime * mime, + char ** result, size_t * result_len) +{ + struct mailimap_section * section; + struct mailimap_fetch_att * fetch_att; + int r; + struct mailimap_fetch_type * fetch_type; + char * text; + size_t text_length; + struct mailmime_section * part; + + if (mime->mm_parent == NULL) + return imap_fetch(msg_info, result, result_len); + + r = mailmime_get_section_id(mime, &part); + if (r != MAILIMF_NO_ERROR) + return maildriver_imf_error_to_mail_error(r); + + r = section_to_imap_section(part, IMAP_SECTION_MESSAGE, §ion); + mailmime_section_free(part); + if (r != MAIL_NO_ERROR) + return r; + + fetch_att = mailimap_fetch_att_new_body_peek_section(section); + if (fetch_att == NULL) { + mailimap_section_free(section); + return MAIL_ERROR_MEMORY; + } + + fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att); + if (fetch_type == NULL) { + mailimap_fetch_att_free(fetch_att); + return MAIL_ERROR_MEMORY; + } + + r = fetch_imap(msg_info, fetch_type, &text, &text_length); + + mailimap_fetch_type_free(fetch_type); + + if (r != MAIL_NO_ERROR) + return r; + + * result = text; + * result_len = text_length; + + return MAIL_NO_ERROR; +} + +static int imap_fetch_section_header(mailmessage * msg_info, + struct mailmime * mime, + char ** result, + size_t * result_len) +{ + struct mailimap_section * section; + struct mailimap_fetch_att * fetch_att; + int r; + struct mailimap_fetch_type * fetch_type; + char * text; + size_t text_length; + struct mailmime_section * part; + + if (mime->mm_parent == NULL) + return imap_fetch_header(msg_info, result, result_len); + + r = mailmime_get_section_id(mime, &part); + if (r != MAILIMF_NO_ERROR) + return maildriver_imf_error_to_mail_error(r); + + r = section_to_imap_section(part, IMAP_SECTION_HEADER, §ion); + mailmime_section_free(part); + if (r != MAIL_NO_ERROR) + return r; + + fetch_att = mailimap_fetch_att_new_body_peek_section(section); + if (fetch_att == NULL) { + mailimap_section_free(section); + return MAIL_ERROR_MEMORY; + } + + fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att); + if (fetch_type == NULL) { + mailimap_fetch_att_free(fetch_att); + return MAIL_ERROR_MEMORY; + } + + r = fetch_imap(msg_info, fetch_type, &text, &text_length); + mailimap_fetch_type_free(fetch_type); + + if (r != MAIL_NO_ERROR) + return r; + + * result = text; + * result_len = text_length; + + return MAIL_NO_ERROR; +} + +static int imap_fetch_section_mime(mailmessage * msg_info, + struct mailmime * mime, + char ** result, + size_t * result_len) +{ + struct mailimap_section * section; + struct mailimap_fetch_att * fetch_att; + int r; + struct mailimap_fetch_type * fetch_type; + char * text; + size_t text_length; + struct mailmime_section * part; + + if (mime->mm_parent == NULL) + return MAIL_ERROR_INVAL; + + if (mime->mm_parent->mm_parent == NULL) + return imap_fetch_header(msg_info, result, result_len); + + r = mailmime_get_section_id(mime, &part); + if (r != MAILIMF_NO_ERROR) + return maildriver_imf_error_to_mail_error(r); + + r = section_to_imap_section(part, IMAP_SECTION_MIME, §ion); + mailmime_section_free(part); + if (r != MAIL_NO_ERROR) + return MAIL_ERROR_MEMORY; + + fetch_att = mailimap_fetch_att_new_body_peek_section(section); + if (fetch_att == NULL) { + mailimap_section_free(section); + return MAIL_ERROR_MEMORY; + } + + fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att); + if (fetch_type == NULL) { + mailimap_fetch_att_free(fetch_att); + return MAIL_ERROR_MEMORY; + } + + r = fetch_imap(msg_info, fetch_type, &text, &text_length); + + mailimap_fetch_type_free(fetch_type); + + if (r != MAIL_NO_ERROR) + return r; + + * result = text; + * result_len = text_length; + + return MAIL_NO_ERROR; +} + +static int imap_fetch_section_body(mailmessage * msg_info, + struct mailmime * mime, + char ** result, + size_t * result_len) +{ + struct mailimap_section * section; + struct mailimap_fetch_att * fetch_att; + int r; + struct mailimap_fetch_type * fetch_type; + char * text; + size_t text_length; + struct mailmime_section * part; + + if (mime->mm_parent == NULL) + return imap_fetch_body(msg_info, result, result_len); + + if (mime->mm_parent->mm_parent == NULL) + return imap_fetch_body(msg_info, result, result_len); + + r = mailmime_get_section_id(mime, &part); + if (r != MAILIMF_NO_ERROR) + return maildriver_imf_error_to_mail_error(r); + + r = section_to_imap_section(part, IMAP_SECTION_BODY, §ion); + mailmime_section_free(part); + if (r != MAIL_NO_ERROR) + return MAIL_ERROR_MEMORY; + + fetch_att = mailimap_fetch_att_new_body_peek_section(section); + if (fetch_att == NULL) { + mailimap_section_free(section); + return MAIL_ERROR_MEMORY; + } + + fetch_type = mailimap_fetch_type_new_fetch_att(fetch_att); + if (fetch_type == NULL) { + mailimap_fetch_att_free(fetch_att); + return MAIL_ERROR_MEMORY; + } + + r = fetch_imap(msg_info, fetch_type, &text, &text_length); + + mailimap_fetch_type_free(fetch_type); + + if (r != MAIL_NO_ERROR) + return r; + + * result = text; + * result_len = text_length; + + return MAIL_NO_ERROR; +} + +static int imap_get_flags(mailmessage * msg_info, + struct mail_flags ** result) +{ + int r; + struct mail_flags * flags; + + if (msg_info->msg_flags != NULL) { + * result = msg_info->msg_flags; + return MAIL_NO_ERROR; + } + + flags = mail_flags_store_get(get_session_data(msg_info)->imap_flags_store, + msg_info->msg_index); + + if (flags == NULL) { + r = imap_fetch_flags(get_imap_session(msg_info), + msg_info->msg_index, &flags); + if (r != MAIL_NO_ERROR) + return r; + } + + msg_info->msg_flags = flags; + + * result = flags; + + return MAIL_NO_ERROR; +} + +static int imap_fetch_envelope(mailmessage * msg_info, + struct mailimf_fields ** result) +{ + int r; + struct mailimap_set * set; + struct mailimap_fetch_att * fetch_att; + struct mailimap_fetch_type * fetch_type; + clist * fetch_result; + struct mailimap_msg_att * msg_att; + int res; + struct mailimf_fields * fields; + struct mailimap_envelope * envelope; + uint32_t uid; + char * references; + size_t ref_size; + + set = mailimap_set_new_single(msg_info->msg_index); + if (set == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + fetch_type = mailimap_fetch_type_new_fetch_att_list_empty(); + if (fetch_type == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_set; + } + + fetch_att = mailimap_fetch_att_new_uid(); + if (fetch_att == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_type; + } + + r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); + if (r != MAILIMAP_NO_ERROR) { + mailimap_fetch_att_free(fetch_att); + res = MAIL_ERROR_MEMORY; + goto free_fetch_type; + } + + r = imap_add_envelope_fetch_att(fetch_type); + if (r != MAIL_NO_ERROR) { + res = r; + goto free_fetch_type; + } + + r = mailimap_uid_fetch(get_imap_session(msg_info), set, + fetch_type, &fetch_result); + + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); + + switch (r) { + case MAILIMAP_NO_ERROR: + break; + default: + return imap_error_to_mail_error(r); + } + + if (clist_begin(fetch_result) == NULL) { + mailimap_fetch_list_free(fetch_result); + return MAIL_ERROR_FETCH; + } + + msg_att = clist_begin(fetch_result)->data; + + uid = 0; + references = NULL; + ref_size = 0; + envelope = NULL; + + r = imap_get_msg_att_info(msg_att, + &uid, + &envelope, + &references, + &ref_size, + NULL, + NULL); + if (r != MAIL_NO_ERROR) { + mailimap_fetch_list_free(fetch_result); + res = r; + goto err; + } + + if (uid != msg_info->msg_index) { + mailimap_fetch_list_free(fetch_result); + res = MAIL_ERROR_MSG_NOT_FOUND; + goto err; + } + + fields = NULL; + if (envelope != NULL) { + r = imap_env_to_fields(envelope, references, ref_size, &fields); + if (r != MAIL_NO_ERROR) { + mailimap_fetch_list_free(fetch_result); + res = r; + goto err; + } + } + + mailimap_fetch_list_free(fetch_result); + + * result = fields; + + return MAIL_NO_ERROR; + + free_fetch_type: + mailimap_fetch_type_free(fetch_type); + free_set: + mailimap_set_free(set); + err: + return res; +} diff --git a/libetpan/src/driver/implementation/imap/imapdriver_message.h b/libetpan/src/driver/implementation/imap/imapdriver_message.h new file mode 100644 index 0000000..74fc2e6 --- a/dev/null +++ b/libetpan/src/driver/implementation/imap/imapdriver_message.h @@ -0,0 +1,52 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef IMAPDRIVER_MESSAGE_H + +#define IMAPDRIVER_MESSAGE_H + +#include <libetpan/imapdriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailmessage_driver * imap_message_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/imap/imapdriver_tools.c b/libetpan/src/driver/implementation/imap/imapdriver_tools.c new file mode 100644 index 0000000..6051281 --- a/dev/null +++ b/libetpan/src/driver/implementation/imap/imapdriver_tools.c @@ -0,0 +1,3623 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "imapdriver_tools.h" + +#include "maildriver.h" + +#include <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; +} + +int imap_flags_to_imap_flags(struct mail_flags * flags, + struct mailimap_flag_list ** result) +{ + struct mailimap_flag * flag; + struct mailimap_flag_list * flag_list; + int res; + clistiter * cur; + int r; + + flag_list = mailimap_flag_list_new_empty(); + if (flag_list == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + if ((flags->fl_flags & MAIL_FLAG_DELETED) != 0) { + flag = mailimap_flag_new_deleted(); + if (flag == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_flag_list; + } + r = mailimap_flag_list_add(flag_list, flag); + if (r != MAILIMAP_NO_ERROR) { + mailimap_flag_free(flag); + res = MAIL_ERROR_MEMORY; + goto free_flag_list; + } + } + + if ((flags->fl_flags & MAIL_FLAG_FLAGGED) != 0) { + flag = mailimap_flag_new_flagged(); + if (flag == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_flag_list; + } + r = mailimap_flag_list_add(flag_list, flag); + if (r != MAILIMAP_NO_ERROR) { + mailimap_flag_free(flag); + res = MAIL_ERROR_MEMORY; + goto free_flag_list; + } + } + + if ((flags->fl_flags & MAIL_FLAG_SEEN) != 0) { + flag = mailimap_flag_new_seen(); + if (flag == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_flag_list; + } + r = mailimap_flag_list_add(flag_list, flag); + if (r != MAILIMAP_NO_ERROR) { + res = MAIL_ERROR_MEMORY; + goto free_flag_list; + } + } + + if ((flags->fl_flags & MAIL_FLAG_ANSWERED) != 0) { + flag = mailimap_flag_new_answered(); + if (flag == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_flag_list; + } + r = mailimap_flag_list_add(flag_list, flag); + if (r != MAILIMAP_NO_ERROR) { + mailimap_flag_free(flag); + res = MAIL_ERROR_MEMORY; + goto free_flag_list; + } + } + + if ((flags->fl_flags & MAIL_FLAG_FORWARDED) != 0) { + char * flag_str; + + flag_str = strdup("$Forwarded"); + if (flag_str == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_flag_list; + } + flag = mailimap_flag_new_flag_keyword(flag_str); + if (flag == NULL) { + free(flag_str); + res = MAIL_ERROR_MEMORY; + goto free_flag_list; + } + r = mailimap_flag_list_add(flag_list, flag); + if (r != MAILIMAP_NO_ERROR) { + mailimap_flag_free(flag); + res = MAIL_ERROR_MEMORY; + goto free_flag_list; + } + } + + for(cur = clist_begin(flags->fl_extension) ; cur != NULL ; + cur = clist_next(cur)) { + char * flag_str; + + flag_str = clist_content(cur); + + if (strcasecmp(flag_str, "Draft") == 0) { + flag = mailimap_flag_new_draft(); + if (flag == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_flag_list; + } + r = mailimap_flag_list_add(flag_list, flag); + if (r != MAILIMAP_NO_ERROR) { + mailimap_flag_free(flag); + res = MAIL_ERROR_MEMORY; + goto free_flag_list; + } + } + else { + flag_str = strdup(flag_str); + if (flag_str == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_flag_list; + } + flag = mailimap_flag_new_flag_keyword(flag_str); + if (flag == NULL) { + free(flag_str); + res = MAIL_ERROR_MEMORY; + goto free_flag_list; + } + r = mailimap_flag_list_add(flag_list, flag); + if (r != MAILIMAP_NO_ERROR) { + mailimap_flag_free(flag); + res = MAIL_ERROR_MEMORY; + goto free_flag_list; + } + } + } + + * result = flag_list; + + return MAIL_NO_ERROR; + + free_flag_list: + mailimap_flag_list_free(flag_list); + err: + return res; +} + +static int flags_to_imap_flags(struct mail_flags * flags, + struct mailimap_store_att_flags ** result) +{ + struct mailimap_flag_list * flag_list; + struct mailimap_store_att_flags * att_flags; + int res; + int r; + + r = imap_flags_to_imap_flags(flags, + &flag_list); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + att_flags = mailimap_store_att_flags_new_set_flags_silent(flag_list); + if (att_flags == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_flag_list; + } + + * result = att_flags; + + return MAIL_NO_ERROR; + + free_flag_list: + mailimap_flag_list_free(flag_list); + err: + return res; +} + + +static int +imap_fetch_result_to_flags(clist * fetch_result, uint32_t index, + struct mail_flags ** result) +{ + clistiter * cur; + int r; + + for(cur = clist_begin(fetch_result) ; cur != NULL ; + cur = clist_next(cur)) { + struct mailimap_msg_att * msg_att; + clistiter * item_cur; + uint32_t uid; + struct mailimap_msg_att_dynamic * att_dyn; + + msg_att = clist_content(cur); + + uid = 0; + att_dyn = NULL; + + for(item_cur = clist_begin(msg_att->att_list) ; item_cur != NULL ; + item_cur = clist_next(item_cur)) { + struct mailimap_msg_att_item * item; + + item = clist_content(item_cur); + + if (item->att_type == MAILIMAP_MSG_ATT_ITEM_STATIC) { + switch (item->att_data.att_static->att_type) { + case MAILIMAP_MSG_ATT_UID: + uid = item->att_data.att_static->att_data.att_uid; + break; + } + } + else if (item->att_type == MAILIMAP_MSG_ATT_ITEM_DYNAMIC) { + if (att_dyn == NULL) { + att_dyn = item->att_data.att_dyn; + } + } + } + + if (uid != 0) { + if (uid == index) { + struct mail_flags * flags; + + if (att_dyn != NULL) { + r = imap_flags_to_flags(att_dyn, &flags); + + if (r == MAIL_NO_ERROR) { + * result = flags; + return MAIL_NO_ERROR; + } + } + } + } + } + + return MAIL_ERROR_MSG_NOT_FOUND; +} + + +int imap_fetch_flags(mailimap * imap, + uint32_t index, struct mail_flags ** result) +{ + struct mailimap_fetch_att * fetch_att; + struct mailimap_fetch_type * fetch_type; + struct mailimap_set * set; + int r; + int res; + clist * fetch_result; + struct mail_flags * flags; + + fetch_type = mailimap_fetch_type_new_fetch_att_list_empty(); + if (fetch_type == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + fetch_att = mailimap_fetch_att_new_uid(); + if (fetch_att == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_type; + } + + r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); + if (r != MAILIMAP_NO_ERROR) { + mailimap_fetch_att_free(fetch_att); + res = MAIL_ERROR_MEMORY; + goto free_fetch_type; + } + + fetch_att = mailimap_fetch_att_new_flags(); + if (fetch_att == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_type; + } + + r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); + if (r != MAILIMAP_NO_ERROR) { + mailimap_fetch_att_free(fetch_att); + res = MAIL_ERROR_MEMORY; + goto free_fetch_type; + } + + set = mailimap_set_new_single(index); + if (set == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_type; + } + + r = mailimap_uid_fetch(imap, set, fetch_type, &fetch_result); + + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); + + switch (r) { + case MAILIMAP_NO_ERROR: + break; + default: + return imap_error_to_mail_error(r); + } + + r = imap_fetch_result_to_flags(fetch_result, index, &flags); + mailimap_fetch_list_free(fetch_result); + + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + * result = flags; + + return MAIL_NO_ERROR; + + free_fetch_type: + mailimap_fetch_type_free(fetch_type); + err: + return res; +} + +int imap_store_flags(mailimap * imap, uint32_t first, uint32_t last, + struct mail_flags * flags) +{ + struct mailimap_store_att_flags * att_flags; + struct mailimap_set * set; + int r; + int res; + + set = mailimap_set_new_interval(first, last); + if (set == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + r = flags_to_imap_flags(flags, &att_flags); + if (r != MAIL_NO_ERROR) { + res = r; + goto free_set; + } + + r = mailimap_uid_store(imap, set, att_flags); + if (r != MAILIMAP_NO_ERROR) { + res = imap_error_to_mail_error(r); + goto free_flag; + } + + mailimap_store_att_flags_free(att_flags); + mailimap_set_free(set); + + return MAIL_NO_ERROR; + + free_flag: + mailimap_store_att_flags_free(att_flags); + free_set: + mailimap_set_free(set); + err: + return res; +} + + + + +int imap_get_messages_list(mailimap * imap, + mailsession * session, mailmessage_driver * driver, + uint32_t first_index, + struct mailmessage_list ** result) +{ + struct mailmessage_list * env_list; + int r; + struct mailimap_fetch_att * fetch_att; + struct mailimap_fetch_type * fetch_type; + struct mailimap_set * set; + clist * fetch_result; + int res; + + set = mailimap_set_new_interval(first_index, 0); + if (set == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + fetch_type = mailimap_fetch_type_new_fetch_att_list_empty(); + if (fetch_type == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_set; + } + + fetch_att = mailimap_fetch_att_new_uid(); + if (fetch_att == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_type; + } + + r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); + if (r != MAILIMAP_NO_ERROR) { + mailimap_fetch_att_free(fetch_att); + res = MAIL_ERROR_MEMORY; + goto free_fetch_type; + } + + fetch_att = mailimap_fetch_att_new_rfc822_size(); + if (fetch_att == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_fetch_type; + } + + r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att); + if (r != MAILIMAP_NO_ERROR) { + mailimap_fetch_att_free(fetch_att); + res = MAIL_ERROR_MEMORY; + goto free_fetch_type; + } + + r = mailimap_uid_fetch(imap, set, + fetch_type, &fetch_result); + + mailimap_fetch_type_free(fetch_type); + mailimap_set_free(set); + + if (r != MAILIMAP_NO_ERROR) { + res = imap_error_to_mail_error(r); + goto err; + } + + r = uid_list_to_env_list(fetch_result, &env_list, session, driver); + mailimap_fetch_list_free(fetch_result); + + * result = env_list; + + return MAIL_NO_ERROR; + + free_fetch_type: + mailimap_fetch_type_free(fetch_type); + free_set: + mailimap_set_free(set); + err: + return res; +} + +static void generate_key_from_message(char * key, size_t size, + mailmessage * msg_info, + int type) +{ + switch (type) { + case MAILIMAP_MSG_ATT_RFC822: + snprintf(key, size, "%s-rfc822", msg_info->msg_uid); + break; + case MAILIMAP_MSG_ATT_RFC822_HEADER: + snprintf(key, size, "%s-rfc822-header", msg_info->msg_uid); + break; + case MAILIMAP_MSG_ATT_RFC822_TEXT: + snprintf(key, size, "%s-rfc822-text", msg_info->msg_uid); + break; + case MAILIMAP_MSG_ATT_ENVELOPE: + snprintf(key, size, "%s-envelope", msg_info->msg_uid); + break; + } +} + +int +imapdriver_get_cached_envelope(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + mailsession * session, mailmessage * msg, + struct mailimf_fields ** result) +{ +#if 0 + mailsession * imap_session; +#endif + mailimap * imap; + int r; + struct mailimf_fields * fields; + int res; + char keyname[PATH_MAX]; + +#if 0 + imap_session = cached_session_get_ancestor(session); + imap = ((struct imap_session_state_data *) (imap_session->data))->session; +#endif + imap = cached_session_get_imap_session(session); + + generate_key_from_message(keyname, PATH_MAX, + msg, MAILIMAP_MSG_ATT_ENVELOPE); + + r = generic_cache_fields_read(cache_db, mmapstr, keyname, &fields); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + * result = fields; + + return MAIL_NO_ERROR; + +err: + return res; +} + +int +imapdriver_write_cached_envelope(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + mailsession * session, mailmessage * msg, + struct mailimf_fields * fields) +{ + char keyname[PATH_MAX]; + int r; + int res; + + generate_key_from_message(keyname, PATH_MAX, + msg, MAILIMAP_MSG_ATT_ENVELOPE); + + r = generic_cache_fields_write(cache_db, mmapstr, keyname, fields); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + return MAIL_NO_ERROR; + +err: + return res; +} + diff --git a/libetpan/src/driver/implementation/imap/imapdriver_tools.h b/libetpan/src/driver/implementation/imap/imapdriver_tools.h new file mode 100644 index 0000000..e15fdda --- a/dev/null +++ b/libetpan/src/driver/implementation/imap/imapdriver_tools.h @@ -0,0 +1,116 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef IMAPDRIVER_TOOLS_H + +#define IMAPDRIVER_TOOLS_H + +#include "mailimap.h" +#include "mailmime.h" +#include "imapdriver_types.h" +#include "mail_cache_db.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int imap_list_to_list(clist * imap_list, struct mail_list ** result); + +int +section_to_imap_section(struct mailmime_section * section, int type, + struct mailimap_section ** result); + +int imap_get_msg_att_info(struct mailimap_msg_att * msg_att, + uint32_t * puid, + struct mailimap_envelope ** pimap_envelope, + char ** preferences, + size_t * pref_size, + struct mailimap_msg_att_dynamic ** patt_dyn, + struct mailimap_body ** pimap_body); + +int imap_add_envelope_fetch_att(struct mailimap_fetch_type * fetch_type); + +int imap_env_to_fields(struct mailimap_envelope * env, + char * ref_str, size_t ref_size, + struct mailimf_fields ** result); + +int +imap_fetch_result_to_envelop_list(clist * fetch_result, + struct mailmessage_list * env_list); + +int imap_body_to_body(struct mailimap_body * imap_body, + struct mailmime ** result); + +#if 0 +int mail_search_to_imap_search(struct mail_search_key * key, + struct mailimap_search_key ** result); +#endif + +int msg_list_to_imap_set(clist * msg_list, + struct mailimap_set ** result); + +int imap_error_to_mail_error(int error); + +int imap_store_flags(mailimap * imap, uint32_t first, uint32_t last, + struct mail_flags * flags); + +int imap_fetch_flags(mailimap * imap, + uint32_t index, struct mail_flags ** result); + +int imap_get_messages_list(mailimap * imap, + mailsession * session, mailmessage_driver * driver, + uint32_t first_index, + struct mailmessage_list ** result); + +int +imapdriver_get_cached_envelope(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + mailsession * session, mailmessage * msg, + struct mailimf_fields ** result); + +int +imapdriver_write_cached_envelope(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + mailsession * session, mailmessage * msg, + struct mailimf_fields * fields); + +int imap_flags_to_imap_flags(struct mail_flags * flags, + struct mailimap_flag_list ** result); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/imap/imapdriver_types.h b/libetpan/src/driver/implementation/imap/imapdriver_types.h new file mode 100644 index 0000000..00559dc --- a/dev/null +++ b/libetpan/src/driver/implementation/imap/imapdriver_types.h @@ -0,0 +1,144 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef IMAPDRIVER_TYPES_H + +#define IMAPDRIVER_TYPES_H + +#include <libetpan/libetpan-config.h> + +#include <libetpan/mailimap.h> +#include <libetpan/maildriver_types.h> +#include <libetpan/generic_cache_types.h> +#include <libetpan/mailstorage_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* IMAP driver for session */ + +struct imap_session_state_data { + mailimap * imap_session; + char * imap_mailbox; + struct mail_flags_store * imap_flags_store; +}; + +enum { + IMAP_SECTION_MESSAGE, + IMAP_SECTION_HEADER, + IMAP_SECTION_MIME, + IMAP_SECTION_BODY +}; + +/* cached IMAP driver for session */ + +enum { + IMAPDRIVER_CACHED_SET_CACHE_DIRECTORY = 1, +}; + +struct imap_cached_session_state_data { + mailsession * imap_ancestor; + char * imap_quoted_mb; + char imap_cache_directory[PATH_MAX]; + carray * imap_uid_list; +}; + + +/* IMAP storage */ + +/* + imap_mailstorage is the state data specific to the IMAP4rev1 storage. + + - servername this is the name of the IMAP4rev1 server + + - port is the port to connect to, on the server. + you give 0 to use the default port. + + - command, if non-NULL the command used to connect to the + server instead of allowing normal TCP connections to be used. + + - connection_type is the type of socket layer to use. + The value can be CONNECTION_TYPE_PLAIN, CONNECTION_TYPE_STARTTLS, + CONNECTION_TYPE_TRY_STARTTLS, CONNECTION_TYPE_TLS or + CONNECTION_TYPE_COMMAND. + + - auth_type is the authenticate mechanism to use. + The value can be IMAP_AUTH_TYPE_PLAIN. + Other values are not yet implemented. + + - login is the login of the IMAP4rev1 account. + + - password is the password of the IMAP4rev1 account. + + - cached if this value is != 0, a persistant cache will be + stored on local system. + + - cache_directory is the location of the cache +*/ + +struct imap_mailstorage { + char * imap_servername; + uint16_t imap_port; + char * imap_command; + int imap_connection_type; + + int imap_auth_type; + char * imap_login; + char * imap_password; + + int imap_cached; + char * imap_cache_directory; +}; + +/* this is the type of IMAP4rev1 authentication */ + +enum { + IMAP_AUTH_TYPE_PLAIN, /* plain text authentication */ + IMAP_AUTH_TYPE_SASL_ANONYMOUS, /* SASL anonymous */ + IMAP_AUTH_TYPE_SASL_CRAM_MD5, /* SASL CRAM MD5 */ + IMAP_AUTH_TYPE_SASL_KERBEROS_V4, /* SASL KERBEROS V4 */ + IMAP_AUTH_TYPE_SASL_PLAIN, /* SASL plain */ + IMAP_AUTH_TYPE_SASL_SCRAM_MD5, /* SASL SCRAM MD5 */ + IMAP_AUTH_TYPE_SASL_GSSAPI, /* SASL GSSAPI */ + IMAP_AUTH_TYPE_SASL_DIGEST_MD5, /* SASL digest MD5 */ +}; + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/imap/imapstorage.c b/libetpan/src/driver/implementation/imap/imapstorage.c new file mode 100644 index 0000000..0bf6ec2 --- a/dev/null +++ b/libetpan/src/driver/implementation/imap/imapstorage.c @@ -0,0 +1,297 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "imapstorage.h" + +#include <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(* imap_storage)); + if (imap_storage == NULL) + goto err; + + imap_storage->imap_servername = strdup(imap_servername); + if (imap_storage->imap_servername == NULL) + goto free; + + imap_storage->imap_connection_type = imap_connection_type; + + if (imap_port == 0) { + switch (imap_connection_type) { + case CONNECTION_TYPE_PLAIN: + case CONNECTION_TYPE_TRY_STARTTLS: + case CONNECTION_TYPE_STARTTLS: + case CONNECTION_TYPE_COMMAND: + case CONNECTION_TYPE_COMMAND_TRY_STARTTLS: + case CONNECTION_TYPE_COMMAND_STARTTLS: + imap_port = IMAP_DEFAULT_PORT; + break; + + case CONNECTION_TYPE_TLS: + case CONNECTION_TYPE_COMMAND_TLS: + imap_port = IMAPS_DEFAULT_PORT; + break; + } + } + + imap_storage->imap_port = imap_port; + + if (imap_command != NULL) { + imap_storage->imap_command = strdup(imap_command); + if (imap_storage->imap_command == NULL) + goto free_servername; + } + else + imap_storage->imap_command = NULL; + + imap_storage->imap_auth_type = imap_auth_type; + + if (imap_login != NULL) { + imap_storage->imap_login = strdup(imap_login); + if (imap_storage->imap_login == NULL) + goto free_command; + } + else + imap_storage->imap_login = NULL; + + if (imap_password != NULL) { + imap_storage->imap_password = strdup(imap_password); + if (imap_storage->imap_password == NULL) + goto free_login; + } + else + imap_storage->imap_password = NULL; + + imap_storage->imap_cached = imap_cached; + + if (imap_cached && (imap_cache_directory != NULL)) { + imap_storage->imap_cache_directory = strdup(imap_cache_directory); + if (imap_storage->imap_cache_directory == NULL) + goto free_password; + } + else { + imap_storage->imap_cached = FALSE; + imap_storage->imap_cache_directory = NULL; + } + + storage->sto_data = imap_storage; + storage->sto_driver = &imap_mailstorage_driver; + + return MAIL_NO_ERROR; + + free_password: + free(imap_storage->imap_password); + free_login: + free(imap_storage->imap_login); + free_command: + free(imap_storage->imap_command); + free_servername: + free(imap_storage->imap_servername); + free: + free(imap_storage); + err: + return MAIL_ERROR_MEMORY; +} + +static void imap_mailstorage_uninitialize(struct mailstorage * storage) +{ + struct imap_mailstorage * imap_storage; + + imap_storage = storage->sto_data; + + if (imap_storage->imap_cache_directory != NULL) + free(imap_storage->imap_cache_directory); + if (imap_storage->imap_password != NULL) + free(imap_storage->imap_password); + if (imap_storage->imap_login != NULL) + free(imap_storage->imap_login); + if (imap_storage->imap_command != NULL) + free(imap_storage->imap_command); + free(imap_storage->imap_servername); + free(imap_storage); + + storage->sto_data = NULL; +} + +static int imap_connect(struct mailstorage * storage, + mailsession ** result) +{ + struct imap_mailstorage * imap_storage; + mailsession_driver * driver; + int r; + int res; + mailsession * session; + + imap_storage = storage->sto_data; + + if (imap_storage->imap_cached) + driver = imap_cached_session_driver; + else + driver = imap_session_driver; + + r = mailstorage_generic_connect(driver, + imap_storage->imap_servername, + imap_storage->imap_port, + imap_storage->imap_command, + imap_storage->imap_connection_type, + IMAPDRIVER_CACHED_SET_CACHE_DIRECTORY, + imap_storage->imap_cache_directory, + 0, NULL, + &session); + switch (r) { + case MAIL_NO_ERROR_NON_AUTHENTICATED: + case MAIL_NO_ERROR_AUTHENTICATED: + case MAIL_NO_ERROR: + break; + default: + res = r; + goto err; + } + + r = mailstorage_generic_auth(session, r, + imap_storage->imap_connection_type, + imap_storage->imap_login, + imap_storage->imap_password); + if (r != MAIL_NO_ERROR) { + res = r; + goto free; + } + + * result = session; + + return MAIL_NO_ERROR; + + free: + mailsession_free(session); + err: + return res; +} + +static int imap_mailstorage_connect(struct mailstorage * storage) +{ + mailsession * session; + int r; + int res; + + r = imap_connect(storage, &session); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + r = mailsession_select_folder(session, "INBOX"); + if (r != MAIL_NO_ERROR) { + mailsession_logout(session); + res = r; + goto err; + } + + storage->sto_session = session; + storage->sto_driver = &imap_mailstorage_driver; + + return MAIL_NO_ERROR; + + err: + return res; +} + +static int +imap_mailstorage_get_folder_session(struct mailstorage * storage, + char * pathname, mailsession ** result) +{ + mailsession * session; + int r; + int res; + + if (strcasecmp(pathname, "INBOX") == 0) { + session = storage->sto_session; + } + else { + r = imap_connect(storage, &session); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + r = mailsession_select_folder(session, pathname); + if (r != MAIL_NO_ERROR) { + mailsession_logout(session); + res = r; + goto free; + } + } + + * result = session; + + return MAIL_NO_ERROR; + + free: + mailsession_free(session); + err: + return res; +} diff --git a/libetpan/src/driver/implementation/imap/imapstorage.h b/libetpan/src/driver/implementation/imap/imapstorage.h new file mode 100644 index 0000000..929a86e --- a/dev/null +++ b/libetpan/src/driver/implementation/imap/imapstorage.h @@ -0,0 +1,90 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef IMAPSTORAGE_H + +#define IMAPSTORAGE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <libetpan/imapdriver_types.h> + +/* + imap_mailstorage_init is the constructor for a IMAP4rev1 storage + + @param storage this is the storage to initialize. + + @param servername this is the name of the IMAP4rev1 server + + @param port is the port to connect to, on the server. + you give 0 to use the default port. + + @param command the command used to connect to the server instead of + allowing normal TCP connections to be used. + + @param connection_type is the type of socket layer to use. + The value can be CONNECTION_TYPE_PLAIN, CONNECTION_TYPE_STARTTLS, + CONNECTION_TYPE_TRY_STARTTLS, CONNECTION_TYPE_TLS, + CONNECTION_TYPE_COMMAND, CONNECTION_TYPE_COMMAND_STARTTLS, + CONNECTION_TYPE_COMMAND_TRY_STARTTLS, CONNECTION_TYPE_COMMAND_TLS,. + + @param auth_type is the authenticate mechanism to use. + The value can be IMAP_AUTH_TYPE_PLAIN. + Other values are not yet implemented. + + @param login is the login of the IMAP4rev1 account. + + @param password is the password of the IMAP4rev1 account. + + @param cached if this value is != 0, a persistant cache will be + stored on local system. + + @param cache_directory is the location of the cache +*/ + +int imap_mailstorage_init(struct mailstorage * storage, + char * imap_servername, uint16_t imap_port, + char * imap_command, + int imap_connection_type, int imap_auth_type, + char * imap_login, char * imap_password, + int imap_cached, char * imap_cache_directory); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/maildir/maildirdriver.c b/libetpan/src/driver/implementation/maildir/maildirdriver.c new file mode 100644 index 0000000..a97fd43 --- a/dev/null +++ b/libetpan/src/driver/implementation/maildir/maildirdriver.c @@ -0,0 +1,676 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + + +/* + 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/libetpan/src/driver/implementation/maildir/maildirdriver.h b/libetpan/src/driver/implementation/maildir/maildirdriver.h new file mode 100644 index 0000000..0abe09d --- a/dev/null +++ b/libetpan/src/driver/implementation/maildir/maildirdriver.h @@ -0,0 +1,53 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MAILDIRDRIVER_H + +#define MAILDIRDRIVER_H + +#include <libetpan/maildriver.h> +#include <libetpan/maildirdriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailsession_driver * maildir_session_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/maildir/maildirdriver_cached.c b/libetpan/src/driver/implementation/maildir/maildirdriver_cached.c new file mode 100644 index 0000000..3664362 --- a/dev/null +++ b/libetpan/src/driver/implementation/maildir/maildirdriver_cached.c @@ -0,0 +1,1158 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "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/libetpan/src/driver/implementation/maildir/maildirdriver_cached.h b/libetpan/src/driver/implementation/maildir/maildirdriver_cached.h new file mode 100644 index 0000000..5c3d8a9 --- a/dev/null +++ b/libetpan/src/driver/implementation/maildir/maildirdriver_cached.h @@ -0,0 +1,53 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MAILDIRDRIVER_CACHED_H + +#define MAILDIRDRIVER_CACHED_H + +#include <libetpan/maildriver.h> +#include <libetpan/maildirdriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailsession_driver * maildir_cached_session_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/maildir/maildirdriver_cached_message.c b/libetpan/src/driver/implementation/maildir/maildirdriver_cached_message.c new file mode 100644 index 0000000..d2c30cc --- a/dev/null +++ b/libetpan/src/driver/implementation/maildir/maildirdriver_cached_message.c @@ -0,0 +1,334 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "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 = 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/libetpan/src/driver/implementation/maildir/maildirdriver_cached_message.h b/libetpan/src/driver/implementation/maildir/maildirdriver_cached_message.h new file mode 100644 index 0000000..b9e0215 --- a/dev/null +++ b/libetpan/src/driver/implementation/maildir/maildirdriver_cached_message.h @@ -0,0 +1,52 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MAILDIRDRIVER_CACHED_MESSAGE_H + +#define MAILDIRDRIVER_CACHED_MESSAGE_H + +#include <libetpan/maildirdriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailmessage_driver * maildir_cached_message_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/maildir/maildirdriver_message.c b/libetpan/src/driver/implementation/maildir/maildirdriver_message.c new file mode 100644 index 0000000..58bc6bd --- a/dev/null +++ b/libetpan/src/driver/implementation/maildir/maildirdriver_message.c @@ -0,0 +1,255 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "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 = 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/libetpan/src/driver/implementation/maildir/maildirdriver_message.h b/libetpan/src/driver/implementation/maildir/maildirdriver_message.h new file mode 100644 index 0000000..ed0a4d1 --- a/dev/null +++ b/libetpan/src/driver/implementation/maildir/maildirdriver_message.h @@ -0,0 +1,52 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MAILDIRDRIVER_MESSAGE_H + +#define MAILDIRDRIVER_MESSAGE_H + +#include <libetpan/maildirdriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailmessage_driver * maildir_message_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/maildir/maildirdriver_tools.c b/libetpan/src/driver/implementation/maildir/maildirdriver_tools.c new file mode 100644 index 0000000..e3036e8 --- a/dev/null +++ b/libetpan/src/driver/implementation/maildir/maildirdriver_tools.c @@ -0,0 +1,198 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "mailmessage.h" +#include "maildirdriver_tools.h" +#include "maildir.h" +#include "generic_cache.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <stdlib.h> +#include <string.h> + +int maildirdriver_maildir_error_to_mail_error(int error) +{ + switch (error) { + case MAILDIR_NO_ERROR: + return MAIL_NO_ERROR; + + case MAILDIR_ERROR_CREATE: + return MAIL_ERROR_FILE; + + case MAILDIR_ERROR_DIRECTORY: + return MAIL_ERROR_FILE; + + case MAILDIR_ERROR_MEMORY: + return MAIL_ERROR_MEMORY; + + case MAILDIR_ERROR_FILE: + return MAIL_ERROR_FILE; + + case MAILDIR_ERROR_FOLDER: + return MAIL_ERROR_FOLDER; + + case MAILDIR_ERROR_NOT_FOUND: + return MAIL_ERROR_MSG_NOT_FOUND; + + default: + return MAIL_ERROR_INVAL; + } +} + + + +uint32_t maildirdriver_maildir_flags_to_flags(uint32_t md_flags) +{ + uint32_t flags; + + flags = 0; + if ((md_flags & MAILDIR_FLAG_NEW) != 0) + flags |= MAIL_FLAG_NEW; + + if ((md_flags & MAILDIR_FLAG_SEEN) != 0) + flags |= MAIL_FLAG_SEEN; + + if ((md_flags & MAILDIR_FLAG_REPLIED) != 0) + flags |= MAIL_FLAG_ANSWERED; + + if ((md_flags & MAILDIR_FLAG_FLAGGED) != 0) + flags |= MAIL_FLAG_FLAGGED; + + if ((md_flags & MAILDIR_FLAG_TRASHED) != 0) + flags |= MAIL_FLAG_DELETED; + + return flags; +} + +uint32_t maildirdriver_flags_to_maildir_flags(uint32_t flags) +{ + uint32_t md_flags; + + md_flags = 0; + if ((flags & MAIL_FLAG_NEW) != 0) + md_flags |= MAILDIR_FLAG_NEW; + + if ((flags & MAIL_FLAG_SEEN) != 0) + md_flags |= MAILDIR_FLAG_SEEN; + + if ((flags & MAIL_FLAG_ANSWERED) != 0) + md_flags |= MAILDIR_FLAG_REPLIED; + + if ((flags & MAIL_FLAG_FLAGGED) != 0) + md_flags |= MAILDIR_FLAG_FLAGGED; + + if ((flags & MAIL_FLAG_DELETED) != 0) + md_flags |= MAILDIR_FLAG_TRASHED; + + return md_flags; +} + + +int maildir_get_messages_list(mailsession * session, struct maildir * md, + mailmessage_driver * message_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(md->mdir_msg_list) ; i++) { + struct maildir_msg * md_msg; + mailmessage * msg; + char * filename; + struct stat stat_info; + + md_msg = carray_get(md->mdir_msg_list, i); + + filename = maildir_message_get(md, md_msg->msg_uid); + r = stat(filename, &stat_info); + free(filename); + if (r < 0) + continue; + + msg = mailmessage_new(); + if (msg == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_list; + } + + r = mailmessage_init(msg, session, message_driver, + i + 1, stat_info.st_size); + if (r != MAIL_NO_ERROR) { + mailmessage_free(msg); + res = r; + goto free_list; + } + + msg->msg_uid = strdup(md_msg->msg_uid); + if (msg->msg_uid == NULL) { + mailmessage_free(msg); + res = MAIL_ERROR_MEMORY; + goto free_list; + } + + r = carray_add(tab, msg, NULL); + if (r < 0) { + mailmessage_free(msg); + res = MAIL_ERROR_MEMORY; + goto free_list; + } + } + + env_list = mailmessage_list_new(tab); + if (env_list == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_list; + } + + * result = env_list; + + return MAIL_NO_ERROR; + + free_list: + for(i = 0 ; i < carray_count(tab) ; i ++) + mailmessage_free(carray_get(tab, i)); + carray_free(tab); + err: + return res; +} diff --git a/libetpan/src/driver/implementation/maildir/maildirdriver_tools.h b/libetpan/src/driver/implementation/maildir/maildirdriver_tools.h new file mode 100644 index 0000000..0a738c9 --- a/dev/null +++ b/libetpan/src/driver/implementation/maildir/maildirdriver_tools.h @@ -0,0 +1,53 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MAILDIRDRIVER_TOOLS_H + +#define MAILDIRDRIVER_TOOLS_H + +#include "maildriver_types.h" +#include "maildir.h" + +int maildirdriver_maildir_error_to_mail_error(int error); + +uint32_t maildirdriver_maildir_flags_to_flags(uint32_t md_flags); + +uint32_t maildirdriver_flags_to_maildir_flags(uint32_t flags); + +int maildir_get_messages_list(mailsession * session, struct maildir * md, + mailmessage_driver * message_driver, + struct mailmessage_list ** result); + +#endif diff --git a/libetpan/src/driver/implementation/maildir/maildirdriver_types.h b/libetpan/src/driver/implementation/maildir/maildirdriver_types.h new file mode 100644 index 0000000..c965b3e --- a/dev/null +++ b/libetpan/src/driver/implementation/maildir/maildirdriver_types.h @@ -0,0 +1,96 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MAILDIRDRIVER_TYPES_H + +#define MAILDIRDRIVER_TYPES_H + +#include <libetpan/libetpan-config.h> + +#include <libetpan/maildriver_types.h> +#include <libetpan/maildir.h> +#include <libetpan/generic_cache_types.h> +#include <libetpan/mailstorage_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct maildir_session_state_data { + struct maildir * md_session; + struct mail_flags_store * md_flags_store; +}; + +enum { + MAILDIRDRIVER_CACHED_SET_CACHE_DIRECTORY = 1, + MAILDIRDRIVER_CACHED_SET_FLAGS_DIRECTORY, +}; + +struct maildir_cached_session_state_data { + mailsession * md_ancestor; + char * md_quoted_mb; + struct mail_flags_store * md_flags_store; + char md_cache_directory[PATH_MAX]; + char md_flags_directory[PATH_MAX]; +}; + +/* maildir storage */ + +/* + maildir_mailstorage is the state data specific to the maildir storage. + + - pathname is the path of the maildir storage. + + - cached if this value is != 0, a persistant cache will be + stored on local system. + + - cache_directory is the location of the cache. + + - flags_directory is the location of the flags. +*/ + +struct maildir_mailstorage { + char * md_pathname; + + int md_cached; + char * md_cache_directory; + char * md_flags_directory; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/maildir/maildirstorage.c b/libetpan/src/driver/implementation/maildir/maildirstorage.c new file mode 100644 index 0000000..09f95c7 --- a/dev/null +++ b/libetpan/src/driver/implementation/maildir/maildirstorage.c @@ -0,0 +1,193 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "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(* 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/libetpan/src/driver/implementation/maildir/maildirstorage.h b/libetpan/src/driver/implementation/maildir/maildirstorage.h new file mode 100644 index 0000000..0ad04b9 --- a/dev/null +++ b/libetpan/src/driver/implementation/maildir/maildirstorage.h @@ -0,0 +1,69 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MAILDIRSTORAGE_H + +#define MAILDIRSTORAGE_H + +#include <libetpan/maildirdriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + 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/libetpan/src/driver/implementation/mbox/mboxdriver.c b/libetpan/src/driver/implementation/mbox/mboxdriver.c new file mode 100644 index 0000000..72afa6d --- a/dev/null +++ b/libetpan/src/driver/implementation/mbox/mboxdriver.c @@ -0,0 +1,515 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "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/libetpan/src/driver/implementation/mbox/mboxdriver.h b/libetpan/src/driver/implementation/mbox/mboxdriver.h new file mode 100644 index 0000000..9b37aa4 --- a/dev/null +++ b/libetpan/src/driver/implementation/mbox/mboxdriver.h @@ -0,0 +1,52 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MBOXDRIVER_H + +#define MBOXDRIVER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <libetpan/mboxdriver_types.h> + +extern mailsession_driver * mbox_session_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/mbox/mboxdriver_cached.c b/libetpan/src/driver/implementation/mbox/mboxdriver_cached.c new file mode 100644 index 0000000..eaa0e48 --- a/dev/null +++ b/libetpan/src/driver/implementation/mbox/mboxdriver_cached.c @@ -0,0 +1,1337 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "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 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-%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-%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/libetpan/src/driver/implementation/mbox/mboxdriver_cached.h b/libetpan/src/driver/implementation/mbox/mboxdriver_cached.h new file mode 100644 index 0000000..25c4027 --- a/dev/null +++ b/libetpan/src/driver/implementation/mbox/mboxdriver_cached.h @@ -0,0 +1,54 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MBOXDRIVER_CACHED_H + +#define MBOXDRIVER_CACHED_H + +#include <libetpan/libetpan-config.h> + +#include <libetpan/mboxdriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailsession_driver * mbox_cached_session_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/mbox/mboxdriver_cached_message.c b/libetpan/src/driver/implementation/mbox/mboxdriver_cached_message.c new file mode 100644 index 0000000..9f77d32 --- a/dev/null +++ b/libetpan/src/driver/implementation/mbox/mboxdriver_cached_message.c @@ -0,0 +1,361 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "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-%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/libetpan/src/driver/implementation/mbox/mboxdriver_cached_message.h b/libetpan/src/driver/implementation/mbox/mboxdriver_cached_message.h new file mode 100644 index 0000000..144e2da --- a/dev/null +++ b/libetpan/src/driver/implementation/mbox/mboxdriver_cached_message.h @@ -0,0 +1,52 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MBOXDRIVER_CACHED_MESSAGE_H + +#define MBOXDRIVER_CACHED_MESSAGE_H + +#include <libetpan/mailmessage.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailmessage_driver * mbox_cached_message_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/mbox/mboxdriver_message.c b/libetpan/src/driver/implementation/mbox/mboxdriver_message.c new file mode 100644 index 0000000..9bb5a18 --- a/dev/null +++ b/libetpan/src/driver/implementation/mbox/mboxdriver_message.c @@ -0,0 +1,225 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "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-%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/libetpan/src/driver/implementation/mbox/mboxdriver_message.h b/libetpan/src/driver/implementation/mbox/mboxdriver_message.h new file mode 100644 index 0000000..686e46e --- a/dev/null +++ b/libetpan/src/driver/implementation/mbox/mboxdriver_message.h @@ -0,0 +1,52 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MBOXDRIVER_MESSAGE_H + +#define MBOXDRIVER_MESSAGE_H + +#include <libetpan/mboxdriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailmessage_driver * mbox_message_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/mbox/mboxdriver_tools.c b/libetpan/src/driver/implementation/mbox/mboxdriver_tools.c new file mode 100644 index 0000000..dc38cbd --- a/dev/null +++ b/libetpan/src/driver/implementation/mbox/mboxdriver_tools.c @@ -0,0 +1,435 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "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-%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/libetpan/src/driver/implementation/mbox/mboxdriver_tools.h b/libetpan/src/driver/implementation/mbox/mboxdriver_tools.h new file mode 100644 index 0000000..eebf98c --- a/dev/null +++ b/libetpan/src/driver/implementation/mbox/mboxdriver_tools.h @@ -0,0 +1,85 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MBOXDRIVER_TOOLS_H + +#define MBOXDRIVER_TOOLS_H + +#include "mail_cache_db_types.h" +#include "mboxdriver_types.h" +#include "mailmbox.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int mboxdriver_mbox_error_to_mail_error(int error); + +int mboxdriver_fetch_msg(mailsession * session, uint32_t index, + char ** result, size_t * result_len); + +int mboxdriver_fetch_size(mailsession * session, uint32_t index, + size_t * result); + +int +mboxdriver_get_cached_flags(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + mailsession * session, + uint32_t num, + struct mail_flags ** result); + +int +mboxdriver_write_cached_flags(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + char * uid, struct mail_flags * flags); + +int mbox_get_uid_messages_list(struct mailmbox_folder * folder, + mailsession * session, + mailmessage_driver * driver, + struct mailmessage_list ** result); + +int mbox_get_messages_list(struct mailmbox_folder * folder, + mailsession * session, + mailmessage_driver * driver, + struct mailmessage_list ** result); + +int mboxdriver_fetch_header(mailsession * session, uint32_t index, + char ** result, size_t * result_len); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/mbox/mboxdriver_types.h b/libetpan/src/driver/implementation/mbox/mboxdriver_types.h new file mode 100644 index 0000000..23b9acf --- a/dev/null +++ b/libetpan/src/driver/implementation/mbox/mboxdriver_types.h @@ -0,0 +1,107 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MBOXDRIVER_TYPES_H + +#define MBOXDRIVER_TYPES_H + +#include <libetpan/maildriver_types.h> +#include <libetpan/mailmbox.h> +#include <libetpan/mailstorage_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* mbox driver */ + +enum { + MBOXDRIVER_SET_READ_ONLY = 1, + MBOXDRIVER_SET_NO_UID, +}; + +struct mbox_session_state_data { + struct mailmbox_folder * mbox_folder; + int mbox_force_read_only; + int mbox_force_no_uid; +}; + +/* cached version */ + +enum { + /* the mapping of the parameters should be the same as for mbox */ + MBOXDRIVER_CACHED_SET_READ_ONLY = 1, + MBOXDRIVER_CACHED_SET_NO_UID, + /* cache specific */ + MBOXDRIVER_CACHED_SET_CACHE_DIRECTORY, + MBOXDRIVER_CACHED_SET_FLAGS_DIRECTORY, +}; + +struct mbox_cached_session_state_data { + mailsession * mbox_ancestor; + char * mbox_quoted_mb; + char mbox_cache_directory[PATH_MAX]; + char mbox_flags_directory[PATH_MAX]; + struct mail_flags_store * mbox_flags_store; +}; + +/* mbox storage */ + +/* + mbox_mailstorage is the state data specific to the mbox storage. + + - pathname is the filename that contains the mailbox. + + - cached if this value is != 0, a persistant cache will be + stored on local system. + + - cache_directory is the location of the cache. + + - flags_directory is the location of the flags. +*/ + +struct mbox_mailstorage { + char * mbox_pathname; + + int mbox_cached; + char * mbox_cache_directory; + char * mbox_flags_directory; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/mbox/mboxstorage.c b/libetpan/src/driver/implementation/mbox/mboxstorage.c new file mode 100644 index 0000000..3944c3b --- a/dev/null +++ b/libetpan/src/driver/implementation/mbox/mboxstorage.c @@ -0,0 +1,192 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "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(* 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/libetpan/src/driver/implementation/mbox/mboxstorage.h b/libetpan/src/driver/implementation/mbox/mboxstorage.h new file mode 100644 index 0000000..45aed7b --- a/dev/null +++ b/libetpan/src/driver/implementation/mbox/mboxstorage.h @@ -0,0 +1,69 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MBOXSTORAGE_H + +#define MBOXSTORAGE_H + +#include <libetpan/mboxdriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + mbox_mailstorage_init is the constructor for a mbox storage. + + @param storage this is the storage to initialize. + + @param pathname is the filename 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 mbox_mailstorage_init(struct mailstorage * storage, + char * mb_pathname, int mb_cached, + char * mb_cache_directory, char * mb_flags_directory); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/mh/mhdriver.c b/libetpan/src/driver/implementation/mh/mhdriver.c new file mode 100644 index 0000000..c44afc9 --- a/dev/null +++ b/libetpan/src/driver/implementation/mh/mhdriver.c @@ -0,0 +1,875 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "mhdriver.h" + +#include <stdio.h> +#include <sys/types.h> +#include <dirent.h> +#include <unistd.h> +#include <sys/stat.h> +#include <ctype.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <stdlib.h> +#include <string.h> + +#include "mailmh.h" +#include "maildriver_tools.h" +#include "mhdriver_tools.h" +#include "mhdriver_message.h" +#include "mailmessage.h" + +static int mhdriver_initialize(mailsession * session); + +static void mhdriver_uninitialize(mailsession * session); + +static int mhdriver_connect_path(mailsession * session, char * path); +static int mhdriver_logout(mailsession * session); + +static int mhdriver_build_folder_name(mailsession * session, char * mb, + char * name, char ** result); +static int mhdriver_create_folder(mailsession * session, char * mb); + +static int mhdriver_delete_folder(mailsession * session, char * mb); + +static int mhdriver_rename_folder(mailsession * session, char * mb, + char * new_name); + +static int mhdriver_select_folder(mailsession * session, char * mb); + +static int mhdriver_status_folder(mailsession * session, char * mb, + uint32_t * result_messages, uint32_t * result_recent, + uint32_t * result_unseen); + +static int mhdriver_messages_number(mailsession * session, char * mb, + uint32_t * result); + +static int mhdriver_list_folders(mailsession * session, char * mb, + struct mail_list ** result); + +static int mhdriver_lsub_folders(mailsession * session, char * mb, + struct mail_list ** result); + +static int mhdriver_subscribe_folder(mailsession * session, char * mb); + +static int mhdriver_unsubscribe_folder(mailsession * session, char * mb); + +static int mhdriver_append_message(mailsession * session, + char * message, size_t size); +static int mhdriver_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags); +static int mhdriver_copy_message(mailsession * session, + uint32_t num, char * mb); + +static int mhdriver_remove_message(mailsession * session, uint32_t num); + +static int mhdriver_move_message(mailsession * session, + uint32_t num, char * mb); + +static int mhdriver_get_messages_list(mailsession * session, + struct mailmessage_list ** result); + +static int mhdriver_get_message(mailsession * session, + uint32_t num, mailmessage ** result); + +static int mhdriver_get_message_by_uid(mailsession * session, + const char * uid, + mailmessage ** result); + +static mailsession_driver local_mh_session_driver = { + .sess_name = "mh", + + .sess_initialize = mhdriver_initialize, + .sess_uninitialize = mhdriver_uninitialize, + + .sess_parameters = NULL, + + .sess_connect_stream = NULL, + .sess_connect_path = mhdriver_connect_path, + .sess_starttls = NULL, + .sess_login = NULL, + .sess_logout = mhdriver_logout, + .sess_noop = NULL, + + .sess_build_folder_name = mhdriver_build_folder_name, + .sess_create_folder = mhdriver_create_folder, + .sess_delete_folder = mhdriver_delete_folder, + .sess_rename_folder = mhdriver_rename_folder, + .sess_check_folder = NULL, + .sess_examine_folder = NULL, + .sess_select_folder = mhdriver_select_folder, + .sess_expunge_folder = NULL, + .sess_status_folder = mhdriver_status_folder, + .sess_messages_number = mhdriver_messages_number, + .sess_recent_number = mhdriver_messages_number, + .sess_unseen_number = mhdriver_messages_number, + .sess_list_folders = mhdriver_list_folders, + .sess_lsub_folders = mhdriver_lsub_folders, + .sess_subscribe_folder = mhdriver_subscribe_folder, + .sess_unsubscribe_folder = mhdriver_unsubscribe_folder, + + .sess_append_message = mhdriver_append_message, + .sess_append_message_flags = mhdriver_append_message_flags, + .sess_copy_message = mhdriver_copy_message, + .sess_move_message = mhdriver_move_message, + + .sess_get_messages_list = mhdriver_get_messages_list, + .sess_get_envelopes_list = maildriver_generic_get_envelopes_list, + .sess_remove_message = mhdriver_remove_message, +#if 0 + .sess_search_messages = maildriver_generic_search_messages, +#endif + + .sess_get_message = mhdriver_get_message, + .sess_get_message_by_uid = mhdriver_get_message_by_uid, +}; + +mailsession_driver * mh_session_driver = &local_mh_session_driver; + +static inline struct mh_session_state_data * get_data(mailsession * session) +{ + return session->sess_data; +} + +static inline struct mailmh * get_mh_session(mailsession * session) +{ + return get_data(session)->mh_session; +} + +static inline struct mailmh_folder * get_mh_cur_folder(mailsession * session) +{ + return get_data(session)->mh_cur_folder; +} + +static int add_to_list(mailsession * session, char * mb) +{ + char * new_mb; + struct mh_session_state_data * data; + int r; + + data = get_data(session); + + new_mb = strdup(mb); + if (new_mb == NULL) + return -1; + + r = clist_append(data->mh_subscribed_list, new_mb); + if (r < 0) { + free(mb); + return -1; + } + + return 0; +} + +static int remove_from_list(mailsession * session, char * mb) +{ + clistiter * cur; + struct mh_session_state_data * data; + + data = get_data(session); + + for(cur = clist_begin(data->mh_subscribed_list) ; + cur != NULL ; cur = clist_next(cur)) { + char * cur_name; + + cur_name = clist_content(cur); + if (strcmp(cur_name, mb) == 0) { + clist_delete(data->mh_subscribed_list, cur); + free(cur_name); + return 0; + } + } + + return -1; +} + +static int mhdriver_initialize(mailsession * session) +{ + struct mh_session_state_data * data; + + data = malloc(sizeof(* data)); + if (data == NULL) + goto err; + + data->mh_session = NULL; + data->mh_cur_folder = NULL; + + data->mh_subscribed_list = clist_new(); + if (data->mh_subscribed_list == NULL) + goto free; + + session->sess_data = data; + + return MAIL_NO_ERROR; + + free: + free(data); + err: + return MAIL_ERROR_MEMORY; +} + +static void mhdriver_uninitialize(mailsession * session) +{ + struct mh_session_state_data * data; + + data = get_data(session); + + if (data->mh_session != NULL) + mailmh_free(data->mh_session); + + clist_foreach(data->mh_subscribed_list, (clist_func) free, NULL); + clist_free(data->mh_subscribed_list); + + free(data); + + session->sess_data = NULL; +} + + +static int mhdriver_connect_path(mailsession * session, char * path) +{ + struct mailmh * mh; + + if (get_mh_session(session) != NULL) + return MAIL_ERROR_BAD_STATE; + + mh = mailmh_new(path); + if (mh == NULL) + return MAIL_ERROR_MEMORY; + + get_data(session)->mh_session = mh; + + return MAIL_NO_ERROR; +} + +static int mhdriver_logout(mailsession * session) +{ + struct mailmh * mh; + + mh = get_mh_session(session); + + if (mh == NULL) + return MAIL_ERROR_BAD_STATE; + + mailmh_free(mh); + get_data(session)->mh_session = NULL; + + return MAIL_NO_ERROR; +} + +/* folders operations */ + +static int mhdriver_build_folder_name(mailsession * session, char * mb, + char * name, char ** result) +{ + char * folder_name; + + folder_name = malloc(strlen(mb) + 2 + strlen(name)); + if (folder_name == NULL) + return MAIL_ERROR_MEMORY; + + strcpy(folder_name, mb); + strcat(folder_name, "/"); + strcat(folder_name, name); + + * result = folder_name; + + return MAIL_NO_ERROR; +} + +static int get_parent(mailsession * session, char * mb, + struct mailmh_folder ** result_folder, + char ** result_name) +{ + char * name; + size_t length; + int i; + char * parent_name; + struct mailmh_folder * parent; + struct mailmh * mh; + + mh = get_mh_session(session); + if (mh == NULL) + return MAIL_ERROR_BAD_STATE; + + length = strlen(mb); + for(i = length - 1 ; i >= 0 ; i--) + if (mb[i] == '/') + break; + name = mb + i + 1; + + parent_name = malloc(i + 1); + /* strndup(mb, i) */ + if (parent_name == NULL) + return MAIL_ERROR_MEMORY; + + strncpy(parent_name, mb, i); + parent_name[i] = '\0'; + + parent = mailmh_folder_find(mh->mh_main, parent_name); + free(parent_name); + if (parent == NULL) + return MAIL_ERROR_FOLDER_NOT_FOUND; + + * result_folder = parent; + * result_name = name; + + return MAIL_NO_ERROR; +} + +static int mhdriver_create_folder(mailsession * session, char * mb) +{ + int r; + struct mailmh_folder * parent; + char * name; + + r = get_parent(session, mb, &parent, &name); + if (r != MAIL_NO_ERROR) + return r; + + r = mailmh_folder_add_subfolder(parent, name); + + return mhdriver_mh_error_to_mail_error(r); +} + +static int mhdriver_delete_folder(mailsession * session, char * mb) +{ + int r; + struct mailmh_folder * folder; + struct mailmh * mh; + + mh = get_mh_session(session); + if (mh == NULL) + return MAIL_ERROR_BAD_STATE; + + folder = mailmh_folder_find(mh->mh_main, mb); + if (folder == NULL) + return MAIL_ERROR_FOLDER_NOT_FOUND; + + if (get_mh_cur_folder(session) == folder) + get_data(session)->mh_cur_folder = NULL; + + r = mailmh_folder_remove_subfolder(folder); + + return mhdriver_mh_error_to_mail_error(r); +} + +static int mhdriver_rename_folder(mailsession * session, char * mb, + char * new_name) +{ + struct mailmh_folder * src_folder; + struct mailmh_folder * dst_folder; + char * name; + struct mailmh * mh; + int r; + + r = get_parent(session, new_name, &dst_folder, &name); + if (r != MAIL_NO_ERROR) + return r; + + mh = get_mh_session(session); + if (mh == NULL) + return MAIL_ERROR_BAD_STATE; + + src_folder = mailmh_folder_find(mh->mh_main, mb); + if (src_folder == NULL) + return MAIL_ERROR_FOLDER_NOT_FOUND; + + if (get_mh_cur_folder(session) == src_folder) + get_data(session)->mh_cur_folder = NULL; + + r = mailmh_folder_rename_subfolder(src_folder, dst_folder, name); + + return mhdriver_mh_error_to_mail_error(r); +} + +static int mhdriver_select_folder(mailsession * session, char * mb) +{ + struct mailmh_folder * folder; + struct mailmh * mh; + int r; + + mh = get_mh_session(session); + if (mh == NULL) + return MAIL_ERROR_BAD_STATE; + + r = mailmh_folder_update(mh->mh_main); + + folder = mailmh_folder_find(mh->mh_main, mb); + if (folder == NULL) + return MAIL_ERROR_FOLDER_NOT_FOUND; + + get_data(session)->mh_cur_folder = folder; + r = mailmh_folder_update(folder); + + return mhdriver_mh_error_to_mail_error(r); +} + +static int mhdriver_status_folder(mailsession * session, char * mb, + uint32_t * result_messages, uint32_t * result_recent, + uint32_t * result_unseen) +{ + uint32_t count; + int r; + + r = mhdriver_messages_number(session, mb, &count); + if (r != MAIL_NO_ERROR) + return r; + + * result_messages = count; + * result_recent = count; + * result_unseen = count; + + return MAIL_NO_ERROR; +} + +static int mhdriver_messages_number(mailsession * session, char * mb, + uint32_t * result) +{ + struct mailmh_folder * folder; + uint32_t count; + struct mailmh * mh; + unsigned int i; + + mh = get_mh_session(session); + if (mh == NULL) + return MAIL_ERROR_BAD_STATE; + + if (mb != NULL) { + folder = mailmh_folder_find(mh->mh_main, mb); + if (folder == NULL) + return MAIL_ERROR_FOLDER_NOT_FOUND; + } + else { + folder = get_mh_cur_folder(session); + if (folder == NULL) + return MAIL_ERROR_BAD_STATE; + } + + mailmh_folder_update(folder); + count = 0; + for (i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i ++) { + struct mailmh_msg_info * msg_info; + + msg_info = carray_get(folder->fl_msgs_tab, i); + if (msg_info != NULL) + count ++; + } + + * result = count; + + return MAIL_NO_ERROR; +} + + +static int get_list_folders(struct mailmh_folder * folder, clist ** result) +{ + unsigned int i; + clist * list; + char * new_filename; + int res; + int r; + + list = * result; + + new_filename = strdup(folder->fl_filename); + if (new_filename == NULL) { + res = MAIL_ERROR_MEMORY; + goto free; + } + + r = mailmh_folder_update(folder); + + switch (r) { + case MAILMH_NO_ERROR: + break; + + default: + res = mhdriver_mh_error_to_mail_error(r); + goto free; + } + + r = clist_append(list, new_filename); + if (r < 0) { + free(new_filename); + res = MAIL_ERROR_MEMORY; + goto free; + } + + if (folder->fl_subfolders_tab != NULL) { + for(i = 0 ; i < carray_count(folder->fl_subfolders_tab) ; i++) { + struct mailmh_folder * subfolder; + + subfolder = carray_get(folder->fl_subfolders_tab, i); + + r = get_list_folders(subfolder, &list); + if (r != MAIL_NO_ERROR) { + res = MAIL_ERROR_MEMORY; + goto free; + } + } + } + + * result = list; + + return MAIL_NO_ERROR; + + free: + clist_foreach(list, (clist_func) free, NULL); + clist_free(list); + return res; +} + + +static int mhdriver_list_folders(mailsession * session, char * mb, + struct mail_list ** result) +{ + clist * list; + int r; + struct mailmh * mh; + struct mail_list * ml; + + mh = get_mh_session(session); + + if (mh == NULL) + return MAIL_ERROR_BAD_STATE; + + list = clist_new(); + if (list == NULL) + return MAIL_ERROR_MEMORY; + + r = get_list_folders(mh->mh_main, &list); + if (r != MAIL_NO_ERROR) + return r; + + ml = mail_list_new(list); + if (ml == NULL) + goto free; + + * result = ml; + + return MAIL_NO_ERROR; + + free: + clist_foreach(list, (clist_func) free, NULL); + clist_free(list); + return MAIL_ERROR_MEMORY; +} + +static int mhdriver_lsub_folders(mailsession * session, char * mb, + struct mail_list ** result) +{ + clist * subscribed; + clist * lsub_result; + clistiter * cur; + struct mail_list * lsub; + size_t length; + int r; + + length = strlen(mb); + + subscribed = get_data(session)->mh_subscribed_list; + + lsub_result = clist_new(); + if (lsub_result == NULL) + return MAIL_ERROR_MEMORY; + + for(cur = clist_begin(subscribed) ; cur != NULL ; + cur = clist_next(cur)) { + char * cur_mb; + char * new_mb; + + cur_mb = clist_content(cur); + + if (strncmp(mb, cur_mb, length) == 0) { + new_mb = strdup(cur_mb); + if (new_mb == NULL) + goto free_list; + + r = clist_append(lsub_result, new_mb); + if (r < 0) { + free(new_mb); + goto free_list; + } + } + } + + lsub = mail_list_new(lsub_result); + if (lsub == NULL) + goto free_list; + + * result = lsub; + + return MAIL_NO_ERROR; + + free_list: + clist_foreach(lsub_result, (clist_func) free, NULL); + clist_free(lsub_result); + return MAIL_ERROR_MEMORY; +} + +static int mhdriver_subscribe_folder(mailsession * session, char * mb) +{ + int r; + + r = add_to_list(session, mb); + if (r < 0) + return MAIL_ERROR_SUBSCRIBE; + + return MAIL_NO_ERROR; +} + +static int mhdriver_unsubscribe_folder(mailsession * session, char * mb) +{ + int r; + + r = remove_from_list(session, mb); + if (r < 0) + return MAIL_ERROR_UNSUBSCRIBE; + + return MAIL_NO_ERROR; +} + +/* messages operations */ + +static int mhdriver_append_message(mailsession * session, + char * message, size_t size) +{ + int r; + struct mailmh_folder * folder; + + folder = get_mh_cur_folder(session); + if (folder == NULL) + return MAIL_ERROR_BAD_STATE; + + r = mailmh_folder_add_message(folder, message, size); + + switch (r) { + case MAILMH_ERROR_FILE: + return MAIL_ERROR_DISKSPACE; + + default: + return mhdriver_mh_error_to_mail_error(r); + } +} + +static int mhdriver_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags) +{ + return mhdriver_append_message(session, message, size); +} + +static int mhdriver_copy_message(mailsession * session, + uint32_t num, char * mb) +{ + int fd; + int r; + struct mailmh_folder * folder; + struct mailmh * mh; + int res; + + mh = get_mh_session(session); + if (mh == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + folder = get_mh_cur_folder(session); + if (folder == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + r = mailmh_folder_get_message_fd(folder, num, O_RDONLY, &fd); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + folder = mailmh_folder_find(mh->mh_main, mb); + if (folder == NULL) { + res = MAIL_ERROR_FOLDER_NOT_FOUND; + goto close; + } + + r = mailmh_folder_add_message_file(folder, fd); + if (r != MAIL_NO_ERROR) { + res = MAIL_ERROR_COPY; + goto close; + } + + close(fd); + + return MAIL_NO_ERROR; + + close: + close(fd); + err: + return res; +} + +static int mhdriver_remove_message(mailsession * session, uint32_t num) +{ + int r; + struct mailmh_folder * folder; + + folder = get_mh_cur_folder(session); + if (folder == NULL) + return MAIL_ERROR_DELETE; + + r = mailmh_folder_remove_message(folder, num); + + return mhdriver_mh_error_to_mail_error(r); +} + +static int mhdriver_move_message(mailsession * session, + uint32_t num, char * mb) +{ + int r; + struct mailmh_folder * src_folder; + struct mailmh_folder * dest_folder; + struct mailmh * mh; + + mh = get_mh_session(session); + if (mh == NULL) + return MAIL_ERROR_BAD_STATE; + + src_folder = get_mh_cur_folder(session); + if (src_folder == NULL) + return MAIL_ERROR_BAD_STATE; + + dest_folder = mailmh_folder_find(mh->mh_main, mb); + if (dest_folder == NULL) + return MAIL_ERROR_FOLDER_NOT_FOUND; + + r = mailmh_folder_move_message(dest_folder, src_folder, num); + + return mhdriver_mh_error_to_mail_error(r); +} + + +static int mhdriver_get_messages_list(mailsession * session, + struct mailmessage_list ** result) +{ + struct mailmh_folder * folder; + int res; + + folder = get_mh_cur_folder(session); + if (folder == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + mailmh_folder_update(folder); + return mh_get_messages_list(folder, session, mh_message_driver, result); + + err: + return res; +} + +static int mhdriver_get_message(mailsession * session, + uint32_t num, mailmessage ** result) +{ + mailmessage * msg_info; + int r; + + msg_info = mailmessage_new(); + if (msg_info == NULL) + return MAIL_ERROR_MEMORY; + + r = mailmessage_init(msg_info, session, mh_message_driver, num, 0); + if (r != MAIL_NO_ERROR) { + mailmessage_free(msg_info); + return r; + } + + * result = msg_info; + + return MAIL_NO_ERROR; +} + +static int mhdriver_get_message_by_uid(mailsession * session, + const char * uid, + mailmessage ** result) +{ + uint32_t index; + char *p; + struct mailmh_msg_info * mh_msg_info; + struct mh_session_state_data * mh_data; + chashdatum key; + chashdatum data; + int r; + time_t mtime; + char * mtime_p; + + if (uid == NULL) + return MAIL_ERROR_INVAL; + + index = strtoul(uid, &p, 10); + if (p == uid || * p != '-') + return MAIL_ERROR_INVAL; + + mh_data = session->sess_data; +#if 0 + mh_msg_info = cinthash_find(mh_data->mh_cur_folder->fl_msgs_hash, index); +#endif + key.data = &index; + key.len = sizeof(index); + r = chash_get(mh_data->mh_cur_folder->fl_msgs_hash, &key, &data); + if (r < 0) + return MAIL_ERROR_MSG_NOT_FOUND; + + mh_msg_info = data.data; + + mtime_p = p + 1; + + mtime = strtoul(mtime_p, &p, 10); + if ((* p == '-') && (mtime == mh_msg_info->msg_mtime)) { + size_t size; + char *size_p; + + size_p = p + 1; + size = strtoul(size_p, &p, 10); + if ((* p == '\0') && (size == mh_msg_info->msg_size)) + return mhdriver_get_message(session, index, result); + } + else if (* p != '-') { + return MAIL_ERROR_INVAL; + } + + return MAIL_ERROR_MSG_NOT_FOUND; +} diff --git a/libetpan/src/driver/implementation/mh/mhdriver.h b/libetpan/src/driver/implementation/mh/mhdriver.h new file mode 100644 index 0000000..a3f45f5 --- a/dev/null +++ b/libetpan/src/driver/implementation/mh/mhdriver.h @@ -0,0 +1,52 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MHDRIVER_H + +#define MHDRIVER_H + +#include <libetpan/maildriver.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailsession_driver * mh_session_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/mh/mhdriver_cached.c b/libetpan/src/driver/implementation/mh/mhdriver_cached.c new file mode 100644 index 0000000..1e5c28b --- a/dev/null +++ b/libetpan/src/driver/implementation/mh/mhdriver_cached.c @@ -0,0 +1,1315 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "mhdriver_cached.h" + +#include <stdio.h> +#include <sys/types.h> +#include <dirent.h> +#include <unistd.h> +#include <sys/stat.h> +#include <ctype.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <stdlib.h> +#include <string.h> + +#include "mail.h" +#include "mail_cache_db.h" + +#include "generic_cache.h" +#include "imfcache.h" +#include "mhdriver.h" + +#include "mhdriver_cached_message.h" +#include "mailmh.h" +#include "maildriver_tools.h" +#include "mhdriver_tools.h" +#include "mailmessage.h" + +static int mhdriver_cached_initialize(mailsession * session); + +static void mhdriver_cached_uninitialize(mailsession * session); + +static int mhdriver_cached_parameters(mailsession * session, + int id, void * value); + +static int mhdriver_cached_connect_path(mailsession * session, char * path); +static int mhdriver_cached_logout(mailsession * session); + +static int mhdriver_cached_build_folder_name(mailsession * session, char * mb, + char * name, char ** result); +static int mhdriver_cached_create_folder(mailsession * session, char * mb); + +static int mhdriver_cached_delete_folder(mailsession * session, char * mb); + +static int mhdriver_cached_rename_folder(mailsession * session, char * mb, + char * new_name); + +static int mhdriver_cached_check_folder(mailsession * session); + +static int mhdriver_cached_select_folder(mailsession * session, char * mb); + +static int mhdriver_cached_expunge_folder(mailsession * session); + +static int mhdriver_cached_status_folder(mailsession * session, char * mb, + uint32_t * result_messages, uint32_t * result_recent, + uint32_t * result_unseen); + +static int mhdriver_cached_messages_number(mailsession * session, char * mb, + uint32_t * result); +static int mhdriver_cached_recent_number(mailsession * session, char * mb, + uint32_t * result); +static int mhdriver_cached_unseen_number(mailsession * session, char * mb, + uint32_t * result); + +static int mhdriver_cached_list_folders(mailsession * session, char * mb, + struct mail_list ** result); + +static int mhdriver_cached_lsub_folders(mailsession * session, char * mb, + struct mail_list ** result); + +static int mhdriver_cached_subscribe_folder(mailsession * session, char * mb); + +static int mhdriver_cached_unsubscribe_folder(mailsession * session, + char * mb); + +static int mhdriver_cached_append_message(mailsession * session, + char * message, size_t size); +static int mhdriver_cached_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags); +static int mhdriver_cached_copy_message(mailsession * session, + uint32_t num, char * mb); + +static int mhdriver_cached_remove_message(mailsession * session, + uint32_t num); + +static int mhdriver_cached_move_message(mailsession * session, + uint32_t num, char * mb); + +static int +mhdriver_cached_get_messages_list(mailsession * session, + struct mailmessage_list ** result); + +static int +mhdriver_cached_get_envelopes_list(mailsession * session, + struct mailmessage_list * env_list); + +static int mhdriver_cached_get_message(mailsession * session, + uint32_t num, mailmessage ** result); + +static int mhdriver_cached_get_message_by_uid(mailsession * session, + const char * uid, + mailmessage ** result); + +static mailsession_driver local_mh_cached_session_driver = { + .sess_name = "mh-cached", + + .sess_initialize = mhdriver_cached_initialize, + .sess_uninitialize = mhdriver_cached_uninitialize, + + .sess_parameters = mhdriver_cached_parameters, + + .sess_connect_stream = NULL, + .sess_connect_path = mhdriver_cached_connect_path, + .sess_starttls = NULL, + .sess_login = NULL, + .sess_logout = mhdriver_cached_logout, + .sess_noop = NULL, + + .sess_build_folder_name = mhdriver_cached_build_folder_name, + .sess_create_folder = mhdriver_cached_create_folder, + .sess_delete_folder = mhdriver_cached_delete_folder, + .sess_rename_folder = mhdriver_cached_rename_folder, + .sess_check_folder = mhdriver_cached_check_folder, + .sess_examine_folder = NULL, + .sess_select_folder = mhdriver_cached_select_folder, + .sess_expunge_folder = mhdriver_cached_expunge_folder, + .sess_status_folder = mhdriver_cached_status_folder, + .sess_messages_number = mhdriver_cached_messages_number, + .sess_recent_number = mhdriver_cached_recent_number, + .sess_unseen_number = mhdriver_cached_unseen_number, + .sess_list_folders = mhdriver_cached_list_folders, + .sess_lsub_folders = mhdriver_cached_lsub_folders, + .sess_subscribe_folder = mhdriver_cached_subscribe_folder, + .sess_unsubscribe_folder = mhdriver_cached_unsubscribe_folder, + + .sess_append_message = mhdriver_cached_append_message, + .sess_append_message_flags = mhdriver_cached_append_message_flags, + .sess_copy_message = mhdriver_cached_copy_message, + .sess_move_message = mhdriver_cached_move_message, + + .sess_get_messages_list = mhdriver_cached_get_messages_list, + .sess_get_envelopes_list = mhdriver_cached_get_envelopes_list, + .sess_remove_message = mhdriver_cached_remove_message, +#if 0 + .sess_search_messages = maildriver_generic_search_messages, +#endif + + .sess_get_message = mhdriver_cached_get_message, + .sess_get_message_by_uid = mhdriver_cached_get_message_by_uid, +}; + +mailsession_driver * mh_cached_session_driver = +&local_mh_cached_session_driver; + +#define ENV_NAME "env.db" +#define FLAGS_NAME "flags.db" + + +static inline struct mh_cached_session_state_data * +get_cached_data(mailsession * session) +{ + return session->sess_data; +} + +static inline mailsession * get_ancestor(mailsession * session) +{ + return get_cached_data(session)->mh_ancestor; +} + +static inline struct mh_session_state_data * +get_ancestor_data(mailsession * session) +{ + return get_ancestor(session)->sess_data; +} + +static inline struct mailmh * +get_mh_session(mailsession * session) +{ + return get_ancestor_data(session)->mh_session; +} + +static inline struct mailmh_folder * +get_mh_cur_folder(mailsession * session) +{ + return get_ancestor_data(session)->mh_cur_folder; +} + + +#define FILENAME_MAX_UID "max-uid" + +/* write max uid current value */ + +static int write_max_uid_value(mailsession * session) +{ + int r; + char filename[PATH_MAX]; + FILE * f; + int res; + struct mh_cached_session_state_data * cached_data; + struct mh_session_state_data * ancestor_data; + int fd; + + MMAPString * mmapstr; + size_t cur_token; + + cached_data = get_cached_data(session); + ancestor_data = get_ancestor_data(session); + + if (cached_data->mh_quoted_mb == NULL) + return MAIL_ERROR_BAD_STATE; + + snprintf(filename, PATH_MAX, "%s/%s/%s", + cached_data->mh_cache_directory, + cached_data->mh_quoted_mb, FILENAME_MAX_UID); + + fd = creat(filename, S_IRUSR | S_IWUSR); + if (fd < 0) { + res = MAIL_ERROR_FILE; + goto err; + } + + f = fdopen(fd, "w"); + if (f == NULL) { + close(fd); + res = MAIL_ERROR_FILE; + goto err; + } + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto close; + } + + r = mail_serialize_clear(mmapstr, &cur_token); + if (r != MAIL_NO_ERROR) { + res = r; + goto free_mmapstr; + } + + r = mailimf_cache_int_write(mmapstr, &cur_token, + ancestor_data->mh_cur_folder->fl_max_index); + if (r != MAIL_NO_ERROR) { + res = r; + goto free_mmapstr; + } + + fwrite(mmapstr->str, 1, mmapstr->len, f); + + mmap_string_free(mmapstr); + fclose(f); + + return MAIL_NO_ERROR; + + free_mmapstr: + mmap_string_free(mmapstr); + close: + fclose(f); + err: + return res; +} + +static int read_max_uid_value(mailsession * session) +{ + int r; + char filename[PATH_MAX]; + FILE * f; + uint32_t written_uid; + int res; + struct mh_cached_session_state_data * cached_data; + struct mh_session_state_data * ancestor_data; + + MMAPString * mmapstr; + size_t cur_token; + char buf[sizeof(uint32_t)]; + size_t read_size; + + cached_data = get_cached_data(session); + ancestor_data = get_ancestor_data(session); + + snprintf(filename, PATH_MAX, "%s/%s/%s", + cached_data->mh_cache_directory, + cached_data->mh_quoted_mb, FILENAME_MAX_UID); + + f = fopen(filename, "r"); + if (f == NULL) { + res = MAIL_ERROR_FILE; + goto err; + } + + read_size = fread(buf, 1, sizeof(uint32_t), f); + + mmapstr = mmap_string_new_len(buf, read_size); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto close; + } + + cur_token = 0; + + r = mailimf_cache_int_read(mmapstr, &cur_token, &written_uid); + if (r != MAIL_NO_ERROR) { + fclose(f); + res = r; + goto free_mmapstr; + } + + mmap_string_free(mmapstr); + fclose(f); + + if (written_uid > ancestor_data->mh_cur_folder->fl_max_index) + ancestor_data->mh_cur_folder->fl_max_index = written_uid; + + return MAIL_NO_ERROR; + + free_mmapstr: + mmap_string_free(mmapstr); + close: + fclose(f); + err: + return res; +} + + +static int mhdriver_cached_initialize(mailsession * session) +{ + struct mh_cached_session_state_data * data; + + data = malloc(sizeof(* data)); + if (data == NULL) + goto err; + + data->mh_flags_store = mail_flags_store_new(); + if (data->mh_flags_store == NULL) + goto free; + + data->mh_ancestor = mailsession_new(mh_session_driver); + if (data->mh_ancestor == NULL) + goto free_store; + + data->mh_quoted_mb = NULL; + + session->sess_data = data; + + return MAIL_NO_ERROR; + + free_store: + mail_flags_store_free(data->mh_flags_store); + free: + free(data); + err: + return MAIL_ERROR_MEMORY; +} + +static void free_state(struct mh_cached_session_state_data * mh_data) +{ + if (mh_data->mh_quoted_mb) { + free(mh_data->mh_quoted_mb); + mh_data->mh_quoted_mb = NULL; + } +} + +static int mh_flags_store_process(char * flags_directory, char * quoted_mb, + struct mail_flags_store * flags_store) +{ + char filename_flags[PATH_MAX]; + struct mail_cache_db * cache_db_flags; + MMAPString * mmapstr; + unsigned int i; + int r; + int res; + + if (carray_count(flags_store->fls_tab) == 0) + return MAIL_NO_ERROR; + + if (quoted_mb == NULL) + return MAIL_NO_ERROR; + + snprintf(filename_flags, PATH_MAX, "%s/%s/%s", + flags_directory, quoted_mb, FLAGS_NAME); + + r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); + if (r < 0) { + res = MAIL_ERROR_FILE; + goto err; + } + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto close_db_flags; + } + + for(i = 0 ; i < carray_count(flags_store->fls_tab) ; i ++) { + mailmessage * msg; + + msg = carray_get(flags_store->fls_tab, i); + + r = mhdriver_write_cached_flags(cache_db_flags, mmapstr, + msg->msg_uid, msg->msg_flags); + } + + mmap_string_free(mmapstr); + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + + mail_flags_store_clear(flags_store); + + return MAIL_NO_ERROR; + + close_db_flags: + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + err: + return res; +} + +static void mhdriver_cached_uninitialize(mailsession * session) +{ + struct mh_cached_session_state_data * data; + + data = get_cached_data(session); + + mh_flags_store_process(data->mh_flags_directory, data->mh_quoted_mb, + data->mh_flags_store); + + mail_flags_store_free(data->mh_flags_store); + + free_state(data); + mailsession_free(data->mh_ancestor); + free(data); + + session->sess_data = NULL; +} + +static int mhdriver_cached_parameters(mailsession * session, + int id, void * value) +{ + struct mh_cached_session_state_data * cached_data; + int r; + + cached_data = get_cached_data(session); + + switch (id) { + case MHDRIVER_CACHED_SET_CACHE_DIRECTORY: + strncpy(cached_data->mh_cache_directory, value, PATH_MAX); + cached_data->mh_cache_directory[PATH_MAX - 1] = '\0'; + + r = generic_cache_create_dir(cached_data->mh_cache_directory); + if (r != MAIL_NO_ERROR) + return r; + + return MAIL_NO_ERROR; + + case MHDRIVER_CACHED_SET_FLAGS_DIRECTORY: + strncpy(cached_data->mh_flags_directory, value, PATH_MAX); + cached_data->mh_flags_directory[PATH_MAX - 1] = '\0'; + + r = generic_cache_create_dir(cached_data->mh_flags_directory); + if (r != MAIL_NO_ERROR) + return r; + + return MAIL_NO_ERROR; + } + + return MAIL_ERROR_INVAL; +} + +static int mhdriver_cached_connect_path(mailsession * session, char * path) +{ + return mailsession_connect_path(get_ancestor(session), path); +} + +static int mhdriver_cached_logout(mailsession * session) +{ + int r; + struct mh_cached_session_state_data * cached_data; + + r = write_max_uid_value(session); + + cached_data = get_cached_data(session); + + mh_flags_store_process(cached_data->mh_flags_directory, + cached_data->mh_quoted_mb, + cached_data->mh_flags_store); + + return mailsession_logout(get_ancestor(session)); +} + +static int mhdriver_cached_check_folder(mailsession * session) +{ + struct mh_cached_session_state_data * cached_data; + + cached_data = get_cached_data(session); + + mh_flags_store_process(cached_data->mh_flags_directory, + cached_data->mh_quoted_mb, + cached_data->mh_flags_store); + + return MAIL_NO_ERROR; +} + +/* folders operations */ + +static int mhdriver_cached_build_folder_name(mailsession * session, char * mb, + char * name, char ** result) +{ + return mailsession_build_folder_name(get_ancestor(session), + mb, name, result); +} + +static int mhdriver_cached_create_folder(mailsession * session, char * mb) +{ + return mailsession_create_folder(get_ancestor(session), mb); +} + +static int mhdriver_cached_delete_folder(mailsession * session, char * mb) +{ + return mailsession_delete_folder(get_ancestor(session), mb); +} + +static int mhdriver_cached_rename_folder(mailsession * session, char * mb, + char * new_name) +{ + return mailsession_rename_folder(get_ancestor(session), mb, new_name); +} + +static int get_cache_directory(mailsession * session, + char * path, char ** result) +{ + char * quoted_mb; + char dirname[PATH_MAX]; + int res; + int r; + struct mh_cached_session_state_data * cached_data; + + cached_data = get_cached_data(session); + + quoted_mb = maildriver_quote_mailbox(path); + if (quoted_mb == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + snprintf(dirname, PATH_MAX, "%s/%s", + cached_data->mh_cache_directory, quoted_mb); + + r = generic_cache_create_dir(dirname); + if (r != MAIL_NO_ERROR) { + res = r; + goto free; + } + + snprintf(dirname, PATH_MAX, "%s/%s", + cached_data->mh_flags_directory, quoted_mb); + + r = generic_cache_create_dir(dirname); + if (r != MAIL_NO_ERROR) { + res = r; + goto free; + } + + * result = quoted_mb; + + return MAIL_NO_ERROR; + + free: + free(quoted_mb); + err: + return res; +} + +static int mhdriver_cached_select_folder(mailsession * session, char * mb) +{ + int r; + int res; + char * quoted_mb; + struct mh_cached_session_state_data * cached_data; + + cached_data = get_cached_data(session); + + mh_flags_store_process(cached_data->mh_flags_directory, + cached_data->mh_quoted_mb, + cached_data->mh_flags_store); + + r = get_cache_directory(session, mb, "ed_mb); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + r = mailsession_select_folder(get_ancestor(session), mb); + if (r != MAIL_NO_ERROR) { + res = r; + goto free; + } + + r = write_max_uid_value(session); + + free_state(cached_data); + cached_data->mh_quoted_mb = quoted_mb; + + r = read_max_uid_value(session); + + return MAIL_NO_ERROR; + + free: + free(quoted_mb); + err: + return res; +} + +static int mhdriver_cached_expunge_folder(mailsession * session) +{ + struct mailmh_folder * folder; + int res; + char filename_flags[PATH_MAX]; + struct mail_cache_db * cache_db_flags; + MMAPString * mmapstr; + struct mh_cached_session_state_data * cached_data; + unsigned int i; + int r; + + cached_data = get_cached_data(session); + if (cached_data->mh_quoted_mb == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + mh_flags_store_process(cached_data->mh_flags_directory, + cached_data->mh_quoted_mb, + cached_data->mh_flags_store); + + folder = get_mh_cur_folder(session); + if (folder == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + snprintf(filename_flags, PATH_MAX, "%s/%s/%s", + cached_data->mh_flags_directory, cached_data->mh_quoted_mb, FLAGS_NAME); + + r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); + if (r < 0) { + res = MAIL_ERROR_FILE; + goto err; + } + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto close_db_flags; + } + + for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i++) { + struct mailmh_msg_info * mh_info; + struct mail_flags * flags; + + mh_info = carray_get(folder->fl_msgs_tab, i); + if (mh_info == NULL) + continue; + + r = mhdriver_get_cached_flags(cache_db_flags, mmapstr, + session, mh_info->msg_index, &flags); + if (r != MAIL_NO_ERROR) + continue; + + if (flags->fl_flags & MAIL_FLAG_DELETED) { + r = mailmh_folder_remove_message(folder, mh_info->msg_index); + } + + mail_flags_free(flags); + } + + mmap_string_free(mmapstr); + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + + mailmh_folder_update(folder); + + return MAIL_NO_ERROR; + + close_db_flags: + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + err: + return res; +} + + +static int mhdriver_cached_status_folder(mailsession * session, char * mb, + uint32_t * result_messages, + uint32_t * result_recent, + uint32_t * result_unseen) +{ + struct mailmh_folder * folder; + int res; + char filename_flags[PATH_MAX]; + struct mail_cache_db * cache_db_flags; + MMAPString * mmapstr; + struct mh_cached_session_state_data * cached_data; + unsigned int i; + int r; + uint32_t count; + uint32_t recent; + uint32_t unseen; + + r = mhdriver_cached_select_folder(session, mb); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + count = 0; + recent = 0; + unseen = 0; + + folder = get_mh_cur_folder(session); + if (folder == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + cached_data = get_cached_data(session); + if (cached_data->mh_quoted_mb == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + snprintf(filename_flags, PATH_MAX, "%s/%s/%s", + cached_data->mh_flags_directory, + cached_data->mh_quoted_mb, FLAGS_NAME); + + r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); + if (r < 0) { + res = MAIL_ERROR_FILE; + goto err; + } + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto close_db_flags; + } + + for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i++) { + struct mailmh_msg_info * mh_info; + struct mail_flags * flags; + + mh_info = carray_get(folder->fl_msgs_tab, i); + if (mh_info == NULL) + continue; + + count ++; + + r = mhdriver_get_cached_flags(cache_db_flags, mmapstr, + session, mh_info->msg_index, + &flags); + + if (r != MAIL_NO_ERROR) { + recent ++; + unseen ++; + continue; + } + + if ((flags->fl_flags & MAIL_FLAG_NEW) != 0) { + recent ++; + } + if ((flags->fl_flags & MAIL_FLAG_SEEN) == 0) { + unseen ++; + } + mail_flags_free(flags); + } + + mmap_string_free(mmapstr); + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + + * result_messages = count; + * result_recent = recent; + * result_unseen = unseen; + + return MAIL_NO_ERROR; + + close_db_flags: + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + err: + return res; +} + +static int mhdriver_cached_messages_number(mailsession * session, char * mb, + uint32_t * result) +{ + return mailsession_messages_number(get_ancestor(session), mb, result); +} + +static int mhdriver_cached_recent_number(mailsession * session, char * mb, + uint32_t * result) +{ + uint32_t messages; + uint32_t recent; + uint32_t unseen; + int r; + + r = mhdriver_cached_status_folder(session, mb, &messages, &recent, &unseen); + if (r != MAIL_NO_ERROR) + return r; + + * result = recent; + + return MAIL_NO_ERROR; +} + + +static int mhdriver_cached_unseen_number(mailsession * session, char * mb, + uint32_t * result) +{ + uint32_t messages; + uint32_t recent; + uint32_t unseen; + int r; + + r = mhdriver_cached_status_folder(session, mb, &messages, &recent, &unseen); + if (r != MAIL_NO_ERROR) + return r; + + * result = recent; + + return MAIL_NO_ERROR; +} + + +static int mhdriver_cached_list_folders(mailsession * session, char * mb, + struct mail_list ** result) +{ + return mailsession_list_folders(get_ancestor(session), mb, result); +} + +static int mhdriver_cached_lsub_folders(mailsession * session, char * mb, + struct mail_list ** result) +{ + return mailsession_lsub_folders(get_ancestor(session), mb, result); +} + +static int mhdriver_cached_subscribe_folder(mailsession * session, char * mb) +{ + return mailsession_subscribe_folder(get_ancestor(session), mb); +} + +static int mhdriver_cached_unsubscribe_folder(mailsession * session, + char * mb) +{ + return mailsession_unsubscribe_folder(get_ancestor(session), mb); +} + +/* messages operations */ + +static int mhdriver_cached_append_message(mailsession * session, + char * message, size_t size) +{ + return mhdriver_cached_append_message_flags(session, + message, size, NULL); +} + +static int mhdriver_cached_append_message_flags(mailsession * session, + char * message, size_t size, struct mail_flags * flags) +{ + int r; + struct mailmh_folder * folder; + struct mailmh_msg_info * msg_info; + chashdatum key; + chashdatum value; + uint32_t uid; + struct mh_cached_session_state_data * data; + char filename_flags[PATH_MAX]; + struct mail_cache_db * cache_db_flags; + MMAPString * mmapstr; + char keyname[PATH_MAX]; + + folder = get_mh_cur_folder(session); + if (folder == NULL) + return MAIL_ERROR_BAD_STATE; + + r = mailmh_folder_add_message_uid(folder, + message, size, &uid); + + switch (r) { + case MAILMH_ERROR_FILE: + return MAIL_ERROR_DISKSPACE; + + case MAILMH_NO_ERROR: + break; + + default: + return mhdriver_mh_error_to_mail_error(r); + } + + if (flags == NULL) + goto exit; + + key.data = &uid; + key.len = sizeof(uid); + r = chash_get(folder->fl_msgs_hash, &key, &value); + if (r < 0) + return MAIL_ERROR_CACHE_MISS; + + msg_info = value.data; + + data = get_cached_data(session); + + snprintf(filename_flags, PATH_MAX, "%s/%s/%s", + data->mh_flags_directory, data->mh_quoted_mb, FLAGS_NAME); + + r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); + if (r < 0) + goto exit; + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) + goto close_db_flags; + + snprintf(keyname, PATH_MAX, "%u-%lu-%lu-flags", + uid, (unsigned long) msg_info->msg_mtime, + (unsigned long) msg_info->msg_size); + + r = mhdriver_write_cached_flags(cache_db_flags, mmapstr, keyname, flags); + + mmap_string_free(mmapstr); + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + + if (r != MAIL_NO_ERROR) + goto exit; + + return MAIL_NO_ERROR; + + close_db_flags: + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + exit: + return MAIL_NO_ERROR; +} + +static int mhdriver_cached_copy_message(mailsession * session, + uint32_t num, char * mb) +{ + return mailsession_copy_message(get_ancestor(session), num, mb); +} + +static int mhdriver_cached_remove_message(mailsession * session, uint32_t num) +{ + return mailsession_remove_message(get_ancestor(session), num); +} + +static int mhdriver_cached_move_message(mailsession * session, + uint32_t num, char * mb) +{ + return mailsession_move_message(get_ancestor(session), num, mb); +} + +static int +mhdriver_cached_get_messages_list(mailsession * session, + struct mailmessage_list ** result) +{ + struct mailmh_folder * folder; + int res; + + folder = get_mh_cur_folder(session); + if (folder == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + return mh_get_messages_list(folder, session, + mh_cached_message_driver, result); + + err: + return res; +} + + + +static int +get_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr, + mailsession * session, uint32_t num, + struct mailimf_fields ** result) +{ + int r; + char keyname[PATH_MAX]; + struct mailimf_fields * fields; + int res; + struct mailmh_folder * folder; + struct mailmh_msg_info * msg_info; + chashdatum key; + chashdatum data; + + folder = get_mh_cur_folder(session); + +#if 0 + msg_info = cinthash_find(mh_data->mh_cur_folder->fl_msgs_hash, num); + if (msg_info == NULL) + return MAIL_ERROR_CACHE_MISS; +#endif + key.data = # + key.len = sizeof(num); + r = chash_get(folder->fl_msgs_hash, &key, &data); + if (r < 0) + return MAIL_ERROR_CACHE_MISS; + msg_info = data.data; + + snprintf(keyname, PATH_MAX, "%u-%lu-%lu-envelope", + num, (unsigned long) msg_info->msg_mtime, + (unsigned long) msg_info->msg_size); + + r = generic_cache_fields_read(cache_db, mmapstr, keyname, &fields); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + * result = fields; + + return MAIL_NO_ERROR; + + err: + return res; +} + +static int +write_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr, + mailsession * session, uint32_t num, + struct mailimf_fields * fields) +{ + int r; + char keyname[PATH_MAX]; + int res; + struct mailmh_folder * folder; + chashdatum key; + chashdatum data; + struct mailmh_msg_info * msg_info; + + folder = get_mh_cur_folder(session); +#if 0 + msg_info = cinthash_find(mh_data->mh_cur_folder->fl_msgs_hash, num); + if (msg_info == NULL) { + res = MAIL_ERROR_CACHE_MISS; + goto err; + } +#endif + key.data = # + key.len = sizeof(num); + r = chash_get(folder->fl_msgs_hash, &key, &data); + if (r < 0) + return MAIL_ERROR_CACHE_MISS; + msg_info = data.data; + + snprintf(keyname, PATH_MAX, "%u-%lu-%lu-envelope", + num, (unsigned long) msg_info->msg_mtime, + (unsigned long) msg_info->msg_size); + + r = generic_cache_fields_write(cache_db, mmapstr, keyname, fields); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + return MAIL_NO_ERROR; + + err: + return res; +} + +static int +mhdriver_cached_get_envelopes_list(mailsession * session, + struct mailmessage_list * env_list) +{ + int r; + unsigned int i; + char filename_env[PATH_MAX]; + char filename_flags[PATH_MAX]; + struct mail_cache_db * cache_db_env; + struct mail_cache_db * cache_db_flags; + MMAPString * mmapstr; + int res; + struct mh_cached_session_state_data * cached_data; + + cached_data = get_cached_data(session); + if (cached_data->mh_quoted_mb == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + mh_flags_store_process(cached_data->mh_flags_directory, + cached_data->mh_quoted_mb, + cached_data->mh_flags_store); + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + snprintf(filename_env, PATH_MAX, "%s/%s/%s", + cached_data->mh_cache_directory, + cached_data->mh_quoted_mb, ENV_NAME); + + r = mail_cache_db_open_lock(filename_env, &cache_db_env); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_mmapstr; + } + + snprintf(filename_flags, PATH_MAX, "%s/%s/%s", + cached_data->mh_flags_directory, cached_data->mh_quoted_mb, FLAGS_NAME); + + r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto close_db_env; + } + + /* fill with cached */ + + for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { + mailmessage * msg; + struct mailimf_fields * fields; + struct mail_flags * flags; + + msg = carray_get(env_list->msg_tab, i); + + if (msg->msg_fields == NULL) { + r = get_cached_envelope(cache_db_env, mmapstr, + msg->msg_session, msg->msg_index, &fields); + if (r == MAIL_NO_ERROR) { + msg->msg_cached = TRUE; + msg->msg_fields = fields; + } + } + + if (msg->msg_flags == NULL) { + r = mhdriver_get_cached_flags(cache_db_flags, mmapstr, + session, msg->msg_index, &flags); + if (r == MAIL_NO_ERROR) { + msg->msg_flags = flags; + } + } + } + + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + mail_cache_db_close_unlock(filename_env, cache_db_env); + + r = mailsession_get_envelopes_list(get_ancestor(session), env_list); + + if (r != MAIL_NO_ERROR) { + res = r; + goto free_mmapstr; + } + + r = mail_cache_db_open_lock(filename_env, &cache_db_env); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_mmapstr; + } + + r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto close_db_env; + } + + /* add flags */ + + for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { + mailmessage * msg; + + msg = carray_get(env_list->msg_tab, i); + + if (msg->msg_flags == NULL) + msg->msg_flags = mail_flags_new_empty(); + } + + /* must write cache */ + + for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { + mailmessage * msg; + + msg = carray_get(env_list->msg_tab, i); + + if (msg->msg_fields != NULL) { + if (!msg->msg_cached) { + r = write_cached_envelope(cache_db_env, mmapstr, + session, msg->msg_index, msg->msg_fields); + } + } + + if (msg->msg_flags != NULL) { + r = mhdriver_write_cached_flags(cache_db_flags, mmapstr, + msg->msg_uid, msg->msg_flags); + } + } + + /* flush cache */ + + maildriver_cache_clean_up(cache_db_env, cache_db_flags, env_list); + + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + mail_cache_db_close_unlock(filename_env, cache_db_env); + + mmap_string_free(mmapstr); + + return MAIL_NO_ERROR; + + close_db_env: + mail_cache_db_close_unlock(filename_env, cache_db_env); + free_mmapstr: + mmap_string_free(mmapstr); + err: + return res; +} + +static int mhdriver_cached_get_message(mailsession * session, + uint32_t num, mailmessage ** result) +{ + mailmessage * msg_info; + int r; + + msg_info = mailmessage_new(); + if (msg_info == NULL) + return MAIL_ERROR_MEMORY; + + r = mailmessage_init(msg_info, session, mh_cached_message_driver, num, 0); + if (r != MAIL_NO_ERROR) + return r; + + * result = msg_info; + + return MAIL_NO_ERROR; +} + +static int mhdriver_cached_get_message_by_uid(mailsession * session, + const char * uid, + mailmessage ** result) +{ + uint32_t index; + char *p; + struct mailmh_msg_info * mh_msg_info; + struct mailmh_folder * folder; + time_t mtime; + char * mtime_p; + chashdatum key; + chashdatum data; + int r; + + if (uid == NULL) + return MAIL_ERROR_INVAL; + + index = strtoul(uid, &p, 10); + if (p == uid || * p != '-') + return MAIL_ERROR_INVAL; + + folder = get_mh_cur_folder(session); + + mh_msg_info = NULL; + key.data = &index; + key.len = sizeof(index); + r = chash_get(folder->fl_msgs_hash, &key, &data); + if (r < 0) + return MAIL_ERROR_MSG_NOT_FOUND; + + mh_msg_info = data.data; + + mtime_p = p + 1; + + mtime = strtoul(mtime_p, &p, 10); + if ((* p == '-') && (mtime == mh_msg_info->msg_mtime)) { + size_t size; + char *size_p; + + size_p = p + 1; + size = strtoul(size_p, &p, 10); + if ((* p == '\0') && (size == mh_msg_info->msg_size)) + return mhdriver_cached_get_message(session, index, result); + } + else if (*p != '-') { + return MAIL_ERROR_INVAL; + } + + return MAIL_ERROR_MSG_NOT_FOUND; +} diff --git a/libetpan/src/driver/implementation/mh/mhdriver_cached.h b/libetpan/src/driver/implementation/mh/mhdriver_cached.h new file mode 100644 index 0000000..d2e5803 --- a/dev/null +++ b/libetpan/src/driver/implementation/mh/mhdriver_cached.h @@ -0,0 +1,52 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MHDRIVER_CACHED_H + +#define MHDRIVER_CACHED_H + +#include <libetpan/mhdriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailsession_driver * mh_cached_session_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/mh/mhdriver_cached_message.c b/libetpan/src/driver/implementation/mh/mhdriver_cached_message.c new file mode 100644 index 0000000..a59beea --- a/dev/null +++ b/libetpan/src/driver/implementation/mh/mhdriver_cached_message.c @@ -0,0 +1,338 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "mhdriver_message.h" + +#include "mailmessage_tools.h" +#include "mhdriver_tools.h" +#include "mhdriver_cached.h" +#include "mailmh.h" +#include "generic_cache.h" + +#include "mail_cache_db.h" + +#include <unistd.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <stdlib.h> + +static int mh_prefetch(mailmessage * msg_info); + +static void mh_prefetch_free(struct generic_message_t * msg); + +static int mh_initialize(mailmessage * msg_info); + +static int mh_fetch_size(mailmessage * msg_info, + size_t * result); + +static int mh_get_flags(mailmessage * msg_info, + struct mail_flags ** result); + +static void mh_uninitialize(mailmessage * msg_info); + +static void mh_flush(mailmessage * msg_info); + +static void mh_check(mailmessage * msg_info); + +static int mh_fetch_header(mailmessage * msg_info, + char ** result, + size_t * result_len); + +static mailmessage_driver local_mh_cached_message_driver = { + .msg_name = "mh-cached", + + .msg_initialize = mh_initialize, + .msg_uninitialize = mh_uninitialize, + + .msg_flush = mh_flush, + .msg_check = mh_check, + + .msg_fetch_result_free = mailmessage_generic_fetch_result_free, + + .msg_fetch = mailmessage_generic_fetch, + .msg_fetch_header = mh_fetch_header, + .msg_fetch_body = mailmessage_generic_fetch_body, + .msg_fetch_size = mh_fetch_size, + .msg_get_bodystructure = mailmessage_generic_get_bodystructure, + .msg_fetch_section = mailmessage_generic_fetch_section, + .msg_fetch_section_header = mailmessage_generic_fetch_section_header, + .msg_fetch_section_mime = mailmessage_generic_fetch_section_mime, + .msg_fetch_section_body = mailmessage_generic_fetch_section_body, + .msg_fetch_envelope = mailmessage_generic_fetch_envelope, + + .msg_get_flags = mh_get_flags, +}; + +mailmessage_driver * mh_cached_message_driver = +&local_mh_cached_message_driver; + +static inline struct mh_cached_session_state_data * +get_cached_session_data(mailmessage * msg) +{ + return msg->msg_session->sess_data; +} + +static inline mailsession * get_ancestor_session(mailmessage * msg) +{ + return get_cached_session_data(msg)->mh_ancestor; +} + +static inline struct mh_session_state_data * +get_ancestor_session_data(mailmessage * msg) +{ + return get_ancestor_session(msg)->sess_data; +} + +static inline struct mailmh * +get_mh_session(mailmessage * msg) +{ + return get_ancestor_session_data(msg)->mh_session; +} + +static inline struct mailmh_folder * +get_mh_cur_folder(mailmessage * msg) +{ + return get_ancestor_session_data(msg)->mh_cur_folder; +} + +static int mh_prefetch(mailmessage * msg_info) +{ + struct generic_message_t * msg; + int r; + char * msg_content; + size_t msg_length; + + r = mhdriver_fetch_message(get_ancestor_session(msg_info), + msg_info->msg_index, &msg_content, &msg_length); + if (r != MAIL_NO_ERROR) + return r; + + msg = msg_info->msg_data; + + msg->msg_message = msg_content; + msg->msg_length = msg_length; + + return MAIL_NO_ERROR; +} + +static void mh_prefetch_free(struct generic_message_t * msg) +{ + if (msg->msg_message != NULL) { + mmap_string_unref(msg->msg_message); + msg->msg_message = NULL; + } +} + +static int mh_initialize(mailmessage * msg_info) +{ + struct generic_message_t * msg; + int r; + char * uid; + char static_uid[PATH_MAX]; + struct mailmh_msg_info * mh_msg_info; + chashdatum key; + chashdatum data; + struct mailmh_folder * folder; + + folder = get_mh_cur_folder(msg_info); + + key.data = &msg_info->msg_index; + key.len = sizeof(msg_info->msg_index); + r = chash_get(folder->fl_msgs_hash, &key, &data); + if (r < 0) + return MAIL_ERROR_INVAL; + + mh_msg_info = data.data; + + snprintf(static_uid, PATH_MAX, "%u-%lu-%lu", msg_info->msg_index, + mh_msg_info->msg_mtime, (unsigned long) mh_msg_info->msg_size); + uid = strdup(static_uid); + if (uid == NULL) + return MAIL_ERROR_MEMORY; + + r = mailmessage_generic_initialize(msg_info); + if (r != MAIL_NO_ERROR) { + free(uid); + return r; + } + + msg = msg_info->msg_data; + msg->msg_prefetch = mh_prefetch; + msg->msg_prefetch_free = mh_prefetch_free; + msg_info->msg_uid = uid; + + return MAIL_NO_ERROR; +} + +static void mh_uninitialize(mailmessage * msg_info) +{ + mailmessage_generic_uninitialize(msg_info); +} + + +#define FLAGS_NAME "flags.db" + +static void mh_flush(mailmessage * msg_info) +{ + mailmessage_generic_flush(msg_info); +} + +static void mh_check(mailmessage * msg_info) +{ + int r; + + if (msg_info->msg_flags != NULL) { + r = mail_flags_store_set(get_cached_session_data(msg_info)->mh_flags_store, + msg_info); + /* ignore errors */ + } +} + +static int mh_fetch_size(mailmessage * msg_info, + size_t * result) +{ + int r; + size_t size; + + r = mhdriver_fetch_size(get_ancestor_session(msg_info), + msg_info->msg_index, &size); + if (r != MAIL_NO_ERROR) + return r; + + * result = size; + + return MAIL_NO_ERROR; +} + +static int mh_get_flags(mailmessage * msg_info, + struct mail_flags ** result) +{ + int r; + struct mail_flags * flags; + struct mail_cache_db * cache_db_flags; + char filename_flags[PATH_MAX]; + int res; + struct mh_cached_session_state_data * cached_data; + MMAPString * mmapstr; + + if (msg_info->msg_flags != NULL) { + * result = msg_info->msg_flags; + + return MAIL_NO_ERROR; + } + + cached_data = get_cached_session_data(msg_info); + + flags = mail_flags_store_get(cached_data->mh_flags_store, + msg_info->msg_index); + + if (flags == NULL) { + if (cached_data->mh_quoted_mb == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + snprintf(filename_flags, PATH_MAX, "%s/%s/%s", + cached_data->mh_flags_directory, + cached_data->mh_quoted_mb, FLAGS_NAME); + + r = mail_cache_db_open_lock(filename_flags, &cache_db_flags); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + mmapstr = mmap_string_new(""); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto close_db_flags; + } + + r = mhdriver_get_cached_flags(cache_db_flags, mmapstr, + msg_info->msg_session, msg_info->msg_index, &flags); + if (r != MAIL_NO_ERROR) { + flags = mail_flags_new_empty(); + if (flags == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_mmapstr; + } + } + + mmap_string_free(mmapstr); + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + } + + msg_info->msg_flags = flags; + + * result = flags; + + return MAIL_NO_ERROR; + + free_mmapstr: + mmap_string_free(mmapstr); + close_db_flags: + mail_cache_db_close_unlock(filename_flags, cache_db_flags); + err: + return res; +} + +static int mh_fetch_header(mailmessage * msg_info, + char ** result, + size_t * result_len) +{ + struct generic_message_t * msg; + int r; + char * msg_content; + size_t msg_length; + + msg = msg_info->msg_data; + if (msg->msg_message != NULL) { + return mailmessage_generic_fetch_header(msg_info, result, result_len); + } + else { + r = mhdriver_fetch_header(get_ancestor_session(msg_info), + msg_info->msg_index, &msg_content, &msg_length); + if (r != MAIL_NO_ERROR) + return r; + + * result = msg_content; + * result_len = msg_length; + + return MAIL_NO_ERROR; + } +} diff --git a/libetpan/src/driver/implementation/mh/mhdriver_cached_message.h b/libetpan/src/driver/implementation/mh/mhdriver_cached_message.h new file mode 100644 index 0000000..f585708 --- a/dev/null +++ b/libetpan/src/driver/implementation/mh/mhdriver_cached_message.h @@ -0,0 +1,52 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MHDRIVER_CACHED_MESSAGE_H + +#define MHDRIVER_CACHED_MESSAGE_H + +#include <libetpan/mhdriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailmessage_driver * mh_cached_message_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/mh/mhdriver_message.c b/libetpan/src/driver/implementation/mh/mhdriver_message.c new file mode 100644 index 0000000..0e486b4 --- a/dev/null +++ b/libetpan/src/driver/implementation/mh/mhdriver_message.c @@ -0,0 +1,213 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "mhdriver_message.h" + +#include "mailmessage_tools.h" +#include "mhdriver_tools.h" +#include "mhdriver.h" +#include "mailmh.h" + +#include <unistd.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <stdlib.h> + +static int mh_prefetch(mailmessage * msg_info); + +static void mh_prefetch_free(struct generic_message_t * msg); + +static int mh_initialize(mailmessage * msg_info); + +static int mh_fetch_size(mailmessage * msg_info, + size_t * result); + +static int mh_fetch_header(mailmessage * msg_info, + char ** result, + size_t * result_len); + +static mailmessage_driver local_mh_message_driver = { + .msg_name = "mh", + + .msg_initialize = mh_initialize, + .msg_uninitialize = mailmessage_generic_uninitialize, + + .msg_flush = mailmessage_generic_flush, + .msg_check = NULL, + + .msg_fetch_result_free = mailmessage_generic_fetch_result_free, + + .msg_fetch = mailmessage_generic_fetch, + .msg_fetch_header = mh_fetch_header, + .msg_fetch_body = mailmessage_generic_fetch_body, + .msg_fetch_size = mh_fetch_size, + .msg_get_bodystructure = mailmessage_generic_get_bodystructure, + .msg_fetch_section = mailmessage_generic_fetch_section, + .msg_fetch_section_header = mailmessage_generic_fetch_section_header, + .msg_fetch_section_mime = mailmessage_generic_fetch_section_mime, + .msg_fetch_section_body = mailmessage_generic_fetch_section_body, + .msg_fetch_envelope = mailmessage_generic_fetch_envelope, + + .msg_get_flags = NULL, +}; + +mailmessage_driver * mh_message_driver = &local_mh_message_driver; + +static int mh_prefetch(mailmessage * msg_info) +{ + struct generic_message_t * msg; + int r; + char * msg_content; + size_t msg_length; + + r = mhdriver_fetch_message(msg_info->msg_session, msg_info->msg_index, + &msg_content, &msg_length); + if (r != MAIL_NO_ERROR) + return r; + + msg = msg_info->msg_data; + + msg->msg_message = msg_content; + msg->msg_length = msg_length; + + return MAIL_NO_ERROR; +} + +static void mh_prefetch_free(struct generic_message_t * msg) +{ + if (msg->msg_message != NULL) { + mmap_string_unref(msg->msg_message); + msg->msg_message = NULL; + } +} + +static inline struct mh_session_state_data * get_data(mailmessage * msg) +{ + return msg->msg_session->sess_data; +} + +static inline struct mailmh_folder * get_mh_cur_folder(mailmessage * msg) +{ + return get_data(msg)->mh_cur_folder; +} + +static int mh_initialize(mailmessage * msg_info) +{ + struct generic_message_t * msg; + int r; + char * uid; + char static_uid[PATH_MAX]; + struct mailmh_msg_info * mh_msg_info; + chashdatum key; + chashdatum value; + + key.data = &msg_info->msg_index; + key.len = sizeof(msg_info->msg_index); + r = chash_get(get_mh_cur_folder(msg_info)->fl_msgs_hash, &key, &value); + if (r < 0) + return MAIL_ERROR_INVAL; + + mh_msg_info = value.data; + + snprintf(static_uid, PATH_MAX, "%u-%lu-%lu", msg_info->msg_index, + (unsigned long) mh_msg_info->msg_mtime, + (unsigned long) mh_msg_info->msg_size); + uid = strdup(static_uid); + if (uid == NULL) + return MAIL_ERROR_MEMORY; + + r = mailmessage_generic_initialize(msg_info); + if (r != MAIL_NO_ERROR) { + free(uid); + return r; + } + + msg = msg_info->msg_data; + msg->msg_prefetch = mh_prefetch; + msg->msg_prefetch_free = mh_prefetch_free; + msg_info->msg_uid = uid; + + return MAIL_NO_ERROR; +} + + +static int mh_fetch_size(mailmessage * msg_info, + size_t * result) +{ + int r; + size_t size; + + r = mhdriver_fetch_size(msg_info->msg_session, msg_info->msg_index, &size); + if (r != MAIL_NO_ERROR) + return r; + + * result = size; + + return MAIL_NO_ERROR; +} + + + + +static int mh_fetch_header(mailmessage * msg_info, + char ** result, + size_t * result_len) +{ + struct generic_message_t * msg; + int r; + char * msg_content; + size_t msg_length; + + msg = msg_info->msg_data; + if (msg->msg_message != NULL) { + + r = mailmessage_generic_fetch_header(msg_info, result, result_len); + return r; + } + else { + r = mhdriver_fetch_header(msg_info->msg_session, msg_info->msg_index, + &msg_content, &msg_length); + if (r != MAIL_NO_ERROR) + return r; + + * result = msg_content; + * result_len = msg_length; + + return MAIL_NO_ERROR; + } +} diff --git a/libetpan/src/driver/implementation/mh/mhdriver_message.h b/libetpan/src/driver/implementation/mh/mhdriver_message.h new file mode 100644 index 0000000..2b11f3e --- a/dev/null +++ b/libetpan/src/driver/implementation/mh/mhdriver_message.h @@ -0,0 +1,52 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MHDRIVER_MESSAGE_H + +#define MHDRIVER_MESSAGE_H + +#include <libetpan/mhdriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailmessage_driver * mh_message_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/mh/mhdriver_tools.c b/libetpan/src/driver/implementation/mh/mhdriver_tools.c new file mode 100644 index 0000000..b8bcf03 --- a/dev/null +++ b/libetpan/src/driver/implementation/mh/mhdriver_tools.c @@ -0,0 +1,484 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "mhdriver_tools.h" + +#include "mailmessage.h" +#include "mhdriver.h" +#include "mhdriver_cached.h" +#include "maildriver_types.h" +#include "mailmh.h" +#include "generic_cache.h" +#include "imfcache.h" +#include "mail_cache_db.h" + +#include <unistd.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <string.h> +#include <stdlib.h> + +int mhdriver_mh_error_to_mail_error(int error) +{ + switch (error) { + case MAILMH_NO_ERROR: + return MAIL_NO_ERROR; + + case MAILMH_ERROR_FOLDER: + return MAIL_ERROR_FOLDER; + + case MAILMH_ERROR_MEMORY: + return MAIL_ERROR_MEMORY; + + case MAILMH_ERROR_FILE: + return MAIL_ERROR_FILE; + + case MAILMH_ERROR_COULD_NOT_ALLOC_MSG: + return MAIL_ERROR_APPEND; + + case MAILMH_ERROR_RENAME: + return MAIL_ERROR_RENAME; + + case MAILMH_ERROR_MSG_NOT_FOUND: + return MAIL_ERROR_MSG_NOT_FOUND; + + default: + return MAIL_ERROR_INVAL; + } +} + + +static inline struct mh_session_state_data * get_data(mailsession * session) +{ + return session->sess_data; +} + +static inline struct mailmh_folder * get_mh_cur_folder(mailsession * session) +{ + return get_data(session)->mh_cur_folder; +} + +static inline struct mh_cached_session_state_data * +cached_get_data(mailsession * session) +{ + return session->sess_data; +} + + +static inline mailsession * cached_get_ancestor(mailsession * session) +{ + return cached_get_data(session)->mh_ancestor; +} + +static inline struct mh_session_state_data * +cached_get_ancestor_data(mailsession * session) +{ + return get_data(cached_get_ancestor(session)); +} + +static inline struct mailmh_folder * +cached_get_mh_cur_folder(mailsession * session) +{ + return get_mh_cur_folder(cached_get_ancestor(session)); +} + +int mhdriver_fetch_message(mailsession * session, uint32_t index, + char ** result, size_t * result_len) +{ + size_t size; + size_t cur_token; + struct mailmh_folder * folder; + int fd; + MMAPString * mmapstr; + char * str; + int res; + int r; + + folder = get_mh_cur_folder(session); + if (folder == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + r = mailmh_folder_get_message_fd(folder, index, O_RDONLY, &fd); + + switch (r) { + case MAILMH_NO_ERROR: + break; + + default: + res = mhdriver_mh_error_to_mail_error(r); + goto close; + } + + r = mhdriver_fetch_size(session, index, &size); + + switch (r) { + case MAILMH_NO_ERROR: + break; + + default: + res = mhdriver_mh_error_to_mail_error(r); + goto close; + } + + str = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); + if (str == MAP_FAILED) { + res = MAIL_ERROR_FETCH; + goto close; + } + + /* strip "From " header for broken implementations */ + /* XXX - called twice, make a function */ + cur_token = 0; + if (strncmp("From ", str, 5) == 0) { + cur_token += 5; + + while (1) { + if (str[cur_token] == '\n') { + cur_token ++; + break; + } + if (cur_token >= size) + break; + cur_token ++; + } + } + + mmapstr = mmap_string_new_len(str + cur_token, size - cur_token); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto unmap; + } + + if (mmap_string_ref(mmapstr) != 0) { + res = MAIL_ERROR_MEMORY; + goto free_str; + } + + munmap(str, size); + close(fd); + + * result = mmapstr->str; + * result_len = mmapstr->len; + + return MAIL_NO_ERROR; + + free_str: + mmap_string_free(mmapstr); + unmap: + munmap(str, size); + close: + close(fd); + err: + return res; +} + + +int mhdriver_fetch_header(mailsession * session, uint32_t index, + char ** result, size_t * result_len) +{ + size_t size; + size_t cur_token; + size_t begin; + struct mailmh_folder * folder; + int fd; + MMAPString * mmapstr; + char * str; + int res; + int r; + + folder = get_mh_cur_folder(session); + if (folder == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + r = mailmh_folder_get_message_fd(folder, index, O_RDONLY, &fd); + + switch (r) { + case MAILMH_NO_ERROR: + break; + + default: + res = mhdriver_mh_error_to_mail_error(r); + goto close; + } + + r = mhdriver_fetch_size(session, index, &size); + + switch (r) { + case MAILMH_NO_ERROR: + break; + + default: + res = mhdriver_mh_error_to_mail_error(r); + goto close; + } + + str = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, 0); + if (str == MAP_FAILED) { + res = MAIL_ERROR_FETCH; + goto close; + } + + /* strip "From " header for broken implementations */ + cur_token = 0; + if (size > 5) { + if (strncmp("From ", str, 5) == 0) { + cur_token += 5; + + while (1) { + if (str[cur_token] == '\n') { + cur_token ++; + break; + } + if (cur_token >= size) + break; + cur_token ++; + } + } + } + + begin = cur_token; + + while (1) { + r = mailimf_ignore_field_parse(str, size, &cur_token); + if (r == MAILIMF_NO_ERROR) { + /* do nothing */ + } + else + break; + } + mailimf_crlf_parse(str, size, &cur_token); + + mmapstr = mmap_string_new_len(str + begin, cur_token - begin); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto unmap; + } + + if (mmap_string_ref(mmapstr) != 0) { + res = MAIL_ERROR_MEMORY; + goto free_str; + } + + munmap(str, size); + close(fd); + + * result = mmapstr->str; + * result_len = mmapstr->len; + + return MAIL_NO_ERROR; + + free_str: + mmap_string_free(mmapstr); + unmap: + munmap(str, size); + close: + close(fd); + err: + return res; +} + + +int mhdriver_fetch_size(mailsession * session, uint32_t index, + size_t * result) +{ + struct mailmh_folder * folder; + int r; + struct stat buf; + char * name; + + folder = get_mh_cur_folder(session); + if (folder == NULL) + return MAIL_ERROR_FETCH; + + r = mailmh_folder_get_message_filename(folder, index, &name); + + switch (r) { + case MAILMH_NO_ERROR: + break; + + default: + return mhdriver_mh_error_to_mail_error(r); + } + + r = stat(name, &buf); + free(name); + if (r == -1) + return MAIL_ERROR_FETCH; + + * result = buf.st_size; + + return MAIL_NO_ERROR; +} + +int +mhdriver_get_cached_flags(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + mailsession * session, + uint32_t num, + struct mail_flags ** result) +{ + int r; + char keyname[PATH_MAX]; + struct mail_flags * flags; + int res; + struct mailmh_msg_info * msg_info; + chashdatum key; + chashdatum data; + struct mailmh_folder * folder; + + folder = cached_get_mh_cur_folder(session); +#if 0 + msg_info = cinthash_find(mh_data->cur_folder->fl_msgs_hash, num); + if (msg_info == NULL) + return MAIL_ERROR_CACHE_MISS; +#endif + key.data = # + key.len = sizeof(num); + r = chash_get(folder->fl_msgs_hash, &key, &data); + if (r < 0) + return MAIL_ERROR_CACHE_MISS; + msg_info = data.data; + + snprintf(keyname, PATH_MAX, "%u-%lu-%lu-flags", + num, (unsigned long) msg_info->msg_mtime, + (unsigned long) msg_info->msg_size); + + r = generic_cache_flags_read(cache_db, mmapstr, keyname, &flags); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + * result = flags; + + return MAIL_NO_ERROR; + + err: + return res; +} + +int +mhdriver_write_cached_flags(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + char * uid, + struct mail_flags * flags) +{ + int r; + char keyname[PATH_MAX]; + int res; + + snprintf(keyname, PATH_MAX, "%s-flags", uid); + + r = generic_cache_flags_write(cache_db, mmapstr, keyname, flags); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + return MAIL_NO_ERROR; + + err: + return res; +} + + +int mh_get_messages_list(struct mailmh_folder * folder, + mailsession * session, mailmessage_driver * driver, + struct mailmessage_list ** result) +{ + unsigned int i; + struct mailmessage_list * env_list; + int r; + carray * tab; + int res; + + tab = carray_new(128); + if (tab == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i++) { + struct mailmh_msg_info * mh_info; + mailmessage * msg; + + mh_info = carray_get(folder->fl_msgs_tab, i); + if (mh_info == NULL) + continue; + + msg = mailmessage_new(); + if (msg == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_list; + } + + r = mailmessage_init(msg, session, driver, + mh_info->msg_index, mh_info->msg_size); + if (r != MAIL_NO_ERROR) { + res = r; + goto free_list; + } + + r = carray_add(tab, msg, NULL); + if (r < 0) { + mailmessage_free(msg); + res = MAIL_ERROR_MEMORY; + goto free_list; + } + } + + env_list = mailmessage_list_new(tab); + if (env_list == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_list; + } + + * result = env_list; + + return MAIL_NO_ERROR; + + free_list: + for(i = 0 ; i < carray_count(tab) ; i ++) + mailmessage_free(carray_get(tab, i)); + carray_free(tab); + err: + return res; +} diff --git a/libetpan/src/driver/implementation/mh/mhdriver_tools.h b/libetpan/src/driver/implementation/mh/mhdriver_tools.h new file mode 100644 index 0000000..7b8928e --- a/dev/null +++ b/libetpan/src/driver/implementation/mh/mhdriver_tools.h @@ -0,0 +1,80 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MHDRIVER_TOOLS_H + +#define MHDRIVER_TOOLS_H + +#include "maildriver_types.h" +#include "mail_cache_db_types.h" +#include "mailmh.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int mhdriver_mh_error_to_mail_error(int error); + +int mhdriver_fetch_message(mailsession * session, uint32_t index, + char ** result, size_t * result_len); + +int mhdriver_fetch_header(mailsession * session, uint32_t index, + char ** result, size_t * result_len); + +int mhdriver_fetch_size(mailsession * session, uint32_t index, + size_t * result); + +int +mhdriver_get_cached_flags(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + mailsession * session, + uint32_t num, + struct mail_flags ** result); + +int +mhdriver_write_cached_flags(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + char * uid, + struct mail_flags * flags); + +int mh_get_messages_list(struct mailmh_folder * folder, + mailsession * session, mailmessage_driver * driver, + struct mailmessage_list ** result); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/mh/mhdriver_types.h b/libetpan/src/driver/implementation/mh/mhdriver_types.h new file mode 100644 index 0000000..45afb64 --- a/dev/null +++ b/libetpan/src/driver/implementation/mh/mhdriver_types.h @@ -0,0 +1,100 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MHDRIVER_TYPES_H + +#define MHDRIVER_TYPES_H + +#include <libetpan/libetpan-config.h> + +#include <libetpan/maildriver_types.h> +#include <libetpan/mailmh.h> +#include <libetpan/clist.h> +#include <libetpan/generic_cache_types.h> +#include <libetpan/mailstorage_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct mh_session_state_data { + struct mailmh * mh_session; + + struct mailmh_folder * mh_cur_folder; + + clist * mh_subscribed_list; +}; + +enum { + MHDRIVER_CACHED_SET_CACHE_DIRECTORY = 1, + MHDRIVER_CACHED_SET_FLAGS_DIRECTORY, +}; + +struct mh_cached_session_state_data { + mailsession * mh_ancestor; + char * mh_quoted_mb; + char mh_cache_directory[PATH_MAX]; + char mh_flags_directory[PATH_MAX]; + struct mail_flags_store * mh_flags_store; +}; + +/* mh storage */ + +/* + mh_mailstorage is the state data specific to the MH storage. + + - pathname is the root path of the MH storage. + + - cached if this value is != 0, a persistant cache will be + stored on local system. + + - cache_directory is the location of the cache. + + - flags_directory is the location of the flags. +*/ + +struct mh_mailstorage { + char * mh_pathname; + + int mh_cached; + char * mh_cache_directory; + char * mh_flags_directory; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/mh/mhstorage.c b/libetpan/src/driver/implementation/mh/mhstorage.c new file mode 100644 index 0000000..e7fc2f0 --- a/dev/null +++ b/libetpan/src/driver/implementation/mh/mhstorage.c @@ -0,0 +1,192 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "mhstorage.h" + +#include "mhdriver.h" +#include "mhdriver_cached.h" +#include "mail.h" + +#include <stdlib.h> +#include <string.h> + +/* mh storage */ + +static int mh_mailstorage_connect(struct mailstorage * storage); +static int mh_mailstorage_get_folder_session(struct mailstorage * storage, + char * pathname, mailsession ** result); +static void mh_mailstorage_uninitialize(struct mailstorage * storage); + +static mailstorage_driver mh_mailstorage_driver = { + .sto_name = "mh", + .sto_connect = mh_mailstorage_connect, + .sto_get_folder_session = mh_mailstorage_get_folder_session, + .sto_uninitialize = mh_mailstorage_uninitialize, +}; + +int mh_mailstorage_init(struct mailstorage * storage, + char * mh_pathname, int mh_cached, + char * mh_cache_directory, char * mh_flags_directory) +{ + struct mh_mailstorage * mh_storage; + + mh_storage = malloc(sizeof(* mh_storage)); + if (mh_storage == NULL) + goto err; + + mh_storage->mh_pathname = strdup(mh_pathname); + if (mh_storage->mh_pathname == NULL) + goto free; + + mh_storage->mh_cached = mh_cached; + + if (mh_cached && (mh_cache_directory != NULL) && + (mh_flags_directory != NULL)) { + mh_storage->mh_cache_directory = strdup(mh_cache_directory); + if (mh_storage->mh_cache_directory == NULL) + goto free_pathname; + mh_storage->mh_flags_directory = strdup(mh_flags_directory); + if (mh_storage->mh_flags_directory == NULL) + goto free_cache_directory; + } + else { + mh_storage->mh_cached = FALSE; + mh_storage->mh_cache_directory = NULL; + mh_storage->mh_flags_directory = NULL; + } + + storage->sto_data = mh_storage; + storage->sto_driver = &mh_mailstorage_driver; + + return MAIL_NO_ERROR; + + free_cache_directory: + free(mh_storage->mh_cache_directory); + free_pathname: + free(mh_storage->mh_pathname); + free: + free(mh_storage); + err: + return MAIL_ERROR_MEMORY; +} + +static void mh_mailstorage_uninitialize(struct mailstorage * storage) +{ + struct mh_mailstorage * mh_storage; + + mh_storage = storage->sto_data; + if (mh_storage->mh_flags_directory != NULL) + free(mh_storage->mh_flags_directory); + if (mh_storage->mh_cache_directory != NULL) + free(mh_storage->mh_cache_directory); + free(mh_storage->mh_pathname); + free(mh_storage); + + storage->sto_data = NULL; +} + +static int mh_mailstorage_connect(struct mailstorage * storage) +{ + struct mh_mailstorage * mh_storage; + mailsession_driver * driver; + int r; + int res; + mailsession * session; + + mh_storage = storage->sto_data; + + if (mh_storage->mh_cached) + driver = mh_cached_session_driver; + else + driver = mh_session_driver; + + session = mailsession_new(driver); + if (session == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + if (mh_storage->mh_cached) { + r = mailsession_parameters(session, + MHDRIVER_CACHED_SET_CACHE_DIRECTORY, + mh_storage->mh_cache_directory); + if (r != MAIL_NO_ERROR) { + res = r; + goto free; + } + + r = mailsession_parameters(session, + MHDRIVER_CACHED_SET_FLAGS_DIRECTORY, + mh_storage->mh_flags_directory); + if (r != MAIL_NO_ERROR) { + res = r; + goto free; + } + } + + r = mailsession_connect_path(session, mh_storage->mh_pathname); + switch (r) { + case MAIL_NO_ERROR_NON_AUTHENTICATED: + case MAIL_NO_ERROR_AUTHENTICATED: + case MAIL_NO_ERROR: + break; + default: + res = r; + goto free; + } + + storage->sto_session = session; + + return MAIL_NO_ERROR; + + free: + mailsession_free(session); + err: + return res; +} + +static int mh_mailstorage_get_folder_session(struct mailstorage * storage, + char * pathname, mailsession ** result) +{ + int r; + + r = mailsession_select_folder(storage->sto_session, pathname); + if (r != MAIL_NO_ERROR) + return r; + + * result = storage->sto_session; + + return MAIL_NO_ERROR; +} diff --git a/libetpan/src/driver/implementation/mh/mhstorage.h b/libetpan/src/driver/implementation/mh/mhstorage.h new file mode 100644 index 0000000..be86007 --- a/dev/null +++ b/libetpan/src/driver/implementation/mh/mhstorage.h @@ -0,0 +1,67 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MHSTORAGE_H + +#define MHSTORAGE_H + +#include <libetpan/mhdriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + mh_mailstorage_init is the constructor for a MH storage + + @param pathname is the filename the root path of the MH storage. + + @param cached if this value is != 0, a persistant cache will be + stored on local system. + + @param cache_directory is the location of the cache. + + @param flags_directory is the location of the flags. +*/ + +int mh_mailstorage_init(struct mailstorage * storage, + char * mh_pathname, int mh_cached, + char * mh_cache_directory, char * mh_flags_directory); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/mime-message/mime_message_driver.c b/libetpan/src/driver/implementation/mime-message/mime_message_driver.c new file mode 100644 index 0000000..06defbd --- a/dev/null +++ b/libetpan/src/driver/implementation/mime-message/mime_message_driver.c @@ -0,0 +1,914 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "mime_message_driver.h" + +#include "libetpan-config.h" + +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <sys/mman.h> +#include <stdlib.h> +#include <string.h> + +#include "mailmessage.h" +#include "mailmessage_tools.h" +#include "maildriver_tools.h" + +#if 0 +static FILE * get_mime_tmp_file(mailmessage * msg, + char * filename, size_t size) +{ + int fd; + mode_t old_mask; + FILE * f; + + if (msg->msg_data == NULL) + return NULL; + + snprintf(filename, size, "%s/libetpan-mime-XXXXXX", + (char *) msg->msg_data); + + old_mask = umask(0077); + fd = mkstemp(filename); + umask(old_mask); + if (fd == -1) + return NULL; + + f = fdopen(fd, "r+"); + if (f == NULL) { + close(fd); + unlink(filename); + } + + return f; +} +#endif + +int mime_message_set_tmpdir(mailmessage * msg, char * tmpdir) +{ +#if 0 + if (msg->msg_data != NULL) + free(msg->msg_data); + + msg->msg_data = strdup(tmpdir); + if (msg->msg_data == NULL) + return MAIL_ERROR_MEMORY; + +#endif + return MAIL_NO_ERROR; +} + +void mime_message_detach_mime(mailmessage * msg) +{ + msg->msg_mime = NULL; +} + +mailmessage * mime_message_init(struct mailmime * mime) +{ + mailmessage * msg; + int r; + + msg = mailmessage_new(); + if (msg == NULL) + goto err; + + r = mailmessage_init(msg, NULL, mime_message_driver, 0, 0); + if (r != MAIL_NO_ERROR) + goto free; + + if (mime != NULL) { + mailmime_free(msg->msg_mime); + msg->msg_mime = mime; + } + + return msg; + + free: + mailmessage_free(msg); + err: + return NULL; +} + +static int initialize(mailmessage * msg) +{ + struct mailmime * mime; + int res; + + mime = mailmime_new_message_data(NULL); + if (mime == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + msg->msg_mime = mime; + + return MAIL_NO_ERROR; + + err: + return res; +} + +static void uninitialize(mailmessage * msg) +{ + /* tmp dir name */ + if (msg->msg_data != NULL) + free(msg->msg_data); + + if (msg->msg_mime != NULL) + mailmime_free(msg->msg_mime); + msg->msg_mime = NULL; +} + +static void flush(mailmessage * msg) +{ + /* do nothing */ +} + +static void check(mailmessage * msg) +{ + /* do nothing */ +} + +static void fetch_result_free(mailmessage * msg_info, char * content) +{ + mmap_string_unref(content); +} + +#if 0 +static int file_to_mmapstr(FILE * f, + char ** result, size_t * result_len) +{ + int fd; + char * data; + struct stat buf; + MMAPString * mmapstr; + int res; + int r; + + fd = fileno(f); + if (fd == -1) { + res = MAIL_ERROR_FILE; + + goto err; + } + + fflush(f); + r = fstat(fd, &buf); + if (r == -1) { + res = MAIL_ERROR_FILE; + + goto err; + } + + data = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (data == MAP_FAILED) { + res = MAIL_ERROR_FILE; + + goto err; + } + + mmapstr = mmap_string_new_len(data, buf.st_size); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + + goto unmap; + } + + munmap(data, buf.st_size); + + r = mmap_string_ref(mmapstr); + if (r != 0) { + res = MAIL_ERROR_MEMORY; + + goto err; + } + + * result = mmapstr->str; + * result_len = mmapstr->len; + + return MAIL_NO_ERROR; + + unmap: + munmap(data, buf.st_size); + err: + return res; +} +#endif + +#if 0 +static int file_body_to_mmapstr(FILE * f, + char ** result, size_t * result_len) +{ + int fd; + char * data; + struct stat buf; + MMAPString * mmapstr; + size_t cur_token; + int res; + int r; + + fd = fileno(f); + if (fd == -1) { + res = MAIL_ERROR_FILE; + + goto err; + } + + fflush(f); + r = fstat(fd, &buf); + if (r == -1) { + res = MAIL_ERROR_FILE; + + goto err; + } + + data = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (data == MAP_FAILED) { + res = MAIL_ERROR_FILE; + + goto err; + } + + cur_token = 0; + + /* skip header */ + + while (1) { + r = mailimf_ignore_field_parse(data, + buf.st_size, &cur_token); + if (r == MAILIMF_NO_ERROR) { + /* do nothing */ + } + else + break; + } + + r = mailimf_crlf_parse(data, buf.st_size, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { + res = maildriver_imf_error_to_mail_error(r); + goto unmap; + } + + mmapstr = mmap_string_new_len(data + cur_token, buf.st_size - cur_token); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + + goto unmap; + } + + munmap(data, buf.st_size); + + r = mmap_string_ref(mmapstr); + if (r != 0) { + res = MAIL_ERROR_MEMORY; + + goto err; + } + + * result = mmapstr->str; + * result_len = mmapstr->len; + + return MAIL_NO_ERROR; + + unmap: + munmap(data, buf.st_size); + err: + return res; +} +#endif + + +static int body_to_mmapstr(char * data, size_t size, + char ** result, size_t * result_len) +{ + MMAPString * mmapstr; + size_t cur_token; + int res; + int r; + + cur_token = 0; + + /* skip header */ + + while (1) { + r = mailimf_ignore_field_parse(data, size, &cur_token); + if (r == MAILIMF_NO_ERROR) { + /* do nothing */ + } + else + break; + } + + r = mailimf_crlf_parse(data, size, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { + res = maildriver_imf_error_to_mail_error(r); + goto err; + } + + mmapstr = mmap_string_new_len(data + cur_token, size - cur_token); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + + goto err; + } + + r = mmap_string_ref(mmapstr); + if (r != 0) { + mmap_string_free(mmapstr); + res = MAIL_ERROR_MEMORY; + + goto err; + } + + * result = mmapstr->str; + * result_len = mmapstr->len; + + return MAIL_NO_ERROR; + + err: + return res; +} + + +#if 0 +static int file_body_body_to_mmapstr(FILE * f, + char ** result, size_t * result_len) +{ + int fd; + char * data; + struct stat buf; + MMAPString * mmapstr; + size_t cur_token; + int res; + int r; + + fd = fileno(f); + if (fd == -1) { + res = MAIL_ERROR_FILE; + + goto err; + } + + fflush(f); + r = fstat(fd, &buf); + if (r == -1) { + res = MAIL_ERROR_FILE; + + goto err; + } + + data = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (data == MAP_FAILED) { + res = MAIL_ERROR_FILE; + + goto err; + } + + cur_token = 0; + + /* skip header */ + + /* MIME header */ + + while (1) { + r = mailimf_ignore_field_parse(data, + buf.st_size, &cur_token); + if (r == MAILIMF_NO_ERROR) { + /* do nothing */ + } + else + break; + } + + r = mailimf_crlf_parse(data, buf.st_size, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { + res = maildriver_imf_error_to_mail_error(r); + goto unmap; + } + + /* headers */ + + while (1) { + r = mailimf_ignore_field_parse(data, + buf.st_size, &cur_token); + if (r == MAILIMF_NO_ERROR) { + /* do nothing */ + } + else + break; + } + + r = mailimf_crlf_parse(data, buf.st_size, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { + res = maildriver_imf_error_to_mail_error(r); + goto unmap; + } + + mmapstr = mmap_string_new_len(data + cur_token, buf.st_size - cur_token); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + + goto unmap; + } + + munmap(data, buf.st_size); + + r = mmap_string_ref(mmapstr); + if (r != 0) { + res = MAIL_ERROR_MEMORY; + + goto err; + } + + * result = mmapstr->str; + * result_len = mmapstr->len; + + return MAIL_NO_ERROR; + + unmap: + munmap(data, buf.st_size); + err: + return res; +} +#endif + +static int body_body_to_mmapstr(char * data, size_t size, + char ** result, size_t * result_len) +{ + MMAPString * mmapstr; + size_t cur_token; + int res; + int r; + + cur_token = 0; + + /* skip header */ + + /* MIME header */ + + while (1) { + r = mailimf_ignore_field_parse(data, size, &cur_token); + if (r == MAILIMF_NO_ERROR) { + /* do nothing */ + } + else + break; + } + + r = mailimf_crlf_parse(data, size, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { + res = maildriver_imf_error_to_mail_error(r); + goto err; + } + + return body_to_mmapstr(data + cur_token, size - cur_token, + result, result_len); + + err: + return res; +} + + +static int fetch_section(mailmessage * msg_info, + struct mailmime * mime, + char ** result, size_t * result_len) +{ + int r; +#if 0 + FILE * f; +#endif + int res; + int col; +#if 0 + char filename[PATH_MAX]; +#endif + MMAPString * str; + + if (msg_info->msg_mime == NULL) + return MAIL_ERROR_INVAL; + +#if 0 + f = get_mime_tmp_file(msg_info, filename, sizeof(filename)); + if (f == NULL) { + res = MAIL_ERROR_FILE; + goto err; + } +#endif + + str = mmap_string_new(""); + if (str == NULL) { + res = MAILIMF_ERROR_MEMORY; + goto err; + } + + col = 0; + r = mailmime_write_mem(str, &col, mime); + if (r != MAILIMF_NO_ERROR) { + res = maildriver_imf_error_to_mail_error(r); + goto free; + } + +#if 0 + if (mime->mm_parent == NULL) + r = file_to_mmapstr(f, result, result_len); + else + r = file_body_to_mmapstr(f, result, result_len); +#endif + if (mime->mm_parent == NULL) { + r = mmap_string_ref(str); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free; + } + + * result = str->str; + * result_len = str->len; + + r = MAIL_NO_ERROR; + } + else { + r = body_to_mmapstr(str->str, str->len, result, result_len); + if (r == MAIL_NO_ERROR) { + mmap_string_free(str); + } + } + + if (r != MAIL_NO_ERROR) { + res = r; + goto free; + } + +#if 0 + fclose(f); + unlink(filename); +#endif + + return MAIL_NO_ERROR; + + free: +#if 0 + fclose(f); + unlink(filename); +#endif + mmap_string_free(str); + err: + return res; +} + + +static int fetch_section_header(mailmessage * msg_info, + struct mailmime * mime, + char ** result, size_t * result_len) +{ + int r; +#if 0 + FILE * f; +#endif + int res; + int col; +#if 0 + char filename[PATH_MAX]; +#endif + MMAPString * str; + + if (msg_info->msg_mime == NULL) + return MAIL_ERROR_INVAL; + +#if 0 + f = get_mime_tmp_file(msg_info, filename, sizeof(filename)); + if (f == NULL) { + res = MAIL_ERROR_FILE; + goto err; + } +#endif + + str = mmap_string_new(""); + if (str == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + col = 0; + if (mime->mm_type == MAILMIME_MESSAGE) { + if (mime->mm_data.mm_message.mm_fields != NULL) { +#if 0 + r = mailimf_fields_write(f, &col, mime->mm_data.mm_message.mm_fields); +#endif + r = mailimf_fields_write_mem(str, &col, mime->mm_data.mm_message.mm_fields); + if (r != MAILIMF_NO_ERROR) { + res = maildriver_imf_error_to_mail_error(r); + goto free; + } +#if 0 + mailimf_string_write(f, &col, "\r\n", 2); +#endif + mailimf_string_write_mem(str, &col, "\r\n", 2); + } + } + + r = mmap_string_ref(str); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free; + } + +#if 0 + r = file_to_mmapstr(f, result, result_len); + if (r != MAIL_NO_ERROR) { + res = r; + goto free; + } +#endif + * result = str->str; + * result_len = str->len; + +#if 0 + fclose(f); + unlink(filename); +#endif + + return MAIL_NO_ERROR; + +#if 0 + close: + fclose(f); + unlink(filename); +#endif + free: + mmap_string_free(str); + err: + return res; +} + + +static int fetch_section_mime(mailmessage * msg_info, + struct mailmime * mime, + char ** result, size_t * result_len) +{ + int r; +#if 0 + FILE * f; +#endif + int res; + int col; +#if 0 + char filename[PATH_MAX]; +#endif + MMAPString * str; + + if (msg_info->msg_mime == NULL) + return MAIL_ERROR_INVAL; + + str = mmap_string_new(""); + if (str == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + +#if 0 + f = get_mime_tmp_file(msg_info, filename, sizeof(filename)); + if (f == NULL) { + res = MAIL_ERROR_FILE; + goto err; + } +#endif + + col = 0; + if (mime->mm_content_type != NULL) { +#if 0 + r = mailmime_content_write(f, &col, mime->mm_content_type); +#endif + r = mailmime_content_write_mem(str, &col, mime->mm_content_type); + if (r != MAILIMF_NO_ERROR) { + res = maildriver_imf_error_to_mail_error(r); + goto free; + } + } + if (mime->mm_mime_fields != NULL) { + r = mailmime_fields_write_mem(str, &col, mime->mm_mime_fields); + if (r != MAILIMF_NO_ERROR) { + res = maildriver_imf_error_to_mail_error(r); + goto free; + } + } + mailimf_string_write_mem(str, &col, "\r\n", 2); + +#if 0 + r = file_to_mmapstr(f, result, result_len); + if (r != MAIL_NO_ERROR) { + res = r; + goto free; + } + + fclose(f); + unlink(filename); +#endif + + r = mmap_string_ref(str); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free; + } + + * result = str->str; + * result_len = str->len; + + return MAIL_NO_ERROR; + +#if 0 + close: + fclose(f); + unlink(filename); +#endif + free: + mmap_string_free(str); + err: + return res; +} + + + +static int fetch_section_body(mailmessage * msg_info, + struct mailmime * mime, + char ** result, size_t * result_len) +{ + int r; +#if 0 + FILE * f; +#endif + int res; + int col; +#if 0 + char filename[PATH_MAX]; +#endif + MMAPString * str; + + if (msg_info->msg_mime == NULL) + return MAIL_ERROR_INVAL; + + str = mmap_string_new(""); + if (str == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + +#if 0 + f = get_mime_tmp_file(msg_info, filename, sizeof(filename)); + if (f == NULL) { + res = MAIL_ERROR_FILE; + goto err; + } +#endif + + col = 0; + if (mime->mm_mime_fields != NULL) { +#if 0 + r = mailmime_write(f, &col, mime); +#endif + r = mailmime_write_mem(str, &col, mime); + if (r != MAILIMF_NO_ERROR) { + res = maildriver_imf_error_to_mail_error(r); + goto free; + } + } + + if (mime->mm_type == MAILMIME_MESSAGE) + r = body_body_to_mmapstr(str->str, str->len, result, result_len); + else + r = body_to_mmapstr(str->str, str->len, result, result_len); + + if (r != MAIL_NO_ERROR) { + res = r; + goto free; + } + + mmap_string_free(str); + +#if 0 + fclose(f); + unlink(filename); +#endif + + return MAIL_NO_ERROR; + +#if 0 + close: + fclose(f); + unlink(filename); +#endif + free: + mmap_string_free(str); + err: + return res; +} + + +static int get_bodystructure(mailmessage * msg_info, + struct mailmime ** result) +{ + if (msg_info->msg_mime == NULL) + return MAIL_ERROR_INVAL; + + * result = msg_info->msg_mime; + + return MAIL_NO_ERROR; +} + + +static int fetch(mailmessage * msg_info, + char ** result, size_t * result_len) +{ + return fetch_section(msg_info, msg_info->msg_mime, result, result_len); +} + +static int fetch_header(mailmessage * msg_info, + char ** result, size_t * result_len) +{ + return fetch_section_header(msg_info, + msg_info->msg_mime, result, result_len); +} + +static int fetch_body(mailmessage * msg_info, + char ** result, size_t * result_len) +{ + return fetch_section_body(msg_info, msg_info->msg_mime, result, result_len); +} + + +static int fetch_size(mailmessage * msg_info, + size_t * result) +{ + char * msg; + int r; + + r = fetch(msg_info, &msg, result); + if (r != MAIL_NO_ERROR) { + return r; + } + + fetch_result_free(msg_info, msg); + + return MAIL_NO_ERROR; +} + + +static mailmessage_driver local_mime_message_driver = { + .msg_name = "mime", + + .msg_initialize = initialize, + .msg_uninitialize = uninitialize, + + .msg_flush = flush, + .msg_check = check, + + .msg_fetch_result_free = fetch_result_free, + + .msg_fetch = fetch, + .msg_fetch_header = fetch_header, + .msg_fetch_body = fetch_body, + .msg_fetch_size = fetch_size, + .msg_get_bodystructure = get_bodystructure, + .msg_fetch_section = fetch_section, + .msg_fetch_section_header = fetch_section_header, + .msg_fetch_section_mime = fetch_section_mime, + .msg_fetch_section_body = fetch_section_body, + .msg_fetch_envelope = mailmessage_generic_fetch_envelope, + + .msg_get_flags = NULL, +}; + +mailmessage_driver * mime_message_driver = &local_mime_message_driver; diff --git a/libetpan/src/driver/implementation/mime-message/mime_message_driver.h b/libetpan/src/driver/implementation/mime-message/mime_message_driver.h new file mode 100644 index 0000000..6cc3c5b --- a/dev/null +++ b/libetpan/src/driver/implementation/mime-message/mime_message_driver.h @@ -0,0 +1,53 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MIME_MESSAGE_DRIVER_H + +#define MIME_MESSAGE_DRIVER_H + +#include <libetpan/mailmessage.h> + +#define LIBETPAN_MIME_MESSAGE + +extern mailmessage_driver * mime_message_driver; + +mailmessage * mime_message_init(struct mailmime * mime); + +void mime_message_detach_mime(mailmessage * msg); + +/* deprecated */ +int mime_message_set_tmpdir(mailmessage * msg, char * tmpdir); + +#endif diff --git a/libetpan/src/driver/implementation/nntp/nntpdriver.c b/libetpan/src/driver/implementation/nntp/nntpdriver.c new file mode 100644 index 0000000..15b764f --- a/dev/null +++ b/libetpan/src/driver/implementation/nntp/nntpdriver.c @@ -0,0 +1,1180 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "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/libetpan/src/driver/implementation/nntp/nntpdriver.h b/libetpan/src/driver/implementation/nntp/nntpdriver.h new file mode 100644 index 0000000..56aaa39 --- a/dev/null +++ b/libetpan/src/driver/implementation/nntp/nntpdriver.h @@ -0,0 +1,52 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef NNTPDRIVER_H + +#define NNTPDRIVER_H + +#include <libetpan/nntpdriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailsession_driver * nntp_session_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/nntp/nntpdriver_cached.c b/libetpan/src/driver/implementation/nntp/nntpdriver_cached.c new file mode 100644 index 0000000..5c29b7b --- a/dev/null +++ b/libetpan/src/driver/implementation/nntp/nntpdriver_cached.c @@ -0,0 +1,1059 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "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) { + mail_flags_free(flags); + 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/libetpan/src/driver/implementation/nntp/nntpdriver_cached.h b/libetpan/src/driver/implementation/nntp/nntpdriver_cached.h new file mode 100644 index 0000000..c0264de --- a/dev/null +++ b/libetpan/src/driver/implementation/nntp/nntpdriver_cached.h @@ -0,0 +1,52 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef NNTPDRIVER_CACHED_H + +#define NNTPDRIVER_CACHED_H + +#include <libetpan/nntpdriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailsession_driver * nntp_cached_session_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/nntp/nntpdriver_cached_message.c b/libetpan/src/driver/implementation/nntp/nntpdriver_cached_message.c new file mode 100644 index 0000000..131b689 --- a/dev/null +++ b/libetpan/src/driver/implementation/nntp/nntpdriver_cached_message.c @@ -0,0 +1,365 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "nntpdriver_cached_message.h" + +#include <string.h> +#include <stdlib.h> + +#include "mail_cache_db.h" + +#include "mailmessage.h" +#include "mailmessage_tools.h" +#include "nntpdriver.h" +#include "nntpdriver_tools.h" +#include "nntpdriver_cached.h" +#include "nntpdriver_message.h" +#include "generic_cache.h" + +static int nntp_prefetch(mailmessage * msg_info); + +static void nntp_prefetch_free(struct generic_message_t * msg); + +static int nntp_initialize(mailmessage * msg_info); + +static int nntp_fetch_header(mailmessage * msg_info, + char ** result, + size_t * result_len); + +static int nntp_fetch_size(mailmessage * msg_info, + size_t * result); + +static void nntp_uninitialize(mailmessage * msg_info); + +static void nntp_flush(mailmessage * msg_info); + +static void nntp_check(mailmessage * msg_info); + +static int nntp_get_flags(mailmessage * msg_info, + struct mail_flags ** result); + +static mailmessage_driver local_nntp_cached_message_driver = { + .msg_name = "nntp-cached", + + .msg_initialize = nntp_initialize, + .msg_uninitialize = nntp_uninitialize, + + .msg_flush = nntp_flush, + .msg_check = nntp_check, + + .msg_fetch_result_free = mailmessage_generic_fetch_result_free, + + .msg_fetch = mailmessage_generic_fetch, + .msg_fetch_header = nntp_fetch_header, + .msg_fetch_body = mailmessage_generic_fetch_body, + .msg_fetch_size = nntp_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 = nntp_get_flags, +}; + +mailmessage_driver * nntp_cached_message_driver = +&local_nntp_cached_message_driver; + +static inline struct nntp_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)->nntp_ancestor; +} + +static inline struct nntp_session_state_data * +get_ancestor_session_data(mailmessage * msg) +{ + return get_ancestor_session(msg)->sess_data; +} + +static inline newsnntp * +get_nntp_session(mailmessage * msg) +{ + return get_ancestor_session_data(msg)->nntp_session; +} + +static int nntp_prefetch(mailmessage * msg_info) +{ + char * msg_content; + size_t msg_length; + struct generic_message_t * msg; + int r; + struct nntp_cached_session_state_data * cached_data; + struct nntp_session_state_data * ancestor_data; + char filename[PATH_MAX]; + + /* we try the cached message */ + + cached_data = get_cached_session_data(msg_info); + + ancestor_data = get_ancestor_session_data(msg_info); + + snprintf(filename, PATH_MAX, "%s/%s/%i", cached_data->nntp_cache_directory, + ancestor_data->nntp_group_name, msg_info->msg_index); + + r = generic_cache_read(filename, &msg_content, &msg_length); + if (r == MAIL_NO_ERROR) { + msg = msg_info->msg_data; + + msg->msg_message = msg_content; + msg->msg_length = msg_length; + + return MAIL_NO_ERROR; + } + + /* we get the message through the network */ + + r = nntpdriver_article(get_ancestor_session(msg_info), + msg_info->msg_index, &msg_content, + &msg_length); + + if (r != MAIL_NO_ERROR) + return r; + + /* we write the message cache */ + + generic_cache_store(filename, msg_content, msg_length); + + msg = msg_info->msg_data; + + msg->msg_message = msg_content; + msg->msg_length = msg_length; + + return MAIL_NO_ERROR; +} + +static void nntp_prefetch_free(struct generic_message_t * msg) +{ + if (msg->msg_message != NULL) { + mmap_string_unref(msg->msg_message); + msg->msg_message = NULL; + } +} + +static int nntp_initialize(mailmessage * msg_info) +{ + struct generic_message_t * msg; + int r; + char * uid; + char static_uid[20]; + + snprintf(static_uid, 20, "%u", msg_info->msg_index); + 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 = nntp_prefetch; + msg->msg_prefetch_free = nntp_prefetch_free; + msg_info->msg_uid = uid; + + return MAIL_NO_ERROR; +} + + +static void nntp_uninitialize(mailmessage * msg_info) +{ + mailmessage_generic_uninitialize(msg_info); +} + +#define FLAGS_NAME "flags.db" + +static void nntp_flush(mailmessage * msg_info) +{ + mailmessage_generic_flush(msg_info); +} + + +static void nntp_check(mailmessage * msg_info) +{ + int r; + + if (msg_info->msg_flags != NULL) { + r = mail_flags_store_set(get_cached_session_data(msg_info)->nntp_flags_store, + msg_info); + /* ignore errors */ + } +} + +static int nntp_fetch_header(mailmessage * msg_info, + char ** result, + size_t * result_len) +{ + struct generic_message_t * msg; + char * headers; + size_t headers_length; + struct nntp_cached_session_state_data * cached_data; + struct nntp_session_state_data * ancestor_data; + int r; + char filename[PATH_MAX]; + + msg = msg_info->msg_data; + + if (msg->msg_message != NULL) + return mailmessage_generic_fetch_header(msg_info, + result, result_len); + + /* we try the cached message */ + + cached_data = get_cached_session_data(msg_info); + + ancestor_data = get_ancestor_session_data(msg_info); + + snprintf(filename, PATH_MAX, "%s/%s/%i-header", + cached_data->nntp_cache_directory, + ancestor_data->nntp_group_name, msg_info->msg_index); + + r = generic_cache_read(filename, &headers, &headers_length); + if (r == MAIL_NO_ERROR) { + * result = headers; + * result_len = headers_length; + + return MAIL_NO_ERROR; + } + + /* we get the message through the network */ + + r = nntpdriver_head(get_ancestor_session(msg_info), msg_info->msg_index, + &headers, &headers_length); + if (r != MAIL_NO_ERROR) + return r; + + /* we write the message cache */ + + generic_cache_store(filename, headers, headers_length); + + * result = headers; + * result_len = headers_length; + + return MAIL_NO_ERROR; +} + +static int nntp_fetch_size(mailmessage * msg_info, + size_t * result) +{ + return nntpdriver_size(get_ancestor_session(msg_info), + msg_info->msg_index, result); +} + +static int nntp_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; + MMAPString * mmapstr; + + 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)->nntp_flags_store, msg_info->msg_index); + + if (flags == NULL) { + struct nntp_cached_session_state_data * cached_data; + struct nntp_session_state_data * ancestor_data; + + cached_data = get_cached_session_data(msg_info); + + ancestor_data = get_ancestor_session_data(msg_info); + if (ancestor_data->nntp_group_name == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + 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; + } + + r = nntpdriver_get_cached_flags(cache_db_flags, mmapstr, + 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; +} diff --git a/libetpan/src/driver/implementation/nntp/nntpdriver_cached_message.h b/libetpan/src/driver/implementation/nntp/nntpdriver_cached_message.h new file mode 100644 index 0000000..f515d48 --- a/dev/null +++ b/libetpan/src/driver/implementation/nntp/nntpdriver_cached_message.h @@ -0,0 +1,52 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include <libetpan/mailmessage_types.h> + +#ifndef NNTPDRIVER_CACHED_MESSAGE_H + +#define NNTPDRIVER_CACHED_MESSAGE_H + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailmessage_driver * nntp_cached_message_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/nntp/nntpdriver_message.c b/libetpan/src/driver/implementation/nntp/nntpdriver_message.c new file mode 100644 index 0000000..117bc56 --- a/dev/null +++ b/libetpan/src/driver/implementation/nntp/nntpdriver_message.c @@ -0,0 +1,169 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "nntpdriver_message.h" + +#include "mailmessage_tools.h" +#include "nntpdriver_tools.h" +#include "nntpdriver.h" +#include "newsnntp.h" +#include <string.h> +#include <stdlib.h> + +static int nntp_prefetch(mailmessage * msg_info); + +static void nntp_prefetch_free(struct generic_message_t * msg); + +static int nntp_initialize(mailmessage * msg_info); + +static int nntp_fetch_header(mailmessage * msg_info, + char ** result, + size_t * result_len); + +static int nntp_fetch_size(mailmessage * msg_info, + size_t * result); + +static mailmessage_driver local_nntp_message_driver = { + .msg_name = "nntp", + + .msg_initialize = nntp_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 = nntp_fetch_header, + .msg_fetch_body = mailmessage_generic_fetch_body, + .msg_fetch_size = nntp_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 * nntp_message_driver = &local_nntp_message_driver; + +static int nntp_prefetch(mailmessage * msg_info) +{ + char * msg_content; + size_t msg_length; + struct generic_message_t * msg; + int r; + + r = nntpdriver_article(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 nntp_prefetch_free(struct generic_message_t * msg) +{ + if (msg->msg_message != NULL) { + mmap_string_unref(msg->msg_message); + msg->msg_message = NULL; + } +} + +static int nntp_initialize(mailmessage * msg_info) +{ + struct generic_message_t * msg; + int r; + char * uid; + char static_uid[20]; + + snprintf(static_uid, 20, "%u", msg_info->msg_index); + 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 = nntp_prefetch; + msg->msg_prefetch_free = nntp_prefetch_free; + msg_info->msg_uid = uid; + + return MAIL_NO_ERROR; +} + +static int nntp_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 = nntpdriver_head(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 nntp_fetch_size(mailmessage * msg_info, + size_t * result) +{ + return nntpdriver_size(msg_info->msg_session, msg_info->msg_index, result); +} diff --git a/libetpan/src/driver/implementation/nntp/nntpdriver_message.h b/libetpan/src/driver/implementation/nntp/nntpdriver_message.h new file mode 100644 index 0000000..15e80b7 --- a/dev/null +++ b/libetpan/src/driver/implementation/nntp/nntpdriver_message.h @@ -0,0 +1,52 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef NNTPDRIVER_MESSAGE_H + +#define NNTPDRIVER_MESSAGE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <libetpan/nntpdriver_types.h> + +extern mailmessage_driver * nntp_message_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/nntp/nntpdriver_tools.c b/libetpan/src/driver/implementation/nntp/nntpdriver_tools.c new file mode 100644 index 0000000..eef0953 --- a/dev/null +++ b/libetpan/src/driver/implementation/nntp/nntpdriver_tools.c @@ -0,0 +1,563 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "nntpdriver_tools.h" + +#include "mail.h" +#include "nntpdriver.h" +#include "nntpdriver_cached.h" +#include "newsnntp.h" +#include "maildriver_types.h" +#include "generic_cache.h" +#include "imfcache.h" +#include "mailmessage.h" +#include "mail_cache_db.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> + +int nntpdriver_nntp_error_to_mail_error(int error) +{ + switch (error) { + case NEWSNNTP_NO_ERROR: + return MAIL_NO_ERROR; + + case NEWSNNTP_ERROR_STREAM: + return MAIL_ERROR_STREAM; + + case NEWSNNTP_ERROR_UNEXPECTED: + return MAIL_ERROR_PROGRAM_ERROR; + + case NEWSNNTP_ERROR_NO_NEWSGROUP_SELECTED: + return MAIL_ERROR_FOLDER_NOT_FOUND; + + case NEWSNNTP_ERROR_NO_ARTICLE_SELECTED: + case NEWSNNTP_ERROR_INVALID_ARTICLE_NUMBER: + case NEWSNNTP_ERROR_ARTICLE_NOT_FOUND: + return MAIL_ERROR_MSG_NOT_FOUND; + + case NEWSNNTP_ERROR_UNEXPECTED_RESPONSE: + case NEWSNNTP_ERROR_INVALID_RESPONSE: + return MAIL_ERROR_PARSE; + + case NEWSNNTP_ERROR_NO_SUCH_NEWS_GROUP: + return MAIL_ERROR_FOLDER_NOT_FOUND; + + case NEWSNNTP_ERROR_POSTING_NOT_ALLOWED: + return MAIL_ERROR_READONLY; + + case NEWSNNTP_ERROR_POSTING_FAILED: + return MAIL_ERROR_APPEND; + + case NEWSNNTP_ERROR_PROGRAM_ERROR: + return MAIL_ERROR_PROGRAM_ERROR; + + case NEWSNNTP_ERROR_NO_PERMISSION: + return MAIL_ERROR_NO_PERMISSION; + + case NEWSNNTP_ERROR_COMMAND_NOT_UNDERSTOOD: + case NEWSNNTP_ERROR_COMMAND_NOT_SUPPORTED: + return MAIL_ERROR_COMMAND_NOT_SUPPORTED; + + case NEWSNNTP_ERROR_CONNECTION_REFUSED: + return MAIL_ERROR_CONNECT; + + case NEWSNNTP_ERROR_MEMORY: + return MAIL_ERROR_MEMORY; + + case NEWSNNTP_ERROR_AUTHENTICATION_REJECTED: + return MAIL_ERROR_LOGIN; + + case NEWSNNTP_ERROR_BAD_STATE: + return MAIL_ERROR_BAD_STATE; + + case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME: + case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD: + default: + return MAIL_ERROR_INVAL; + } +} + +static inline struct nntp_session_state_data * +session_get_data(mailsession * session) +{ + return session->sess_data; +} + +static inline newsnntp * session_get_nntp_session(mailsession * session) +{ + return session_get_data(session)->nntp_session; +} + +static inline struct nntp_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)->nntp_ancestor; +} + +static inline struct nntp_session_state_data * +cached_session_get_ancestor_data(mailsession * session) +{ + return session_get_data(cached_session_get_ancestor(session)); +} + +static inline newsnntp * cached_session_get_nntp_session(mailsession * session) +{ + return session_get_nntp_session(cached_session_get_ancestor(session)); +} + + +int nntpdriver_authenticate_password(mailsession * session) +{ + struct nntp_session_state_data * data; + int r; + + data = session_get_data(session); + + if (data->nntp_password == NULL) + return MAIL_ERROR_LOGIN; + + r = newsnntp_authinfo_password(session_get_nntp_session(session), + data->nntp_password); + + return nntpdriver_nntp_error_to_mail_error(r); +} + +int nntpdriver_mode_reader(mailsession * session) +{ + int done; + int r; + + done = FALSE; + + do { + r = newsnntp_mode_reader(session_get_nntp_session(session)); + + 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: + done = TRUE; + break; + } + } + while (!done); + + return MAIL_NO_ERROR; +} + +int nntpdriver_authenticate_user(mailsession * session) +{ + struct nntp_session_state_data * data; + int r; + + data = session_get_data(session); + + if (data->nntp_userid == NULL) + return MAIL_ERROR_LOGIN; + + r = newsnntp_authinfo_username(session_get_nntp_session(session), + data->nntp_userid); + + switch (r) { + case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD: + return nntpdriver_authenticate_password(session); + + default: + return nntpdriver_nntp_error_to_mail_error(r); + } +} + +int nntpdriver_article(mailsession * session, uint32_t index, + char ** result, + size_t * result_len) +{ + char * msg_content; + size_t msg_length; + int r; + int done; + + done = FALSE; + do { + r = newsnntp_article(session_get_nntp_session(session), + index, &msg_content, &msg_length); + + 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); + + * result = msg_content; + * result_len = msg_length; + + return MAIL_NO_ERROR; +} + +int nntpdriver_head(mailsession * session, uint32_t index, + char ** result, + size_t * result_len) +{ + char * headers; + size_t headers_length; + int r; + int done; + + done = FALSE; + do { + r = newsnntp_head(session_get_nntp_session(session), + index, &headers, &headers_length); + + 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); + + * result = headers; + * result_len = headers_length; + + return MAIL_NO_ERROR; +} + +int nntpdriver_size(mailsession * session, uint32_t index, + size_t * result) +{ + newsnntp * nntp; + struct newsnntp_xover_resp_item * item; + int r; + int done; + + nntp = session_get_nntp_session(session); + + done = FALSE; + do { + r = newsnntp_xover_single(nntp, index, &item); + 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); + + * result = item->ovr_size; + + xover_resp_item_free(item); + + return MAIL_NO_ERROR; +} + +int +nntpdriver_get_cached_flags(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + uint32_t num, + struct mail_flags ** result) +{ + int r; + char keyname[PATH_MAX]; + struct mail_flags * flags; + int res; + + snprintf(keyname, PATH_MAX, "%u-flags", num); + + 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 +nntpdriver_write_cached_flags(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + uint32_t num, + struct mail_flags * flags) +{ + int r; + char keyname[PATH_MAX]; + int res; + + snprintf(keyname, PATH_MAX, "%u-flags", num); + + 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 nntpdriver_select_folder(mailsession * session, char * mb) +{ + int r; + struct newsnntp_group_info * info; + newsnntp * nntp_session; + struct nntp_session_state_data * data; + char * new_name; + int done; + + data = session_get_data(session); + + if (!data->nntp_mode_reader) { + r = nntpdriver_mode_reader(session); + if (r != MAIL_NO_ERROR) + return r; + + data->nntp_mode_reader = TRUE; + } + + if (data->nntp_group_name != NULL) + if (strcmp(data->nntp_group_name, mb) == 0) + return MAIL_NO_ERROR; + + nntp_session = session_get_nntp_session(session); + + done = FALSE; + do { + r = newsnntp_group(nntp_session, mb, &info); + + 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); + + new_name = strdup(mb); + if (new_name == NULL) + return MAIL_ERROR_MEMORY; + + if (data->nntp_group_name != NULL) + free(data->nntp_group_name); + data->nntp_group_name = new_name; + if (data->nntp_group_info != NULL) + newsnntp_group_free(data->nntp_group_info); + data->nntp_group_info = info; + + return MAIL_NO_ERROR; +} + + +int nntp_get_messages_list(mailsession * nntp_session, + mailsession * session, + mailmessage_driver * driver, + struct mailmessage_list ** result) +{ + carray * tab; + struct mailmessage_list * env_list; + uint32_t i; + int res; + int r; + struct nntp_session_state_data * data; + struct newsnntp_group_info * group_info; + uint32_t max; + unsigned int cur; + + data = session_get_data(nntp_session); + + if (data->nntp_group_name == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + r = nntpdriver_select_folder(nntp_session, data->nntp_group_name); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + group_info = data->nntp_group_info; + + if (group_info == NULL) { + res = MAIL_ERROR_BAD_STATE; + goto err; + } + + max = group_info->grp_first; + if (data->nntp_max_articles != 0) { + if (group_info->grp_last - data->nntp_max_articles + 1 > max) + max = group_info->grp_last - data->nntp_max_articles + 1; + } + + tab = carray_new(128); + if (tab == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + for(i = max ; i <= group_info->grp_last ; i++) { + mailmessage * msg; + + msg = mailmessage_new(); + if (msg == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_list; + } + + r = mailmessage_init(msg, session, driver, i, 0); + if (r != MAIL_NO_ERROR) { + mailmessage_free(msg); + 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(cur = 0 ; cur < carray_count(tab) ; cur ++) + mailmessage_free(carray_get(tab, cur)); + carray_free(tab); + err: + return res; +} diff --git a/libetpan/src/driver/implementation/nntp/nntpdriver_tools.h b/libetpan/src/driver/implementation/nntp/nntpdriver_tools.h new file mode 100644 index 0000000..8ca9d16 --- a/dev/null +++ b/libetpan/src/driver/implementation/nntp/nntpdriver_tools.h @@ -0,0 +1,88 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef NNTPDRIVER_TOOLS_H + +#define NNTPDRIVER_TOOLS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "mail_cache_db_types.h" +#include "nntpdriver_types.h" + +int nntpdriver_nntp_error_to_mail_error(int error); + +int nntpdriver_authenticate_password(mailsession * session); + +int nntpdriver_authenticate_user(mailsession * session); + +int nntpdriver_article(mailsession * session, uint32_t index, + char ** result, size_t * result_len); + +int nntpdriver_head(mailsession * session, uint32_t index, + char ** result, + size_t * result_len); + +int nntpdriver_size(mailsession * session, uint32_t index, + size_t * result); + +int +nntpdriver_get_cached_flags(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + uint32_t num, + struct mail_flags ** result); + +int +nntpdriver_write_cached_flags(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + uint32_t num, + struct mail_flags * flags); + +int nntpdriver_select_folder(mailsession * session, char * mb); + +int nntp_get_messages_list(mailsession * nntp_session, + mailsession * session, + mailmessage_driver * driver, + struct mailmessage_list ** result); + +int nntpdriver_mode_reader(mailsession * session); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/nntp/nntpdriver_types.h b/libetpan/src/driver/implementation/nntp/nntpdriver_types.h new file mode 100644 index 0000000..7d4b74d --- a/dev/null +++ b/libetpan/src/driver/implementation/nntp/nntpdriver_types.h @@ -0,0 +1,146 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef NNTPDRIVER_TYPES_H + +#define NNTPDRIVER_TYPES_H + +#include <libetpan/libetpan-config.h> + +#include <libetpan/maildriver_types.h> +#include <libetpan/newsnntp.h> +#include <libetpan/clist.h> +#include <libetpan/generic_cache_types.h> +#include <libetpan/mailstorage_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* NNTP driver for session */ + +enum { + NNTPDRIVER_SET_MAX_ARTICLES = 1, +}; + +struct nntp_session_state_data { + newsnntp * nntp_session; + char * nntp_userid; + char * nntp_password; + + struct newsnntp_group_info * nntp_group_info; + char * nntp_group_name; + + clist * nntp_subscribed_list; + + uint32_t nntp_max_articles; + + int nntp_mode_reader; +}; + +/* cached NNTP driver for session */ + +enum { + /* the mapping of the parameters should be the same as for nntp */ + NNTPDRIVER_CACHED_SET_MAX_ARTICLES = 1, + /* cache specific */ + NNTPDRIVER_CACHED_SET_CACHE_DIRECTORY, + NNTPDRIVER_CACHED_SET_FLAGS_DIRECTORY, +}; + +struct nntp_cached_session_state_data { + mailsession * nntp_ancestor; + char nntp_cache_directory[PATH_MAX]; + char nntp_flags_directory[PATH_MAX]; + struct mail_flags_store * nntp_flags_store; +}; + + +/* nntp storage */ + +/* + nntp_mailstorage is the state data specific to the IMAP4rev1 storage. + + - storage this is the storage to initialize. + + - servername this is the name of the NNTP server + + - port is the port to connect to, on the server. + you give 0 to use the default port. + + - connection_type is the type of socket layer to use. + The value can be CONNECTION_TYPE_PLAIN or CONNECTION_TYPE_TLS. + + - auth_type is the authenticate mechanism to use. + The value can be NNTP_AUTH_TYPE_PLAIN. + + - login is the login of the POP3 account. + + - password is the password of the POP3 account. + + - cached if this value is != 0, a persistant cache will be + stored on local system. + + - cache_directory is the location of the cache + + - flags_directory is the location of the flags +*/ + +struct nntp_mailstorage { + char * nntp_servername; + uint16_t nntp_port; + char * nntp_command; + int nntp_connection_type; + + int nntp_auth_type; + char * nntp_login; + char * nntp_password; + + int nntp_cached; + char * nntp_cache_directory; + char * nntp_flags_directory; +}; + +/* this is the type of NNTP authentication */ + +enum { + NNTP_AUTH_TYPE_PLAIN, /* plain text authentication */ +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/nntp/nntpstorage.c b/libetpan/src/driver/implementation/nntp/nntpstorage.c new file mode 100644 index 0000000..8d0e4ff --- a/dev/null +++ b/libetpan/src/driver/implementation/nntp/nntpstorage.c @@ -0,0 +1,267 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "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(* 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/libetpan/src/driver/implementation/nntp/nntpstorage.h b/libetpan/src/driver/implementation/nntp/nntpstorage.h new file mode 100644 index 0000000..7b046f4 --- a/dev/null +++ b/libetpan/src/driver/implementation/nntp/nntpstorage.h @@ -0,0 +1,93 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef NNTPSTORAGE_H + +#define NNTPSTORAGE_H + +#include <libetpan/nntpdriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + + +/* + nntp_mailstorage_init is the constructor for a NNTP storage + + @param storage this is the storage to initialize. + + @param servername this is the name of the NNTP server + + @param port is the port to connect to, on the server. + you give 0 to use the default port. + + @param command the command used to connect to the server instead of + allowing normal TCP connections to be used. + + @param connection_type is the type of socket layer to use. + The value can be CONNECTION_TYPE_PLAIN, CONNECTION_TYPE_STARTTLS, + CONNECTION_TYPE_TRY_STARTTLS, CONNECTION_TYPE_TLS, + CONNECTION_TYPE_COMMAND, CONNECTION_TYPE_COMMAND_STARTTLS, + CONNECTION_TYPE_COMMAND_TRY_STARTTLS, CONNECTION_TYPE_COMMAND_TLS,. + + @param auth_type is the authenticate mechanism to use. + The value can be NNTP_AUTH_TYPE_PLAIN. + + @param login is the login of the POP3 account. + + @param password is the password of the POP3 account. + + @param cached if this value is != 0, a persistant cache will be + stored on local system. + + @param cache_directory is the location of the cache + + @param flags_directory is the location of the flags +*/ + +int nntp_mailstorage_init(struct mailstorage * storage, + char * nntp_servername, uint16_t nntp_port, + char * nntp_command, + int nntp_connection_type, int nntp_auth_type, + char * nntp_login, char * nntp_password, + int nntp_cached, char * nntp_cache_directory, + char * nntp_flags_directory); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/pop3/pop3driver.c b/libetpan/src/driver/implementation/pop3/pop3driver.c new file mode 100644 index 0000000..ea69923 --- a/dev/null +++ b/libetpan/src/driver/implementation/pop3/pop3driver.c @@ -0,0 +1,388 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "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/libetpan/src/driver/implementation/pop3/pop3driver.h b/libetpan/src/driver/implementation/pop3/pop3driver.h new file mode 100644 index 0000000..b70f69e --- a/dev/null +++ b/libetpan/src/driver/implementation/pop3/pop3driver.h @@ -0,0 +1,52 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef POP3DRIVER_H + +#define POP3DRIVER_H + +#include <libetpan/pop3driver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailsession_driver * pop3_session_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/pop3/pop3driver_cached.c b/libetpan/src/driver/implementation/pop3/pop3driver_cached.c new file mode 100644 index 0000000..d3cc98e --- a/dev/null +++ b/libetpan/src/driver/implementation/pop3/pop3driver_cached.c @@ -0,0 +1,899 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "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 = 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/libetpan/src/driver/implementation/pop3/pop3driver_cached.h b/libetpan/src/driver/implementation/pop3/pop3driver_cached.h new file mode 100644 index 0000000..4f4b6c9 --- a/dev/null +++ b/libetpan/src/driver/implementation/pop3/pop3driver_cached.h @@ -0,0 +1,52 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef POP3DRIVER_CACHED_H + +#define POP3DRIVER_CACHED_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <libetpan/pop3driver_types.h> + +extern mailsession_driver * pop3_cached_session_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/pop3/pop3driver_cached_message.c b/libetpan/src/driver/implementation/pop3/pop3driver_cached_message.c new file mode 100644 index 0000000..4eed0db --- a/dev/null +++ b/libetpan/src/driver/implementation/pop3/pop3driver_cached_message.c @@ -0,0 +1,355 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "pop3driver_cached_message.h" + +#include <string.h> +#include <stdlib.h> + +#include "mail_cache_db.h" + +#include "mailmessage.h" +#include "mailmessage_tools.h" +#include "pop3driver.h" +#include "pop3driver_tools.h" +#include "pop3driver_cached.h" +#include "pop3driver_message.h" +#include "generic_cache.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 void pop3_flush(mailmessage * msg_info); + +static void pop3_check(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 int pop3_get_flags(mailmessage * msg_info, + struct mail_flags ** result); + +static void pop3_uninitialize(mailmessage * msg_info); + +static mailmessage_driver local_pop3_cached_message_driver = { + .msg_name = "pop3-cached", + + .msg_initialize = pop3_initialize, + .msg_uninitialize = pop3_uninitialize, + + .msg_flush = pop3_flush, + .msg_check = pop3_check, + + .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 = pop3_get_flags, +}; + +mailmessage_driver * pop3_cached_message_driver = +&local_pop3_cached_message_driver; + + +static inline struct pop3_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)->pop3_ancestor; +} + +static inline struct pop3_session_state_data * +get_ancestor_session_data(mailmessage * msg) +{ + return get_ancestor_session(msg)->sess_data; +} + +static inline mailpop3 * get_pop3_session(mailmessage * msg) +{ + return get_ancestor_session_data(msg)->pop3_session; +} + + +static int pop3_prefetch(mailmessage * msg_info) +{ + char * msg_content; + size_t msg_length; + struct generic_message_t * msg; + int r; + struct pop3_cached_session_state_data * cached_data; + char filename[PATH_MAX]; + + /* we try the cached message */ + + cached_data = get_cached_session_data(msg_info); + + snprintf(filename, PATH_MAX, "%s/%s", + cached_data->pop3_cache_directory, msg_info->msg_uid); + + r = generic_cache_read(filename, &msg_content, &msg_length); + if (r == MAIL_NO_ERROR) { + msg = msg_info->msg_data; + + msg->msg_message = msg_content; + msg->msg_length = msg_length; + + return MAIL_NO_ERROR; + } + + /* we get the message through the network */ + + r = pop3driver_retr(get_ancestor_session(msg_info), msg_info->msg_index, + &msg_content, &msg_length); + if (r != MAIL_NO_ERROR) + return r; + + /* we write the message cache */ + + generic_cache_store(filename, msg_content, msg_length); + + 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); + + 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) { + 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 void pop3_uninitialize(mailmessage * msg_info) +{ + mailmessage_generic_uninitialize(msg_info); +} + +#define FLAGS_NAME "flags.db" + +static void pop3_flush(mailmessage * msg_info) +{ + mailmessage_generic_flush(msg_info); +} + +static void pop3_check(mailmessage * msg_info) +{ + int r; + + if (msg_info->msg_flags != NULL) { + r = mail_flags_store_set(get_cached_session_data(msg_info)->pop3_flags_store, + msg_info); + } +} + + +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; + struct pop3_cached_session_state_data * cached_data; + char filename[PATH_MAX]; + + msg = msg_info->msg_data; + + if (msg->msg_message != NULL) + return mailmessage_generic_fetch_header(msg_info, + result, result_len); + + /* we try the cached message */ + + cached_data = get_cached_session_data(msg_info); + + snprintf(filename, PATH_MAX, "%s/%s-header", + cached_data->pop3_cache_directory, msg_info->msg_uid); + + r = generic_cache_read(filename, &headers, &headers_length); + if (r == MAIL_NO_ERROR) { + * result = headers; + * result_len = headers_length; + + return MAIL_NO_ERROR; + } + + /* we get the message trough the network */ + + r = pop3driver_header(get_ancestor_session(msg_info), msg_info->msg_index, + &headers, &headers_length); + if (r != MAIL_NO_ERROR) + return r; + + generic_cache_store(filename, headers, headers_length); + + * result = headers; + * result_len = headers_length; + + return MAIL_NO_ERROR; +} + +static int pop3_fetch_size(mailmessage * msg_info, + size_t * result) +{ + return pop3driver_size(get_ancestor_session(msg_info), + msg_info->msg_index, result); +} + +static int pop3_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 pop3_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->pop3_flags_store, + msg_info->msg_index); + + if (flags == NULL) { + 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; + } + + r = pop3driver_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; +} diff --git a/libetpan/src/driver/implementation/pop3/pop3driver_cached_message.h b/libetpan/src/driver/implementation/pop3/pop3driver_cached_message.h new file mode 100644 index 0000000..f13cec7 --- a/dev/null +++ b/libetpan/src/driver/implementation/pop3/pop3driver_cached_message.h @@ -0,0 +1,52 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef POP3DRIVER_CACHED_MESSAGE_H + +#define POP3DRIVER_CACHED_MESSAGE_H + +#include <libetpan/pop3driver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailmessage_driver * pop3_cached_message_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/pop3/pop3driver_message.c b/libetpan/src/driver/implementation/pop3/pop3driver_message.c new file mode 100644 index 0000000..6ea8979 --- a/dev/null +++ b/libetpan/src/driver/implementation/pop3/pop3driver_message.c @@ -0,0 +1,193 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "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) { + 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/libetpan/src/driver/implementation/pop3/pop3driver_message.h b/libetpan/src/driver/implementation/pop3/pop3driver_message.h new file mode 100644 index 0000000..ad0a01b --- a/dev/null +++ b/libetpan/src/driver/implementation/pop3/pop3driver_message.h @@ -0,0 +1,52 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef POP3DRIVER_MESSAGE_H + +#define POP3DRIVER_MESSAGE_H + +#include <libetpan/pop3driver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +extern mailmessage_driver * pop3_message_driver; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/pop3/pop3driver_tools.c b/libetpan/src/driver/implementation/pop3/pop3driver_tools.c new file mode 100644 index 0000000..73dd22a --- a/dev/null +++ b/libetpan/src/driver/implementation/pop3/pop3driver_tools.c @@ -0,0 +1,344 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "pop3driver_tools.h" + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include "maildriver_types.h" +#include "mailpop3.h" +#include "pop3driver.h" +#include "pop3driver_cached.h" +#include "generic_cache.h" +#include "imfcache.h" +#include "mailmessage.h" +#include "mail_cache_db.h" + +int pop3driver_pop3_error_to_mail_error(int error) +{ + switch (error) { + case MAILPOP3_NO_ERROR: + return MAIL_NO_ERROR; + + case MAILPOP3_ERROR_BAD_STATE: + return MAIL_ERROR_BAD_STATE; + + case MAILPOP3_ERROR_UNAUTHORIZED: + return MAIL_ERROR_CONNECT; + + case MAILPOP3_ERROR_STREAM: + return MAIL_ERROR_STREAM; + + case MAILPOP3_ERROR_DENIED: + return MAIL_ERROR_CONNECT; + + case MAILPOP3_ERROR_BAD_USER: + case MAILPOP3_ERROR_BAD_PASSWORD: + return MAIL_ERROR_LOGIN; + + case MAILPOP3_ERROR_CANT_LIST: + return MAIL_ERROR_LIST; + + case MAILPOP3_ERROR_NO_SUCH_MESSAGE: + return MAIL_ERROR_MSG_NOT_FOUND; + + case MAILPOP3_ERROR_MEMORY: + return MAIL_ERROR_MEMORY; + + case MAILPOP3_ERROR_CONNECTION_REFUSED: + return MAIL_ERROR_CONNECT; + + case MAILPOP3_ERROR_APOP_NOT_SUPPORTED: + return MAIL_ERROR_NO_APOP; + + case MAILPOP3_ERROR_CAPA_NOT_SUPPORTED: + return MAIL_ERROR_CAPABILITY; + + case MAILPOP3_ERROR_STLS_NOT_SUPPORTED: + return MAIL_ERROR_NO_TLS; + + default: + return MAIL_ERROR_INVAL; + } +}; + +static inline struct pop3_session_state_data * +session_get_data(mailsession * session) +{ + return session->sess_data; +} + +static inline mailpop3 * session_get_pop3_session(mailsession * session) +{ + return session_get_data(session)->pop3_session; +} + +static inline struct pop3_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)->pop3_ancestor; +} + +static inline struct pop3_session_state_data * +cached_session_get_ancestor_data(mailsession * session) +{ + return session_get_data(cached_session_get_ancestor(session)); +} + +static inline mailpop3 * +cached_session_get_pop3_session(mailsession * session) +{ + return session_get_pop3_session(cached_session_get_ancestor(session)); +} + + +int pop3driver_retr(mailsession * session, uint32_t index, + char ** result, size_t * result_len) +{ + char * msg_content; + size_t msg_length; + int r; + + r = mailpop3_retr(session_get_pop3_session(session), index, + &msg_content, &msg_length); + + switch (r) { + case MAILPOP3_NO_ERROR: + break; + default: + return pop3driver_pop3_error_to_mail_error(r); + } + + * result = msg_content; + * result_len = msg_length; + + return MAIL_NO_ERROR; +} + +int pop3driver_header(mailsession * session, uint32_t index, + char ** result, + size_t * result_len) +{ + char * headers; + size_t headers_length; + int r; + + r = mailpop3_header(session_get_pop3_session(session), + index, &headers, &headers_length); + + switch (r) { + case MAILPOP3_NO_ERROR: + break; + default: + return pop3driver_pop3_error_to_mail_error(r); + } + + * result = headers; + * result_len = headers_length; + + return MAIL_NO_ERROR; +} + +int pop3driver_size(mailsession * session, uint32_t index, + size_t * result) +{ + mailpop3 * pop3; + carray * msg_tab; + struct mailpop3_msg_info * info; + int r; + + pop3 = session_get_pop3_session(session); + + mailpop3_list(pop3, &msg_tab); + + r = mailpop3_get_msg_info(pop3, index, &info); + switch (r) { + case MAILPOP3_NO_ERROR: + break; + default: + return pop3driver_pop3_error_to_mail_error(r); + } + + * result = info->msg_size; + + return MAIL_NO_ERROR; +} + +int +pop3driver_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 mailpop3_msg_info * info; + + r = mailpop3_get_msg_info(cached_session_get_pop3_session(session), + 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-flags", info->msg_uidl); + + 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 +pop3driver_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 pop3_get_messages_list(mailpop3 * pop3, + mailsession * session, + mailmessage_driver * driver, + struct mailmessage_list ** result) +{ + carray * msg_tab; + carray * tab; + struct mailmessage_list * env_list; + unsigned int i; + int res; + int r; + + mailpop3_list(pop3, &msg_tab); + + tab = carray_new(128); + if (tab == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + for(i = 0 ; i < carray_count(msg_tab) ; i++) { + struct mailpop3_msg_info * pop3_info; + mailmessage * msg; + + pop3_info = carray_get(msg_tab, i); + + if (pop3_info == NULL) + continue; + + if (pop3_info->msg_deleted) + continue; + + msg = mailmessage_new(); + if (msg == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_list; + } + + r = mailmessage_init(msg, session, driver, + (uint32_t) pop3_info->msg_index, pop3_info->msg_size); + if (r != MAIL_NO_ERROR) { + mailmessage_free(msg); + 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(/*list*/ tab); + if (env_list == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_list; + } + + * result = env_list; + + return MAIL_NO_ERROR; + + free_list: + for(i = 0 ; i < carray_count(tab) ; i ++) + mailmessage_free(carray_get(tab, i)); + carray_free(tab); + err: + return res; +} diff --git a/libetpan/src/driver/implementation/pop3/pop3driver_tools.h b/libetpan/src/driver/implementation/pop3/pop3driver_tools.h new file mode 100644 index 0000000..e6413aa --- a/dev/null +++ b/libetpan/src/driver/implementation/pop3/pop3driver_tools.h @@ -0,0 +1,82 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef POP3DRIVER_TOOLS_H + +#define POP3DRIVER_TOOLS_H + +#include "mail_cache_db_types.h" +#include "pop3driver_types.h" +#include "mailpop3.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int pop3driver_pop3_error_to_mail_error(int error); + +int pop3driver_retr(mailsession * session, uint32_t index, + char ** result, size_t * result_len); + +int pop3driver_header(mailsession * session, uint32_t index, + char ** result, + size_t * result_len); + +int pop3driver_size(mailsession * session, uint32_t index, + size_t * result); + +int +pop3driver_get_cached_flags(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + mailsession * session, + uint32_t num, + struct mail_flags ** result); + +int +pop3driver_write_cached_flags(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + char * uid, + struct mail_flags * flags); + +int pop3_get_messages_list(mailpop3 * pop3, + mailsession * session, + mailmessage_driver * driver, + struct mailmessage_list ** result); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/pop3/pop3driver_types.h b/libetpan/src/driver/implementation/pop3/pop3driver_types.h new file mode 100644 index 0000000..4bb872c --- a/dev/null +++ b/libetpan/src/driver/implementation/pop3/pop3driver_types.h @@ -0,0 +1,153 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef POP3DRIVER_TYPES_H + +#define POP3DRIVER_TYPES_H + +#include <libetpan/libetpan-config.h> + +#include <libetpan/maildriver_types.h> +#include <libetpan/mailpop3.h> +#include <libetpan/maildriver_types.h> +#include <libetpan/chash.h> +#include <libetpan/mailstorage_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* POP3 driver for session */ + +enum { + POP3DRIVER_SET_AUTH_TYPE = 1, +}; + +enum { + POP3DRIVER_AUTH_TYPE_PLAIN = 0, + POP3DRIVER_AUTH_TYPE_APOP, + POP3DRIVER_AUTH_TYPE_TRY_APOP, +}; + +struct pop3_session_state_data { + int pop3_auth_type; + mailpop3 * pop3_session; +}; + +/* cached POP3 driver for session */ + +enum { + /* the mapping of the parameters should be the same as for pop3 */ + POP3DRIVER_CACHED_SET_AUTH_TYPE = 1, + /* cache specific */ + POP3DRIVER_CACHED_SET_CACHE_DIRECTORY, + POP3DRIVER_CACHED_SET_FLAGS_DIRECTORY, +}; + +struct pop3_cached_session_state_data { + mailsession * pop3_ancestor; + char pop3_cache_directory[PATH_MAX]; + char pop3_flags_directory[PATH_MAX]; + chash * pop3_flags_hash; + carray * pop3_flags_array; + struct mail_flags_store * pop3_flags_store; +}; + +/* pop3 storage */ + +/* + pop3_mailstorage is the state data specific to the POP3 storage. + + - servername this is the name of the POP3 server + + - port is the port to connect to, on the server. + you give 0 to use the default port. + + - connection_type is the type of socket layer to use. + The value can be CONNECTION_TYPE_PLAIN, CONNECTION_TYPE_STARTTLS, + CONNECTION_TYPE_TRY_STARTTLS or CONNECTION_TYPE_TLS. + + - auth_type is the authenticate mechanism to use. + The value can be POP3_AUTH_TYPE_PLAIN, POP3_AUTH_TYPE_APOP + or POP3_AUTH_TYPE_TRY_APOP. Other values are not yet implemented. + + - login is the login of the POP3 account. + + - password is the password of the POP3 account. + + - cached if this value is != 0, a persistant cache will be + stored on local system. + + - cache_directory is the location of the cache. + + - flags_directory is the location of the flags. +*/ + +struct pop3_mailstorage { + 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; +}; + +/* this is the type of POP3 authentication */ + +enum { + POP3_AUTH_TYPE_PLAIN, /* plain text authentication */ + POP3_AUTH_TYPE_APOP, /* APOP authentication */ + POP3_AUTH_TYPE_TRY_APOP, /* first, try APOP, if it fails, + try plain text */ + POP3_AUTH_TYPE_SASL_ANONYMOUS, /* SASL anonymous */ + POP3_AUTH_TYPE_SASL_CRAM_MD5, /* SASL CRAM MD5 */ + POP3_AUTH_TYPE_SASL_KERBEROS_V4, /* SASL KERBEROS V4 */ + POP3_AUTH_TYPE_SASL_PLAIN, /* SASL plain */ + POP3_AUTH_TYPE_SASL_SCRAM_MD5, /* SASL SCRAM MD5 */ + POP3_AUTH_TYPE_SASL_GSSAPI, /* SASL GSSAPI */ + POP3_AUTH_TYPE_SASL_DIGEST_MD5, /* SASL digest MD5 */ +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/implementation/pop3/pop3storage.c b/libetpan/src/driver/implementation/pop3/pop3storage.c new file mode 100644 index 0000000..1cff650 --- a/dev/null +++ b/libetpan/src/driver/implementation/pop3/pop3storage.c @@ -0,0 +1,284 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "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(* 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/libetpan/src/driver/implementation/pop3/pop3storage.h b/libetpan/src/driver/implementation/pop3/pop3storage.h new file mode 100644 index 0000000..e8cd513 --- a/dev/null +++ b/libetpan/src/driver/implementation/pop3/pop3storage.h @@ -0,0 +1,95 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef POP3STORAGE_H + +#define POP3STORAGE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <libetpan/pop3driver_types.h> +#include <libetpan/pop3driver.h> +#include <libetpan/pop3driver_cached.h> + +/* + pop3_mailstorage_init is the constructor for a POP3 storage + + @param storage this is the storage to initialize. + + @param servername this is the name of the POP3 server + + @param port is the port to connect to, on the server. + you give 0 to use the default port. + + @param command the command used to connect to the server instead of + allowing normal TCP connections to be used. + + @param connection_type is the type of socket layer to use. + The value can be CONNECTION_TYPE_PLAIN, CONNECTION_TYPE_STARTTLS, + CONNECTION_TYPE_TRY_STARTTLS, CONNECTION_TYPE_TLS, + CONNECTION_TYPE_COMMAND, CONNECTION_TYPE_COMMAND_STARTTLS, + CONNECTION_TYPE_COMMAND_TRY_STARTTLS, CONNECTION_TYPE_COMMAND_TLS,. + + @param auth_type is the authenticate mechanism to use. + The value can be POP3_AUTH_TYPE_PLAIN, POP3_AUTH_TYPE_APOP + or POP3_AUTH_TYPE_TRY_APOP. Other values are not yet implemented. + + @param login is the login of the POP3 account. + + @param password is the password of the POP3 account. + + @param cached if this value is != 0, a persistant cache will be + stored on local system. + + @param cache_directory is the location of the cache + + @param flags_directory is the location of the flags +*/ + +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); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/interface/maildriver.c b/libetpan/src/driver/interface/maildriver.c new file mode 100644 index 0000000..5b6c4f2 --- a/dev/null +++ b/libetpan/src/driver/interface/maildriver.c @@ -0,0 +1,383 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "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/libetpan/src/driver/interface/maildriver.h b/libetpan/src/driver/interface/maildriver.h new file mode 100644 index 0000000..16e830b --- a/dev/null +++ b/libetpan/src/driver/interface/maildriver.h @@ -0,0 +1,546 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef 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/libetpan/src/driver/interface/maildriver_errors.h b/libetpan/src/driver/interface/maildriver_errors.h new file mode 100644 index 0000000..99ec25c --- a/dev/null +++ b/libetpan/src/driver/interface/maildriver_errors.h @@ -0,0 +1,102 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MAILDRIVER_ERRORS_H + +#define MAILDRIVER_ERRORS_H + +enum { + MAIL_NO_ERROR = 0, + MAIL_NO_ERROR_AUTHENTICATED, + MAIL_NO_ERROR_NON_AUTHENTICATED, + MAIL_ERROR_NOT_IMPLEMENTED, + MAIL_ERROR_UNKNOWN, + MAIL_ERROR_CONNECT, + MAIL_ERROR_BAD_STATE, + MAIL_ERROR_FILE, + MAIL_ERROR_STREAM, + MAIL_ERROR_LOGIN, + MAIL_ERROR_CREATE, /* 10 */ + MAIL_ERROR_DELETE, + MAIL_ERROR_LOGOUT, + MAIL_ERROR_NOOP, + MAIL_ERROR_RENAME, + MAIL_ERROR_CHECK, + MAIL_ERROR_EXAMINE, + MAIL_ERROR_SELECT, + MAIL_ERROR_MEMORY, + MAIL_ERROR_STATUS, + MAIL_ERROR_SUBSCRIBE, /* 20 */ + MAIL_ERROR_UNSUBSCRIBE, + MAIL_ERROR_LIST, + MAIL_ERROR_LSUB, + MAIL_ERROR_APPEND, + MAIL_ERROR_COPY, + MAIL_ERROR_FETCH, + MAIL_ERROR_STORE, + MAIL_ERROR_SEARCH, + MAIL_ERROR_DISKSPACE, + MAIL_ERROR_MSG_NOT_FOUND, /* 30 */ + MAIL_ERROR_PARSE, + MAIL_ERROR_INVAL, + MAIL_ERROR_PART_NOT_FOUND, + MAIL_ERROR_REMOVE, + MAIL_ERROR_FOLDER_NOT_FOUND, + MAIL_ERROR_MOVE, + MAIL_ERROR_STARTTLS, + MAIL_ERROR_CACHE_MISS, + MAIL_ERROR_NO_TLS, + MAIL_ERROR_EXPUNGE, /* 40 */ + /* misc errors */ + MAIL_ERROR_MISC, + MAIL_ERROR_PROTOCOL, + MAIL_ERROR_CAPABILITY, + MAIL_ERROR_CLOSE, + MAIL_ERROR_FATAL, + MAIL_ERROR_READONLY, + MAIL_ERROR_NO_APOP, + MAIL_ERROR_COMMAND_NOT_SUPPORTED, + MAIL_ERROR_NO_PERMISSION, + MAIL_ERROR_PROGRAM_ERROR, /* 50 */ + MAIL_ERROR_SUBJECT_NOT_FOUND, + MAIL_ERROR_CHAR_ENCODING_FAILED, + MAIL_ERROR_SEND, + MAIL_ERROR_COMMAND, + MAIL_ERROR_SYSTEM, + MAIL_ERROR_UNABLE, + MAIL_ERROR_FOLDER, +}; + +#endif diff --git a/libetpan/src/driver/interface/maildriver_tools.c b/libetpan/src/driver/interface/maildriver_tools.c new file mode 100644 index 0000000..4501b23 --- a/dev/null +++ b/libetpan/src/driver/interface/maildriver_tools.c @@ -0,0 +1,841 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "maildriver_tools.h" + +#include "libetpan-config.h" + +#include <stdlib.h> +#include <ctype.h> +#include <string.h> +#include <dirent.h> +#include <unistd.h> + +#include "maildriver.h" +#include "mailmessage.h" +#include "mailstream.h" +#include "mailmime.h" +#include "mail_cache_db.h" + +/* ********************************************************************* */ +/* tools */ + + +int +maildriver_generic_get_envelopes_list(mailsession * session, + struct mailmessage_list * env_list) +{ + int r; + unsigned i; +#if 0 + uint32_t j; + uint32_t last_msg; + + last_msg = 0; +#endif + +#if 0 + j = 0; + i = 0; + while (i < env_list->tab->len) { + mailmessage * msg; + uint32_t index; + + msg = carray_get(env_list->tab, i); + + index = msg->index; + + if (msg->fields == NULL) { + struct mailimf_fields * fields; + + r = mailmessage_fetch_envelope(msg, &fields); + if (r != MAIL_NO_ERROR) { + /* do nothing */ + } + else { + msg->fields = fields; + + carray_set(env_list->tab, j, msg); + + j ++; + last_msg = i + 1; + } + mailmessage_flush(msg); + } + else { + j ++; + last_msg = i + 1; + } + + i ++; + } + + for(i = last_msg ; i < env_list->tab->len ; i ++) { + mailmessage_free(carray_get(env_list->tab, i)); + carray_set(env_list->tab, i, NULL); + } + + r = carray_set_size(env_list->tab, j); + if (r < 0) + return MAIL_ERROR_MEMORY; +#endif + + 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) { + struct mailimf_fields * fields; + + r = mailmessage_fetch_envelope(msg, &fields); + if (r != MAIL_NO_ERROR) { + /* do nothing */ + } + else { + msg->msg_fields = fields; + } + mailmessage_flush(msg); + } + } + + return MAIL_NO_ERROR; +} + + +#if 0 +static int is_search_header_only(struct mail_search_key * key) +{ + clistiter * cur; + int result; + + switch (key->type) { + case MAIL_SEARCH_KEY_ANSWERED: + case MAIL_SEARCH_KEY_BCC: + case MAIL_SEARCH_KEY_BEFORE: + case MAIL_SEARCH_KEY_CC: + case MAIL_SEARCH_KEY_DELETED: + case MAIL_SEARCH_KEY_FLAGGED: + case MAIL_SEARCH_KEY_FROM: + case MAIL_SEARCH_KEY_NEW: + case MAIL_SEARCH_KEY_OLD: + case MAIL_SEARCH_KEY_ON: + case MAIL_SEARCH_KEY_RECENT: + case MAIL_SEARCH_KEY_SEEN: + case MAIL_SEARCH_KEY_SINCE: + case MAIL_SEARCH_KEY_SUBJECT: + case MAIL_SEARCH_KEY_TO: + case MAIL_SEARCH_KEY_UNANSWERED: + case MAIL_SEARCH_KEY_UNDELETED: + case MAIL_SEARCH_KEY_UNFLAGGED: + case MAIL_SEARCH_KEY_UNSEEN: + case MAIL_SEARCH_KEY_HEADER: + case MAIL_SEARCH_KEY_LARGER: + case MAIL_SEARCH_KEY_NOT: + case MAIL_SEARCH_KEY_SMALLER: + case MAIL_SEARCH_KEY_ALL: + return TRUE; + + case MAIL_SEARCH_KEY_BODY: + case MAIL_SEARCH_KEY_TEXT: + return FALSE; + + case MAIL_SEARCH_KEY_OR: + return (is_search_header_only(key->or1) && + is_search_header_only(key->or2)); + + case MAIL_SEARCH_KEY_MULTIPLE: + result = TRUE; + for (cur = clist_begin(key->multiple) ; cur != NULL ; + cur = clist_next(cur)) + result = result && is_search_header_only(clist_content(cur)); + return result; + + default: + return TRUE; + } +} + +static int match_header(struct mailimf_fields * fields, + char * name, char * value) +{ + clistiter * cur; + + for(cur = clist_begin(fields->list) ; cur != NULL ; + cur = clist_content(cur)) { + struct mailimf_field * field; + struct mailimf_optional_field * opt_field; + + field = clist_content(cur); + opt_field = field->optional_field; + if ((char) toupper((unsigned char) opt_field->name[0]) == + (char) toupper((unsigned char) name[0])) { + if (strcasecmp(opt_field->name, name) == 0) + if (strstr(opt_field->value, value) != NULL) + return TRUE; + } + } + return FALSE; +} + +static int comp_date(struct mailimf_fields * fields, + struct mailimf_date_time * ref_date) +{ + clistiter * cur; + struct mailimf_date_time * date; + int r; + + date = NULL; + for(cur = clist_begin(fields->list) ; cur != NULL ; + cur = clist_content(cur)) { + struct mailimf_field * field; + struct mailimf_optional_field * opt_field; + + field = clist_content(cur); + opt_field = field->optional_field; + if ((char) toupper((unsigned char) opt_field->name[0]) == 'D') { + if (strcasecmp(opt_field->name, "Date") == 0) { + size_t cur_token; + + cur_token = 0; + r = mailimf_date_time_parse(opt_field->value, strlen(opt_field->value), + &cur_token, &date); + if (r == MAILIMF_NO_ERROR) + break; + else if (r == MAILIMF_ERROR_PARSE) { + /* do nothing */ + } + else + break; + } + } + } + + if (date == NULL) + return 0; + + return mailimf_date_time_comp(date, ref_date); +} + +static int match_messages(char * message, + size_t size, + struct mailimf_fields * fields, + int32_t flags, + char * charset, + struct mail_search_key * key) +{ + clistiter * cur; + size_t length; + size_t cur_token; + int r; + + switch (key->type) { + + /* flags */ + case MAIL_SEARCH_KEY_ANSWERED: + return ((flags & MAIL_FLAG_ANSWERED) != 0); + + case MAIL_SEARCH_KEY_FLAGGED: + return ((flags & MAIL_FLAG_FLAGGED) != 0); + + case MAIL_SEARCH_KEY_DELETED: + return ((flags & MAIL_FLAG_DELETED) != 0); + + case MAIL_SEARCH_KEY_RECENT: + return ((flags & MAIL_FLAG_NEW) != 0) && + ((flags & MAIL_FLAG_SEEN) == 0); + + case MAIL_SEARCH_KEY_SEEN: + return ((flags & MAIL_FLAG_SEEN) != 0); + + case MAIL_SEARCH_KEY_NEW: + return ((flags & MAIL_FLAG_NEW) != 0); + + case MAIL_SEARCH_KEY_OLD: + return ((flags & MAIL_FLAG_NEW) == 0); + + case MAIL_SEARCH_KEY_UNANSWERED: + return ((flags & MAIL_FLAG_ANSWERED) == 0); + + case MAIL_SEARCH_KEY_UNDELETED: + return ((flags & MAIL_FLAG_DELETED) == 0); + + case MAIL_SEARCH_KEY_UNFLAGGED: + return ((flags & MAIL_FLAG_FLAGGED) == 0); + + case MAIL_SEARCH_KEY_UNSEEN: + return ((flags & MAIL_FLAG_SEEN) == 0); + + /* headers */ + case MAIL_SEARCH_KEY_BCC: + return match_header(fields, "Bcc", key->bcc); + + case MAIL_SEARCH_KEY_CC: + return match_header(fields, "Cc", key->cc); + + case MAIL_SEARCH_KEY_FROM: + return match_header(fields, "From", key->from); + + case MAIL_SEARCH_KEY_SUBJECT: + return match_header(fields, "Subject", key->subject); + + case MAIL_SEARCH_KEY_TO: + return match_header(fields, "To", key->to); + + case MAIL_SEARCH_KEY_HEADER: + return match_header(fields, key->header_name, key->header_value); + + /* date */ + case MAIL_SEARCH_KEY_BEFORE: + return (comp_date(fields, key->before) <= 0); + + case MAIL_SEARCH_KEY_ON: + return (comp_date(fields, key->before) == 0); + + case MAIL_SEARCH_KEY_SINCE: + return (comp_date(fields, key->before) >= 0); + + /* boolean */ + case MAIL_SEARCH_KEY_NOT: + return (!match_messages(message, size, fields, flags, charset, key->not)); + case MAIL_SEARCH_KEY_OR: + return (match_messages(message, size, fields, flags, charset, key->or1) || + match_messages(message, size, fields, flags, charset, key->or2)); + + case MAIL_SEARCH_KEY_MULTIPLE: + for(cur = clist_begin(key->multiple) ; cur != NULL ; + cur = clist_next(cur)) { + if (!match_messages(message, size, fields, flags, charset, + clist_content(cur))) + return FALSE; + } + + return TRUE; + + /* size */ + case MAIL_SEARCH_KEY_SMALLER: + return (size <= key->smaller); + + case MAIL_SEARCH_KEY_LARGER: + return (size >= key->larger); + + case MAIL_SEARCH_KEY_BODY: + length = strlen(message); + + cur_token = 0; + while (1) { + r = mailimf_ignore_field_parse(message, length, &cur_token); + if (r == MAILIMF_NO_ERROR) { + /* do nothing */ + } + else + break; + } + + return (strstr(message + cur_token, key->body) != NULL); + + case MAIL_SEARCH_KEY_TEXT: + return (strstr(message, key->body) != NULL); + + case MAIL_SEARCH_KEY_ALL: + default: + return TRUE; + } +} + +int maildriver_generic_search_messages(mailsession * session, char * charset, + struct mail_search_key * key, + struct mail_search_result ** result) +{ + int header; + clist * list; + struct mail_search_result * search_result; + int r; + struct mailmessage_list * env_list; + int res; + unsigned int i; + + header = is_search_header_only(key); + + r = mailsession_get_messages_list(session, &env_list); + if (r != MAIL_NO_ERROR) + return r; + + list = NULL; + for(i = 0 ; i < carray_count(env_list->tab) ; i ++) { + char * message; + size_t length; + struct mail_info * info; + uint32_t flags; + struct mailimf_fields * fields; + size_t cur_token; + + info = carray_get(env_list->tab, i); + + if (!header) { + r = mailsession_fetch_message(session, info->index, &message, &length); + if (r != MAIL_NO_ERROR) { + res = r; + goto free_list; + } + + cur_token = 0; + r = mailimf_optional_fields_parse(message, length, + &cur_token, &fields); + if (r != MAILIMF_NO_ERROR) { + res = MAIL_ERROR_PARSE; + goto free_list; + } + } + else { + char * msg_header; + int r; + size_t cur_token; + size_t header_len; + + r = mailsession_fetch_message_header(session, info->index, &msg_header, + &header_len); + if (r != MAIL_NO_ERROR) { + res = r; + goto free_list; + } + + message = NULL; + cur_token = 0; + r = mailimf_optional_fields_parse(msg_header, header_len, + &cur_token, &fields); + if (r != MAILIMF_NO_ERROR) { + res = MAIL_ERROR_PARSE; + goto free_list; + } + + mailsession_fetch_result_free(session, msg_header); + } + + r = mailsession_get_message_flags(session, info->index, &flags); + if (r != MAIL_NO_ERROR) { + res = r; + goto free_list; + } + + if (match_messages(message, info->size, fields, flags, + charset, key)) { + uint32_t * pnum; + + pnum = malloc(sizeof(* pnum)); + if (pnum == NULL) { + if (message != NULL) + mailsession_fetch_result_free(session, message); + res = MAIL_ERROR_MEMORY; + goto free_list; + } + + * pnum = info->index; + + r = clist_append(list, pnum); + if (r < 0) { + free(pnum); + if (message != NULL) + mailsession_fetch_result_free(session, message); + res = MAIL_ERROR_MEMORY; + goto free_list; + } + } + + if (message != NULL) + mailsession_fetch_result_free(session, message); + } + + search_result = mail_search_result_new(list); + if (search_result == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_list; + } + + * result = search_result; + + return MAIL_NO_ERROR; + + free_list: + clist_foreach(list, (clist_func) free, NULL); + clist_free(list); + mailmessage_list_free(env_list); + return res; +} +#endif + +#if 0 +int maildriver_generic_search_messages(mailsession * session, char * charset, + struct mail_search_key * key, + struct mail_search_result ** result) +{ + return MAIL_ERROR_NOT_IMPLEMENTED; +} +#endif + +int +maildriver_env_list_to_msg_list(struct mailmessage_list * env_list, + clist ** result) +{ + clist * msg_list; + int r; + int res; + unsigned int i; + + msg_list = clist_new(); + if (msg_list == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + 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) { + uint32_t * pindex; + + pindex = malloc(sizeof(* pindex)); + if (pindex == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_msg_list; + } + + * pindex = msg->msg_index; + + r = clist_append(msg_list, pindex); + if (r < 0) { + free(pindex); + res = MAIL_ERROR_MEMORY; + goto free_msg_list; + } + + } + } + + * result = msg_list; + + return MAIL_NO_ERROR; + + free_msg_list: + clist_foreach(msg_list, (clist_func) free, NULL); + clist_free(msg_list); + err: + return res; +} + + +int +maildriver_env_list_to_msg_list_no_flags(struct mailmessage_list * env_list, + clist ** result) +{ + clist * msg_list; + int r; + int res; + unsigned int i; + + msg_list = clist_new(); + if (msg_list == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + 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) { + uint32_t * pindex; + + pindex = malloc(sizeof(* pindex)); + if (pindex == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_msg_list; + } + + * pindex = msg->msg_index; + + r = clist_append(msg_list, pindex); + if (r < 0) { + free(pindex); + res = MAIL_ERROR_MEMORY; + goto free_msg_list; + } + + } + } + + * result = msg_list; + + return MAIL_NO_ERROR; + + free_msg_list: + clist_foreach(msg_list, (clist_func) free, NULL); + clist_free(msg_list); + err: + return res; +} + + + +int maildriver_imf_error_to_mail_error(int error) +{ + switch (error) { + case MAILIMF_NO_ERROR: + return MAIL_NO_ERROR; + + case MAILIMF_ERROR_PARSE: + return MAIL_ERROR_PARSE; + + case MAILIMF_ERROR_MEMORY: + return MAIL_ERROR_MEMORY; + + case MAILIMF_ERROR_INVAL: + return MAIL_ERROR_INVAL; + + case MAILIMF_ERROR_FILE: + return MAIL_ERROR_FILE; + + default: + return MAIL_ERROR_INVAL; + } +} + +char * maildriver_quote_mailbox(char * mb) +{ + MMAPString * gstr; + char * str; + + gstr = mmap_string_new(""); + if (gstr == NULL) + return NULL; + + while (* mb != 0) { + char hex[3]; + + if (((* mb >= 'a') && (* mb <= 'z')) || + ((* mb >= 'A') && (* mb <= 'Z')) || + ((* mb >= '0') && (* mb <= '9'))) + mmap_string_append_c(gstr, * mb); + else { + if (mmap_string_append_c(gstr, '%') == NULL) + goto free; + snprintf(hex, 3, "%02x", (unsigned char) (* mb)); + if (mmap_string_append(gstr, hex) == NULL) + goto free; + } + mb ++; + } + + str = strdup(gstr->str); + if (str == NULL) + goto free; + + mmap_string_free(gstr); + + return str; + + free: + mmap_string_free(gstr); + return NULL; +} + + + +int maildriver_cache_clean_up(struct mail_cache_db * cache_db_env, + struct mail_cache_db * cache_db_flags, + struct mailmessage_list * env_list) +{ + chash * hash_exist; + int res; + int r; + char keyname[PATH_MAX]; + unsigned int i; + + /* flush cache */ + + hash_exist = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYALL); + if (hash_exist == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { + mailmessage * msg; + chashdatum key; + chashdatum value; + + msg = carray_get(env_list->msg_tab, i); + + value.data = NULL; + value.len = 0; + + if (cache_db_env != NULL) { + snprintf(keyname, PATH_MAX, "%s-envelope", msg->msg_uid); + + key.data = keyname; + key.len = strlen(keyname); + r = chash_set(hash_exist, &key, &value, NULL); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free; + } + } + + if (cache_db_flags != NULL) { + snprintf(keyname, PATH_MAX, "%s-flags", msg->msg_uid); + + key.data = keyname; + key.len = strlen(keyname); + r = chash_set(hash_exist, &key, &value, NULL); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free; + } + } + } + + /* clean up */ + if (cache_db_env != NULL) + mail_cache_db_clean_up(cache_db_env, hash_exist); + if (cache_db_flags != NULL) + mail_cache_db_clean_up(cache_db_flags, hash_exist); + + chash_free(hash_exist); + + return MAIL_NO_ERROR; + + free: + chash_free(hash_exist); + err: + return res; +} + + +/* + maildriver_message_cache_clean_up() + + remove files in cache_dir that does not correspond to a message. + + get_uid_from_filename() modifies the given filename so that it + is a uid when returning from the function. If get_uid_from_filename() + clears the content of file (set to empty string), this means that + this file should not be deleted. +*/ + +int maildriver_message_cache_clean_up(char * cache_dir, + struct mailmessage_list * env_list, + void (* get_uid_from_filename)(char *)) +{ + chash * hash_exist; + DIR * d; + char cached_filename[PATH_MAX]; + struct dirent * ent; + char keyname[PATH_MAX]; + unsigned int i; + int res; + int r; + + /* remove files */ + + hash_exist = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYALL); + if (hash_exist == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { + mailmessage * msg; + chashdatum key; + chashdatum value; + + msg = carray_get(env_list->msg_tab, i); + + key.data = msg->msg_uid; + key.len = strlen(msg->msg_uid); + value.data = NULL; + value.len = 0; + r = chash_set(hash_exist, &key, &value, NULL); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free; + } + } + + d = opendir(cache_dir); + while ((ent = readdir(d)) != NULL) { + chashdatum key; + chashdatum value; + + if (strcmp(ent->d_name, ".") == 0) + continue; + + if (strcmp(ent->d_name, "..") == 0) + continue; + + if (strstr(ent->d_name, ".db") != NULL) + continue; + + strncpy(keyname, ent->d_name, sizeof(keyname)); + keyname[sizeof(keyname) - 1] = '\0'; + + get_uid_from_filename(keyname); + + if (* keyname == '\0') + continue; + + key.data = keyname; + key.len = strlen(keyname); + + r = chash_get(hash_exist, &key, &value); + if (r < 0) { + snprintf(cached_filename, sizeof(cached_filename), + "%s/%s", cache_dir, ent->d_name); + unlink(cached_filename); + } + } + closedir(d); + + chash_free(hash_exist); + + return MAIL_NO_ERROR; + + free: + chash_free(hash_exist); + err: + return res; +} diff --git a/libetpan/src/driver/interface/maildriver_tools.h b/libetpan/src/driver/interface/maildriver_tools.h new file mode 100644 index 0000000..a92af42 --- a/dev/null +++ b/libetpan/src/driver/interface/maildriver_tools.h @@ -0,0 +1,81 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MAILDRIVER_TOOLS_H + +#define MAILDRIVER_TOOLS_H + +#include "maildriver_types.h" +#include "mail_cache_db_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int +maildriver_generic_get_envelopes_list(mailsession * session, + struct mailmessage_list * env_list); + +#if 0 +int maildriver_generic_search_messages(mailsession * session, char * charset, + struct mail_search_key * key, + struct mail_search_result ** result); +#endif + +int +maildriver_env_list_to_msg_list(struct mailmessage_list * env_list, + clist ** result); + +int maildriver_imf_error_to_mail_error(int error); + +char * maildriver_quote_mailbox(char * mb); + +int +maildriver_env_list_to_msg_list_no_flags(struct mailmessage_list * env_list, + clist ** result); + +int maildriver_cache_clean_up(struct mail_cache_db * cache_db_env, + struct mail_cache_db * cache_db_flags, + struct mailmessage_list * env_list); + +int maildriver_message_cache_clean_up(char * cache_dir, + struct mailmessage_list * env_list, + void (* get_uid_from_filename)(char *)); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/interface/maildriver_types.c b/libetpan/src/driver/interface/maildriver_types.c new file mode 100644 index 0000000..43f5c4f --- a/dev/null +++ b/libetpan/src/driver/interface/maildriver_types.c @@ -0,0 +1,340 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "maildriver_types.h" +#include <time.h> +#include <stdlib.h> +#include "mailmessage.h" + +struct mailmessage_list * mailmessage_list_new(carray * msg_tab) +{ + struct mailmessage_list * env_list; + + env_list = malloc(sizeof(* env_list)); + if (env_list == NULL) + return NULL; + + env_list->msg_tab = msg_tab; + + return env_list; +} + +void mailmessage_list_free(struct mailmessage_list * env_list) +{ + unsigned int i; + + for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { + mailmessage * msg; + + msg = carray_get(env_list->msg_tab, i); + if (msg != NULL) + mailmessage_free(msg); + } + carray_free(env_list->msg_tab); + free(env_list); +} + +struct mail_list * mail_list_new(clist * list) +{ + struct mail_list * resp; + + resp = malloc(sizeof(* resp)); + if (resp == NULL) + return NULL; + resp->mb_list = list; + + return resp; +} + +void mail_list_free(struct mail_list * resp) +{ + clist_foreach(resp->mb_list, (clist_func) free, NULL); + clist_free(resp->mb_list); + free(resp); +} + +static int32_t mailimf_date_time_to_int(struct mailimf_date_time * date) +{ + return date->dt_year * 12 * 30 * 24 * 60 * 60 + + date->dt_month * 30 * 24 * 60 * 60 + date->dt_day * 24 * 60 * 60 + + (date->dt_hour - date->dt_zone) * 60 * 60 + + date->dt_min * 60 + date->dt_sec; +} + +int32_t mailimf_date_time_comp(struct mailimf_date_time * date1, + struct mailimf_date_time * date2) +{ + return mailimf_date_time_to_int(date1) - mailimf_date_time_to_int(date2); +} + + + + + + + +#if 0 +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) +{ + struct mail_search_key * key; + + key = malloc(sizeof(* key)); + if (key == NULL) + return NULL; + + key->sk_type = sk_type; + key->sk_bcc = sk_bcc; + key->sk_before = sk_before; + key->sk_body = sk_body; + key->sk_cc = sk_cc; + key->sk_from = sk_from; + key->sk_on = sk_on; + key->sk_since = sk_since; + key->sk_subject = sk_subject; + key->sk_text = sk_text; + key->sk_to = sk_to; + key->sk_header_name = sk_header_name; + key->sk_header_value = sk_header_value; + key->sk_larger = sk_larger; + key->sk_not = sk_not; + key->sk_or1 = sk_or1; + key->sk_or2 = sk_or2; + key->sk_smaller = sk_smaller; + key->sk_multiple = sk_multiple; + + return key; +} + + +void mail_search_key_free(struct mail_search_key * key) +{ + if (key->sk_bcc) + free(key->sk_bcc); + if (key->sk_before) + mailimf_date_time_free(key->sk_before); + if (key->sk_body) + free(key->sk_body); + if (key->sk_cc) + free(key->sk_cc); + if (key->sk_from) + free(key->sk_from); + if (key->sk_on) + mailimf_date_time_free(key->sk_on); + if (key->sk_since) + mailimf_date_time_free(key->sk_since); + if (key->sk_subject) + free(key->sk_subject); + if (key->sk_text) + free(key->sk_text); + if (key->sk_to) + free(key->sk_to); + if (key->sk_header_name) + free(key->sk_header_name); + if (key->sk_header_value) + free(key->sk_header_value); + if (key->sk_not) + mail_search_key_free(key->sk_not); + if (key->sk_or1) + mail_search_key_free(key->sk_or1); + if (key->sk_or2) + mail_search_key_free(key->sk_or2); + if (key->sk_multiple) { + clist_foreach(key->sk_multiple, (clist_func) mail_search_key_free, NULL); + clist_free(key->sk_multiple); + } + + free(key); +} + + +struct mail_search_result * mail_search_result_new(clist * list) +{ + struct mail_search_result * search_result; + + search_result = malloc(sizeof(* search_result)); + if (search_result == NULL) + return NULL; + search_result->list = list; + + return search_result; +} + +void mail_search_result_free(struct mail_search_result * search_result) +{ + clist_foreach(search_result->list, (clist_func) free, NULL); + clist_free(search_result->list); + free(search_result); +} +#endif + +struct error_message { + int code; + char * message; +}; + +static struct error_message message_tab[] = { +{ MAIL_NO_ERROR, "no error" }, +{ MAIL_NO_ERROR_AUTHENTICATED, "no error - authenticated" }, +{ MAIL_NO_ERROR_NON_AUTHENTICATED, "no error - not authenticated" }, +{ MAIL_ERROR_NOT_IMPLEMENTED, "not implemented" }, +{ MAIL_ERROR_UNKNOWN, "unknown"}, +{ MAIL_ERROR_CONNECT, "connect"}, +{ MAIL_ERROR_BAD_STATE, "bad state"}, +{ MAIL_ERROR_FILE, "file error - file could not be accessed" }, +{ MAIL_ERROR_STREAM, "stream error - socket could not be read or written" }, +{ MAIL_ERROR_LOGIN, "login error" }, +{ MAIL_ERROR_CREATE, "create error" }, +{ MAIL_ERROR_DELETE, /* 10 */ "delete error" }, +{ MAIL_ERROR_LOGOUT, "logout error" }, +{ MAIL_ERROR_NOOP, "noop error" }, +{ MAIL_ERROR_RENAME, "rename error" }, +{ MAIL_ERROR_CHECK, "check error" }, +{ MAIL_ERROR_EXAMINE, "examine error" }, +{ MAIL_ERROR_SELECT, "select error - folder does not exist" }, +{ MAIL_ERROR_MEMORY, "not enough memory" }, +{ MAIL_ERROR_STATUS, "status error" }, +{ MAIL_ERROR_SUBSCRIBE, "subscribe error" }, +{ MAIL_ERROR_UNSUBSCRIBE, /* 20 */ "unsubscribe error" }, +{ MAIL_ERROR_LIST, "list error" }, +{ MAIL_ERROR_LSUB, "lsub error" }, +{ MAIL_ERROR_APPEND, "append error - mail could not be appended" }, +{ MAIL_ERROR_COPY, "copy error" }, +{ MAIL_ERROR_FETCH, "fetch error" }, +{ MAIL_ERROR_STORE, "store error" }, +{ MAIL_ERROR_SEARCH, "search error" }, +{ MAIL_ERROR_DISKSPACE, " error: not enough diskspace" }, +{ MAIL_ERROR_MSG_NOT_FOUND, "message not found" }, +{ MAIL_ERROR_PARSE, /* 30 */ "parse error" }, +{ MAIL_ERROR_INVAL, "invalid parameter for the function" }, +{ MAIL_ERROR_PART_NOT_FOUND, "mime part of the message is not found" }, +{ MAIL_ERROR_REMOVE, "remove error - the message did not exist" }, +{ MAIL_ERROR_FOLDER_NOT_FOUND, "folder not found" }, +{ MAIL_ERROR_MOVE, "move error" }, +{ MAIL_ERROR_STARTTLS, "starttls error" }, +{ MAIL_ERROR_CACHE_MISS, "mail cache missed" }, +{ MAIL_ERROR_NO_TLS, "no starttls" }, +{ MAIL_ERROR_EXPUNGE, "expunge error" }, +{ MAIL_ERROR_PROTOCOL, "protocol error - server did not respect the protocol" }, +{ MAIL_ERROR_CAPABILITY, "capability error" }, +{ MAIL_ERROR_CLOSE, "close error" }, +{ MAIL_ERROR_FATAL, "fatal error" }, +{ MAIL_ERROR_READONLY, "mailbox is readonly" }, +{ MAIL_ERROR_NO_APOP, "pop3 error - no apop" }, +{ MAIL_ERROR_COMMAND_NOT_SUPPORTED, "nntp error - command not supported" }, +{ MAIL_ERROR_NO_PERMISSION, "nntp error - no permission" }, +{ MAIL_ERROR_PROGRAM_ERROR, "nntp error - program error" }, +{ MAIL_ERROR_SUBJECT_NOT_FOUND, "internal threading error - subject not found" }}; + +const char * maildriver_strerror(int err) +{ + int count; + int i; + + count = sizeof(message_tab) / sizeof(struct error_message); + + for(i = 0 ; i < count ; i++) { + if (message_tab[i].code == err) { + return message_tab[i].message; + } + } + + return "unknown error"; +} + + +struct mail_flags * mail_flags_new_empty(void) +{ + struct mail_flags * flags; + + flags = malloc(sizeof(* flags)); + if (flags == NULL) + goto err; + + flags->fl_flags = MAIL_FLAG_NEW; + flags->fl_extension = clist_new(); + if (flags->fl_extension == NULL) + goto free; + + return flags; + + free: + free(flags); + err: + return NULL; +} + +struct mail_flags * mail_flags_new(uint32_t fl_flags, clist * fl_extension) +{ + struct mail_flags * flags; + + flags = malloc(sizeof(* flags)); + if (flags == NULL) + goto err; + + flags->fl_flags = fl_flags; + flags->fl_extension = fl_extension; + + return flags; + +err: + return NULL; +} + +void mail_flags_free(struct mail_flags * flags) +{ + clist_foreach(flags->fl_extension, (clist_func) free, NULL); + clist_free(flags->fl_extension); + free(flags); +} + diff --git a/libetpan/src/driver/interface/maildriver_types.h b/libetpan/src/driver/interface/maildriver_types.h new file mode 100644 index 0000000..2225236 --- a/dev/null +++ b/libetpan/src/driver/interface/maildriver_types.h @@ -0,0 +1,795 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef 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/libetpan/src/driver/interface/maildriver_types_helper.c b/libetpan/src/driver/interface/maildriver_types_helper.c new file mode 100644 index 0000000..6e3abf4 --- a/dev/null +++ b/libetpan/src/driver/interface/maildriver_types_helper.c @@ -0,0 +1,104 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 200 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "maildriver_types_helper.h" + +#include "mail.h" + +#include "clist.h" +#include <string.h> +#include <stdlib.h> + +int mail_flags_add_extension(struct mail_flags * flags, + char * ext_flag) +{ + char * str; + int r; + + if (mail_flags_has_extension(flags, ext_flag)) + return MAIL_NO_ERROR; + + str = strdup(ext_flag); + if (str == NULL) + return MAIL_ERROR_MEMORY; + + r = clist_append(flags->fl_extension, str); + if (r < 0) { + free(str); + return MAIL_ERROR_MEMORY; + } + + return MAIL_NO_ERROR; +} + +int mail_flags_remove_extension(struct mail_flags * flags, + char * ext_flag) +{ + clistiter * cur; + + cur = clist_begin(flags->fl_extension); + while (cur != NULL) { + char * flag_name; + + flag_name = clist_content(cur); + + if (strcasecmp(flag_name, ext_flag) == 0) { + free(flag_name); + cur = clist_delete(flags->fl_extension, cur); + } + else + cur = clist_next(cur); + } + + return MAIL_NO_ERROR; +} + +int mail_flags_has_extension(struct mail_flags * flags, + char * ext_flag) +{ + clistiter * cur; + + for(cur = clist_begin(flags->fl_extension) ; cur != NULL ; + cur = clist_next(cur)) { + char * flag_name; + + flag_name = clist_content(cur); + + if (strcasecmp(flag_name, ext_flag) == 0) + return TRUE; + } + + return FALSE; +} diff --git a/libetpan/src/driver/interface/maildriver_types_helper.h b/libetpan/src/driver/interface/maildriver_types_helper.h new file mode 100644 index 0000000..50ccc70 --- a/dev/null +++ b/libetpan/src/driver/interface/maildriver_types_helper.h @@ -0,0 +1,99 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MAILDRIVER_TYPES_HELPER_H + +#define MAILDRIVER_TYPES_HELPER_H + +#include <libetpan/maildriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + mail_flags_add_extension adds the given flag if it does not exists in + the flags. + + @param flags this is the flag to change + + @param ext_flag this is the name of an extension flag + the given flag name is duplicated and is no more needed after + the function call. + + @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned + on error +*/ + +int mail_flags_add_extension(struct mail_flags * flags, + char * ext_flag); + +/* + mail_flags_remove_extension removes the given flag if it does not exists in + the flags. + + @param flags this is the flag to change + + @param ext_flag this is the name of an extension flag + the given flag name is no more needed after the function call. + + @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned + on error +*/ + +int mail_flags_remove_extension(struct mail_flags * flags, + char * ext_flag); + +/* + mail_flags_has_extension returns 1 if the flags is in the given flags, + 0 is returned otherwise. + + @param flags this is the flag to change + + @param ext_flag this is the name of an extension flag + the given flag name is no more needed after the function call. + + @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned + on error +*/ + +int mail_flags_has_extension(struct mail_flags * flags, + char * ext_flag); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/interface/mailfolder.c b/libetpan/src/driver/interface/mailfolder.c new file mode 100644 index 0000000..eb69d7f --- a/dev/null +++ b/libetpan/src/driver/interface/mailfolder.c @@ -0,0 +1,138 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "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/libetpan/src/driver/interface/mailfolder.h b/libetpan/src/driver/interface/mailfolder.h new file mode 100644 index 0000000..55ea3be --- a/dev/null +++ b/libetpan/src/driver/interface/mailfolder.h @@ -0,0 +1,70 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef 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/libetpan/src/driver/interface/mailmessage.c b/libetpan/src/driver/interface/mailmessage.c new file mode 100644 index 0000000..b4921e5 --- a/dev/null +++ b/libetpan/src/driver/interface/mailmessage.c @@ -0,0 +1,240 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "mailmessage.h" + +#include "mail.h" + +#include <string.h> + +int mailmessage_init(mailmessage * msg_info, + mailsession * msg_session, + mailmessage_driver * msg_driver, + uint32_t msg_index, size_t msg_size) +{ + int r; + int res; + + msg_info->msg_driver = msg_driver; + msg_info->msg_session = msg_session; + msg_info->msg_index = msg_index; + msg_info->msg_uid = NULL; + + msg_info->msg_cached = FALSE; + msg_info->msg_size = msg_size; + msg_info->msg_fields = NULL; + memset(&msg_info->msg_single_fields, 0, + sizeof(struct mailimf_single_fields)); + msg_info->msg_resolved = FALSE; + msg_info->msg_flags = NULL; + + msg_info->msg_mime = NULL; + msg_info->msg_data = NULL; + msg_info->msg_folder = NULL; + msg_info->msg_user_data = NULL; + + if (msg_driver->msg_initialize != NULL) { + r = msg_driver->msg_initialize(msg_info); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + } + + return MAIL_NO_ERROR; + + err: + msg_info->msg_driver = NULL; + msg_info->msg_session = NULL; + return res; +} + +int mailmessage_flush(mailmessage * msg_info) +{ + if (msg_info->msg_driver->msg_flush == NULL) + return MAIL_ERROR_NOT_IMPLEMENTED; + + msg_info->msg_driver->msg_flush(msg_info); + + return MAIL_NO_ERROR; +} + +int mailmessage_check(mailmessage * msg_info) +{ + if (msg_info->msg_driver->msg_check == NULL) + return MAIL_ERROR_NOT_IMPLEMENTED; + + msg_info->msg_driver->msg_check(msg_info); + + return MAIL_NO_ERROR; +} + +int mailmessage_fetch_result_free(mailmessage * msg_info, + char * msg) +{ + if (msg_info->msg_driver->msg_fetch_result_free == NULL) + return MAIL_ERROR_NOT_IMPLEMENTED; + + msg_info->msg_driver->msg_fetch_result_free(msg_info, msg); + + return MAIL_NO_ERROR; +} + +int mailmessage_fetch(mailmessage * msg_info, + char ** result, + size_t * result_len) +{ + if (msg_info->msg_driver->msg_fetch == NULL) + return MAIL_ERROR_NOT_IMPLEMENTED; + + return msg_info->msg_driver->msg_fetch(msg_info, result, result_len); +} + +int mailmessage_fetch_header(mailmessage * msg_info, + char ** result, + size_t * result_len) +{ + if (msg_info->msg_driver->msg_fetch_header == NULL) + return MAIL_ERROR_NOT_IMPLEMENTED; + + return msg_info->msg_driver->msg_fetch_header(msg_info, result, result_len); +} + +int mailmessage_fetch_body(mailmessage * msg_info, + char ** result, size_t * result_len) +{ + if (msg_info->msg_driver->msg_fetch_body == NULL) + return MAIL_ERROR_NOT_IMPLEMENTED; + + return msg_info->msg_driver->msg_fetch_body(msg_info, result, result_len); +} + +int mailmessage_fetch_size(mailmessage * msg_info, + size_t * result) +{ + if (msg_info->msg_driver->msg_fetch_size == NULL) + return MAIL_ERROR_NOT_IMPLEMENTED; + + return msg_info->msg_driver->msg_fetch_size(msg_info, result); +} + +int mailmessage_get_bodystructure(mailmessage * msg_info, + struct mailmime ** result) +{ + if (msg_info->msg_driver->msg_get_bodystructure == NULL) + return MAIL_ERROR_NOT_IMPLEMENTED; + + return msg_info->msg_driver->msg_get_bodystructure(msg_info, result); +} + +int mailmessage_fetch_section(mailmessage * msg_info, + struct mailmime * mime, + char ** result, size_t * result_len) +{ + if (msg_info->msg_driver->msg_fetch_section == NULL) + return MAIL_ERROR_NOT_IMPLEMENTED; + + return msg_info->msg_driver->msg_fetch_section(msg_info, mime, result, result_len); +} + +int mailmessage_fetch_section_header(mailmessage * msg_info, + struct mailmime * mime, + char ** result, + size_t * result_len) +{ + if (msg_info->msg_driver->msg_fetch_section_header == NULL) + return MAIL_ERROR_NOT_IMPLEMENTED; + + return msg_info->msg_driver->msg_fetch_section_header(msg_info, mime, + result, result_len); +} + +int mailmessage_fetch_section_mime(mailmessage * msg_info, + struct mailmime * mime, + char ** result, + size_t * result_len) +{ + if (msg_info->msg_driver->msg_fetch_section_mime == NULL) + return MAIL_ERROR_NOT_IMPLEMENTED; + + return msg_info->msg_driver->msg_fetch_section_mime(msg_info, mime, + result, result_len); +} + +int mailmessage_fetch_section_body(mailmessage * msg_info, + struct mailmime * mime, + char ** result, + size_t * result_len) +{ + if (msg_info->msg_driver->msg_fetch_section_body == NULL) + return MAIL_ERROR_NOT_IMPLEMENTED; + + return msg_info->msg_driver->msg_fetch_section_body(msg_info, mime, + result, result_len); +} + +int mailmessage_fetch_envelope(mailmessage * msg_info, + struct mailimf_fields ** result) +{ + if (msg_info->msg_driver->msg_fetch_envelope == NULL) + return MAIL_ERROR_NOT_IMPLEMENTED; + + return msg_info->msg_driver->msg_fetch_envelope(msg_info, result); +} + +int mailmessage_get_flags(mailmessage * msg_info, + struct mail_flags ** result) +{ + struct mail_flags * dummy; + + if (msg_info->msg_driver->msg_get_flags == NULL) + return MAIL_ERROR_NOT_IMPLEMENTED; + + if (result != NULL) + return msg_info->msg_driver->msg_get_flags(msg_info, result); + else + return msg_info->msg_driver->msg_get_flags(msg_info, &dummy); +} + +void mailmessage_resolve_single_fields(mailmessage * msg_info) +{ + if (!msg_info->msg_resolved) { + if (msg_info->msg_fields != NULL) { + mailimf_single_fields_init(&msg_info->msg_single_fields, + msg_info->msg_fields); + msg_info->msg_resolved = TRUE; + } + } +} diff --git a/libetpan/src/driver/interface/mailmessage.h b/libetpan/src/driver/interface/mailmessage.h new file mode 100644 index 0000000..02b351b --- a/dev/null +++ b/libetpan/src/driver/interface/mailmessage.h @@ -0,0 +1,379 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include <libetpan/mailmessage_types.h> + +#ifndef MAILMESSAGE_H + +#define MAILMESSAGE_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* + mailmessage_new + + This function will initializes a new empty message. + + @return a new empty message will be returned. +*/ + +mailmessage * mailmessage_new(void); + +/* + mailmessage_free + + This function will release the memory used by this message. +*/ + +void mailmessage_free(mailmessage * info); + +/* + mailmessage_init + + This function will initializes a mailmessage structure + with a message from a given session. + + @param msg_info This is the message to initialize. + + @param session This is the source session of the message. It + can be NULL if the message does not get the information + through the session. + + @param driver This is the driver to use for the message. + + @param index This is the message number in the session. 0 can + be given if the message is not attached to a session. + + @param size is an optional parameter, 0 can be given. + This is informational. This is the size of message content. + + @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned + on error +*/ + +int mailmessage_init(mailmessage * msg_info, + mailsession * session, + mailmessage_driver * driver, + uint32_t index, size_t size); + +/* + mailmessage_flush + + This function will release all the temporary resources that are not + necessary to use the mailmessage structure from memory. These + resources are for example cached information, such as the MIME + structure. + + @param info is the message to clean. + + @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned + on error. We can assume that MAIL_NO_ERROR is always returned. +*/ + +int mailmessage_flush(mailmessage * info); + +/* + mailmessage_check + + This function will notify the new value of the flags to the session, + it must be called before mailsession_check_folder() in case the flags have + been changed. + + @param info is the message to checkpoint. + + @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned + on error. We can assume that MAIL_NO_ERROR is always returned. +*/ + +int mailmessage_check(mailmessage * info); + +/* + mailmessage_fetch_result_free + + This function releases the memory used by a message returned + by any of the fetch function that returns a (char *). + + @param msg_info is the message which the given buffer is from. + + @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned + on error. We can assume that MAIL_NO_ERROR is always returned. +*/ + +int mailmessage_fetch_result_free(mailmessage * msg_info, + char * msg); + +/* + mailmessage_fetch + + This function returns the content of the message (headers and text). + + @param msg_info is the message from which we want to fetch information. + + @param result The content of the message is returned in (* result) + + @param result_len The length of the returned string is stored + in (* result_len). + + @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned + on error. +*/ + +int mailmessage_fetch(mailmessage * msg_info, + char ** result, + size_t * result_len); + +/* + mailmessage_fetch_header + + This function returns the header of the message as a string. + + @param msg_info is the message from which we want to fetch information. + + @param result The header of the message is returned in (* result) + + @param result_len The length of the returned string is stored + in (* result_len). + + @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned + on error. +*/ + +int mailmessage_fetch_header(mailmessage * msg_info, + char ** result, + size_t * result_len); + +/* + mailmessage_fetch_body + + This function returns the content of the message (without headers). + + @param msg_info is the message from which we want to fetch information. + @param result The message text (without headers) is returned + in (* result) + @param result_len The length of the returned string is stored + in (* result_len). + + @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned + on error. +*/ + +int mailmessage_fetch_body(mailmessage * msg_info, + char ** result, size_t * result_len); + +/* + mailmessage_fetch_size + + This function returns the size of the message content. + + @param msg_info is the message from which we want to fetch information. + + @param result The length of the message content is stored in (* result). + + @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned + on error. +*/ + +int mailmessage_fetch_size(mailmessage * msg_info, + size_t * result); + +/* + mailmessage_get_bodystructure + + This functions returns the MIME structure of the message. + The returned information MUST not be freed by hand. It is freed by + mailmessage_flush() or mailmessage_free(). + + @param msg_info is the message from which we want to fetch information. + + @param result The MIME structure is stored in (* result). + + @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned + on error. +*/ + +int mailmessage_get_bodystructure(mailmessage * msg_info, + struct mailmime ** result); + +/* + mailmessage_fetch_section + + This function returns the content of a MIME part. + + @param msg_info is the message from which we want to fetch information. + + @param mime is the MIME part identifier. + + @param result The content is returned in (* result) + + @param result_len The length of the returned string is stored + in (* result_len). + + @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned + on error. + */ + +int mailmessage_fetch_section(mailmessage * msg_info, + struct mailmime * mime, + char ** result, size_t * result_len); + +/* + mailmessage_fetch_section_header + + This function returns the header of the message contained + in the given MIME part. + + @param msg_info is the message from which we want to fetch information. + + @param mime is the MIME part identifier. + + @param result The header is returned in (* result) + + @param result_len The length of the returned string is stored + in (* result_len). + + @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned + on error. +*/ + +int mailmessage_fetch_section_header(mailmessage * msg_info, + struct mailmime * mime, + char ** result, + size_t * result_len); + +/* + mailmessage_fetch_section_mime + + This function returns the MIME header of the given MIME part. + + @param msg_info is the message from which we want to fetch information. + + @param mime is the MIME part identifier. + + @param result The MIME header is returned in (* result) + + @param result_len The length of the returned string is stored + in (* result_len). + + @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned + on error. +*/ + +int mailmessage_fetch_section_mime(mailmessage * msg_info, + struct mailmime * mime, + char ** result, + size_t * result_len); + +/* + mailmessage_fetch_section_body + + This function returns the text part of the message contained + in the given MIME part. + + @param msg_info is the message from which we want to fetch information. + + @param mime is the MIME part identifier. + + @param result The message text is returned in (* result) + + @param result_len The length of the returned string is stored + in (* result_len). + + @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned + on error. + */ + +int mailmessage_fetch_section_body(mailmessage * msg_info, + struct mailmime * mime, + char ** result, + size_t * result_len); + +/* + mailmessage_fetch_envelope + + This function returns a list of parsed fields of the message, + chosen by the driver. + The returned structure must be freed with mailimf_fields_free(). + + @param msg_info is the message from which we want to fetch information. + + @param result The headers list is returned in (* result) + + @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned + on error. + */ + +int mailmessage_fetch_envelope(mailmessage * msg_info, + struct mailimf_fields ** result); + + +/* + mailmessage_get_flags + + This function returns the flags related to the message. + The returned information MUST not be freed by hand. It is freed by + mailmessage_free(). + + @param msg_info is the message from which we want to fetch information. + + @param result The flags are stored in (* result). + + @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned + on error. +*/ + +int mailmessage_get_flags(mailmessage * msg_info, + struct mail_flags ** result); + +/* + mailmessage_resolve_single_fields + + This function will use the fields information to fill the single_fields + structure in the mailmessage structure. + + @param msg_info This is the msg_info to process. + + @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned + on error. +*/ + +void mailmessage_resolve_single_fields(mailmessage * msg_info); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/interface/mailmessage_tools.c b/libetpan/src/driver/interface/mailmessage_tools.c new file mode 100644 index 0000000..9e53173 --- a/dev/null +++ b/libetpan/src/driver/interface/mailmessage_tools.c @@ -0,0 +1,600 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "mailmessage_tools.h" +#include "mailmessage.h" + +#include <stdlib.h> + +#include "maildriver.h" +#include "maildriver_tools.h" + +int +mailmessage_generic_initialize(mailmessage * msg_info) +{ + struct generic_message_t * msg; + + msg = malloc(sizeof(* msg)); + + if (msg == NULL) { + return MAIL_ERROR_MEMORY; + } + + msg->msg_fetched = 0; + msg->msg_message = NULL; + msg->msg_length = 0; + + msg->msg_prefetch = NULL; + msg->msg_prefetch_free = NULL; + msg->msg_data = NULL; + + msg_info->msg_data = msg; + + return MAIL_NO_ERROR; +} + +void mailmessage_generic_flush(mailmessage * msg_info) +{ + struct generic_message_t * msg; + + if (msg_info->msg_mime != NULL) { + mailmime_free(msg_info->msg_mime); + msg_info->msg_mime = NULL; + } + msg = msg_info->msg_data; + if (msg != NULL) { + if (msg->msg_prefetch_free != NULL) + msg->msg_prefetch_free(msg); + msg->msg_fetched = 0; + } +} + +void mailmessage_generic_uninitialize(mailmessage * msg_info) +{ + struct generic_message_t * msg; + + mailmessage_generic_flush(msg_info); + + msg = msg_info->msg_data; + msg_info->msg_data = NULL; + free(msg); +} + +static inline int +mailmessage_generic_prefetch(mailmessage * msg_info) +{ + struct generic_message_t * msg; + int r; + + msg = msg_info->msg_data; + + if (msg->msg_fetched) + return MAIL_NO_ERROR; + +#if 0 + if (msg->message != NULL) + return MAIL_NO_ERROR; +#endif + + r = msg->msg_prefetch(msg_info); + if (r != MAIL_NO_ERROR) + return r; + + msg->msg_fetched = 1; + + return MAIL_NO_ERROR; +} + +static int +mailmessage_generic_prefetch_bodystructure(mailmessage * msg_info) +{ + size_t length; + char * message; + size_t cur_token; + struct mailmime * mime; + int r; + int res; + struct generic_message_t * msg; + + if (msg_info->msg_mime != NULL) { + /* it has already been fetched */ + return MAIL_NO_ERROR; + } + +#if 0 + msg = msg_info->data; + if (msg->message == NULL) { + r = mailmessage_generic_prefetch(msg_info); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + } +#endif + r = mailmessage_generic_prefetch(msg_info); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + msg = msg_info->msg_data; + message = msg->msg_message; + length = msg->msg_length; + cur_token = 0; + r = mailmime_parse(message, length, &cur_token, &mime); + if (r != MAILIMF_NO_ERROR) { + res = MAIL_ERROR_PARSE; + goto err; + } + + msg_info->msg_mime = mime; + + return MAIL_NO_ERROR; + + err: + return res; +} + +void +mailmessage_generic_fetch_result_free(mailmessage * msg_info, char * msg) +{ + int r; + + r = mmap_string_unref(msg); +} + +int mailmessage_generic_fetch(mailmessage * msg_info, + char ** result, + size_t * result_len) +{ + int r; + char * message; + size_t cur_token; + size_t length; + MMAPString * mmapstr; + int res; + struct generic_message_t * msg; + + msg = msg_info->msg_data; + r = mailmessage_generic_prefetch(msg_info); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + message = msg->msg_message; + length = msg->msg_length; + cur_token = 0; + + mmapstr = mmap_string_new_len(message, length); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + r = mmap_string_ref(mmapstr); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_mmap; + } + + * result = mmapstr->str; + * result_len = length; + + return MAIL_NO_ERROR; + + free_mmap: + mmap_string_free(mmapstr); + err: + return res; +} + +int mailmessage_generic_fetch_header(mailmessage * msg_info, + char ** result, + size_t * result_len) +{ + int r; + char * message; + size_t cur_token; + size_t length; + MMAPString * mmapstr; + char * headers; + int res; + struct generic_message_t * msg; + + msg = msg_info->msg_data; + r = mailmessage_generic_prefetch(msg_info); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + message = msg->msg_message; + length = msg->msg_length; + cur_token = 0; + + while (1) { + r = mailimf_ignore_field_parse(message, length, &cur_token); + if (r == MAILIMF_NO_ERROR) { + /* do nothing */ + } + else + break; + } + mailimf_crlf_parse(message, length, &cur_token); + + mmapstr = mmap_string_new_len(message, cur_token); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + r = mmap_string_ref(mmapstr); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_mmap; + } + + headers = mmapstr->str; + + * result = headers; + * result_len = cur_token; + + return MAIL_NO_ERROR; + + free_mmap: + mmap_string_free(mmapstr); + err: + return res; +} + +int mailmessage_generic_fetch_body(mailmessage * msg_info, + char ** result, size_t * result_len) +{ + int r; + char * message; + size_t cur_token; + MMAPString * mmapstr; + size_t length; + int res; + struct generic_message_t * msg; + + msg = msg_info->msg_data; + r = mailmessage_generic_prefetch(msg_info); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + message = msg->msg_message; + length = msg->msg_length; + cur_token = 0; + + while (1) { + r = mailimf_ignore_field_parse(message, length, &cur_token); + if (r == MAILIMF_NO_ERROR) { + /* do nothing */ + } + else + break; + } + mailimf_crlf_parse(message, length, &cur_token); + + mmapstr = mmap_string_new_len(message + cur_token, length - cur_token); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + r = mmap_string_ref(mmapstr); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_mmap; + } + + * result = mmapstr->str; + * result_len = length - cur_token; + + return MAIL_NO_ERROR; + + free_mmap: + mmap_string_free(mmapstr); + err: + return res; +} + + + + +int +mailmessage_generic_get_bodystructure(mailmessage * msg_info, + struct mailmime ** result) +{ + int r; + + r = mailmessage_generic_prefetch_bodystructure(msg_info); + if (r != MAIL_NO_ERROR) + return r; + + * result = msg_info->msg_mime; + + return MAIL_NO_ERROR; +} + + + + +int +mailmessage_generic_fetch_section(mailmessage * msg_info, + struct mailmime * mime, + char ** result, size_t * result_len) +{ + MMAPString * mmapstr; + int r; + int res; + + mmapstr = mmap_string_new_len(mime->mm_body->dt_data.dt_text.dt_data, + mime->mm_body->dt_data.dt_text.dt_length); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + r = mmap_string_ref(mmapstr); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_mmap; + } + + * result = mmapstr->str; + * result_len = mmapstr->len; + + return MAIL_NO_ERROR; + + free_mmap: + mmap_string_free(mmapstr); + err: + return res; +} + +int +mailmessage_generic_fetch_section_header(mailmessage * msg_info, + struct mailmime * mime, + char ** result, + size_t * result_len) +{ + MMAPString * mmapstr; + int r; + int res; + size_t cur_token; + + /* skip mime */ + + cur_token = 0; + + if (mime->mm_type == MAILMIME_MESSAGE) { + + while (1) { + r = mailimf_ignore_field_parse(mime->mm_body->dt_data.dt_text.dt_data, + mime->mm_body->dt_data.dt_text.dt_length, &cur_token); + if (r == MAILIMF_NO_ERROR) { + /* do nothing */ + } + else + break; + } + + r = mailimf_crlf_parse(mime->mm_body->dt_data.dt_text.dt_data, + mime->mm_body->dt_data.dt_text.dt_length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { + res = maildriver_imf_error_to_mail_error(r); + goto err; + } + } + + mmapstr = mmap_string_new_len(mime->mm_body->dt_data.dt_text.dt_data, + cur_token); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + r = mmap_string_ref(mmapstr); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_mmap; + } + + * result = mmapstr->str; + * result_len = mmapstr->len; + + return MAIL_NO_ERROR; + + free_mmap: + mmap_string_free(mmapstr); + err: + return res; +} + +int +mailmessage_generic_fetch_section_mime(mailmessage * msg_info, + struct mailmime * mime, + char ** result, + size_t * result_len) +{ + MMAPString * mmapstr; + int r; + int res; + size_t cur_token; + + cur_token = 0; + + /* skip header */ + + while (1) { + r = mailimf_ignore_field_parse(mime->mm_mime_start, + mime->mm_length, &cur_token); + if (r == MAILIMF_NO_ERROR) { + /* do nothing */ + } + else + break; + } + + r = mailimf_crlf_parse(mime->mm_mime_start, mime->mm_length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { + res = maildriver_imf_error_to_mail_error(r); + goto err; + } + + mmapstr = mmap_string_new_len(mime->mm_mime_start, cur_token); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + r = mmap_string_ref(mmapstr); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_mmap; + } + + * result = mmapstr->str; + * result_len = mmapstr->len; + + return MAIL_NO_ERROR; + + free_mmap: + mmap_string_free(mmapstr); + err: + return res; +} + +int +mailmessage_generic_fetch_section_body(mailmessage * msg_info, + struct mailmime * mime, + char ** result, + size_t * result_len) +{ + MMAPString * mmapstr; + int r; + int res; + size_t cur_token; + + cur_token = 0; + + if (mime->mm_type == MAILMIME_MESSAGE) { + + /* skip header */ + + while (1) { + r = mailimf_ignore_field_parse(mime->mm_body->dt_data.dt_text.dt_data, + mime->mm_body->dt_data.dt_text.dt_length, &cur_token); + if (r == MAILIMF_NO_ERROR) { + /* do nothing */ + } + else + break; + } + + r = mailimf_crlf_parse(mime->mm_body->dt_data.dt_text.dt_data, + mime->mm_body->dt_data.dt_text.dt_length, &cur_token); + if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { + res = maildriver_imf_error_to_mail_error(r); + goto err; + } + } + + mmapstr = mmap_string_new_len(mime->mm_body->dt_data.dt_text.dt_data + + cur_token, mime->mm_body->dt_data.dt_text.dt_length - cur_token); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + r = mmap_string_ref(mmapstr); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_mmap; + } + + * result = mmapstr->str; + * result_len = mmapstr->len; + + return MAIL_NO_ERROR; + + free_mmap: + mmap_string_free(mmapstr); + err: + return res; +} + +int mailmessage_generic_fetch_envelope(mailmessage * msg_info, + struct mailimf_fields ** result) +{ + int r; + int res; + size_t cur_token; + char * header; + size_t length; + struct mailimf_fields * fields; + + r = mailmessage_fetch_header(msg_info, &header, &length); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + cur_token = 0; + + r = mailimf_envelope_fields_parse(header, length, &cur_token, + &fields); + if (r != MAILIMF_NO_ERROR) { + res = maildriver_imf_error_to_mail_error(r); + goto free; + /* do nothing */ + } + + mailmessage_fetch_result_free(msg_info, header); + + * result = fields; + + return MAIL_NO_ERROR; + + free: + mailmessage_fetch_result_free(msg_info, header); + err: + return res; +} diff --git a/libetpan/src/driver/interface/mailmessage_tools.h b/libetpan/src/driver/interface/mailmessage_tools.h new file mode 100644 index 0000000..fd055c7 --- a/dev/null +++ b/libetpan/src/driver/interface/mailmessage_tools.h @@ -0,0 +1,103 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MAILMESSAGE_TOOLS_H + +#define MAILMESSAGE_TOOLS_H + +#include "mailmessage_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int +mailmessage_generic_initialize(mailmessage * + msg_info); + +void mailmessage_generic_uninitialize(mailmessage * + msg_info); + +void mailmessage_generic_flush(mailmessage * msg_info); + +void mailmessage_generic_fetch_result_free(mailmessage * msg_info, + char * msg); + +int mailmessage_generic_fetch(mailmessage * msg_info, + char ** result, + size_t * result_len); + +int mailmessage_generic_fetch_header(mailmessage * msg_info, + char ** result, + size_t * result_len); + +int mailmessage_generic_fetch_body(mailmessage * msg_info, + char ** result, size_t * result_len); + +int mailmessage_generic_get_bodystructure(mailmessage * + msg_info, + struct mailmime ** result); + +int +mailmessage_generic_fetch_section(mailmessage * msg_info, + struct mailmime * mime, + char ** result, size_t * result_len); + +int +mailmessage_generic_fetch_section_header(mailmessage * msg_info, + struct mailmime * mime, + char ** result, + size_t * result_len); + +int +mailmessage_generic_fetch_section_mime(mailmessage * msg_info, + struct mailmime * mime, + char ** result, + size_t * result_len); + +int +mailmessage_generic_fetch_section_body(mailmessage * msg_info, + struct mailmime * mime, + char ** result, + size_t * result_len); + +int mailmessage_generic_fetch_envelope(mailmessage * msg_info, + struct mailimf_fields ** result); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/interface/mailmessage_types.c b/libetpan/src/driver/interface/mailmessage_types.c new file mode 100644 index 0000000..e0955e4 --- a/dev/null +++ b/libetpan/src/driver/interface/mailmessage_types.c @@ -0,0 +1,92 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "mailmessage_types.h" + +#include "mail.h" + +#include <stdlib.h> +#include <string.h> + +mailmessage * mailmessage_new(void) +{ + mailmessage * msg_info; + + msg_info = malloc(sizeof(* msg_info)); + if (msg_info == NULL) + goto err; + + msg_info->msg_driver = NULL; + msg_info->msg_session = NULL; + msg_info->msg_index = 0; + msg_info->msg_uid = NULL; + + msg_info->msg_cached = FALSE; + msg_info->msg_size = 0; + msg_info->msg_fields = NULL; + memset(&msg_info->msg_single_fields, + 0, sizeof(struct mailimf_single_fields)); + msg_info->msg_resolved = FALSE; + msg_info->msg_flags = NULL; + + msg_info->msg_mime = NULL; + msg_info->msg_data = NULL; + + msg_info->msg_folder = NULL; + msg_info->msg_user_data = NULL; + + return msg_info; + + err: + return NULL; +} + +void mailmessage_free(mailmessage * msg_info) +{ + if (msg_info->msg_driver != NULL) { + if (msg_info->msg_driver->msg_uninitialize != NULL) + msg_info->msg_driver->msg_uninitialize(msg_info); + } + + if (msg_info->msg_fields != NULL) + mailimf_fields_free(msg_info->msg_fields); + if (msg_info->msg_mime != NULL) + mailmime_free(msg_info->msg_mime); + if (msg_info->msg_flags != NULL) + mail_flags_free(msg_info->msg_flags); + if (msg_info->msg_uid != NULL) + free(msg_info->msg_uid); + free(msg_info); +} diff --git a/libetpan/src/driver/interface/mailmessage_types.h b/libetpan/src/driver/interface/mailmessage_types.h new file mode 100644 index 0000000..c3ed2c4 --- a/dev/null +++ b/libetpan/src/driver/interface/mailmessage_types.h @@ -0,0 +1,50 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MAILMESSAGE_TYPES_H + +#define MAILMESSAGE_TYPES_H + +#include <libetpan/maildriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/interface/mailstorage.c b/libetpan/src/driver/interface/mailstorage.c new file mode 100644 index 0000000..2e2ddcb --- a/dev/null +++ b/libetpan/src/driver/interface/mailstorage.c @@ -0,0 +1,341 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "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/libetpan/src/driver/interface/mailstorage.h b/libetpan/src/driver/interface/mailstorage.h new file mode 100644 index 0000000..e8cbda3 --- a/dev/null +++ b/libetpan/src/driver/interface/mailstorage.h @@ -0,0 +1,99 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef 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/libetpan/src/driver/interface/mailstorage_tools.c b/libetpan/src/driver/interface/mailstorage_tools.c new file mode 100644 index 0000000..9d39cab --- a/dev/null +++ b/libetpan/src/driver/interface/mailstorage_tools.c @@ -0,0 +1,372 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "mailstorage_tools.h" + +#include "libetpan-config.h" + +#include <sys/types.h> +#include <netdb.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/wait.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <string.h> + +#include "mail.h" +#include "mailmessage.h" +#include "maildriver.h" + +/* tools */ + +/* connection to TCP/IP server */ + +static int tcp_connect(char * server, uint16_t port) +{ + struct hostent * remotehost; + struct sockaddr_in sa; + int s; + int r; + + s = socket(PF_INET, SOCK_STREAM, 0); + if (s == -1) + goto err; + + remotehost = gethostbyname(server); + if (remotehost == NULL) + goto close_socket; + + sa.sin_family = AF_INET; + sa.sin_port = htons(port); + memcpy(&sa.sin_addr, remotehost->h_addr, remotehost->h_length); + + r = connect(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in)); + if (r == -1) + goto close_socket; + + return s; + + close_socket: + close(s); + err: + return -1; +} + + +/* connection through a shell command */ + +static void do_exec_command(int fd, const char *command, + char *servername, uint16_t port) +{ + int i, maxopen; + + if (fork() > 0) { + /* Fork again to become a child of init rather than + the etpan client. */ + exit(0); + } + + if (servername) + setenv("ETPANSERVER", servername, 1); + else + unsetenv("ETPANSERVER"); + + if (port) { + char porttext[20]; + + snprintf(porttext, sizeof(porttext), "%d", port); + setenv("ETPANPORT", porttext, 1); + } + else { + unsetenv("ETPANPORT"); + } + + /* Not a lot we can do if there's an error other than bail. */ + if (dup2(fd, 0) == -1) + exit(1); + if (dup2(fd, 1) == -1) + exit(1); + + /* Should we close stderr and reopen /dev/null? */ + + maxopen = sysconf(_SC_OPEN_MAX); + for (i=3; i < maxopen; i++) + close(i); + +#ifdef TIOCNOTTY + /* Detach from the controlling tty if we have one. Otherwise, + SSH might do something stupid like trying to use it instead + of running $SSH_ASKPASS. Doh. */ + fd = open("/dev/tty", O_RDONLY); + if (fd != -1) { + ioctl(fd, TIOCNOTTY, NULL); + close(fd); + } +#endif /* TIOCNOTTY */ + + execl("/bin/sh", "/bin/sh", "-c", command, NULL); + + /* Eep. Shouldn't reach this */ + exit(1); +} + +static int subcommand_connect(char *command, char *servername, uint16_t port) +{ + int sockfds[2]; + pid_t childpid; + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds)) + return -1; + + childpid = fork(); + if (!childpid) { + do_exec_command(sockfds[1], command, servername, port); + } + else if (childpid == -1) { + close(sockfds[0]); + close(sockfds[1]); + return -1; + } + + close(sockfds[1]); + + /* Reap child, leaving grandchild process to run */ + waitpid(childpid, NULL, 0); + + return sockfds[0]; +} + +int mailstorage_generic_connect(mailsession_driver * driver, + char * servername, + uint16_t port, + char * command, + int connection_type, + int cache_function_id, + char * cache_directory, + int flags_function_id, + char * flags_directory, + mailsession ** result) +{ + int r; + int res; + mailstream * stream; + int fd; + mailsession * session; + int connect_result; + + switch (connection_type) { + case CONNECTION_TYPE_PLAIN: + case CONNECTION_TYPE_TRY_STARTTLS: + case CONNECTION_TYPE_STARTTLS: + case CONNECTION_TYPE_TLS: + fd = tcp_connect(servername, port); + if (fd == -1) { + res = MAIL_ERROR_CONNECT; + goto err; + } + break; + + case CONNECTION_TYPE_COMMAND: + case CONNECTION_TYPE_COMMAND_TRY_STARTTLS: + case CONNECTION_TYPE_COMMAND_STARTTLS: + case CONNECTION_TYPE_COMMAND_TLS: + fd = subcommand_connect(command, servername, port); + break; + + default: + fd = -1; + break; + } + + if (fd == -1) { + res = MAIL_ERROR_INVAL; + goto err; + } + + switch (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: + stream = mailstream_socket_open(fd); + break; + + case CONNECTION_TYPE_TLS: + case CONNECTION_TYPE_COMMAND_TLS: + stream = mailstream_ssl_open(fd); + break; + + default: + stream = NULL; + break; + } + + if (stream == NULL) { + res = MAIL_ERROR_STREAM; + close(fd); + goto err; + } + + session = mailsession_new(driver); + if (session == NULL) { + res = MAIL_ERROR_MEMORY; + goto close_stream; + } + + if (cache_directory != NULL) { + char cache_directory_server[PATH_MAX]; + + snprintf(cache_directory_server, PATH_MAX, "%s/%s", + cache_directory, servername); + + r = mailsession_parameters(session, + cache_function_id, + cache_directory_server); + if (r != MAIL_NO_ERROR) { + res = r; + goto close_stream; + } + } + + if (flags_directory != NULL) { + char flags_directory_server[PATH_MAX]; + + snprintf(flags_directory_server, PATH_MAX, "%s/%s", + flags_directory, servername); + + r = mailsession_parameters(session, + flags_function_id, + flags_directory_server); + if (r != MAIL_NO_ERROR) { + res = r; + goto close_stream; + } + } + + r = mailsession_connect_stream(session, stream); + switch (r) { + case MAIL_NO_ERROR_NON_AUTHENTICATED: + case MAIL_NO_ERROR_AUTHENTICATED: + case MAIL_NO_ERROR: + break; + default: + res = r; + goto free; + } + + connect_result = r; + + switch (connection_type) { + case CONNECTION_TYPE_TRY_STARTTLS: + case CONNECTION_TYPE_COMMAND_TRY_STARTTLS: + r = mailsession_starttls(session); + if ((r != MAIL_NO_ERROR) && (r != MAIL_ERROR_NO_TLS)) { + res = r; + goto free; + } + break; + + case CONNECTION_TYPE_STARTTLS: + case CONNECTION_TYPE_COMMAND_STARTTLS: + r = mailsession_starttls(session); + if (r != MAIL_NO_ERROR) { + res = r; + goto free; + } + } + + * result = session; + + return connect_result; + + close_stream: + mailstream_close(stream); + free: + mailsession_free(session); + err: + return res; +} + + + + + +int mailstorage_generic_auth(mailsession * session, + int connect_result, + int auth_type, + char * login, + char * password) +{ + int must_auth; + int r; + int res; + + r = connect_result; + + must_auth = FALSE; + switch (r) { + case MAIL_NO_ERROR_NON_AUTHENTICATED: + must_auth = TRUE; + break; + case MAIL_NO_ERROR_AUTHENTICATED: + case MAIL_NO_ERROR: + break; + default: + res = r; + goto err; + } + + if ((login == NULL) || (password == NULL)) + must_auth = FALSE; + + if (must_auth) { + r = mailsession_login(session, login, password); + if (r != MAIL_NO_ERROR) { + mailsession_logout(session); + res = r; + goto err; + } + } + + return MAIL_NO_ERROR; + + err: + return res; +} diff --git a/libetpan/src/driver/interface/mailstorage_tools.h b/libetpan/src/driver/interface/mailstorage_tools.h new file mode 100644 index 0000000..113dcdf --- a/dev/null +++ b/libetpan/src/driver/interface/mailstorage_tools.h @@ -0,0 +1,67 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "mailstorage.h" + +#ifndef MAILSTORAGE_TOOLS_H + +#define MAILSTORAGE_TOOLS_H + +#ifdef __cplusplus +extern "C" { +#endif + +int mailstorage_generic_connect(mailsession_driver * driver, + char * servername, + uint16_t port, + char * command, + int connection_type, + int cache_function_id, + char * cache_directory, + int flags_function_id, + char * flags_directory, + mailsession ** result); + +int mailstorage_generic_auth(mailsession * session, + int connect_result, + int auth_type, + char * login, + char * password); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/interface/mailstorage_types.h b/libetpan/src/driver/interface/mailstorage_types.h new file mode 100644 index 0000000..d0d18c8 --- a/dev/null +++ b/libetpan/src/driver/interface/mailstorage_types.h @@ -0,0 +1,203 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MAILSTORAGE_TYPES_H + +#define MAILSTORAGE_TYPES_H + +#include <libetpan/maildriver_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct mailstorage; + +typedef struct mailstorage_driver mailstorage_driver; + + +/* + 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. +*/ + +/* + mailstorage_driver is the driver structure for mail storages + + - name is the name of the driver + + - connect() connects the storage to the remote access or to + the path in the local filesystem. + + - get_folder() can have two kinds of behaviour. + Either it creates a new session and independant from the session + used by the storage and select the given mailbox or + it selects the given mailbox in the current session. + It depends on the efficiency of the mail driver. + + - uninitialize() frees the data created with mailstorage constructor. +*/ + +struct mailstorage_driver { + char * sto_name; + int (* sto_connect)(struct mailstorage * storage); + int (* sto_get_folder_session)(struct mailstorage * storage, + char * pathname, mailsession ** result); + void (* sto_uninitialize)(struct mailstorage * storage); +}; + +/* + mailstorage is the data structure for a storage + + - id is the name of the storage, it can be NULL. + + - data is the data specific to the driver. + This is the internal state of the storage. + + - session is the session related to the storage. + + - driver is the driver for the storage. + + - shared_folders is the list of folders returned by the storage. +*/ + +struct mailstorage { + char * sto_id; + void * sto_data; + mailsession * sto_session; + mailstorage_driver * sto_driver; + clist * sto_shared_folders; /* list of (struct mailfolder *) */ + + void * sto_user_data; +}; + + + +/* + mailfolder is the data structure for a mailbox + + - pathname is the path of the mailbox on the storage + + - virtual_name is the folder identifier, it can be a path, + a name or NULL. + + - storage is the storage to which the folder belongs to. + + - session is the session related to the folder. It can be + different of the session of the storage. + + - shared_session is != 0 if the session is the same as the + session of the storage. + + - pos is the position of the folder in the "shared_folders" field + of the storage. + + folders can be chained into a tree. + + - parent is the parent of the folder. + + - sibling_index is the index of the folder in the list of children + of the parent. + + - children is the folder. +*/ + +struct mailfolder { + char * fld_pathname; + char * fld_virtual_name; + + struct mailstorage * fld_storage; + + mailsession * fld_session; + int fld_shared_session; + clistiter * fld_pos; + + struct mailfolder * fld_parent; + unsigned int fld_sibling_index; + carray * fld_children; /* array of (struct mailfolder *) */ + + void * fld_user_data; +}; + +/* + this is the type of socket connection +*/ + +enum { + CONNECTION_TYPE_PLAIN, /* when the connection is plain text */ + CONNECTION_TYPE_STARTTLS, /* when the connection is first plain, + then, we want to switch to + TLS (secure connection) */ + CONNECTION_TYPE_TRY_STARTTLS, /* the connection is first plain, + then, we will try to switch to TLS */ + CONNECTION_TYPE_TLS, /* the connection is over TLS */ + CONNECTION_TYPE_COMMAND, /* the connection is over a shell command */ + CONNECTION_TYPE_COMMAND_STARTTLS, /* the connection is over a shell + command and STARTTLS will be used */ + CONNECTION_TYPE_COMMAND_TRY_STARTTLS, /* the connection is over + a shell command and STARTTLS will + be tried */ + CONNECTION_TYPE_COMMAND_TLS, /* the connection is over a shell + command in TLS */ +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/tools/generic_cache.c b/libetpan/src/driver/tools/generic_cache.c new file mode 100644 index 0000000..3ff6e43 --- a/dev/null +++ b/libetpan/src/driver/tools/generic_cache.c @@ -0,0 +1,729 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "generic_cache.h" + +#include "libetpan-config.h" + +#include <unistd.h> +#include <string.h> +#include <sys/mman.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> + +#include "maildriver_types.h" +#include "imfcache.h" +#include "chash.h" +#include "mailmessage.h" +#include "mail_cache_db.h" + +int generic_cache_create_dir(char * dirname) +{ + struct stat buf; + int r; + + r = stat(dirname, &buf); + if (r != 0) { + r = mkdir(dirname, 0700); + + if (r < 0) + return MAIL_ERROR_FILE; + } + else { + if (!S_ISDIR(buf.st_mode)) + return MAIL_ERROR_FILE; + } + + return MAIL_NO_ERROR; +} + +int generic_cache_store(char * filename, char * content, size_t length) +{ + int fd; + char * str; + + fd = open(filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + if (fd == -1) + return MAIL_ERROR_FILE; + + if (ftruncate(fd, length) < 0) + return MAIL_ERROR_FILE; + + str = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (str == MAP_FAILED) + return MAIL_ERROR_FILE; + + memcpy(str, content, length); + msync(str, length, MS_SYNC); + munmap(str, length); + + close(fd); + + return MAIL_NO_ERROR; +} + +int generic_cache_read(char * filename, char ** result, size_t * result_len) +{ + int fd; + char * str; + struct stat buf; + MMAPString * mmapstr; + char * content; + int res; + + if (stat(filename, &buf) < 0) { + res = MAIL_ERROR_CACHE_MISS; + goto err; + } + + fd = open(filename, O_RDONLY); + if (fd == -1) { + res = MAIL_ERROR_CACHE_MISS; + goto err; + } + + str = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (str == MAP_FAILED) { + res = MAIL_ERROR_FILE; + goto close; + } + + mmapstr = mmap_string_new_len(str, buf.st_size); + if (mmapstr == NULL) { + res = MAIL_ERROR_MEMORY; + goto unmap; + } + + if (mmap_string_ref(mmapstr) < 0) { + res = MAIL_ERROR_MEMORY; + goto free; + } + + content = mmapstr->str; + + munmap(str, buf.st_size); + close(fd); + + * result = content; + * result_len = buf.st_size; + + return MAIL_NO_ERROR; + + free: + mmap_string_free(mmapstr); + unmap: + munmap(str, buf.st_size); + close: + close(fd); + err: + return res; +} + +static int flags_extension_read(MMAPString * mmapstr, size_t * index, + clist ** result) +{ + clist * list; + int r; + uint32_t count; + uint32_t i; + int res; + + r = mailimf_cache_int_read(mmapstr, index, &count); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + list = clist_new(); + if (list == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + for(i = 0 ; i < count ; i++) { + char * str; + + r = mailimf_cache_string_read(mmapstr, index, &str); + if (r != MAIL_NO_ERROR) { + res = r; + goto free_list; + } + + r = clist_append(list, str); + if (r < 0) { + free(str); + res = MAIL_ERROR_MEMORY; + goto free_list; + } + } + + * result = list; + + return MAIL_NO_ERROR; + + free_list: + clist_foreach(list, (clist_func) free, NULL); + clist_free(list); + err: + return res; +} + +static int generic_flags_read(MMAPString * mmapstr, size_t * index, + struct mail_flags ** result) +{ + clist * ext; + int r; + struct mail_flags * flags; + uint32_t value; + int res; + + r = mailimf_cache_int_read(mmapstr, index, &value); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + r = flags_extension_read(mmapstr, index, &ext); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + flags = mail_flags_new(value, ext); + if (flags == NULL) { + res = r; + goto free; + } + + * result = flags; + + return MAIL_NO_ERROR; + + free: + clist_foreach(ext, (clist_func) free, NULL); + clist_free(ext); + err: + return res; +} + +static int flags_extension_write(MMAPString * mmapstr, size_t * index, + clist * ext) +{ + int r; + clistiter * cur; + + r = mailimf_cache_int_write(mmapstr, index, clist_count(ext)); + if (r != MAIL_NO_ERROR) + return r; + + for(cur = clist_begin(ext) ; cur != NULL ; cur = clist_next(cur)) { + r = mailimf_cache_string_write(mmapstr, index, + clist_content(cur), strlen(clist_content(cur))); + if (r != MAIL_NO_ERROR) + return r; + } + + return MAIL_NO_ERROR; +} + +static int generic_flags_write(MMAPString * mmapstr, size_t * index, + struct mail_flags * flags) +{ + int r; + + r = mailimf_cache_int_write(mmapstr, index, + flags->fl_flags & ~MAIL_FLAG_NEW); + if (r != MAIL_NO_ERROR) + return r; + + r = flags_extension_write(mmapstr, index, + flags->fl_extension); + if (r != MAIL_NO_ERROR) + return r; + + return MAIL_NO_ERROR; +} + + + + +static struct mail_flags * mail_flags_dup(struct mail_flags * flags) +{ + clist * list; + struct mail_flags * new_flags; + int r; + clistiter * cur; + + list = clist_new(); + if (list == NULL) { + goto err; + } + + for(cur = clist_begin(flags->fl_extension) ; cur != NULL ; + cur = clist_next(cur)) { + char * ext; + + ext = strdup(clist_content(cur)); + if (ext == NULL) { + goto free; + } + + r = clist_append(list, ext); + if (r < 0) { + free(ext); + goto free; + } + } + + new_flags = mail_flags_new(flags->fl_flags, list); + if (new_flags == NULL) { + goto free; + } + + return new_flags; + + free: + clist_foreach(list, (clist_func) free, NULL); + clist_free(list); + err: + return NULL; +} + +static mailmessage * mailmessage_build(mailmessage * msg) +{ + mailmessage * new_msg; + + new_msg = malloc(sizeof(* new_msg)); + if (new_msg == NULL) + goto err; + + new_msg->msg_session = msg->msg_session; + new_msg->msg_driver = msg->msg_driver; + new_msg->msg_index = msg->msg_index; + if (msg->msg_uid == NULL) + new_msg->msg_uid = NULL; + else { + new_msg->msg_uid = strdup(msg->msg_uid); + if (new_msg->msg_uid == NULL) + goto free; + } + + new_msg->msg_cached = msg->msg_cached; + new_msg->msg_size = msg->msg_size; + new_msg->msg_fields = NULL; + new_msg->msg_flags = mail_flags_dup(msg->msg_flags); + if (new_msg->msg_flags == NULL) { + free(new_msg->msg_uid); + goto free; + } + + new_msg->msg_mime = NULL; + new_msg->msg_data = NULL; + + return new_msg; + + free: + free(new_msg); + err: + return NULL; +} + +struct mail_flags_store * mail_flags_store_new(void) +{ + struct mail_flags_store * flags_store; + + flags_store = malloc(sizeof(struct mail_flags_store)); + if (flags_store == NULL) + goto err; + + flags_store->fls_tab = carray_new(128); + if (flags_store->fls_tab == NULL) + goto free; + + flags_store->fls_hash = chash_new(128, CHASH_COPYALL); + if (flags_store->fls_hash == NULL) + goto free_tab; + + return flags_store; + + free_tab: + carray_free(flags_store->fls_tab); + free: + free(flags_store); + err: + return NULL; +} + +void mail_flags_store_clear(struct mail_flags_store * flags_store) +{ + unsigned int i; + + for(i = 0 ; i < carray_count(flags_store->fls_tab) ; i ++) { + chashdatum key; + mailmessage * msg; + + msg = carray_get(flags_store->fls_tab, i); + + key.data = &msg->msg_index; + key.len = sizeof(msg->msg_index); + chash_delete(flags_store->fls_hash, &key, NULL); + + mailmessage_free(msg); + } + carray_set_size(flags_store->fls_tab, 0); +} + +void mail_flags_store_free(struct mail_flags_store * flags_store) +{ + mail_flags_store_clear(flags_store); + chash_free(flags_store->fls_hash); + carray_free(flags_store->fls_tab); + free(flags_store); +} + +int mail_flags_store_set(struct mail_flags_store * flags_store, + mailmessage * msg) +{ + chashdatum key; + chashdatum value; + unsigned int index; + int res; + int r; + mailmessage * new_msg; + + if (msg->msg_flags == NULL) { + res = MAIL_NO_ERROR; + goto err; + } + + /* duplicate needed message info */ + new_msg = mailmessage_build(msg); + if (new_msg == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + key.data = &new_msg->msg_index; + key.len = sizeof(new_msg->msg_index); + + r = chash_get(flags_store->fls_hash, &key, &value); + if (r == 0) { + mailmessage * old_msg; + + index = * (unsigned int *) value.data; + old_msg = carray_get(flags_store->fls_tab, index); + mailmessage_free(old_msg); + } + else { + r = carray_set_size(flags_store->fls_tab, + carray_count(flags_store->fls_tab) + 1); + if (r != 0) { + res = MAIL_ERROR_MEMORY; + goto err; + } + index = carray_count(flags_store->fls_tab) - 1; + } + + carray_set(flags_store->fls_tab, index, new_msg); + + value.data = &index; + value.len = sizeof(index); + + r = chash_set(flags_store->fls_hash, &key, &value, NULL); + if (r < 0) { + carray_delete(flags_store->fls_tab, index); + res = MAIL_ERROR_MEMORY; + goto free; + } + + return MAIL_NO_ERROR; + + free: + mailmessage_free(new_msg); + err: + return res; +} + +static int msg_index_compare(mailmessage ** msg1, mailmessage ** msg2) +{ + return (* msg1)->msg_index - (* msg2)->msg_index; +} + +void mail_flags_store_sort(struct mail_flags_store * flags_store) +{ + qsort(carray_data(flags_store->fls_tab), + carray_count(flags_store->fls_tab), sizeof(mailmessage *), + (int (*)(const void *, const void *)) msg_index_compare); +} + +struct mail_flags * +mail_flags_store_get(struct mail_flags_store * flags_store, uint32_t index) +{ + struct mail_flags * flags; + chashdatum key; + chashdatum value; + int r; + unsigned int tab_index; + mailmessage * msg; + + key.data = &index; + key.len = sizeof(index); + + r = chash_get(flags_store->fls_hash, &key, &value); + + if (r < 0) + return NULL; + +#if 0 + flags = mail_flags_dup((struct mail_flags *) value.data); +#endif + tab_index = * (unsigned int *) value.data; + msg = carray_get(flags_store->fls_tab, tab_index); + if (msg->msg_flags == NULL) + return NULL; + + flags = mail_flags_dup(msg->msg_flags); + + return flags; +} + +int mail_flags_compare(struct mail_flags * flags1, struct mail_flags * flags2) +{ + clistiter * cur1; + + if (clist_count(flags1->fl_extension) != clist_count(flags2->fl_extension)) + return -1; + + for(cur1 = clist_begin(flags1->fl_extension) ; cur1 != NULL ; + cur1 = clist_next(cur1)) { + char * flag1; + clistiter * cur2; + int found; + + flag1 = clist_content(cur1); + + found = 0; + for(cur2 = clist_begin(flags2->fl_extension) ; cur2 != NULL ; + cur2 = clist_next(cur2)) { + char * flag2; + + flag2 = clist_content(cur2); + + if (strcasecmp(flag1, flag2) == 0) { + found = 1; + break; + } + } + + if (!found) + return -1; + } + + return flags1->fl_flags - flags2->fl_flags; +} + + +int generic_cache_fields_read(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + char * keyname, struct mailimf_fields ** result) +{ + int r; + int res; + size_t cur_token; + struct mailimf_fields * fields; + void * data; + size_t data_len; + + r = mail_cache_db_get(cache_db, keyname, strlen(keyname), &data, &data_len); + if (r != 0) { + res = MAIL_ERROR_CACHE_MISS; + goto err; + } + + r = mail_serialize_clear(mmapstr, &cur_token); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + if (mmap_string_append_len(mmapstr, data, data_len) == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + r = mailimf_cache_fields_read(mmapstr, &cur_token, &fields); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + * result = fields; + + return MAIL_NO_ERROR; + + err: + return res; +} + +int generic_cache_fields_write(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + char * keyname, struct mailimf_fields * fields) +{ + int r; + int res; + size_t cur_token; + + r = mail_serialize_clear(mmapstr, &cur_token); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_cache_fields_write(mmapstr, &cur_token, fields); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + r = mail_cache_db_put(cache_db, keyname, strlen(keyname), + mmapstr->str, mmapstr->len); + if (r != 0) { + res = MAIL_ERROR_FILE; + goto err; + } + + return MAIL_NO_ERROR; + + err: + return res; +} + +int generic_cache_flags_read(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + char * keyname, struct mail_flags ** result) +{ + int r; + int res; + size_t cur_token; + struct mail_flags * flags; + void * data; + size_t data_len; + + r = mail_cache_db_get(cache_db, keyname, strlen(keyname), &data, &data_len); + if (r != 0) { + res = MAIL_ERROR_CACHE_MISS; + goto err; + } + + r = mail_serialize_clear(mmapstr, &cur_token); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + if (mmap_string_append_len(mmapstr, data, data_len) == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + r = generic_flags_read(mmapstr, &cur_token, &flags); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + * result = flags; + + return MAIL_NO_ERROR; + + err: + return res; +} + +int generic_cache_flags_write(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + char * keyname, struct mail_flags * flags) +{ + int r; + int res; + size_t cur_token; + + r = mail_serialize_clear(mmapstr, &cur_token); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + r = generic_flags_write(mmapstr, &cur_token, flags); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + r = mail_cache_db_put(cache_db, keyname, strlen(keyname), + mmapstr->str, mmapstr->len); + if (r != 0) { + res = MAIL_ERROR_FILE; + goto err; + } + + return MAIL_NO_ERROR; + + err: + return res; +} + + +int generic_cache_delete(struct mail_cache_db * cache_db, + char * keyname) +{ + int r; + int res; + + r = mail_cache_db_del(cache_db, keyname, strlen(keyname)); + if (r != 0) { + res = MAIL_ERROR_FILE; + goto err; + } + + return MAIL_NO_ERROR; + + err: + return res; +} diff --git a/libetpan/src/driver/tools/generic_cache.h b/libetpan/src/driver/tools/generic_cache.h new file mode 100644 index 0000000..934a53d --- a/dev/null +++ b/libetpan/src/driver/tools/generic_cache.h @@ -0,0 +1,109 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef GENERIC_CACHE_H + +#define GENERIC_CACHE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "generic_cache_types.h" +#include "mailmessage_types.h" +#include "chash.h" +#include "carray.h" +#include "mail_cache_db_types.h" + +int generic_cache_create_dir(char * dirname); + +int generic_cache_store(char * filename, char * content, size_t length); +int generic_cache_read(char * filename, char ** result, size_t * result_len); + +int generic_cache_fields_read(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + char * keyname, struct mailimf_fields ** result); + +int generic_cache_fields_write(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + char * keyname, struct mailimf_fields * fields); + +int generic_cache_flags_read(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + char * keyname, struct mail_flags ** result); + +int generic_cache_flags_write(struct mail_cache_db * cache_db, + MMAPString * mmapstr, + char * keyname, struct mail_flags * flags); + +int generic_cache_delete(struct mail_cache_db * cache_db, char * keyname); + +#if 0 +int generic_cache_fields_read(DB * dbp, MMAPString * mmapstr, + char * keyname, struct mailimf_fields ** result); + +int generic_cache_fields_write(DB * dbp, MMAPString * mmapstr, + char * keyname, struct mailimf_fields * fields); + +int generic_cache_flags_read(DB * dbp, MMAPString * mmapstr, + char * keyname, struct mail_flags ** result); + +int generic_cache_flags_write(DB * dbp, MMAPString * mmapstr, + char * keyname, struct mail_flags * flags); + +int generic_cache_delete(DB * dbp, char * keyname); +#endif + +struct mail_flags_store * mail_flags_store_new(void); + +void mail_flags_store_clear(struct mail_flags_store * flags_store); + +void mail_flags_store_free(struct mail_flags_store * flags_store); + +int mail_flags_store_set(struct mail_flags_store * flags_store, + mailmessage * msg); + +void mail_flags_store_sort(struct mail_flags_store * flags_store); + +struct mail_flags * +mail_flags_store_get(struct mail_flags_store * flags_store, uint32_t index); + +int mail_flags_compare(struct mail_flags * flags1, struct mail_flags * flags2); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/tools/generic_cache_types.h b/libetpan/src/driver/tools/generic_cache_types.h new file mode 100644 index 0000000..bc69b3c --- a/dev/null +++ b/libetpan/src/driver/tools/generic_cache_types.h @@ -0,0 +1,56 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef GENERIC_CACHE_TYPE_H + +#define GENERIC_CACHE_TYPE_H + +#include <libetpan/carray.h> +#include <libetpan/chash.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct mail_flags_store { + carray * fls_tab; + chash * fls_hash; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/tools/imfcache.c b/libetpan/src/driver/tools/imfcache.c new file mode 100644 index 0000000..7c6a5be --- a/dev/null +++ b/libetpan/src/driver/tools/imfcache.c @@ -0,0 +1,1429 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "imfcache.h" + +#include <stdlib.h> +#include <string.h> + +static int mailimf_cache_field_write(MMAPString * mmapstr, size_t * index, + struct mailimf_field * field); +static int mailimf_cache_orig_date_write(MMAPString * mmapstr, size_t * index, + struct mailimf_orig_date * date); +static int mailimf_cache_date_time_write(MMAPString * mmapstr, size_t * index, + struct mailimf_date_time * date_time); +static int mailimf_cache_from_write(MMAPString * mmapstr, size_t * index, + struct mailimf_from * from); +static int mailimf_cache_sender_write(MMAPString * mmapstr, size_t * index, + struct mailimf_sender * sender); +static int mailimf_cache_reply_to_write(MMAPString * mmapstr, size_t * index, + struct mailimf_reply_to * reply_to); +static int mailimf_cache_to_write(MMAPString * mmapstr, size_t * index, + struct mailimf_to * to); +static int mailimf_cache_cc_write(MMAPString * mmapstr, size_t * index, + struct mailimf_cc * to); +static int mailimf_cache_bcc_write(MMAPString * mmapstr, size_t * index, + struct mailimf_bcc * to); +static int mailimf_cache_message_id_write(MMAPString * mmapstr, size_t * index, + struct mailimf_message_id * message_id); +static int mailimf_cache_msg_id_list_write(MMAPString * mmapstr, size_t * index, + clist * list); +static int mailimf_cache_in_reply_to_write(MMAPString * mmapstr, size_t * index, + struct mailimf_in_reply_to * + in_reply_to); +static int mailimf_cache_references_write(MMAPString * mmapstr, size_t * index, + struct mailimf_references * references); +static int mailimf_cache_subject_write(MMAPString * mmapstr, size_t * index, + struct mailimf_subject * subject); +static int mailimf_cache_address_list_write(MMAPString * mmapstr, + size_t * index, + struct mailimf_address_list * + addr_list); +static int mailimf_cache_address_write(MMAPString * mmapstr, size_t * index, + struct mailimf_address * addr); +static int mailimf_cache_group_write(MMAPString * mmapstr, size_t * index, + struct mailimf_group * group); +static int mailimf_cache_mailbox_list_write(MMAPString * mmapstr, + size_t * index, + struct mailimf_mailbox_list * mb_list); +static int mailimf_cache_mailbox_write(MMAPString * mmapstr, size_t * index, + struct mailimf_mailbox * mb); + + +static int mailimf_cache_field_read(MMAPString * mmapstr, size_t * index, + struct mailimf_field ** result); +static int mailimf_cache_orig_date_read(MMAPString * mmapstr, size_t * index, + struct mailimf_orig_date ** result); +static int mailimf_cache_date_time_read(MMAPString * mmapstr, size_t * index, + struct mailimf_date_time ** result); +static int mailimf_cache_from_read(MMAPString * mmapstr, size_t * index, + struct mailimf_from ** result); +static int mailimf_cache_sender_read(MMAPString * mmapstr, size_t * index, + struct mailimf_sender ** result); +static int mailimf_cache_reply_to_read(MMAPString * mmapstr, size_t * index, + struct mailimf_reply_to ** result); +static int mailimf_cache_to_read(MMAPString * mmapstr, size_t * index, + struct mailimf_to ** result); +static int mailimf_cache_cc_read(MMAPString * mmapstr, size_t * index, + struct mailimf_cc ** result); +static int mailimf_cache_bcc_read(MMAPString * mmapstr, size_t * index, + struct mailimf_bcc ** result); +static int mailimf_cache_message_id_read(MMAPString * mmapstr, size_t * index, + struct mailimf_message_id ** result); +static int mailimf_cache_msg_id_list_read(MMAPString * mmapstr, size_t * index, + clist ** result); +static int +mailimf_cache_in_reply_to_read(MMAPString * mmapstr, size_t * index, + struct mailimf_in_reply_to ** result); + +static int mailimf_cache_references_read(MMAPString * mmapstr, size_t * index, + struct mailimf_references ** result); +static int mailimf_cache_subject_read(MMAPString * mmapstr, size_t * index, + struct mailimf_subject ** result); +static int mailimf_cache_address_list_read(MMAPString * mmapstr, size_t * index, + struct mailimf_address_list ** result); +static int mailimf_cache_address_read(MMAPString * mmapstr, size_t * index, + struct mailimf_address ** result); +static int mailimf_cache_group_read(MMAPString * mmapstr, size_t * index, + struct mailimf_group ** result); +static int +mailimf_cache_mailbox_list_read(MMAPString * mmapstr, size_t * index, + struct mailimf_mailbox_list ** result); +static int mailimf_cache_mailbox_read(MMAPString * mmapstr, size_t * index, + struct mailimf_mailbox ** result); + +enum { + CACHE_NULL_POINTER = 0, + CACHE_NOT_NULL = 1, +}; + +int mail_serialize_clear(MMAPString * mmapstr, size_t * index) +{ + if (mmap_string_set_size(mmapstr, 0) == NULL) + return MAIL_ERROR_MEMORY; + + * index = 0; + + return MAIL_NO_ERROR; +} + +int mail_serialize_write(MMAPString * mmapstr, size_t * index, + char * buf, size_t size) +{ + if (mmap_string_append_len(mmapstr, buf, size) == NULL) + return MAIL_ERROR_MEMORY; + + * index = * index + size; + + return MAIL_NO_ERROR; +} + +int mail_serialize_read(MMAPString * mmapstr, size_t * index, + char * buf, size_t size) +{ + size_t cur_token; + + cur_token = * index; + + if (cur_token + size > mmapstr->len) + return MAIL_ERROR_STREAM; + + memcpy(buf, mmapstr->str + cur_token, size); + * index = cur_token + size; + + return MAIL_NO_ERROR; +} + +int mailimf_cache_int_write(MMAPString * mmapstr, size_t * index, + uint32_t value) +{ + unsigned char ch; + int r; + int i; + + for(i = 0 ; i < 4 ; i ++) { + ch = value % 256; + + r = mail_serialize_write(mmapstr, index, &ch, 1); + if (r != MAIL_NO_ERROR) + return r; + value /= 256; + } + + return MAIL_NO_ERROR; +} + +int mailimf_cache_int_read(MMAPString * mmapstr, size_t * index, + uint32_t * result) +{ + unsigned char ch; + uint32_t value; + int i; + int r; + + value = 0; + for(i = 0 ; i < 4 ; i ++) { + r = mail_serialize_read(mmapstr, index, &ch, 1); + if (r != MAIL_NO_ERROR) + return r; + value = value | ch << (i << 3); + } + + * result = value; + + return MAIL_NO_ERROR; +} + + +int mailimf_cache_string_write(MMAPString * mmapstr, size_t * index, + char * str, size_t length) +{ + int r; + + if (str == NULL) { + r = mailimf_cache_int_write(mmapstr, index, CACHE_NULL_POINTER); + if (r != MAIL_NO_ERROR) + return r; + } + else { + r = mailimf_cache_int_write(mmapstr, index, CACHE_NOT_NULL); + if (r != MAIL_NO_ERROR) + return r; + + r = mailimf_cache_int_write(mmapstr, index, length); + if (r != MAIL_NO_ERROR) + return r; + + if (length != 0) { + r = mail_serialize_write(mmapstr, index, str, length); + if (r != MAIL_NO_ERROR) + return MAIL_ERROR_FILE; + } + } + + return MAIL_NO_ERROR; +} + +int mailimf_cache_string_read(MMAPString * mmapstr, size_t * index, + char ** result) +{ + int r; + uint32_t length; + char * str; + uint32_t type; + + r = mailimf_cache_int_read(mmapstr, index, &type); + if (r != MAIL_NO_ERROR) + return r; + + if (type == CACHE_NULL_POINTER) { + str = NULL; + } + else { + r = mailimf_cache_int_read(mmapstr, index, &length); + if (r != MAIL_NO_ERROR) + return r; + + str = malloc(length + 1); + if (str == NULL) + return MAIL_ERROR_MEMORY; + + r = mail_serialize_read(mmapstr, index, str, length); + if (r != MAIL_NO_ERROR) + return MAIL_ERROR_FILE; + + str[length] = 0; + } + + * result = str; + + return MAIL_NO_ERROR; +} + +int mailimf_cache_fields_write(MMAPString * mmapstr, size_t * index, + struct mailimf_fields * fields) +{ + clistiter * cur; + int r; + + r = mailimf_cache_int_write(mmapstr, index, + clist_count(fields->fld_list)); + if (r != MAIL_NO_ERROR) + return r; + + for(cur = clist_begin(fields->fld_list) ; cur != NULL ; + cur = clist_next(cur)) { + r = mailimf_cache_field_write(mmapstr, index, clist_content(cur)); + if (r != MAIL_NO_ERROR) + return r; + } + + return MAIL_NO_ERROR; +} + +int mailimf_cache_fields_read(MMAPString * mmapstr, size_t * index, + struct mailimf_fields ** result) +{ + clist * list; + int r; + uint32_t count; + uint32_t i; + struct mailimf_fields * fields; + int res; + + r = mailimf_cache_int_read(mmapstr, index, &count); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + list = clist_new(); + if (list == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + for(i = 0 ; i < count ; i++) { + struct mailimf_field * field; + + r = mailimf_cache_field_read(mmapstr, index, &field); + if (r != MAIL_NO_ERROR) { + res = r; + goto free_list; + } + + r = clist_append(list, field); + if (r < 0) { + mailimf_field_free(field); + res = MAIL_ERROR_MEMORY; + 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; +} + + +static int mailimf_cache_field_write(MMAPString * mmapstr, size_t * index, + struct mailimf_field * field) +{ + int r; + + r = mailimf_cache_int_write(mmapstr, index, field->fld_type); + if (r != MAIL_NO_ERROR) + return r; + + switch (field->fld_type) { + case MAILIMF_FIELD_ORIG_DATE: + r = mailimf_cache_orig_date_write(mmapstr, index, + field->fld_data.fld_orig_date); + break; + case MAILIMF_FIELD_FROM: + r = mailimf_cache_from_write(mmapstr, index, + field->fld_data.fld_from); + break; + case MAILIMF_FIELD_SENDER: + r = mailimf_cache_sender_write(mmapstr, index, + field->fld_data.fld_sender); + break; + case MAILIMF_FIELD_REPLY_TO: + r = mailimf_cache_reply_to_write(mmapstr, index, + field->fld_data.fld_reply_to); + break; + case MAILIMF_FIELD_TO: + r = mailimf_cache_to_write(mmapstr, index, + field->fld_data.fld_to); + break; + case MAILIMF_FIELD_CC: + r = mailimf_cache_cc_write(mmapstr, index, + field->fld_data.fld_cc); + break; + case MAILIMF_FIELD_BCC: + r = mailimf_cache_bcc_write(mmapstr, index, + field->fld_data.fld_bcc); + break; + case MAILIMF_FIELD_MESSAGE_ID: + r = mailimf_cache_message_id_write(mmapstr, index, + field->fld_data.fld_message_id); + break; + case MAILIMF_FIELD_IN_REPLY_TO: + r = mailimf_cache_in_reply_to_write(mmapstr, index, + field->fld_data.fld_in_reply_to); + break; + case MAILIMF_FIELD_REFERENCES: + r = mailimf_cache_references_write(mmapstr, index, + field->fld_data.fld_references); + break; + case MAILIMF_FIELD_SUBJECT: + r = mailimf_cache_subject_write(mmapstr, index, + field->fld_data.fld_subject); + break; + default: + r = 0; + break; + } + + if (r != MAIL_NO_ERROR) + return r; + + return MAIL_NO_ERROR; +} + + +static int mailimf_cache_field_read(MMAPString * mmapstr, size_t * index, + struct mailimf_field ** result) +{ + int r; + uint32_t type; + struct mailimf_orig_date * orig_date; + struct mailimf_from * from; + struct mailimf_sender * sender; + struct mailimf_to * to; + struct mailimf_reply_to * reply_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_field * field; + int res; + + orig_date = NULL; + from = NULL; + sender = NULL; + to = NULL; + reply_to = NULL; + cc = NULL; + bcc = NULL; + message_id = NULL; + in_reply_to = NULL; + references = NULL; + subject = NULL; + field = NULL; + + r = mailimf_cache_int_read(mmapstr, index, &type); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + switch (type) { + case MAILIMF_FIELD_ORIG_DATE: + r = mailimf_cache_orig_date_read(mmapstr, index, &orig_date); + break; + case MAILIMF_FIELD_FROM: + r = mailimf_cache_from_read(mmapstr, index, &from); + break; + case MAILIMF_FIELD_SENDER: + r = mailimf_cache_sender_read(mmapstr, index, &sender); + break; + case MAILIMF_FIELD_REPLY_TO: + r = mailimf_cache_reply_to_read(mmapstr, index, &reply_to); + break; + case MAILIMF_FIELD_TO: + r = mailimf_cache_to_read(mmapstr, index, &to); + break; + case MAILIMF_FIELD_CC: + r = mailimf_cache_cc_read(mmapstr, index, &cc); + break; + case MAILIMF_FIELD_BCC: + r = mailimf_cache_bcc_read(mmapstr, index, &bcc); + break; + case MAILIMF_FIELD_MESSAGE_ID: + r = mailimf_cache_message_id_read(mmapstr, index, &message_id); + break; + case MAILIMF_FIELD_IN_REPLY_TO: + r = mailimf_cache_in_reply_to_read(mmapstr, index, &in_reply_to); + break; + case MAILIMF_FIELD_REFERENCES: + r = mailimf_cache_references_read(mmapstr, index, &references); + break; + case MAILIMF_FIELD_SUBJECT: + r = mailimf_cache_subject_read(mmapstr, index, &subject); + break; + default: + r = MAIL_ERROR_INVAL; + break; + } + + if (r != MAIL_NO_ERROR) { + res = r; + goto free; + } + + 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, NULL); + if (field == NULL) { + res = MAIL_ERROR_MEMORY; + goto free; + } + + * result = field; + + return MAIL_NO_ERROR; + + free: + 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); + err: + return res; +} + +static int mailimf_cache_orig_date_write(MMAPString * mmapstr, size_t * index, + struct mailimf_orig_date * date) +{ + return mailimf_cache_date_time_write(mmapstr, index, date->dt_date_time); +} + +static int mailimf_cache_orig_date_read(MMAPString * mmapstr, size_t * index, + struct mailimf_orig_date ** result) +{ + int r; + struct mailimf_date_time * date_time; + struct mailimf_orig_date * orig_date; + + r = mailimf_cache_date_time_read(mmapstr, index, &date_time); + if (r != MAIL_NO_ERROR) + return r; + + orig_date = mailimf_orig_date_new(date_time); + if (orig_date == NULL) { + mailimf_date_time_free(date_time); + return MAIL_ERROR_MEMORY; + } + + * result = orig_date; + + return MAIL_NO_ERROR; +} + +static int mailimf_cache_date_time_write(MMAPString * mmapstr, size_t * index, + struct mailimf_date_time * date_time) +{ + int r; + + r = mailimf_cache_int_write(mmapstr, index, date_time->dt_day); + if (r != MAIL_NO_ERROR) + return r; + + r = mailimf_cache_int_write(mmapstr, index, date_time->dt_month); + if (r != MAIL_NO_ERROR) + return r; + + r = mailimf_cache_int_write(mmapstr, index, date_time->dt_year); + if (r != MAIL_NO_ERROR) + return r; + + r = mailimf_cache_int_write(mmapstr, index, date_time->dt_hour); + if (r != MAIL_NO_ERROR) + return r; + + r = mailimf_cache_int_write(mmapstr, index, date_time->dt_min); + if (r != MAIL_NO_ERROR) + return r; + + r = mailimf_cache_int_write(mmapstr, index, date_time->dt_sec); + if (r != MAIL_NO_ERROR) + return r; + + r = mailimf_cache_int_write(mmapstr, index, date_time->dt_zone); + if (r != MAIL_NO_ERROR) + return r; + + return MAIL_NO_ERROR; +} + +static int mailimf_cache_date_time_read(MMAPString * mmapstr, size_t * index, + struct mailimf_date_time ** result) +{ + int r; + uint32_t day; + uint32_t month; + uint32_t year; + uint32_t hour; + uint32_t min; + uint32_t sec; + uint32_t zone; + struct mailimf_date_time * date_time; + + r = mailimf_cache_int_read(mmapstr, index, &day); + if (r != MAIL_NO_ERROR) + return r; + + r = mailimf_cache_int_read(mmapstr, index, &month); + if (r != MAIL_NO_ERROR) + return r; + + r = mailimf_cache_int_read(mmapstr, index, &year); + if (r != MAIL_NO_ERROR) + return r; + + r = mailimf_cache_int_read(mmapstr, index, &hour); + if (r != MAIL_NO_ERROR) + return r; + + r = mailimf_cache_int_read(mmapstr, index, &min); + if (r != MAIL_NO_ERROR) + return r; + + r = mailimf_cache_int_read(mmapstr, index, &sec); + if (r != MAIL_NO_ERROR) + return r; + + r = mailimf_cache_int_read(mmapstr, index, &zone); + if (r != MAIL_NO_ERROR) + return r; + + date_time = mailimf_date_time_new(day, month, year, hour, min, sec, zone); + if (date_time == NULL) + return MAIL_ERROR_MEMORY; + + * result = date_time; + + return MAIL_NO_ERROR; + +} + + +static int mailimf_cache_from_write(MMAPString * mmapstr, size_t * index, + struct mailimf_from * from) +{ + return mailimf_cache_mailbox_list_write(mmapstr, index, from->frm_mb_list); +} + +static int mailimf_cache_from_read(MMAPString * mmapstr, size_t * index, + struct mailimf_from ** result) +{ + struct mailimf_mailbox_list * mb_list; + struct mailimf_from * from; + int r; + + r = mailimf_cache_mailbox_list_read(mmapstr, index, &mb_list); + if (r != MAIL_NO_ERROR) + return r; + + from = mailimf_from_new(mb_list); + if (from == NULL) { + mailimf_mailbox_list_free(mb_list); + return MAIL_ERROR_MEMORY; + } + + * result = from; + + return MAIL_NO_ERROR; +} + +static int mailimf_cache_sender_write(MMAPString * mmapstr, size_t * index, + struct mailimf_sender * sender) +{ + return mailimf_cache_mailbox_write(mmapstr, index, sender->snd_mb); +} + +static int mailimf_cache_sender_read(MMAPString * mmapstr, size_t * index, + struct mailimf_sender ** result) +{ + int r; + struct mailimf_mailbox * mb; + struct mailimf_sender * sender; + + r = mailimf_cache_mailbox_read(mmapstr, index, &mb); + if (r != MAIL_NO_ERROR) + return r; + + sender = mailimf_sender_new(mb); + if (sender == NULL) { + mailimf_mailbox_free(mb); + return MAIL_ERROR_MEMORY; + } + + * result = sender; + + return MAIL_NO_ERROR; +} + +static int mailimf_cache_reply_to_write(MMAPString * mmapstr, size_t * index, + struct mailimf_reply_to * reply_to) +{ + return mailimf_cache_address_list_write(mmapstr, index, + reply_to->rt_addr_list); +} + +static int mailimf_cache_reply_to_read(MMAPString * mmapstr, size_t * index, + struct mailimf_reply_to ** result) +{ + int r; + struct mailimf_address_list * addr_list; + struct mailimf_reply_to * reply_to; + + r = mailimf_cache_address_list_read(mmapstr, index, &addr_list); + if (r != MAIL_NO_ERROR) + return r; + + reply_to = mailimf_reply_to_new(addr_list); + if (reply_to == NULL) { + mailimf_address_list_free(addr_list); + return MAIL_ERROR_MEMORY; + } + + * result = reply_to; + + return MAIL_NO_ERROR; +} + +static int mailimf_cache_to_write(MMAPString * mmapstr, size_t * index, + struct mailimf_to * to) +{ + return mailimf_cache_address_list_write(mmapstr, index, to->to_addr_list); +} + +static int mailimf_cache_to_read(MMAPString * mmapstr, size_t * index, + struct mailimf_to ** result) +{ + int r; + struct mailimf_address_list * addr_list; + struct mailimf_to * to; + + r = mailimf_cache_address_list_read(mmapstr, index, &addr_list); + if (r != MAIL_NO_ERROR) + return r; + + to = mailimf_to_new(addr_list); + if (to == NULL) { + mailimf_address_list_free(addr_list); + return MAIL_ERROR_MEMORY; + } + + * result = to; + + return MAIL_NO_ERROR; +} + +static int mailimf_cache_cc_write(MMAPString * mmapstr, size_t * index, + struct mailimf_cc * cc) +{ + return mailimf_cache_address_list_write(mmapstr, index, cc->cc_addr_list); +} + +static int mailimf_cache_cc_read(MMAPString * mmapstr, size_t * index, + struct mailimf_cc ** result) +{ + int r; + struct mailimf_address_list * addr_list; + struct mailimf_cc * cc; + + r = mailimf_cache_address_list_read(mmapstr, index, &addr_list); + if (r != MAIL_NO_ERROR) + return r; + + cc = mailimf_cc_new(addr_list); + if (cc == NULL) { + mailimf_address_list_free(addr_list); + return MAIL_ERROR_MEMORY; + } + + * result = cc; + + return MAIL_NO_ERROR; +} + +static int mailimf_cache_bcc_write(MMAPString * mmapstr, size_t * index, + struct mailimf_bcc * bcc) +{ + return mailimf_cache_address_list_write(mmapstr, index, bcc->bcc_addr_list); +} + +static int mailimf_cache_bcc_read(MMAPString * mmapstr, size_t * index, + struct mailimf_bcc ** result) +{ + int r; + struct mailimf_address_list * addr_list; + struct mailimf_bcc * bcc; + + r = mailimf_cache_address_list_read(mmapstr, index, &addr_list); + if (r != MAIL_NO_ERROR) + return r; + + bcc = mailimf_bcc_new(addr_list); + if (bcc == NULL) { + mailimf_address_list_free(addr_list); + return MAIL_ERROR_MEMORY; + } + + * result = bcc; + + return MAIL_NO_ERROR; +} + +static int +mailimf_cache_message_id_write(MMAPString * mmapstr, size_t * index, + struct mailimf_message_id * message_id) +{ + return mailimf_cache_string_write(mmapstr, index, + message_id->mid_value, strlen(message_id->mid_value)); +} + +static int mailimf_cache_message_id_read(MMAPString * mmapstr, size_t * index, + struct mailimf_message_id ** result) +{ + struct mailimf_message_id * message_id; + char * str; + int r; + + r = mailimf_cache_string_read(mmapstr, index, &str); + if (r != MAIL_NO_ERROR) + return r; + + message_id = mailimf_message_id_new(str); + if (message_id == NULL) { + free(str); + return MAIL_ERROR_MEMORY; + } + + * result = message_id; + + return MAIL_NO_ERROR; +} + +static int +mailimf_cache_msg_id_list_write(MMAPString * mmapstr, size_t * index, + clist * list) +{ + clistiter * cur; + int r; + + r = mailimf_cache_int_write(mmapstr, index, clist_count(list)); + if (r != MAIL_NO_ERROR) + return r; + + for(cur = clist_begin(list) ; cur != NULL ; cur = clist_next(cur)) { + char * msgid; + + msgid = clist_content(cur); + + r = mailimf_cache_string_write(mmapstr, index, msgid, strlen(msgid)); + if (r != MAIL_NO_ERROR) + return r; + } + + return MAIL_NO_ERROR; +} + +static int mailimf_cache_msg_id_list_read(MMAPString * mmapstr, size_t * index, + clist ** result) +{ + clist * list; + int r; + uint32_t count; + uint32_t i; + int res; + + r = mailimf_cache_int_read(mmapstr, index, &count); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + list = clist_new(); + if (list == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + for(i = 0 ; i < count ; i++) { + char * msgid; + + r = mailimf_cache_string_read(mmapstr, index, &msgid); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + r = clist_append(list, msgid); + if (r < 0) { + free(msgid); + res = MAIL_ERROR_MEMORY; + goto free_list; + } + } + + * result = list; + + return MAIL_NO_ERROR; + + free_list: + clist_foreach(list, (clist_func) free, NULL); + clist_free(list); + err: + return res; +} + +static int +mailimf_cache_in_reply_to_write(MMAPString * mmapstr, size_t * index, + struct mailimf_in_reply_to * in_reply_to) +{ + return mailimf_cache_msg_id_list_write(mmapstr, index, + in_reply_to->mid_list); +} + +static int mailimf_cache_in_reply_to_read(MMAPString * mmapstr, size_t * index, + struct mailimf_in_reply_to ** result) +{ + int r; + clist * msg_id_list; + struct mailimf_in_reply_to * in_reply_to; + + r = mailimf_cache_msg_id_list_read(mmapstr, index, &msg_id_list); + if (r != MAIL_NO_ERROR) + return r; + + in_reply_to = mailimf_in_reply_to_new(msg_id_list); + if (in_reply_to == NULL) { + clist_foreach(msg_id_list, (clist_func) free, NULL); + clist_free(msg_id_list); + return MAIL_ERROR_MEMORY; + } + + * result = in_reply_to; + + return MAIL_NO_ERROR; +} + +static int mailimf_cache_references_write(MMAPString * mmapstr, size_t * index, + struct mailimf_references * references) +{ + return mailimf_cache_msg_id_list_write(mmapstr, index, + references->mid_list); +} + +static int mailimf_cache_references_read(MMAPString * mmapstr, size_t * index, + struct mailimf_references ** result) +{ + int r; + clist * msg_id_list; + struct mailimf_references * references; + + r = mailimf_cache_msg_id_list_read(mmapstr, index, &msg_id_list); + if (r != MAIL_NO_ERROR) + return r; + + references = mailimf_references_new(msg_id_list); + if (references == NULL) { + clist_foreach(msg_id_list, (clist_func) free, NULL); + clist_free(msg_id_list); + return MAIL_ERROR_MEMORY; + } + + * result = references; + + return MAIL_NO_ERROR; +} + + +static int mailimf_cache_subject_write(MMAPString * mmapstr, size_t * index, + struct mailimf_subject * subject) +{ + return mailimf_cache_string_write(mmapstr, index, + subject->sbj_value, strlen(subject->sbj_value)); +} + +static int mailimf_cache_subject_read(MMAPString * mmapstr, size_t * index, + struct mailimf_subject ** result) +{ + char * str; + struct mailimf_subject * subject; + int r; + + r = mailimf_cache_string_read(mmapstr, index, &str); + if (r != MAIL_NO_ERROR) + return r; + + if (str == NULL) { + str = strdup(""); + if (str == NULL) + return MAIL_ERROR_MEMORY; + } + + subject = mailimf_subject_new(str); + if (subject == NULL) { + free(str); + return MAIL_ERROR_MEMORY; + } + + * result = subject; + + return MAIL_NO_ERROR; +} + + +static int +mailimf_cache_address_list_write(MMAPString * mmapstr, size_t * index, + struct mailimf_address_list * addr_list) +{ + clistiter * cur; + int r; + + if (addr_list == NULL) { + r = mailimf_cache_int_write(mmapstr, index, CACHE_NULL_POINTER); + if (r != MAIL_NO_ERROR) + return r; + } + else { + r = mailimf_cache_int_write(mmapstr, index, CACHE_NOT_NULL); + if (r != MAIL_NO_ERROR) + return r; + + r = mailimf_cache_int_write(mmapstr, index, + clist_count(addr_list->ad_list)); + if (r != MAIL_NO_ERROR) + return r; + + for(cur = clist_begin(addr_list->ad_list) ; cur != NULL ; + cur = clist_next(cur)) { + struct mailimf_address * addr; + + addr = clist_content(cur); + + r = mailimf_cache_address_write(mmapstr, index, addr); + if (r != MAIL_NO_ERROR) + return r; + } + } + + return MAIL_NO_ERROR; +} + +static int +mailimf_cache_address_list_read(MMAPString * mmapstr, size_t * index, + struct mailimf_address_list ** result) +{ + struct mailimf_address_list * addr_list; + uint32_t count; + uint32_t i; + int r; + clist * list; + int res; + uint32_t type; + + r = mailimf_cache_int_read(mmapstr, index, &type); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + if (type == CACHE_NULL_POINTER) { + * result = NULL; + return MAIL_NO_ERROR; + } + + r = mailimf_cache_int_read(mmapstr, index, &count); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + list = clist_new(); + if (list == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + for(i = 0 ; i < count ; i++) { + struct mailimf_address * addr; + + r = mailimf_cache_address_read(mmapstr, index, &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; +} + +static int mailimf_cache_address_write(MMAPString * mmapstr, size_t * index, + struct mailimf_address * addr) +{ + int r; + + r = mailimf_cache_int_write(mmapstr, index, addr->ad_type); + if (r != MAIL_NO_ERROR) + return r; + + switch(addr->ad_type) { + case MAILIMF_ADDRESS_MAILBOX: + r = mailimf_cache_mailbox_write(mmapstr, index, addr->ad_data.ad_mailbox); + if (r != MAIL_NO_ERROR) + return r; + + break; + + case MAILIMF_ADDRESS_GROUP: + r = mailimf_cache_group_write(mmapstr, index, addr->ad_data.ad_group); + if (r != MAIL_NO_ERROR) + return r; + + break; + } + + return MAIL_NO_ERROR; +} + +static int mailimf_cache_address_read(MMAPString * mmapstr, size_t * index, + struct mailimf_address ** result) +{ + uint32_t type; + int r; + struct mailimf_mailbox * mailbox; + struct mailimf_group * group; + struct mailimf_address * addr; + + r = mailimf_cache_int_read(mmapstr, index, &type); + if (r != MAIL_NO_ERROR) + return r; + + mailbox = NULL; + group = NULL; + + switch (type) { + case MAILIMF_ADDRESS_MAILBOX: + r = mailimf_cache_mailbox_read(mmapstr, index, &mailbox); + if (r != MAIL_NO_ERROR) + return r; + + break; + + case MAILIMF_ADDRESS_GROUP: + r = mailimf_cache_group_read(mmapstr, index, &group); + if (r != MAIL_NO_ERROR) + return r; + + break; + } + + addr = mailimf_address_new(type, mailbox, group); + if (addr == NULL) + goto free; + + * result = addr; + + return MAIL_NO_ERROR; + + free: + if (mailbox != NULL) + mailimf_mailbox_free(mailbox); + if (group != NULL) + mailimf_group_free(group); + return MAIL_ERROR_MEMORY; +} + +static int mailimf_cache_group_write(MMAPString * mmapstr, size_t * index, + struct mailimf_group * group) +{ + int r; + + r = mailimf_cache_string_write(mmapstr, index, group->grp_display_name, + strlen(group->grp_display_name)); + if (r != MAIL_NO_ERROR) + return r; + + r = mailimf_cache_mailbox_list_write(mmapstr, index, group->grp_mb_list); + if (r != MAIL_NO_ERROR) + return r; + + return MAIL_NO_ERROR; +} + +static int mailimf_cache_group_read(MMAPString * mmapstr, size_t * index, + struct mailimf_group ** result) +{ + int r; + char * display_name; + struct mailimf_mailbox_list * mb_list; + struct mailimf_group * group; + int res; + + r = mailimf_cache_string_read(mmapstr, index, &display_name); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + r = mailimf_cache_mailbox_list_read(mmapstr, index, &mb_list); + if (r != MAIL_NO_ERROR) { + res = r; + goto free_dsp_name; + } + + group = mailimf_group_new(display_name, mb_list); + if (group == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_mb_list; + } + + * result = group; + + return MAIL_NO_ERROR; + + free_mb_list: + mailimf_mailbox_list_free(mb_list); + free_dsp_name: + free(display_name); + err: + return res; +} + +static int +mailimf_cache_mailbox_list_write(MMAPString * mmapstr, size_t * index, + struct mailimf_mailbox_list * mb_list) +{ + clistiter * cur; + int r; + + if (mb_list == NULL) { + r = mailimf_cache_int_write(mmapstr, index, CACHE_NULL_POINTER); + if (r != MAIL_NO_ERROR) + return r; + } + else { + r = mailimf_cache_int_write(mmapstr, index, CACHE_NOT_NULL); + if (r != MAIL_NO_ERROR) + return r; + + r = mailimf_cache_int_write(mmapstr, index, + clist_count(mb_list->mb_list)); + if (r != MAIL_NO_ERROR) + return r; + + for(cur = clist_begin(mb_list->mb_list) ; cur != NULL ; + cur = clist_next(cur)) { + struct mailimf_mailbox * mb; + + mb = clist_content(cur); + + r = mailimf_cache_mailbox_write(mmapstr, index, mb); + if (r != MAIL_NO_ERROR) + return r; + } + } + + return MAIL_NO_ERROR; +} + +static int +mailimf_cache_mailbox_list_read(MMAPString * mmapstr, size_t * index, + struct mailimf_mailbox_list ** result) +{ + clist * list; + int r; + uint32_t count; + uint32_t i; + struct mailimf_mailbox_list * mb_list; + int res; + uint32_t type; + + r = mailimf_cache_int_read(mmapstr, index, &type); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + if (type == CACHE_NULL_POINTER) { + * result = NULL; + return MAIL_NO_ERROR; + } + + r = mailimf_cache_int_read(mmapstr, index, &count); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + + list = clist_new(); + if (list == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + for(i = 0 ; i < count ; i++) { + struct mailimf_mailbox * mb; + + r = mailimf_cache_mailbox_read(mmapstr, index, &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 res; +} + +static int mailimf_cache_mailbox_write(MMAPString * mmapstr, size_t * index, + struct mailimf_mailbox * mb) +{ + int r; + + if (mb->mb_display_name) { + r = mailimf_cache_string_write(mmapstr, index, + mb->mb_display_name, strlen(mb->mb_display_name)); + if (r != MAIL_NO_ERROR) + return r; + } + else { + r = mailimf_cache_string_write(mmapstr, index, NULL, 0); + if (r != MAIL_NO_ERROR) + return r; + } + + r = mailimf_cache_string_write(mmapstr, index, + mb->mb_addr_spec, strlen(mb->mb_addr_spec)); + if (r != MAIL_NO_ERROR) + return r; + + return MAIL_NO_ERROR; +} + +static int mailimf_cache_mailbox_read(MMAPString * mmapstr, size_t * index, + struct mailimf_mailbox ** result) +{ + int r; + char * dsp_name; + char * addr_spec; + struct mailimf_mailbox * mb; + + dsp_name = NULL; + + r = mailimf_cache_string_read(mmapstr, index, &dsp_name); + if (r != MAIL_NO_ERROR) + return r; + + r = mailimf_cache_string_read(mmapstr, index, &addr_spec); + if (r != MAIL_NO_ERROR) + goto free_dsp_name; + + mb = mailimf_mailbox_new(dsp_name, addr_spec); + if (mb == NULL) + goto free_addr; + + * result = mb; + + return MAIL_NO_ERROR; + + free_addr: + free(addr_spec); + free_dsp_name: + if (dsp_name != NULL) + free(dsp_name); + return MAIL_ERROR_MEMORY; +} diff --git a/libetpan/src/driver/tools/imfcache.h b/libetpan/src/driver/tools/imfcache.h new file mode 100644 index 0000000..f054a12 --- a/dev/null +++ b/libetpan/src/driver/tools/imfcache.h @@ -0,0 +1,75 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef IMFCACHE_H + +#define IMFCACHE_H + +#include <stdio.h> +#include "mailimf.h" +#include "maildriver_types.h" +#include "mmapstring.h" + +#ifdef __cplusplus +extern "C" { +#endif + +int mail_serialize_clear(MMAPString * mmapstr, size_t * index); + +int mail_serialize_write(MMAPString * mmapstr, size_t * index, + char * buf, size_t size); + +int mail_serialize_read(MMAPString * mmapstr, size_t * index, + char * buf, size_t size); + +int mailimf_cache_int_write(MMAPString * mmapstr, size_t * index, + uint32_t value); +int mailimf_cache_string_write(MMAPString * mmapstr, size_t * index, + char * str, size_t length); +int mailimf_cache_int_read(MMAPString * mmapstr, size_t * index, + uint32_t * result); +int mailimf_cache_string_read(MMAPString * mmapstr, size_t * index, + char ** result); + +int mailimf_cache_fields_write(MMAPString * mmapstr, size_t * index, + struct mailimf_fields * fields); +int mailimf_cache_fields_read(MMAPString * mmapstr, size_t * index, + struct mailimf_fields ** result); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/tools/mailthread.c b/libetpan/src/driver/tools/mailthread.c new file mode 100644 index 0000000..32f73cd --- a/dev/null +++ b/libetpan/src/driver/tools/mailthread.c @@ -0,0 +1,1742 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "mailthread.h" +#include "mailthread_types.h" + +#include <string.h> +#include <time.h> +#include <stdlib.h> +#include <ctype.h> + +#include "mail.h" +#include "chash.h" +#include "carray.h" +#include "clist.h" +#include "mailmessage.h" + +static inline char * get_msg_id(mailmessage * msg) +{ + if (msg->msg_single_fields.fld_message_id != NULL) + return msg->msg_single_fields.fld_message_id->mid_value; + else + return NULL; +} + +static inline clist * get_ref(mailmessage * msg) +{ + if (msg->msg_single_fields.fld_references != NULL) + return msg->msg_single_fields.fld_references->mid_list; + else + return NULL; +} + +static inline clist * get_in_reply_to(mailmessage * msg) +{ + if (msg->msg_single_fields.fld_in_reply_to != NULL) + return msg->msg_single_fields.fld_in_reply_to->mid_list; + else + return NULL; +} + +static inline int skip_subj_blob(char * subj, size_t * begin, + size_t length) +{ + /* subj-blob = "[" *BLOBCHAR "]" *WSP */ + size_t cur_token; + + cur_token = * begin; + + if (subj[cur_token] != '[') + return FALSE; + + cur_token ++; + + while (1) { + if (cur_token >= length) + return FALSE; + + if (subj[cur_token] == '[') + return FALSE; + + if (subj[cur_token] == ']') + break; + + cur_token ++; + } + + cur_token ++; + + while (1) { + if (cur_token >= length) + break; + + if (subj[cur_token] != ' ') + break; + + cur_token ++; + } + + * begin = cur_token; + + return TRUE; +} + +static inline int skip_subj_refwd(char * subj, size_t * begin, + size_t length) +{ + /* subj-refwd = ("re" / ("fw" ["d"])) *WSP [subj-blob] ":" */ + size_t cur_token; + int prefix; + + cur_token = * begin; + + prefix = FALSE; + if (length >= 3) { + if (strncasecmp(subj + cur_token, "fwd", 3) == 0) { + cur_token += 3; + prefix = TRUE; + } + } + if (!prefix) { + if (length >= 2) { + if (strncasecmp(subj + cur_token, "fw", 2) == 0) { + cur_token += 2; + prefix = TRUE; + } + else if (strncasecmp(subj + cur_token, "re", 2) == 0) { + cur_token += 2; + prefix = TRUE; + } + } + } + + if (!prefix) + return FALSE; + + while (1) { + if (cur_token >= length) + break; + + if (subj[cur_token] != ' ') + break; + + cur_token ++; + } + + skip_subj_blob(subj, &cur_token, length); + + if (subj[cur_token] != ':') + return FALSE; + + cur_token ++; + + * begin = cur_token; + + return TRUE; +} + +static inline int skip_subj_leader(struct mailmessage_tree * tree, + char * subj, size_t * begin, + size_t length) +{ + size_t cur_token; + + cur_token = * begin; + + /* subj-leader = (*subj-blob subj-refwd) / WSP */ + + if (subj[cur_token] == ' ') { + cur_token ++; + } + else { + while (cur_token < length) { + if (!skip_subj_blob(subj, &cur_token, length)) + break; + } + if (!skip_subj_refwd(subj, &cur_token, length)) + return FALSE; + tree->node_is_reply = TRUE; + } + + * begin = cur_token; + + return TRUE; +} + + +static char * extract_subject(char * default_from, + struct mailmessage_tree * tree, + char * str) +{ + char * subj; + char * cur; + char * write_pos; + size_t len; + size_t begin; + + char * decoded; + size_t cur_token; + + int do_repeat_5; + int do_repeat_6; + int r; + + /* + (1) Convert any RFC 2047 encoded-words in the subject to + UTF-8. + */ + + decoded = NULL; + + cur_token = 0; + r = mailmime_encoded_phrase_parse(default_from, str, strlen(str), + &cur_token, "utf-8", + &decoded); + + if (r == MAILIMF_NO_ERROR) { + subj = decoded; + } + else + subj = strdup(str); + + len = strlen(subj); + + /* + Convert all tabs and continuations to space. + Convert all multiple spaces to a single space. + */ + + cur = subj; + write_pos = subj; + while (* cur != '\0') { + int cont; + + switch (* cur) { + case '\t': + case '\r': + case '\n': + cont = TRUE; + + cur ++; + while (* cur && cont) { + switch (* cur) { + case '\t': + case '\r': + case '\n': + cont = TRUE; + break; + default: + cont = FALSE; + break; + } + cur ++; + } + + * write_pos = ' '; + write_pos ++; + + break; + + default: + * write_pos = * cur; + write_pos ++; + + cur ++; + + break; + } + } + * write_pos = '\0'; + + begin = 0; + + do { + do_repeat_6 = FALSE; + + /* + (2) Remove all trailing text of the subject that matches + the subj-trailer ABNF, repeat until no more matches are + possible. + */ + + while (len > 0) { + int chg; + + chg = FALSE; + + /* subj-trailer = "(fwd)" / WSP */ + if (subj[len - 1] == ' ') { + subj[len - 1] = '\0'; + len --; + } + else { + if (len < 5) + break; + + if (strncasecmp(subj + len - 5, "(fwd)", 5) != 0) + break; + + subj[len - 5] = '\0'; + len -= 5; + tree->node_is_reply = TRUE; + } + } + + do { + size_t saved_begin; + + do_repeat_5 = FALSE; + + /* + (3) Remove all prefix text of the subject that matches the + subj-leader ABNF. + */ + + if (skip_subj_leader(tree, subj, &begin, len)) + do_repeat_5 = TRUE; + + /* + (4) If there is prefix text of the subject that matches the + subj-blob ABNF, and removing that prefix leaves a non-empty + subj-base, then remove the prefix text. + */ + + saved_begin = begin; + if (skip_subj_blob(subj, &begin, len)) { + if (begin == len) { + /* this will leave a empty subject base */ + begin = saved_begin; + } + else + do_repeat_5 = TRUE; + } + + /* + (5) Repeat (3) and (4) until no matches remain. + Note: it is possible to defer step (2) until step (6), + but this requires checking for subj-trailer in step (4). + */ + + } + while (do_repeat_5); + + /* + (6) If the resulting text begins with the subj-fwd-hdr ABNF + and ends with the subj-fwd-trl ABNF, remove the + subj-fwd-hdr and subj-fwd-trl and repeat from step (2). + */ + + if (len >= 5) { + size_t saved_begin; + + saved_begin = begin; + if (strncasecmp(subj + begin, "[fwd:", 5) == 0) { + begin += 5; + + if (subj[len - 1] != ']') + saved_begin = begin; + else { + tree->node_is_reply = TRUE; + + subj[len - 1] = '\0'; + len --; + do_repeat_6 = TRUE; + } + } + } + + } + while (do_repeat_6); + + /* + (7) The resulting text is the "base subject" used in + threading. + */ + + /* convert to upper case */ + + cur = subj + begin; + write_pos = subj; + + while (* cur != '\0') { + * write_pos = (char) toupper((unsigned char) * cur); + cur ++; + write_pos ++; + } + * write_pos = '\0'; + + return subj; +} + +static int get_extracted_subject(char * default_from, + struct mailmessage_tree * tree, + char ** result) +{ + if (tree->node_msg->msg_single_fields.fld_subject != NULL) { + char * subj; + + subj = extract_subject(default_from, + tree, tree->node_msg->msg_single_fields.fld_subject->sbj_value); + if (subj == NULL) + return MAIL_ERROR_MEMORY; + + * result = subj; + + return MAIL_NO_ERROR; + } + + return MAIL_ERROR_SUBJECT_NOT_FOUND; +} + +static int get_thread_subject(char * default_from, + struct mailmessage_tree * tree, + char ** result) +{ + char * thread_subject; + int r; + unsigned int i; + + if (tree->node_msg != NULL) { + if (tree->node_msg->msg_fields != NULL) { + r = get_extracted_subject(default_from, tree, &thread_subject); + + if (r != MAIL_NO_ERROR) + return r; + + * result = thread_subject; + return MAIL_NO_ERROR; + } + } + + for(i = 0 ; i < carray_count(tree->node_children) ; i ++) { + struct mailmessage_tree * child; + + child = carray_get(tree->node_children, i); + + r = get_thread_subject(default_from, child, &thread_subject); + + switch (r) { + case MAIL_NO_ERROR: + * result = thread_subject; + return MAIL_NO_ERROR; + + case MAIL_ERROR_SUBJECT_NOT_FOUND: + /* do nothing */ + break; + + default: + return r; + } + } + + return MAIL_ERROR_SUBJECT_NOT_FOUND; +} + + + +#ifndef WRONG +#define WRONG (-1) +#endif /* !defined WRONG */ + +static int tmcomp(struct tm * atmp, struct tm * btmp) +{ + register int result; + + if ((result = (atmp->tm_year - btmp->tm_year)) == 0 && + (result = (atmp->tm_mon - btmp->tm_mon)) == 0 && + (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && + (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && + (result = (atmp->tm_min - btmp->tm_min)) == 0) + result = atmp->tm_sec - btmp->tm_sec; + return result; +} + +static time_t mkgmtime(struct tm * tmp) +{ + register int dir; + register int bits; + register int saved_seconds; + time_t t; + struct tm yourtm, *mytm; + + yourtm = *tmp; + saved_seconds = yourtm.tm_sec; + yourtm.tm_sec = 0; + /* + ** Calculate the number of magnitude bits in a time_t + ** (this works regardless of whether time_t is + ** signed or unsigned, though lint complains if unsigned). + */ + for (bits = 0, t = 1; t > 0; ++bits, t <<= 1) + ; + /* + ** If time_t is signed, then 0 is the median value, + ** if time_t is unsigned, then 1 << bits is median. + */ + t = (t < 0) ? 0 : ((time_t) 1 << bits); + for ( ; ; ) { + mytm = gmtime(&t); + dir = tmcomp(mytm, &yourtm); + if (dir != 0) { + if (bits-- < 0) + return WRONG; + if (bits < 0) + --t; + else if (dir > 0) + t -= (time_t) 1 << bits; + else t += (time_t) 1 << bits; + continue; + } + break; + } + t += saved_seconds; + return t; +} + +static inline time_t get_date(mailmessage * msg) +{ + struct tm tmval; + time_t timeval; + struct mailimf_date_time * date_time; + + if (msg->msg_single_fields.fld_orig_date == NULL) + return (time_t) -1; + + date_time = msg->msg_single_fields.fld_orig_date->dt_date_time; + + tmval.tm_sec = date_time->dt_sec; + tmval.tm_min = date_time->dt_min; + tmval.tm_hour = date_time->dt_hour; + tmval.tm_sec = date_time->dt_sec; + tmval.tm_mday = date_time->dt_day; + tmval.tm_mon = date_time->dt_month - 1; + tmval.tm_year = date_time->dt_year - 1900; + + timeval = mkgmtime(&tmval); + + timeval -= date_time->dt_zone * 36; + + return timeval; +} + +static inline int is_descendant(struct mailmessage_tree * node, + struct mailmessage_tree * maybe_child) +{ + unsigned int i; + + for(i = 0 ; i < carray_count(node->node_children) ; i++) { + struct mailmessage_tree * tree; + + tree = carray_get(node->node_children, i); + if (tree == maybe_child) + return TRUE; + if (carray_count(tree->node_children) != 0) + if (is_descendant(tree, maybe_child)) + return TRUE; + } + + return FALSE; +} + +static int delete_dummy(carray * rootlist, carray * sibling_list, + unsigned int cur, unsigned int * pnext) +{ + struct mailmessage_tree * env_tree; + int res; + int r; + unsigned int cur_child; + unsigned int next; + + env_tree = carray_get(sibling_list, cur); + + cur_child = 0; + while (cur_child < carray_count(env_tree->node_children)) { + delete_dummy(rootlist, env_tree->node_children, cur_child, &cur_child); + } + + if (env_tree->node_msg == NULL) { + if (carray_count(env_tree->node_children) == 0) { + + /* If it is a dummy message with NO children, delete it. */ + mailmessage_tree_free(env_tree); + carray_delete(sibling_list, cur); + next = cur; + } + else { + /* If it is a dummy message with children, delete it, but + promote its children to the current level. */ + + /* + Do not promote the children if doing so would make them + children of the root, unless there is only one child. + */ + + cur_child = 0; + if ((sibling_list != rootlist) || + (carray_count(env_tree->node_children) == 1)) { + while (cur_child < carray_count(env_tree->node_children)) { + struct mailmessage_tree * child; + + child = carray_get(env_tree->node_children, cur_child); + r = carray_add(sibling_list, child, NULL); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto err; + } + /* set new parent of the children */ + child->node_parent = env_tree->node_parent; + + carray_delete(env_tree->node_children, cur_child); + } + mailmessage_tree_free(env_tree); + carray_delete(sibling_list, cur); + next = cur; + } + else + next = cur + 1; + } + } + else + next = cur + 1; + + * pnext = next; + + return MAIL_NO_ERROR; + + err: + return res; +} + +static inline time_t tree_get_date(struct mailmessage_tree * tree) +{ + if (tree->node_msg != NULL) { + return tree->node_date; + } + else { + struct mailmessage_tree * subtree; + + if (carray_count(tree->node_children) == 0) + return (time_t) -1; + + subtree = carray_get(tree->node_children, 0); + + return subtree->node_date; + } +} + +static inline uint32_t tree_get_index(struct mailmessage_tree * tree) +{ + if (tree->node_msg == NULL) + return 0; + + return tree->node_msg->msg_index; +} + +int mailthread_tree_timecomp(struct mailmessage_tree ** ptree1, + struct mailmessage_tree ** ptree2) +{ + time_t date1; + time_t date2; + + date1 = tree_get_date(* ptree1); + date2 = tree_get_date(* ptree2); + + if ((date1 == (time_t) -1) || (date2 == (time_t) -1)) { + uint32_t index1; + uint32_t index2; + + index1 = tree_get_index(* ptree1); + index2 = tree_get_index(* ptree2); + return (int) ((long) index1 - (long) index2); + } + + return (int) ((long) date1 - (long) date2); +} + +static int tree_subj_time_comp(struct mailmessage_tree ** ptree1, + struct mailmessage_tree ** ptree2) +{ + char * subj1; + char * subj2; + time_t date1; + time_t date2; + int r; + + subj1 = (* ptree1)->node_base_subject; + subj2 = (* ptree2)->node_base_subject; + + if ((subj1 != NULL) && (subj2 != NULL)) + r = strcmp(subj1, subj2); + else { + if ((subj1 == NULL) && (subj2 == NULL)) + r = 0; + else if (subj1 == NULL) + r = -1; + else /* subj2 == NULL */ + r = 1; + } + + if (r != 0) + return r; + + date1 = (* ptree1)->node_date; + date2 = (* ptree2)->node_date; + + if ((date1 == (time_t) -1) || (date2 == (time_t) -1)) + return ((int32_t) (* ptree1)->node_msg->msg_index) - + ((int32_t) (* ptree2)->node_msg->msg_index); + + return (int) ((long) date1 - (long) date2); +} + + + +int mail_thread_sort(struct mailmessage_tree * tree, + int (* comp_func)(struct mailmessage_tree **, + struct mailmessage_tree **), + int sort_sub) +{ + unsigned int cur; + int r; + int res; + + for(cur = 0 ; cur < carray_count(tree->node_children) ; cur ++) { + struct mailmessage_tree * subtree; + + subtree = carray_get(tree->node_children, cur); + + if (sort_sub) { + r = mail_thread_sort(subtree, comp_func, sort_sub); + if (r != MAIL_NO_ERROR) { + res = r; + goto err; + } + } + } + + qsort(carray_data(tree->node_children), carray_count(tree->node_children), + sizeof(struct mailmessage_tree *), + (int (*)(const void *, const void *)) comp_func); + + return MAIL_NO_ERROR; + + err: + return res; +} + + +static int +mail_build_thread_references(char * default_from, + struct mailmessage_list * env_list, + struct mailmessage_tree ** result, + int use_subject, + int (* comp_func)(struct mailmessage_tree **, + struct mailmessage_tree **)) +{ + int r; + int res; + chash * msg_id_hash; + unsigned int cur; + struct mailmessage_tree * root; + carray * rootlist; + carray * msg_list; + unsigned int i; + chash * subject_hash; + + msg_id_hash = chash_new(128, CHASH_COPYNONE); + if (msg_id_hash == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + + root = mailmessage_tree_new(NULL, (time_t) -1, NULL); + if (root == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_hash; + } + rootlist = root->node_children; + + msg_list = carray_new(128); + if (msg_list == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_root; + } + + /* collect message-ID */ + for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { + mailmessage * msg; + char * msgid; + struct mailmessage_tree * env_tree; + chashdatum hashkey; + chashdatum hashdata; + chashdatum hashold; + time_t date; + + msg = carray_get(env_list->msg_tab, i); + + if (msg == NULL) + continue; + + if (msg->msg_fields != NULL) { + msgid = get_msg_id(msg); + + if (msgid == NULL) { + msgid = mailimf_get_message_id(); + } + else { + hashkey.data = msgid; + hashkey.len = strlen(msgid); + + if (chash_get(msg_id_hash, &hashkey, &hashdata) == 0) + msgid = mailimf_get_message_id(); + else + msgid = strdup(msgid); + } + + if (msgid == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_list; + } + + date = get_date(msg); + + env_tree = mailmessage_tree_new(msgid, date, msg); + if (env_tree == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_list; + } + + r = carray_add(msg_list, env_tree, NULL); + if (r < 0) { + mailmessage_tree_free(env_tree); + res = MAIL_ERROR_MEMORY; + goto free_list; + } + + hashkey.data = msgid; + hashkey.len = strlen(msgid); + + hashdata.data = env_tree; + hashdata.len = 0; + + r = chash_set(msg_id_hash, &hashkey, &hashdata, &hashold); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_list; + } + } + } + + /* (1) for all messages */ + + for(cur = 0 ; cur < carray_count(msg_list) ; cur ++) { + struct mailmessage_tree * env_tree; + mailmessage * msg; + clist * ref; + + env_tree = carray_get(msg_list, cur); + + msg = env_tree->node_msg; + + ref = NULL; + if (msg != NULL) { + ref = get_ref(msg); + if (ref == NULL) + ref = get_in_reply_to(msg); + } + + /* (A) Using the Message IDs in the message's references, link + the corresponding messages (those whose Message-ID header + line contains the given reference Message ID) together as + parent/child. + */ + + if (ref != NULL) { + /* try to start a tree */ + + clistiter * cur_ref; + chashdatum hashkey; + chashdatum hashdata; + chashdatum hashold; + struct mailmessage_tree * env_cur_tree; + struct mailmessage_tree * last_env_cur_tree; + + env_cur_tree = NULL; + for(cur_ref = clist_begin(ref) ; cur_ref != NULL ; + cur_ref = clist_next(cur_ref)) { + char * msgid; + + last_env_cur_tree = env_cur_tree; + + msgid = clist_content(cur_ref); + + hashkey.data = msgid; + hashkey.len = strlen(msgid); + + r = chash_get(msg_id_hash, &hashkey, &hashdata); + if (r < 0) { + /* not found, create a dummy message */ + msgid = strdup(msgid); + if (msgid == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_list; + } + + env_cur_tree = mailmessage_tree_new(msgid, (time_t) -1, NULL); + if (env_cur_tree == NULL) { + free(msgid); + res = MAIL_ERROR_MEMORY; + goto free_list; + } + + r = carray_add(msg_list, env_cur_tree, NULL); + if (r < 0) { + mailmessage_tree_free(env_cur_tree); + res = MAIL_ERROR_MEMORY; + goto free_list; + } + + hashkey.data = msgid; + hashkey.len = strlen(msgid); + + hashdata.data = env_cur_tree; + hashdata.len = 0; + + r = chash_set(msg_id_hash, &hashkey, &hashdata, &hashold); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_list; + } + } + else { + env_cur_tree = hashdata.data; + } + + if (last_env_cur_tree != NULL) { + if (env_cur_tree->node_parent == NULL) { + /* make it one child */ + if (env_cur_tree != last_env_cur_tree) { + if (!is_descendant(env_cur_tree, last_env_cur_tree)) { + /* set parent */ + env_cur_tree->node_parent = last_env_cur_tree; + r = carray_add(last_env_cur_tree->node_children, + env_cur_tree, NULL); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_list; + } + } + } + } + } + } + + /* (B) Create a parent/child link between the last reference + (or NIL if there are no references) and the current message. + If the current message already has a parent, it is probably + the result of a truncated References header line, so break + the current parent/child link before creating the new + correct one. + */ + + last_env_cur_tree = env_cur_tree; + + if (last_env_cur_tree != NULL) { + if (env_tree->node_parent == NULL) { + if (last_env_cur_tree != env_tree) { + if (!is_descendant(env_tree, last_env_cur_tree)) { + /* set parent */ + env_tree->node_parent = last_env_cur_tree; + r = carray_add(last_env_cur_tree->node_children, env_tree, NULL); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_list; + } + } + } + } + } + } + } + + chash_free(msg_id_hash); + msg_id_hash = NULL; + + /* (2) Gather together all of the messages that have no parents + and make them all children (siblings of one another) of a dummy + parent (the "root"). + */ + + for(cur = 0 ; cur < carray_count(msg_list) ; cur ++) { + struct mailmessage_tree * env_tree; + + env_tree = carray_get(msg_list, cur); + if (env_tree->node_parent == NULL) { + r = carray_add(rootlist, env_tree, NULL); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_list; + } + /* set parent */ + env_tree->node_parent = root; + } + } + + carray_free(msg_list); + msg_list = NULL; + + /* (3) Prune dummy messages from the thread tree. + */ + + cur = 0; + while (cur < carray_count(rootlist)) { + r = delete_dummy(rootlist, rootlist, cur, &cur); + if (r != MAIL_NO_ERROR) { + res = r; + goto free_list; + } + } + + /* (4) Sort the messages under the root (top-level siblings only) + by sent date. + */ + + r = mail_thread_sort(root, mailthread_tree_timecomp, FALSE); + if (r != MAIL_NO_ERROR) { + res = r; + goto free_list; + } + + if (use_subject) { + + /* (5) Gather together messages under the root that have the same + extracted subject text. + + (A) Create a table for associating extracted subjects with + messages. + */ + + subject_hash = chash_new(128, CHASH_COPYVALUE); + if (subject_hash == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_list; + } + + /* + (B) Populate the subject table with one message per + extracted subject. For each child of the root: + */ + + for(cur = 0 ; cur < carray_count(rootlist) ; cur ++) { + struct mailmessage_tree * env_tree; + chashdatum key; + chashdatum data; + char * base_subject; + int r; + + env_tree = carray_get(rootlist, cur); + + /* + (i) Find the subject of this thread by extracting the + base subject from the current message, or its first child + if the current message is a dummy. + */ + + r = get_thread_subject(default_from, env_tree, &base_subject); + + /* + (ii) If the extracted subject is empty, skip this + message. + */ + + if (r == MAIL_ERROR_SUBJECT_NOT_FOUND) { + /* no subject found */ + continue; + } + else if (r == MAIL_NO_ERROR) { + if (* base_subject == '\0') { + /* subject empty */ + free(base_subject); + continue; + } + else { + /* do nothing */ + } + } + else { + res = r; + goto free_subject_hash; + } + + env_tree->node_base_subject = base_subject; + + /* + (iii) Lookup the message associated with this extracted + subject in the table. + */ + + key.data = base_subject; + key.len = strlen(base_subject); + + r = chash_get(subject_hash, &key, &data); + + if (r < 0) { + /* + (iv) If there is no message in the table with this + subject, add the current message and the extracted + subject to the subject table. + */ + + data.data = &cur; + data.len = sizeof(cur); + + r = chash_set(subject_hash, &key, &data, NULL); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_subject_hash; + } + } + else { + /* + Otherwise, replace the message in the table with the + current message if the message in the table is not a + dummy AND either of the following criteria are true: + The current message is a dummy, OR + The message in the table is a reply or forward (its + original subject contains a subj-refwd part and/or a + "(fwd)" subj-trailer) and the current message is not. + */ + struct mailmessage_tree * msg_in_table; + unsigned int * iter_in_table; + int replace; + + iter_in_table = data.data; + msg_in_table = carray_get(rootlist, cur); + + replace = FALSE; + /* message is dummy if info is NULL */ + if (msg_in_table->node_msg != NULL) { + + if (env_tree->node_msg == NULL) + replace = TRUE; + else { + if (env_tree->node_is_reply && !env_tree->node_is_reply) + replace = TRUE; + } + } + + if (replace) { + data.data = &cur; + data.len = sizeof(cur); + + r = chash_set(subject_hash, &key, &data, NULL); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_subject_hash; + } + } + } + } + + /* + (C) Merge threads with the same subject. For each child of + the root: + */ + + cur = 0; + while (cur < carray_count(rootlist)) { + struct mailmessage_tree * env_tree; + chashdatum key; + chashdatum data; + int r; + struct mailmessage_tree * main_tree; + unsigned int * main_cur; + + env_tree = carray_get(rootlist, cur); + + if (env_tree == NULL) + goto next_msg; + + /* + (i) Find the subject of this thread as in step 4.B.i + above. + */ + + /* already done in tree->node_base_subject */ + + /* + (ii) If the extracted subject is empty, skip this + message. + */ + + if (env_tree->node_base_subject == NULL) + goto next_msg; + + if (* env_tree->node_base_subject == '\0') + goto next_msg; + + /* + (iii) Lookup the message associated with this extracted + subject in the table. + */ + + key.data = env_tree->node_base_subject; + key.len = strlen(env_tree->node_base_subject); + + r = chash_get(subject_hash, &key, &data); + if (r < 0) + goto next_msg; + + /* + (iv) If the message in the table is the current message, + skip this message. + */ + + main_cur = data.data; + if (* main_cur == cur) + goto next_msg; + + /* + Otherwise, merge the current message with the one in the + table using the following rules: + */ + + main_tree = carray_get(rootlist, * main_cur); + + /* + If both messages are dummies, append the current + message's children to the children of the message in + the table (the children of both messages become + siblings), and then delete the current message. + */ + + if ((env_tree->node_msg == NULL) && (main_tree->node_msg == NULL)) { + unsigned int old_size; + + old_size = carray_count(main_tree->node_children); + + r = carray_set_size(main_tree->node_children, old_size + + carray_count(env_tree->node_children)); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_subject_hash; + } + + for(i = 0 ; i < carray_count(env_tree->node_children) ; i ++) { + struct mailmessage_tree * child; + + child = carray_get(env_tree->node_children, i); + carray_set(main_tree->node_children, old_size + i, child); + /* set parent */ + child->node_parent = main_tree; + } + carray_set_size(env_tree->node_children, 0); + /* this is the only case where children can be NULL, + this is before freeing it */ + mailmessage_tree_free(env_tree); + carray_delete_fast(rootlist, cur); + } + + /* + If the message in the table is a dummy and the current + message is not, make the current message a child of + the message in the table (a sibling of it's children). + */ + + else if (main_tree->node_msg == NULL) { + r = carray_add(main_tree->node_children, env_tree, NULL); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_subject_hash; + } + /* set parent */ + env_tree->node_parent = main_tree; + + carray_delete_fast(rootlist, cur); + } + + /* + If the current message is a reply or forward and the + message in the table is not, make the current message + a child of the message in the table (a sibling of it's + children). + */ + + else if (env_tree->node_is_reply && !main_tree->node_is_reply) { + r = carray_add(main_tree->node_children, env_tree, NULL); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_subject_hash; + } + /* set parent */ + env_tree->node_parent = main_tree; + + carray_delete_fast(rootlist, cur); + } + + /* + Otherwise, create a new dummy message and make both + the current message and the message in the table + children of the dummy. Then replace the message in + the table with the dummy message. + Note: Subject comparisons are case-insensitive, as + described under "Internationalization + Considerations." + */ + + else { + struct mailmessage_tree * new_main_tree; + char * base_subject; + unsigned int last; + + new_main_tree = mailmessage_tree_new(NULL, (time_t) -1, NULL); + if (new_main_tree == NULL) { + res = MAIL_ERROR_MEMORY; + goto free_subject_hash; + } + + /* main_tree->node_base_subject is never NULL */ + + base_subject = strdup(main_tree->node_base_subject); + if (base_subject == NULL) { + mailmessage_tree_free(new_main_tree); + res = MAIL_ERROR_MEMORY; + goto free_subject_hash; + } + + new_main_tree->node_base_subject = base_subject; + + r = carray_add(rootlist, new_main_tree, &last); + if (r < 0) { + mailmessage_tree_free(new_main_tree); + res = MAIL_ERROR_MEMORY; + goto free_subject_hash; + } + + r = carray_add(new_main_tree->node_children, main_tree, NULL); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_subject_hash; + } + /* set parent */ + main_tree->node_parent = new_main_tree; + + carray_delete_fast(rootlist, * main_cur); + + r = carray_add(new_main_tree->node_children, env_tree, NULL); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_subject_hash; + } + /* set parent */ + env_tree->node_parent = new_main_tree; + + carray_delete_fast(rootlist, cur); + + data.data = &last; + data.len = sizeof(last); + + r = chash_set(subject_hash, &key, &data, NULL); + + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free_subject_hash; + } + } + + continue; + + next_msg: + cur ++; + continue; + } + + i = 0; + for(cur = 0 ; cur < carray_count(rootlist) ; cur ++) { + struct mailmessage_tree * env_tree; + + env_tree = carray_get(rootlist, cur); + if (env_tree == NULL) + continue; + + carray_set(rootlist, i, env_tree); + i ++; + } + carray_set_size(rootlist, i); + + chash_free(subject_hash); + } + + /* + (6) Traverse the messages under the root and sort each set of + siblings by sent date. Traverse the messages in such a way + that the "youngest" set of siblings are sorted first, and the + "oldest" set of siblings are sorted last (grandchildren are + sorted before children, etc). + + In the case of an exact match on + sent date or if either of the Date: headers used in a + comparison can not be parsed, use the order in which the + messages appear in the mailbox (that is, by sequence number) to + determine the order. In the case of a dummy message (which can + only occur with top-level siblings), use its first child for + sorting. + */ + +#if 0 + if (comp_func != NULL) { + r = mail_thread_sort(root, comp_func, TRUE); + if (r != MAIL_NO_ERROR) { + res = r; + goto free_list; + } + } +#endif + if (comp_func == NULL) + comp_func = mailthread_tree_timecomp; + + r = mail_thread_sort(root, comp_func, TRUE); + if (r != MAIL_NO_ERROR) { + res = r; + goto free_list; + } + + * result = root; + + return MAIL_NO_ERROR; + + free_subject_hash: + chash_free(subject_hash); + free_list: + if (msg_list != NULL) { + for(i = 0 ; i < carray_count(msg_list) ; i ++) + mailmessage_tree_free(carray_get(msg_list, i)); + carray_free(msg_list); + } + free_root: + mailmessage_tree_free_recursive(root); + free_hash: + if (msg_id_hash != NULL) + chash_free(msg_id_hash); + err: + return res; +} + + + +static int +mail_build_thread_orderedsubject(char * default_from, + struct mailmessage_list * env_list, + struct mailmessage_tree ** result, + int (* comp_func)(struct mailmessage_tree **, + struct mailmessage_tree **)) +{ + unsigned int i; + carray * rootlist; + unsigned int cur; + struct mailmessage_tree * root; + int res; + int r; + struct mailmessage_tree * current_thread; + + root = mailmessage_tree_new(NULL, (time_t) -1, NULL); + if (root == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + rootlist = root->node_children; + + /* + The ORDEREDSUBJECT threading algorithm is also referred to as + "poor man's threading." + */ + + for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { + mailmessage * msg; + struct mailmessage_tree * env_tree; + char * base_subject; + time_t date; + + msg = carray_get(env_list->msg_tab, i); + + if (msg == NULL) + continue; + + if (msg->msg_fields != NULL) { + + date = get_date(msg); + + env_tree = mailmessage_tree_new(NULL, date, msg); + if (env_tree == NULL) { + res = MAIL_ERROR_MEMORY; + goto free; + } + + /* set parent */ + env_tree->node_parent = root; + r = carray_add(rootlist, env_tree, NULL); + if (r < 0) { + mailmessage_tree_free(env_tree); + res = MAIL_ERROR_MEMORY; + goto free; + } + + r = get_extracted_subject(default_from, env_tree, &base_subject); + switch (r) { + case MAIL_NO_ERROR: + env_tree->node_base_subject = base_subject; + break; + + case MAIL_ERROR_SUBJECT_NOT_FOUND: + break; + + default: + res = r; + goto free; + } + } + } + + /* + The searched messages are sorted by + subject and then by the sent date. + */ + + r = mail_thread_sort(root, tree_subj_time_comp, FALSE); + if (r != MAIL_NO_ERROR) { + res = r; + goto free; + } + + /* + The messages are then split + into separate threads, with each thread containing messages + with the same extracted subject text. + */ + + current_thread = NULL; + + cur = 0; + while (cur < carray_count(rootlist)) { + struct mailmessage_tree * cur_env_tree; + + cur_env_tree = carray_get(rootlist, cur); + if (current_thread == NULL) { + current_thread = cur_env_tree; + cur ++; + continue; + } + + if ((cur_env_tree->node_base_subject == NULL) || + (current_thread->node_base_subject == NULL)) { + current_thread = cur_env_tree; + cur ++; + continue; + } + + if (strcmp(cur_env_tree->node_base_subject, + current_thread->node_base_subject) == 0) { + + /* set parent */ + cur_env_tree->node_parent = current_thread; + r = carray_add(current_thread->node_children, cur_env_tree, NULL); + if (r < 0) { + res = MAIL_ERROR_MEMORY; + goto free; + } + + carray_delete(rootlist, cur); + } + else + cur ++; + current_thread = cur_env_tree; + } + + /* + Finally, the threads are + sorted by the sent date of the first message in the thread. + Note that each message in a thread is a child (as opposed to a + sibling) of the previous message. + */ + +#if 0 + if (comp_func != NULL) { + r = mail_thread_sort(root, comp_func, FALSE); + if (r != MAIL_NO_ERROR) { + res = r; + goto free; + } + } +#endif + + if (comp_func == NULL) + comp_func = mailthread_tree_timecomp; + + r = mail_thread_sort(root, comp_func, FALSE); + if (r != MAIL_NO_ERROR) { + res = r; + goto free; + } + + * result = root; + + return MAIL_NO_ERROR; + + free: + mailmessage_tree_free_recursive(root); + err: + return res; +} + + +static int +mail_build_thread_none(char * default_from, + struct mailmessage_list * env_list, + struct mailmessage_tree ** result, + int (* comp_func)(struct mailmessage_tree **, + struct mailmessage_tree **)) +{ + unsigned int i; + carray * rootlist; + struct mailmessage_tree * root; + int res; + int r; + + root = mailmessage_tree_new(NULL, (time_t) -1, NULL); + if (root == NULL) { + res = MAIL_ERROR_MEMORY; + goto err; + } + rootlist = root->node_children; + + for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) { + mailmessage * msg; + struct mailmessage_tree * env_tree; + char * base_subject; + time_t date; + + msg = carray_get(env_list->msg_tab, i); + + if (msg == NULL) + continue; + + if (msg->msg_fields != NULL) { + + date = get_date(msg); + + env_tree = mailmessage_tree_new(NULL, date, msg); + if (env_tree == NULL) { + res = MAIL_ERROR_MEMORY; + goto free; + } + + /* set parent */ + env_tree->node_parent = root; + r = carray_add(rootlist, env_tree, NULL); + if (r < 0) { + mailmessage_tree_free(env_tree); + res = MAIL_ERROR_MEMORY; + goto free; + } + + r = get_extracted_subject(default_from, env_tree, &base_subject); + switch (r) { + case MAIL_NO_ERROR: + env_tree->node_base_subject = base_subject; + break; + + case MAIL_ERROR_SUBJECT_NOT_FOUND: + break; + + default: + res = r; + goto free; + } + } + } + + if (comp_func == NULL) + comp_func = mailthread_tree_timecomp; + + r = mail_thread_sort(root, comp_func, FALSE); + if (r != MAIL_NO_ERROR) { + res = r; + goto free; + } + + * result = root; + + return MAIL_NO_ERROR; + + free: + mailmessage_tree_free_recursive(root); + err: + return res; +} + + +int mail_build_thread(int type, char * default_from, + struct mailmessage_list * env_list, + struct mailmessage_tree ** result, + int (* comp_func)(struct mailmessage_tree **, + struct mailmessage_tree **)) +{ + unsigned int i; + + for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) + mailmessage_resolve_single_fields(carray_get(env_list->msg_tab, i)); + + switch (type) { + case MAIL_THREAD_REFERENCES: + return mail_build_thread_references(default_from, + env_list, result, TRUE, comp_func); + + case MAIL_THREAD_REFERENCES_NO_SUBJECT: + return mail_build_thread_references(default_from, + env_list, result, FALSE, comp_func); + + case MAIL_THREAD_ORDEREDSUBJECT: + return mail_build_thread_orderedsubject(default_from, + env_list, result, comp_func); + + case MAIL_THREAD_NONE: + return mail_build_thread_none(default_from, + env_list, result, comp_func); + + default: + return MAIL_ERROR_NOT_IMPLEMENTED; + } +} diff --git a/libetpan/src/driver/tools/mailthread.h b/libetpan/src/driver/tools/mailthread.h new file mode 100644 index 0000000..fa2f4bc --- a/dev/null +++ b/libetpan/src/driver/tools/mailthread.h @@ -0,0 +1,108 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MAILTHREAD_H + +#define MAILTHREAD_H + +#include <libetpan/mailthread_types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* + mail_build_thread constructs a tree with the message using the + given style. + + @param type is the type of threading to apply, the value can be + MAIL_THREAD_REFERENCES, MAIL_THREAD_REFERENCES_NO_SUBJECT, + MAIL_THREAD_ORDEREDSUBJECT or MAIL_THREAD_NONE, + + @param default_from is the default charset to use whenever the + subject is not tagged with a charset. "US-ASCII" can be used + if you don't know what to use. + + @param env_list is the message list (with header fields fetched) + to use to build the message tree. + + @param result * result) will contain the resulting message tree. + + @param if comp_func is NULL, no sorting algorithm is used. + + @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned + on error +*/ + +int mail_build_thread(int type, char * default_from, + struct mailmessage_list * env_list, + struct mailmessage_tree ** result, + int (* comp_func)(struct mailmessage_tree **, + struct mailmessage_tree **)); + +/* + mail_thread_sort sort the messages in the message tree, using the + given sort function. + + @param tree is the message tree to sort. + + @param comp_func is the sort function to use (this is the same kind of + functions than those used for qsort()). mailthread_tree_timecomp can be + used for default sort. + + @param sort_sub if this value is 0, only the children of the root message + are sorted. +*/ + +int mail_thread_sort(struct mailmessage_tree * tree, + int (* comp_func)(struct mailmessage_tree **, + struct mailmessage_tree **), + int sort_sub); + +/* + mailthread_tree_timecomp is the default sort function. + + The message are compared by date, then by message numbers. + The tree are given in (* ptree1) and (* ptree2). +*/ + +int mailthread_tree_timecomp(struct mailmessage_tree ** ptree1, + struct mailmessage_tree ** ptree2); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libetpan/src/driver/tools/mailthread_types.c b/libetpan/src/driver/tools/mailthread_types.c new file mode 100644 index 0000000..dc2a4ca --- a/dev/null +++ b/libetpan/src/driver/tools/mailthread_types.c @@ -0,0 +1,90 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#include "mailthread_types.h" + +#include "mail.h" +#include <stdlib.h> + +struct mailmessage_tree * +mailmessage_tree_new(char * node_msgid, time_t node_date, + mailmessage * node_msg) +{ + struct mailmessage_tree * tree; + carray * array; + + array = carray_new(16); + if (array == NULL) + return NULL; + + tree = malloc(sizeof(* tree)); + tree->node_parent = NULL; + tree->node_date = node_date; + tree->node_msgid = node_msgid; + tree->node_msg = node_msg; + tree->node_children = array; + tree->node_base_subject = NULL; + tree->node_is_reply = FALSE; + + return tree; +} + +void mailmessage_tree_free(struct mailmessage_tree * tree) +{ + if (tree->node_base_subject != NULL) + free(tree->node_base_subject); + + if (tree->node_children != NULL) + carray_free(tree->node_children); + if (tree->node_msgid != NULL) + free(tree->node_msgid); + + free(tree); +} + +void mailmessage_tree_free_recursive(struct mailmessage_tree * tree) +{ + unsigned int i; + + for(i = 0 ; i < carray_count(tree->node_children) ; i++) { + struct mailmessage_tree * child; + + child = carray_get(tree->node_children, i); + + mailmessage_tree_free_recursive(child); + } + + mailmessage_tree_free(tree); +} diff --git a/libetpan/src/driver/tools/mailthread_types.h b/libetpan/src/driver/tools/mailthread_types.h new file mode 100644 index 0000000..3325904 --- a/dev/null +++ b/libetpan/src/driver/tools/mailthread_types.h @@ -0,0 +1,64 @@ +/* + * libEtPan! -- a mail stuff library + * + * Copyright (C) 2001, 2005 - DINH Viet Hoa + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the libEtPan! project nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * $Id$ + */ + +#ifndef MAILTHREAD_TYPES_H + +#define MAILTHREAD_TYPES_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <libetpan/maildriver_types.h> +#include <libetpan/mailmessage_types.h> + +/* + This is the type of tree construction to apply. +*/ + +enum { + MAIL_THREAD_REFERENCES, /* this is threading using + References fields only) */ + MAIL_THREAD_REFERENCES_NO_SUBJECT, /* this is threading using References + fields, then subject */ + MAIL_THREAD_ORDEREDSUBJECT, /* this is threading using only subject */ + MAIL_THREAD_NONE, /* no thread */ +}; + +#ifdef __cplusplus +} +#endif + +#endif |