Diffstat (limited to 'libetpan/src/driver/implementation') (more/less context) (ignore whitespace changes)
91 files changed, 29843 insertions, 0 deletions
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 |