summaryrefslogtreecommitdiffabout
path: root/libetpan/src/driver
authorzautrix <zautrix>2005-03-18 20:17:03 (UTC)
committer zautrix <zautrix>2005-03-18 20:17:03 (UTC)
commit9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf (patch) (side-by-side diff)
tree2528e6cc740225ca0f47d5ac8ff70f7d3bb10621 /libetpan/src/driver
parent9319998f20f03dcc217fbb39656755dc65226276 (diff)
downloadkdepimpi-9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf.zip
kdepimpi-9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf.tar.gz
kdepimpi-9e549686b23b6dffdcbd09c9b10dc2cb795fbcdf.tar.bz2
Initial revision
Diffstat (limited to 'libetpan/src/driver') (more/less context) (ignore whitespace changes)
-rw-r--r--libetpan/src/driver/TODO9
-rw-r--r--libetpan/src/driver/implementation/data-message/data_message_driver.c119
-rw-r--r--libetpan/src/driver/implementation/data-message/data_message_driver.h50
-rw-r--r--libetpan/src/driver/implementation/db/dbdriver.c1134
-rw-r--r--libetpan/src/driver/implementation/db/dbdriver.h53
-rw-r--r--libetpan/src/driver/implementation/db/dbdriver_message.c308
-rw-r--r--libetpan/src/driver/implementation/db/dbdriver_message.h52
-rw-r--r--libetpan/src/driver/implementation/db/dbdriver_types.h71
-rw-r--r--libetpan/src/driver/implementation/db/dbstorage.c144
-rw-r--r--libetpan/src/driver/implementation/db/dbstorage.h61
-rw-r--r--libetpan/src/driver/implementation/hotmail/hotmailstorage.c62
-rw-r--r--libetpan/src/driver/implementation/hotmail/hotmailstorage.h56
-rw-r--r--libetpan/src/driver/implementation/imap/imapdriver.c1226
-rw-r--r--libetpan/src/driver/implementation/imap/imapdriver.h52
-rw-r--r--libetpan/src/driver/implementation/imap/imapdriver_cached.c1370
-rw-r--r--libetpan/src/driver/implementation/imap/imapdriver_cached.h52
-rw-r--r--libetpan/src/driver/implementation/imap/imapdriver_cached_message.c664
-rw-r--r--libetpan/src/driver/implementation/imap/imapdriver_cached_message.h52
-rw-r--r--libetpan/src/driver/implementation/imap/imapdriver_message.c1239
-rw-r--r--libetpan/src/driver/implementation/imap/imapdriver_message.h52
-rw-r--r--libetpan/src/driver/implementation/imap/imapdriver_tools.c3623
-rw-r--r--libetpan/src/driver/implementation/imap/imapdriver_tools.h116
-rw-r--r--libetpan/src/driver/implementation/imap/imapdriver_types.h144
-rw-r--r--libetpan/src/driver/implementation/imap/imapstorage.c297
-rw-r--r--libetpan/src/driver/implementation/imap/imapstorage.h90
-rw-r--r--libetpan/src/driver/implementation/maildir/maildirdriver.c676
-rw-r--r--libetpan/src/driver/implementation/maildir/maildirdriver.h53
-rw-r--r--libetpan/src/driver/implementation/maildir/maildirdriver_cached.c1158
-rw-r--r--libetpan/src/driver/implementation/maildir/maildirdriver_cached.h53
-rw-r--r--libetpan/src/driver/implementation/maildir/maildirdriver_cached_message.c334
-rw-r--r--libetpan/src/driver/implementation/maildir/maildirdriver_cached_message.h52
-rw-r--r--libetpan/src/driver/implementation/maildir/maildirdriver_message.c255
-rw-r--r--libetpan/src/driver/implementation/maildir/maildirdriver_message.h52
-rw-r--r--libetpan/src/driver/implementation/maildir/maildirdriver_tools.c198
-rw-r--r--libetpan/src/driver/implementation/maildir/maildirdriver_tools.h53
-rw-r--r--libetpan/src/driver/implementation/maildir/maildirdriver_types.h96
-rw-r--r--libetpan/src/driver/implementation/maildir/maildirstorage.c193
-rw-r--r--libetpan/src/driver/implementation/maildir/maildirstorage.h69
-rw-r--r--libetpan/src/driver/implementation/mbox/mboxdriver.c515
-rw-r--r--libetpan/src/driver/implementation/mbox/mboxdriver.h52
-rw-r--r--libetpan/src/driver/implementation/mbox/mboxdriver_cached.c1337
-rw-r--r--libetpan/src/driver/implementation/mbox/mboxdriver_cached.h54
-rw-r--r--libetpan/src/driver/implementation/mbox/mboxdriver_cached_message.c361
-rw-r--r--libetpan/src/driver/implementation/mbox/mboxdriver_cached_message.h52
-rw-r--r--libetpan/src/driver/implementation/mbox/mboxdriver_message.c225
-rw-r--r--libetpan/src/driver/implementation/mbox/mboxdriver_message.h52
-rw-r--r--libetpan/src/driver/implementation/mbox/mboxdriver_tools.c435
-rw-r--r--libetpan/src/driver/implementation/mbox/mboxdriver_tools.h85
-rw-r--r--libetpan/src/driver/implementation/mbox/mboxdriver_types.h107
-rw-r--r--libetpan/src/driver/implementation/mbox/mboxstorage.c192
-rw-r--r--libetpan/src/driver/implementation/mbox/mboxstorage.h69
-rw-r--r--libetpan/src/driver/implementation/mh/mhdriver.c875
-rw-r--r--libetpan/src/driver/implementation/mh/mhdriver.h52
-rw-r--r--libetpan/src/driver/implementation/mh/mhdriver_cached.c1315
-rw-r--r--libetpan/src/driver/implementation/mh/mhdriver_cached.h52
-rw-r--r--libetpan/src/driver/implementation/mh/mhdriver_cached_message.c338
-rw-r--r--libetpan/src/driver/implementation/mh/mhdriver_cached_message.h52
-rw-r--r--libetpan/src/driver/implementation/mh/mhdriver_message.c213
-rw-r--r--libetpan/src/driver/implementation/mh/mhdriver_message.h52
-rw-r--r--libetpan/src/driver/implementation/mh/mhdriver_tools.c484
-rw-r--r--libetpan/src/driver/implementation/mh/mhdriver_tools.h80
-rw-r--r--libetpan/src/driver/implementation/mh/mhdriver_types.h100
-rw-r--r--libetpan/src/driver/implementation/mh/mhstorage.c192
-rw-r--r--libetpan/src/driver/implementation/mh/mhstorage.h67
-rw-r--r--libetpan/src/driver/implementation/mime-message/mime_message_driver.c914
-rw-r--r--libetpan/src/driver/implementation/mime-message/mime_message_driver.h53
-rw-r--r--libetpan/src/driver/implementation/nntp/nntpdriver.c1180
-rw-r--r--libetpan/src/driver/implementation/nntp/nntpdriver.h52
-rw-r--r--libetpan/src/driver/implementation/nntp/nntpdriver_cached.c1059
-rw-r--r--libetpan/src/driver/implementation/nntp/nntpdriver_cached.h52
-rw-r--r--libetpan/src/driver/implementation/nntp/nntpdriver_cached_message.c365
-rw-r--r--libetpan/src/driver/implementation/nntp/nntpdriver_cached_message.h52
-rw-r--r--libetpan/src/driver/implementation/nntp/nntpdriver_message.c169
-rw-r--r--libetpan/src/driver/implementation/nntp/nntpdriver_message.h52
-rw-r--r--libetpan/src/driver/implementation/nntp/nntpdriver_tools.c563
-rw-r--r--libetpan/src/driver/implementation/nntp/nntpdriver_tools.h88
-rw-r--r--libetpan/src/driver/implementation/nntp/nntpdriver_types.h146
-rw-r--r--libetpan/src/driver/implementation/nntp/nntpstorage.c267
-rw-r--r--libetpan/src/driver/implementation/nntp/nntpstorage.h93
-rw-r--r--libetpan/src/driver/implementation/pop3/pop3driver.c388
-rw-r--r--libetpan/src/driver/implementation/pop3/pop3driver.h52
-rw-r--r--libetpan/src/driver/implementation/pop3/pop3driver_cached.c899
-rw-r--r--libetpan/src/driver/implementation/pop3/pop3driver_cached.h52
-rw-r--r--libetpan/src/driver/implementation/pop3/pop3driver_cached_message.c355
-rw-r--r--libetpan/src/driver/implementation/pop3/pop3driver_cached_message.h52
-rw-r--r--libetpan/src/driver/implementation/pop3/pop3driver_message.c193
-rw-r--r--libetpan/src/driver/implementation/pop3/pop3driver_message.h52
-rw-r--r--libetpan/src/driver/implementation/pop3/pop3driver_tools.c344
-rw-r--r--libetpan/src/driver/implementation/pop3/pop3driver_tools.h82
-rw-r--r--libetpan/src/driver/implementation/pop3/pop3driver_types.h153
-rw-r--r--libetpan/src/driver/implementation/pop3/pop3storage.c284
-rw-r--r--libetpan/src/driver/implementation/pop3/pop3storage.h95
-rw-r--r--libetpan/src/driver/interface/maildriver.c383
-rw-r--r--libetpan/src/driver/interface/maildriver.h546
-rw-r--r--libetpan/src/driver/interface/maildriver_errors.h102
-rw-r--r--libetpan/src/driver/interface/maildriver_tools.c841
-rw-r--r--libetpan/src/driver/interface/maildriver_tools.h81
-rw-r--r--libetpan/src/driver/interface/maildriver_types.c340
-rw-r--r--libetpan/src/driver/interface/maildriver_types.h795
-rw-r--r--libetpan/src/driver/interface/maildriver_types_helper.c104
-rw-r--r--libetpan/src/driver/interface/maildriver_types_helper.h99
-rw-r--r--libetpan/src/driver/interface/mailfolder.c138
-rw-r--r--libetpan/src/driver/interface/mailfolder.h70
-rw-r--r--libetpan/src/driver/interface/mailmessage.c240
-rw-r--r--libetpan/src/driver/interface/mailmessage.h379
-rw-r--r--libetpan/src/driver/interface/mailmessage_tools.c600
-rw-r--r--libetpan/src/driver/interface/mailmessage_tools.h103
-rw-r--r--libetpan/src/driver/interface/mailmessage_types.c92
-rw-r--r--libetpan/src/driver/interface/mailmessage_types.h50
-rw-r--r--libetpan/src/driver/interface/mailstorage.c341
-rw-r--r--libetpan/src/driver/interface/mailstorage.h99
-rw-r--r--libetpan/src/driver/interface/mailstorage_tools.c372
-rw-r--r--libetpan/src/driver/interface/mailstorage_tools.h67
-rw-r--r--libetpan/src/driver/interface/mailstorage_types.h203
-rw-r--r--libetpan/src/driver/tools/generic_cache.c729
-rw-r--r--libetpan/src/driver/tools/generic_cache.h109
-rw-r--r--libetpan/src/driver/tools/generic_cache_types.h56
-rw-r--r--libetpan/src/driver/tools/imfcache.c1429
-rw-r--r--libetpan/src/driver/tools/imfcache.h75
-rw-r--r--libetpan/src/driver/tools/mailthread.c1742
-rw-r--r--libetpan/src/driver/tools/mailthread.h108
-rw-r--r--libetpan/src/driver/tools/mailthread_types.c90
-rw-r--r--libetpan/src/driver/tools/mailthread_types.h64
123 files changed, 40299 insertions, 0 deletions
diff --git a/libetpan/src/driver/TODO b/libetpan/src/driver/TODO
new file mode 100644
index 0000000..4ba2c46
--- a/dev/null
+++ b/libetpan/src/driver/TODO
@@ -0,0 +1,9 @@
+- get_message_list() will disconnect and reconnect POP3 box
+- add UID to non-cached drivers, help clients to recognize messages
+- move IMAP UID cache to non-cached driver
+- fix message size (put it in cache)
+- XXX : fetch body in nntp do not use generic_fetch_body
+- add flags prototype to add or remove flags
+- cache bodystructures
+- search is not implemented
+- list of folder new implementation
diff --git a/libetpan/src/driver/implementation/data-message/data_message_driver.c b/libetpan/src/driver/implementation/data-message/data_message_driver.c
new file mode 100644
index 0000000..fbdffcd
--- a/dev/null
+++ b/libetpan/src/driver/implementation/data-message/data_message_driver.c
@@ -0,0 +1,119 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "data_message_driver.h"
+
+#include "mailmessage.h"
+#include "mailmessage_tools.h"
+
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+
+static int fetch_size(mailmessage * msg, size_t * result)
+{
+ struct generic_message_t * msg_data;
+
+ msg_data = msg->msg_data;
+ * result = msg_data->msg_length;
+
+ return MAIL_NO_ERROR;
+}
+
+
+static mailmessage_driver local_data_message_driver = {
+ .msg_name = "data",
+
+ .msg_initialize = mailmessage_generic_initialize,
+ .msg_uninitialize = mailmessage_generic_uninitialize,
+
+ .msg_flush = mailmessage_generic_flush,
+ .msg_check = NULL,
+
+ .msg_fetch_result_free = mailmessage_generic_fetch_result_free,
+
+ .msg_fetch = mailmessage_generic_fetch,
+ .msg_fetch_header = mailmessage_generic_fetch_header,
+ .msg_fetch_body = mailmessage_generic_fetch_body,
+ .msg_fetch_size = fetch_size,
+ .msg_get_bodystructure = mailmessage_generic_get_bodystructure,
+ .msg_fetch_section = mailmessage_generic_fetch_section,
+ .msg_fetch_section_header = mailmessage_generic_fetch_section_header,
+ .msg_fetch_section_mime = mailmessage_generic_fetch_section_mime,
+ .msg_fetch_section_body = mailmessage_generic_fetch_section_body,
+ .msg_fetch_envelope = mailmessage_generic_fetch_envelope,
+
+ .msg_get_flags = NULL,
+};
+
+mailmessage_driver * data_message_driver = &local_data_message_driver;
+
+
+
+mailmessage * data_message_init(char * data, size_t len)
+{
+ struct generic_message_t * msg_data;
+ mailmessage * msg;
+ int r;
+
+ msg = mailmessage_new();
+ if (msg == NULL)
+ goto err;
+
+ r = mailmessage_init(msg, NULL, data_message_driver, 0, len);
+ if (r < 0)
+ goto free;
+
+ msg_data = msg->msg_data;
+ msg_data->msg_fetched = 1;
+ msg_data->msg_message = data;
+ msg_data->msg_length = len;
+
+ return msg;
+
+ free:
+ mailmessage_free(msg);
+ err:
+ return NULL;
+}
+
+void data_message_detach_mime(mailmessage * msg)
+{
+ msg->msg_mime = NULL;
+}
diff --git a/libetpan/src/driver/implementation/data-message/data_message_driver.h b/libetpan/src/driver/implementation/data-message/data_message_driver.h
new file mode 100644
index 0000000..b6569c2
--- a/dev/null
+++ b/libetpan/src/driver/implementation/data-message/data_message_driver.h
@@ -0,0 +1,50 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef DATA_MESSAGE_DRIVER_H
+
+#define DATA_MESSAGE_DRIVER_H
+
+#include <libetpan/mailmessage.h>
+
+#define LIBETPAN_DATA_MESSAGE
+
+extern mailmessage_driver * data_message_driver;
+
+mailmessage * data_message_init(char * data, size_t len);
+
+void data_message_detach_mime(mailmessage * msg);
+
+#endif
diff --git a/libetpan/src/driver/implementation/db/dbdriver.c b/libetpan/src/driver/implementation/db/dbdriver.c
new file mode 100644
index 0000000..e374e64
--- a/dev/null
+++ b/libetpan/src/driver/implementation/db/dbdriver.c
@@ -0,0 +1,1134 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "dbdriver.h"
+#include "imfcache.h"
+#include "generic_cache.h"
+#include "libetpan-config.h"
+#include "dbdriver_message.h"
+#include "mail_cache_db.h"
+#include <string.h>
+#include <stdlib.h>
+#include "mailmessage.h"
+
+static int initialize(mailsession * session);
+
+static void uninitialize(mailsession * session);
+
+static int connect_path(mailsession * session, char * path);
+
+static int logout(mailsession * session);
+
+static int expunge_folder(mailsession * session);
+
+static int status_folder(mailsession * session, char * mb,
+ uint32_t * result_messages, uint32_t * result_recent,
+ uint32_t * result_unseen);
+
+static int recent_number(mailsession * session, char * mb,
+ uint32_t * result);
+
+static int unseen_number(mailsession * session, char * mb,
+ uint32_t * result);
+
+static int messages_number(mailsession * session, char * mb,
+ uint32_t * result);
+
+static int append_message(mailsession * session,
+ char * message, size_t size);
+
+static int append_message_flags(mailsession * session,
+ char * message, size_t size, struct mail_flags * flags);
+
+static int get_messages_list(mailsession * session,
+ struct mailmessage_list ** result);
+
+static int get_envelopes_list(mailsession * session,
+ struct mailmessage_list * env_list);
+
+static int check_folder(mailsession * session);
+
+static int get_message(mailsession * session,
+ uint32_t num, mailmessage ** result);
+
+static int get_message_by_uid(mailsession * session,
+ const char * uid, mailmessage ** result);
+
+static mailsession_driver local_db_session_driver = {
+ .sess_name = "db",
+
+ .sess_initialize = initialize,
+ .sess_uninitialize = uninitialize,
+
+ .sess_parameters = NULL,
+
+ .sess_connect_stream = NULL,
+ .sess_connect_path = connect_path,
+ .sess_starttls = NULL,
+ .sess_login = NULL,
+ .sess_logout = logout,
+ .sess_noop = NULL,
+
+ .sess_build_folder_name = NULL,
+ .sess_create_folder = NULL,
+ .sess_delete_folder = NULL,
+ .sess_rename_folder = NULL,
+ .sess_check_folder = check_folder,
+ .sess_examine_folder = NULL,
+ .sess_select_folder = NULL,
+ .sess_expunge_folder = expunge_folder,
+ .sess_status_folder = status_folder,
+ .sess_messages_number = messages_number,
+ .sess_recent_number = recent_number,
+ .sess_unseen_number = unseen_number,
+ .sess_list_folders = NULL,
+ .sess_lsub_folders = NULL,
+ .sess_subscribe_folder = NULL,
+ .sess_unsubscribe_folder = NULL,
+
+ .sess_append_message = append_message,
+ .sess_append_message_flags = append_message_flags,
+ .sess_copy_message = NULL,
+ .sess_move_message = NULL,
+
+ .sess_get_messages_list = get_messages_list,
+ .sess_get_envelopes_list = get_envelopes_list,
+ .sess_remove_message = NULL,
+
+ .sess_get_message = get_message,
+ .sess_get_message_by_uid = get_message_by_uid,
+};
+
+mailsession_driver * db_session_driver = &local_db_session_driver;
+
+static inline struct db_session_state_data * get_data(mailsession * session)
+{
+ return session->sess_data;
+}
+
+static int flags_store_process(mailsession * session)
+{
+ unsigned int i;
+ MMAPString * mmapstr;
+ int r;
+ int res;
+ struct mail_cache_db * maildb;
+ struct db_session_state_data * data;
+ struct mail_flags_store * flags_store;
+
+ data = get_data(session);
+
+ flags_store = data->db_flags_store;
+
+ if (carray_count(flags_store->fls_tab) == 0)
+ return MAIL_NO_ERROR;
+
+ mmapstr = mmap_string_new("");
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ r = mail_cache_db_open_lock(data->db_filename, &maildb);
+ if (r < 0) {
+ res = MAIL_ERROR_FILE;
+ goto free_mmapstr;
+ }
+
+ for(i = 0 ; i < carray_count(flags_store->fls_tab) ; i ++) {
+ mailmessage * msg;
+ char key[PATH_MAX];
+
+ msg = carray_get(flags_store->fls_tab, i);
+
+ snprintf(key, sizeof(key), "%lu-flags", (unsigned long) msg->msg_index);
+
+ r = generic_cache_flags_write(maildb, mmapstr,
+ key, msg->msg_flags);
+ }
+
+ mail_flags_store_clear(flags_store);
+
+ mail_cache_db_close_unlock(data->db_filename, maildb);
+ mmap_string_free(mmapstr);
+
+ return MAIL_NO_ERROR;
+
+ free_mmapstr:
+ mmap_string_free(mmapstr);
+ err:
+ return res;
+}
+
+static int db_get_next_validity(struct mail_cache_db * maildb,
+ uint32_t * p_validity)
+{
+ int r;
+ char key_value[PATH_MAX];
+ uint32_t validity;
+ void * serialized;
+ size_t serialized_len;
+ int res;
+ MMAPString * mmapstr;
+ size_t cur_token;
+
+ mmapstr = mmap_string_new_len(serialized, serialized_len);
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ snprintf(key_value, sizeof(key_value), "next-validity");
+
+ r = mail_cache_db_get(maildb, key_value, strlen(key_value),
+ &serialized, &serialized_len);
+
+ if (r >= 0) {
+ size_t cur_token;
+
+ cur_token = 0;
+ r = mailimf_cache_int_read(mmapstr, &cur_token, &validity);
+ if (r < 0)
+ validity = 0;
+ }
+ else {
+ validity = 0;
+ }
+
+ mmap_string_set_size(mmapstr, 0);
+ cur_token = 0;
+ r = mailimf_cache_int_write(mmapstr, &cur_token, validity + 1);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_mmapstr;
+ }
+
+ r = mail_cache_db_put(maildb, key_value, strlen(key_value),
+ mmapstr->str, mmapstr->len);
+ if (r < 0) {
+ res = MAIL_ERROR_FILE;
+ goto free_mmapstr;
+ }
+
+ mmap_string_free(mmapstr);
+
+ * p_validity = validity;
+
+ return MAIL_NO_ERROR;
+
+ free_mmapstr:
+ mmap_string_free(mmapstr);
+ err:
+ return res;
+}
+
+static int db_get_next_msg_number(struct mail_cache_db * maildb,
+ uint32_t * p_num)
+{
+ int r;
+ char key_value[PATH_MAX];
+ uint32_t num;
+ void * serialized;
+ size_t serialized_len;
+ int res;
+ MMAPString * mmapstr;
+ size_t cur_token;
+
+ mmapstr = mmap_string_new("");
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ snprintf(key_value, sizeof(key_value), "next-msg");
+
+ r = mail_cache_db_get(maildb, key_value, strlen(key_value),
+ &serialized, &serialized_len);
+
+ if (r >= 0) {
+ size_t cur_token;
+
+ if (mmap_string_append_len(mmapstr, serialized, serialized_len) == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ cur_token = 0;
+ r = mailimf_cache_int_read(mmapstr, &cur_token, &num);
+ if (r < 0)
+ num = 1;
+ }
+ else {
+ num = 1;
+ }
+
+ mmap_string_set_size(mmapstr, 0);
+ cur_token = 0;
+ r = mailimf_cache_int_write(mmapstr, &cur_token, num + 1);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_mmapstr;
+ }
+
+ r = mail_cache_db_put(maildb, key_value, strlen(key_value),
+ mmapstr->str, mmapstr->len);
+ if (r < 0) {
+ res = MAIL_ERROR_FILE;
+ goto free_mmapstr;
+ }
+
+ mmap_string_free(mmapstr);
+
+ * p_num = num;
+
+ return MAIL_NO_ERROR;
+
+ free_mmapstr:
+ mmap_string_free(mmapstr);
+ err:
+ return res;
+}
+
+static int db_set_message_list(struct mail_cache_db * maildb,
+ carray * msglist)
+{
+ MMAPString * mmapstr;
+ char key_value[PATH_MAX];
+ int r;
+ unsigned int i;
+ size_t cur_token;
+ int res;
+
+ mmapstr = mmap_string_new("");
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ cur_token = 0;
+ for(i = 0 ; i < carray_count(msglist) ; i ++) {
+ uint32_t * msg;
+
+ msg = carray_get(msglist, i);
+ r = mailimf_cache_int_write(mmapstr, &cur_token, * msg);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free_mmapstr;
+ }
+ }
+
+ snprintf(key_value, sizeof(key_value), "message-list");
+ r = mail_cache_db_put(maildb, key_value, strlen(key_value),
+ mmapstr->str, mmapstr->len);
+ if (r < 0) {
+ res = MAIL_ERROR_FILE;
+ goto err;
+ }
+
+ mmap_string_free(mmapstr);
+
+ return MAIL_NO_ERROR;
+
+ free_mmapstr:
+ mmap_string_free(mmapstr);
+ err:
+ return res;
+}
+
+static int db_get_message_list(struct mail_cache_db * maildb,
+ carray ** p_msglist)
+{
+ carray * msglist;
+ void * serialized;
+ size_t serialized_len;
+ int r;
+ char key_value[PATH_MAX];
+ int res;
+ unsigned int i;
+
+ msglist = carray_new(16);
+ if (msglist == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ snprintf(key_value, sizeof(key_value), "message-list");
+ r = mail_cache_db_get(maildb, key_value, strlen(key_value),
+ &serialized, &serialized_len);
+ if (r >= 0) {
+ MMAPString * mmapstr;
+ size_t cur_token;
+
+ /* collect message list */
+
+ mmapstr = mmap_string_new_len(serialized, serialized_len);
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_msglist;
+ }
+
+ cur_token = 0;
+ do {
+ uint32_t num;
+ uint32_t * msg;
+
+ r = mailimf_cache_int_read(mmapstr, &cur_token, &num);
+ if (r != MAIL_NO_ERROR)
+ break;
+
+ msg = malloc(sizeof(* msg));
+ if (msg == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ mmap_string_free(mmapstr);
+ goto free_msglist;
+ }
+ * msg = num;
+
+ r = carray_add(msglist, msg, NULL);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ free(msg);
+ mmap_string_free(mmapstr);
+ goto free_msglist;
+ }
+ } while (1);
+
+ mmap_string_free(mmapstr);
+ }
+
+ * p_msglist = msglist;
+
+ return MAIL_NO_ERROR;
+
+ free_msglist:
+ for(i = 0 ; i < carray_count(msglist) ; i ++) {
+ uint32_t * msg;
+
+ msg = carray_get(msglist, i);
+ free(msg);
+ }
+ carray_free(msglist);
+ err:
+ return res;
+}
+
+static int initialize(mailsession * session)
+{
+ struct db_session_state_data * data;
+
+ data = malloc(sizeof(* data));
+ if (data == NULL)
+ goto err;
+
+ data->db_filename[0] = '\0';
+
+ data->db_flags_store = mail_flags_store_new();
+ if (data->db_flags_store == NULL)
+ goto free;
+
+ session->sess_data = data;
+
+ return MAIL_NO_ERROR;
+
+ free:
+ free(data);
+ err:
+ return MAIL_ERROR_MEMORY;
+}
+
+static void uninitialize(mailsession * session)
+{
+ struct db_session_state_data * data;
+
+ data = get_data(session);
+
+ flags_store_process(session);
+
+ mail_flags_store_free(data->db_flags_store);
+
+ free(data);
+
+ session->sess_data = NULL;
+}
+
+static int connect_path(mailsession * session, char * path)
+{
+ struct db_session_state_data * data;
+
+ data = get_data(session);
+
+ strncpy(data->db_filename, path, sizeof(data->db_filename));
+
+ return MAIL_NO_ERROR;
+}
+
+static int logout(mailsession * session)
+{
+ return MAIL_NO_ERROR;
+}
+
+static int expunge_folder(mailsession * session)
+{
+ int r;
+ char key_value[PATH_MAX];
+ struct mail_cache_db * maildb;
+ carray * msglist;
+ unsigned int i;
+ struct db_session_state_data * data;
+ int res;
+ chash * msg_table;
+ MMAPString * mmapstr;
+
+ data = get_data(session);
+
+ flags_store_process(session);
+
+ r = mail_cache_db_open_lock(data->db_filename, &maildb);
+ if (r < 0) {
+ res = MAIL_ERROR_FILE;
+ goto err;
+ }
+
+ r = db_get_message_list(maildb, &msglist);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto close_db;
+ }
+
+ msg_table = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYKEY);
+ if (msg_table == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_msglist;
+ }
+
+ mmapstr = mmap_string_new("");
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_msgtable;
+ }
+
+ i = 0;
+ while (i < carray_count(msglist)) {
+ uint32_t num;
+ uint32_t * msg;
+ chashdatum key;
+ chashdatum value;
+ struct mail_flags * flags;
+ int deleted;
+
+ msg = carray_get(msglist, i);
+ num = * msg;
+
+ deleted = 0;
+ snprintf(key_value, sizeof(key_value), "%lu-flags",
+ (unsigned long) num);
+ r = generic_cache_flags_read(maildb, mmapstr, key_value, &flags);
+ if (r == MAIL_NO_ERROR) {
+ if ((flags->fl_flags & MAIL_FLAG_DELETED) != 0)
+ deleted = 1;
+ }
+
+ if (!deleted) {
+ snprintf(key_value, sizeof(key_value), "%lu", (unsigned long) num);
+ key.data = key_value;
+ key.len = strlen(key_value);
+ chash_set(msg_table, &key, &value, NULL);
+
+ snprintf(key_value, sizeof(key_value), "%lu-envelope",
+ (unsigned long) num);
+ key.data = key_value;
+ key.len = strlen(key_value);
+ chash_set(msg_table, &key, &value, NULL);
+
+ snprintf(key_value, sizeof(key_value), "%lu-flags",
+ (unsigned long) num);
+ key.data = key_value;
+ key.len = strlen(key_value);
+ chash_set(msg_table, &key, &value, NULL);
+
+ i ++;
+ }
+ else {
+ free(msg);
+ carray_delete(msglist, i);
+ }
+ }
+
+ mmap_string_free(mmapstr);
+
+ r = mail_cache_db_clean_up(maildb, msg_table);
+
+ chash_free(msg_table);
+
+ r = db_set_message_list(maildb, msglist);
+
+ for(i = 0 ; i < carray_count(msglist) ; i ++) {
+ uint32_t * msg;
+
+ msg = carray_get(msglist, i);
+ free(msg);
+ }
+ carray_free(msglist);
+
+ mail_cache_db_close_unlock(data->db_filename, maildb);
+
+ return MAIL_NO_ERROR;
+
+ free_msgtable:
+ chash_free(msg_table);
+ free_msglist:
+ for(i = 0 ; i < carray_count(msglist) ; i ++) {
+ uint32_t * msg;
+
+ msg = carray_get(msglist, i);
+ free(msg);
+ }
+ close_db:
+ mail_cache_db_close_unlock(data->db_filename, maildb);
+ err:
+ return res;
+}
+
+static int status_folder(mailsession * session, char * mb,
+ uint32_t * result_messages, uint32_t * result_recent,
+ uint32_t * result_unseen)
+{
+ struct mail_cache_db * maildb;
+ char key_value[PATH_MAX];
+ MMAPString * mmapstr;
+ uint32_t messages;
+ uint32_t recent;
+ uint32_t unseen;
+ struct db_session_state_data * data;
+ int r;
+ int res;
+ carray * msglist;
+ unsigned int i;
+
+ data = get_data(session);
+
+ flags_store_process(session);
+
+ r = mail_cache_db_open_lock(data->db_filename, &maildb);
+ if (r < 0) {
+ res = MAIL_ERROR_FILE;
+ goto err;
+ }
+
+ r = db_get_message_list(maildb, &msglist);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto close_db;
+ }
+
+ mmapstr = mmap_string_new("");
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ messages = 0;
+ recent = 0;
+ unseen = 0;
+ for(i = 0 ; i < carray_count(msglist) ; i ++) {
+ uint32_t num;
+ uint32_t * msg;
+ int r;
+ struct mail_flags * flags;
+
+ msg = carray_get(msglist, i);
+ num = * msg;
+ free(msg);
+ carray_set(msglist, i, NULL);
+
+ messages ++;
+
+ snprintf(key_value, sizeof(key_value), "%lu-flags", (unsigned long) num);
+
+ r = generic_cache_flags_read(maildb, mmapstr, key_value, &flags);
+ if (r == MAIL_NO_ERROR) {
+ if ((flags->fl_flags & MAIL_FLAG_NEW) != 0) {
+ recent ++;
+ }
+ if ((flags->fl_flags & MAIL_FLAG_SEEN) == 0) {
+ unseen ++;
+ }
+ mail_flags_free(flags);
+ }
+ }
+
+ mmap_string_free(mmapstr);
+
+ carray_free(msglist);
+
+ mail_cache_db_close_unlock(data->db_filename, maildb);
+
+ * result_messages = messages;
+ * result_unseen = unseen;
+ * result_recent = recent;
+
+ return MAIL_NO_ERROR;
+
+ free_list:
+ for(i = 0 ; i < carray_count(msglist) ; i ++) {
+ uint32_t * msg;
+
+ msg = carray_get(msglist, i);
+ if (msg != NULL)
+ free(msg);
+ }
+ carray_free(msglist);
+ close_db:
+ mail_cache_db_close_unlock(data->db_filename, maildb);
+ err:
+ return res;
+}
+
+static int recent_number(mailsession * session, char * mb,
+ uint32_t * result)
+{
+ uint32_t dummy_messages;
+ uint32_t dummy_unseen;
+
+ return status_folder(session, mb,
+ &dummy_messages, result, &dummy_unseen);
+}
+
+static int unseen_number(mailsession * session, char * mb,
+ uint32_t * result)
+{
+ uint32_t dummy_messages;
+ uint32_t dummy_recent;
+
+ return status_folder(session, mb,
+ &dummy_messages, &dummy_recent, result);
+}
+
+static int messages_number(mailsession * session, char * mb,
+ uint32_t * result)
+{
+ uint32_t dummy_unseen;
+ uint32_t dummy_recent;
+
+ return status_folder(session, mb,
+ result, &dummy_recent, &dummy_unseen);
+}
+
+static int append_message(mailsession * session,
+ char * message, size_t size)
+{
+ return append_message_flags(session, message, size, NULL);
+}
+
+static int append_message_flags(mailsession * session,
+ char * message, size_t size, struct mail_flags * flags)
+{
+ carray * msglist;
+ unsigned int i;
+ uint32_t * msg;
+ uint32_t num;
+ char key_value[PATH_MAX];
+ MMAPString * mmapstr;
+ struct mail_cache_db * maildb;
+ struct db_session_state_data * data;
+ size_t cur_token;
+ struct mailimf_fields * fields;
+ int r;
+ int res;
+
+ data = get_data(session);
+
+ r = mail_cache_db_open_lock(data->db_filename, &maildb);
+ if (r < 0) {
+ res = MAIL_ERROR_FILE;
+ goto err;
+ }
+
+ r = db_get_next_msg_number(maildb, &num);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = db_get_message_list(maildb, &msglist);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto close_db;
+ }
+
+ msg = malloc(sizeof(* msg));
+ if (msg == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_msglist;
+ }
+
+ * msg = num;
+
+ r = carray_add(msglist, msg, NULL);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ free(msg);
+ goto free_msglist;
+ }
+
+ r = db_set_message_list(maildb, msglist);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free_msglist;
+ }
+
+ /* free msglist */
+
+ for(i = 0 ; i < carray_count(msglist) ; i ++) {
+ uint32_t * msg;
+
+ msg = carray_get(msglist, i);
+ free(msg);
+ }
+ carray_free(msglist);
+
+ snprintf(key_value, sizeof(key_value), "%lu", (unsigned long) num);
+
+ r = mail_cache_db_put(maildb, key_value, strlen(key_value),
+ message, size);
+ if (r < 0) {
+ res = MAIL_ERROR_FILE;
+ goto close_db;
+ }
+
+ /* write envelope */
+
+ cur_token = 0;
+ r = mailimf_envelope_fields_parse(message, size, &cur_token, &fields);
+ if (r != MAILIMF_NO_ERROR) {
+ res = MAIL_ERROR_PARSE;
+ goto close_db;
+ }
+
+ mmapstr = mmap_string_new("");
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto close_db;
+ }
+
+ cur_token = 0;
+ r = mailimf_cache_fields_write(mmapstr, &cur_token, fields);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ mmap_string_free(mmapstr);
+ goto close_db;
+ }
+
+ snprintf(key_value, sizeof(key_value), "%lu-envelope", (unsigned long) num);
+
+ r = mail_cache_db_put(maildb, key_value, strlen(key_value),
+ mmapstr->str, mmapstr->len);
+
+ mmap_string_free(mmapstr);
+
+ mailimf_fields_free(fields);
+
+ /* write flags */
+
+ if (flags != NULL) {
+ snprintf(key_value, sizeof(key_value), "%lu-flags", (unsigned long) num);
+
+ mmapstr = mmap_string_new("");
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto close_db;
+ }
+
+ r = generic_cache_flags_write(maildb, mmapstr,
+ key_value, flags);
+
+ mmap_string_free(mmapstr);
+
+ if (r != MAIL_NO_ERROR) {
+ res = MAIL_ERROR_FILE;
+ goto close_db;
+ }
+ }
+
+ mail_cache_db_close_unlock(data->db_filename, maildb);
+
+ return MAIL_NO_ERROR;
+
+ free_msglist:
+ for(i = 0 ; i < carray_count(msglist) ; i ++) {
+ uint32_t * msg;
+
+ msg = carray_get(msglist, i);
+ free(msg);
+ }
+ carray_free(msglist);
+ close_db:
+ mail_cache_db_close_unlock(data->db_filename, maildb);
+ err:
+ return res;
+}
+
+static int get_messages_list(mailsession * session,
+ struct mailmessage_list ** result)
+{
+ int r;
+ char key[PATH_MAX];
+ struct mail_cache_db * maildb;
+ struct db_session_state_data * data;
+ int res;
+ carray * msglist;
+ unsigned int i;
+ carray * msgtab;
+ struct mailmessage_list * driver_msglist;
+
+ data = get_data(session);
+
+ r = mail_cache_db_open_lock(data->db_filename, &maildb);
+ if (r < 0) {
+ res = MAIL_ERROR_FILE;
+ goto err;
+ }
+
+ r = db_get_message_list(maildb, &msglist);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto close_db;
+ }
+
+ msgtab = carray_new(16);
+ if (msgtab == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto close_db;
+ }
+
+ for(i = 0 ; i < carray_count(msglist) ; i ++) {
+ uint32_t msg_num;
+ uint32_t * pmsg_num;
+ mailmessage * msg;
+ size_t size;
+
+ pmsg_num = carray_get(msglist, i);
+ msg_num = * pmsg_num;
+ free(pmsg_num);
+ carray_set(msglist, i, NULL);
+
+ snprintf(key, sizeof(key), "%lu", (unsigned long) msg_num);
+ r = mail_cache_db_get_size(maildb, key, strlen(key), &size);
+ if (r < 0) {
+ continue;
+ }
+
+ msg = mailmessage_new();
+ if (msg == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ r = mailmessage_init(msg, session, db_message_driver,
+ msg_num, size);
+ if (r != MAIL_NO_ERROR) {
+ mailmessage_free(msg);
+ res = r;
+ goto free_list;
+ }
+
+ r = carray_add(msgtab, msg, NULL);
+ if (r < 0) {
+ mailmessage_free(msg);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+ }
+ carray_free(msglist);
+
+ driver_msglist = mailmessage_list_new(msgtab);
+ if (driver_msglist == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ mail_cache_db_close_unlock(data->db_filename, maildb);
+
+ * result = driver_msglist;
+
+ return MAIL_NO_ERROR;
+
+ free_list:
+ for(i = 0 ; i < carray_count(msgtab) ; i ++) {
+ mailmessage * msg;
+
+ msg = carray_get(msgtab, i);
+ mailmessage_free(msg);
+ }
+ carray_free(msgtab);
+
+ for(i = 0 ; i < carray_count(msglist) ; i ++) {
+ uint32_t * msg;
+
+ msg = carray_get(msglist, i);
+ if (msg != NULL)
+ free(msg);
+ }
+ carray_free(msglist);
+ close_db:
+ mail_cache_db_close_unlock(data->db_filename, maildb);
+ err:
+ return res;
+}
+
+static int get_envelopes_list(mailsession * session,
+ struct mailmessage_list * env_list)
+{
+ unsigned int i;
+ char key[PATH_MAX];
+ int r;
+ struct mail_cache_db * maildb;
+ int res;
+ struct db_session_state_data * data;
+ MMAPString * mmapstr;
+
+ data = get_data(session);
+
+ flags_store_process(session);
+
+ r = mail_cache_db_open_lock(data->db_filename, &maildb);
+ if (r < 0) {
+ res = MAIL_ERROR_FILE;
+ goto err;
+ }
+
+ mmapstr = mmap_string_new("");
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto close_db;
+ }
+
+ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
+ mailmessage * msg;
+
+ msg = carray_get(env_list->msg_tab, i);
+ if (msg->msg_fields == NULL) {
+ snprintf(key, sizeof(key), "%lu-envelope",
+ (unsigned long) msg->msg_index);
+
+ r = generic_cache_fields_read(maildb, mmapstr,
+ key, &msg->msg_fields);
+ }
+
+ if (msg->msg_flags == NULL) {
+ snprintf(key, sizeof(key), "%lu-flags",
+ (unsigned long) msg->msg_index);
+
+ r = generic_cache_flags_read(maildb, mmapstr,
+ key, &msg->msg_flags);
+ }
+ }
+
+ mmap_string_free(mmapstr);
+
+ mail_cache_db_close_unlock(data->db_filename, maildb);
+
+ return MAIL_NO_ERROR;
+
+ close_db:
+ mail_cache_db_close_unlock(data->db_filename, maildb);
+ err:
+ return res;
+}
+
+static int check_folder(mailsession * session)
+{
+ flags_store_process(session);
+
+ return MAIL_NO_ERROR;
+}
+
+static int get_message(mailsession * session,
+ uint32_t num, mailmessage ** result)
+{
+ mailmessage * msg;
+ int r;
+ size_t size;
+ char key[PATH_MAX];
+ struct db_session_state_data * data;
+ struct mail_cache_db * maildb;
+ int res;
+
+ data = get_data(session);
+
+ r = mail_cache_db_open_lock(data->db_filename, &maildb);
+ if (r < 0) {
+ res = MAIL_ERROR_FILE;
+ goto err;
+ }
+
+ msg = mailmessage_new();
+ if (msg == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto close_db;
+ }
+
+ size = 0;
+ snprintf(key, sizeof(key), "%lu", (unsigned long) num);
+ r = mail_cache_db_get_size(maildb, key, strlen(key), &size);
+ /* ignore error */
+
+ r = mailmessage_init(msg, session, db_message_driver,
+ num, size);
+ if (r != MAIL_NO_ERROR) {
+ mailmessage_free(msg);
+ res = r;
+ goto close_db;
+ }
+
+ mail_cache_db_close_unlock(data->db_filename, maildb);
+
+ return MAIL_NO_ERROR;
+
+ close_db:
+ mail_cache_db_close_unlock(data->db_filename, maildb);
+ err:
+ return res;
+}
+
+static int get_message_by_uid(mailsession * session,
+ const char * uid, mailmessage ** result)
+{
+ uint32_t msg_num;
+
+ msg_num = strtoul(uid, NULL, 10);
+
+ return get_message(session, msg_num, result);
+}
diff --git a/libetpan/src/driver/implementation/db/dbdriver.h b/libetpan/src/driver/implementation/db/dbdriver.h
new file mode 100644
index 0000000..1c2a96d
--- a/dev/null
+++ b/libetpan/src/driver/implementation/db/dbdriver.h
@@ -0,0 +1,53 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef DBDRIVER_H
+
+#define DBDRIVER_H
+
+#include <libetpan/dbdriver_message.h>
+#include <libetpan/dbdriver_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern mailsession_driver * db_session_driver;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/implementation/db/dbdriver_message.c b/libetpan/src/driver/implementation/db/dbdriver_message.c
new file mode 100644
index 0000000..70e9dca
--- a/dev/null
+++ b/libetpan/src/driver/implementation/db/dbdriver_message.c
@@ -0,0 +1,308 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "dbdriver_message.h"
+#include "dbdriver.h"
+#include "mail_cache_db.h"
+
+#include "mailmessage_tools.h"
+#include "generic_cache.h"
+
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+
+static int fetch_envelope(mailmessage * msg_info,
+ struct mailimf_fields ** result);
+
+static int get_flags(mailmessage * msg_info,
+ struct mail_flags ** result);
+
+static int prefetch(mailmessage * msg_info);
+
+static void prefetch_free(struct generic_message_t * msg);
+
+static int initialize(mailmessage * msg_info);
+
+static void check(mailmessage * msg_info);
+
+static mailmessage_driver local_db_message_driver = {
+ .msg_name = "db",
+
+ .msg_initialize = initialize,
+ .msg_uninitialize = mailmessage_generic_uninitialize,
+
+ .msg_flush = mailmessage_generic_flush,
+ .msg_check = check,
+
+ .msg_fetch_result_free = mailmessage_generic_fetch_result_free,
+
+ .msg_fetch = mailmessage_generic_fetch,
+ .msg_fetch_header = mailmessage_generic_fetch_header,
+ .msg_fetch_body = mailmessage_generic_fetch_header,
+ .msg_fetch_size = NULL,
+ .msg_get_bodystructure = mailmessage_generic_get_bodystructure,
+ .msg_fetch_section = mailmessage_generic_fetch_section,
+ .msg_fetch_section_header = mailmessage_generic_fetch_section_header,
+ .msg_fetch_section_mime = mailmessage_generic_fetch_section_mime,
+ .msg_fetch_section_body = mailmessage_generic_fetch_section_body,
+ .msg_fetch_envelope = fetch_envelope,
+
+ .msg_get_flags = get_flags,
+};
+
+mailmessage_driver * db_message_driver = &local_db_message_driver;
+
+struct db_msg_data {
+ MMAPString * msg_content;
+};
+
+static inline struct db_session_state_data *
+get_session_data(mailmessage * msg)
+{
+ return msg->msg_session->sess_data;
+}
+
+static int prefetch(mailmessage * msg_info)
+{
+ struct generic_message_t * msg;
+ int res;
+ struct db_msg_data * data;
+ struct db_session_state_data * sess_data;
+ MMAPString * msg_content;
+ struct mail_cache_db * maildb;
+ int r;
+ char key[PATH_MAX];
+ void * msg_data;
+ size_t msg_data_len;
+
+ sess_data = get_session_data(msg_info);
+
+ r = mail_cache_db_open_lock(sess_data->db_filename, &maildb);
+ if (r < 0) {
+ res = MAIL_ERROR_FILE;
+ goto err;
+ }
+
+ snprintf(key, sizeof(key), "%lu", (unsigned long) msg_info->msg_index);
+ r = mail_cache_db_get(maildb, key, strlen(key), &msg_data, &msg_data_len);
+ if (r < 0) {
+ res = MAIL_ERROR_MSG_NOT_FOUND;
+ goto close_db;
+ }
+
+ msg_content = mmap_string_new_len(msg_data, msg_data_len);
+ if (msg_content == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto close_db;
+ }
+
+ data = malloc(sizeof(* data));
+ if (data == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_mmapstr;
+ }
+
+ data->msg_content = msg_content;
+
+ msg = msg_info->msg_data;
+
+ msg->msg_data = data;
+ msg->msg_message = msg_content->str;
+ msg->msg_length = msg_content->len;
+
+ mail_cache_db_close_unlock(sess_data->db_filename, maildb);
+
+ return MAIL_NO_ERROR;
+
+ free_mmapstr:
+ mmap_string_free(msg_content);
+ close_db:
+ mail_cache_db_close_unlock(sess_data->db_filename, maildb);
+ err:
+ return res;
+}
+
+static void prefetch_free(struct generic_message_t * msg)
+{
+ if (msg->msg_message != NULL) {
+ struct db_msg_data * data;
+
+ data = msg->msg_data;
+ mmap_string_free(data->msg_content);
+ data->msg_content = NULL;
+ free(data);
+ msg->msg_message = NULL;
+ }
+}
+
+static int initialize(mailmessage * msg_info)
+{
+ struct generic_message_t * msg;
+ int r;
+ char key[PATH_MAX];
+
+ snprintf(key, sizeof(key), "%lu", (unsigned long) msg_info->msg_index);
+ msg_info->msg_uid = strdup(key);
+ if (msg_info->msg_uid == NULL)
+ return MAIL_ERROR_MEMORY;
+
+ r = mailmessage_generic_initialize(msg_info);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ msg = msg_info->msg_data;
+ msg->msg_prefetch = prefetch;
+ msg->msg_prefetch_free = prefetch_free;
+
+ return MAIL_NO_ERROR;
+}
+
+static void check(mailmessage * msg_info)
+{
+ int r;
+
+ if (msg_info->msg_flags != NULL) {
+ r = mail_flags_store_set(get_session_data(msg_info)->db_flags_store,
+ msg_info);
+ /* ignore errors */
+ }
+}
+
+static int fetch_envelope(mailmessage * msg_info,
+ struct mailimf_fields ** result)
+{
+ char key[PATH_MAX];
+ int r;
+ struct db_session_state_data * sess_data;
+ struct mail_cache_db * maildb;
+ int res;
+ struct mailimf_fields * fields;
+ MMAPString * mmapstr;
+
+ sess_data = get_session_data(msg_info);
+
+ r = mail_cache_db_open_lock(sess_data->db_filename, &maildb);
+ if (r < 0) {
+ res = MAIL_ERROR_FILE;
+ goto err;
+ }
+
+ snprintf(key, sizeof(key), "%lu-envelope",
+ (unsigned long) msg_info->msg_index);
+
+ mmapstr = mmap_string_new("");
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto close_db;
+ }
+
+ r = generic_cache_fields_read(maildb, mmapstr,
+ key, &fields);
+
+ mmap_string_free(mmapstr);
+
+ if (r != MAIL_NO_ERROR) {
+ res = MAIL_ERROR_MSG_NOT_FOUND;
+ goto close_db;
+ }
+
+ mail_cache_db_close_unlock(sess_data->db_filename, maildb);
+
+ * result = fields;
+
+ return MAIL_NO_ERROR;
+
+ close_db:
+ mail_cache_db_close_unlock(sess_data->db_filename, maildb);
+ err:
+ return res;
+}
+
+static int get_flags(mailmessage * msg_info,
+ struct mail_flags ** result)
+{
+ char key[PATH_MAX];
+ int r;
+ struct db_session_state_data * sess_data;
+ struct mail_cache_db * maildb;
+ int res;
+ MMAPString * mmapstr;
+
+ sess_data = get_session_data(msg_info);
+
+ r = mail_cache_db_open_lock(sess_data->db_filename, &maildb);
+ if (r < 0) {
+ res = MAIL_ERROR_FILE;
+ goto err;
+ }
+
+ snprintf(key, sizeof(key), "%lu-flags", (unsigned long) msg_info->msg_index);
+
+ mmapstr = mmap_string_new("");
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto close_db;
+ }
+
+ r = generic_cache_flags_read(maildb, mmapstr,
+ key, &msg_info->msg_flags);
+
+ mmap_string_free(mmapstr);
+
+ if (r != MAIL_NO_ERROR) {
+ msg_info->msg_flags = mail_flags_new_empty();
+ if (msg_info->msg_flags == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto close_db;
+ }
+ }
+
+ mail_cache_db_close_unlock(sess_data->db_filename, maildb);
+
+ * result = msg_info->msg_flags;
+
+ return MAIL_NO_ERROR;
+
+ close_db:
+ mail_cache_db_close_unlock(sess_data->db_filename, maildb);
+ err:
+ return res;
+}
+
diff --git a/libetpan/src/driver/implementation/db/dbdriver_message.h b/libetpan/src/driver/implementation/db/dbdriver_message.h
new file mode 100644
index 0000000..f634775
--- a/dev/null
+++ b/libetpan/src/driver/implementation/db/dbdriver_message.h
@@ -0,0 +1,52 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef DBDRIVER_MESSAGE_H
+
+#define DBDRIVER_MESSAGE_H
+
+#include <libetpan/dbdriver_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern mailmessage_driver * db_message_driver;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/implementation/db/dbdriver_types.h b/libetpan/src/driver/implementation/db/dbdriver_types.h
new file mode 100644
index 0000000..052e3db
--- a/dev/null
+++ b/libetpan/src/driver/implementation/db/dbdriver_types.h
@@ -0,0 +1,71 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef DBDRIVER_TYPES_H
+
+#define DBDRIVER_TYPES_H
+
+#include <libetpan/libetpan-config.h>
+
+#include <libetpan/maildriver_types.h>
+#include <libetpan/generic_cache_types.h>
+#include <libetpan/mailstorage_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct db_session_state_data {
+ char db_filename[PATH_MAX];
+ struct mail_flags_store * db_flags_store;
+};
+
+/* db storage */
+
+/*
+ db_mailstorage is the state data specific to the db storage.
+
+ - pathname is the path of the db storage.
+*/
+
+struct db_mailstorage {
+ char * db_pathname;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/implementation/db/dbstorage.c b/libetpan/src/driver/implementation/db/dbstorage.c
new file mode 100644
index 0000000..c4be63c
--- a/dev/null
+++ b/libetpan/src/driver/implementation/db/dbstorage.c
@@ -0,0 +1,144 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "dbstorage.h"
+#include "mailstorage.h"
+
+#include "mail.h"
+#include "mailmessage.h"
+#include "dbdriver.h"
+#include "maildriver.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/* db storage */
+
+static int db_mailstorage_connect(struct mailstorage * storage);
+static int
+db_mailstorage_get_folder_session(struct mailstorage * storage,
+ char * pathname, mailsession ** result);
+static void db_mailstorage_uninitialize(struct mailstorage * storage);
+
+static mailstorage_driver db_mailstorage_driver = {
+ .sto_name = "db",
+ .sto_connect = db_mailstorage_connect,
+ .sto_get_folder_session = db_mailstorage_get_folder_session,
+ .sto_uninitialize = db_mailstorage_uninitialize,
+};
+
+int db_mailstorage_init(struct mailstorage * storage,
+ char * db_pathname)
+{
+ struct db_mailstorage * db_storage;
+
+ db_storage = malloc(sizeof(* db_storage));
+ if (db_storage == NULL)
+ goto err;
+
+ db_storage->db_pathname = strdup(db_pathname);
+ if (db_storage->db_pathname == NULL)
+ goto free;
+
+ storage->sto_data = db_storage;
+ storage->sto_driver = &db_mailstorage_driver;
+
+ return MAIL_NO_ERROR;
+
+ free:
+ free(db_storage);
+ err:
+ return MAIL_ERROR_MEMORY;
+}
+
+static void db_mailstorage_uninitialize(struct mailstorage * storage)
+{
+ struct db_mailstorage * db_storage;
+
+ db_storage = storage->sto_data;
+ free(db_storage->db_pathname);
+ free(db_storage);
+
+ storage->sto_data = NULL;
+}
+
+static int db_mailstorage_connect(struct mailstorage * storage)
+{
+ struct db_mailstorage * db_storage;
+ mailsession_driver * driver;
+ int r;
+ int res;
+ mailsession * session;
+
+ db_storage = storage->sto_data;
+
+ driver = db_session_driver;
+
+ session = mailsession_new(driver);
+ if (session == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ r = mailsession_connect_path(session, db_storage->db_pathname);
+ switch (r) {
+ case MAIL_NO_ERROR_NON_AUTHENTICATED:
+ case MAIL_NO_ERROR_AUTHENTICATED:
+ case MAIL_NO_ERROR:
+ break;
+ default:
+ res = r;
+ goto free;
+ }
+
+ storage->sto_session = session;
+
+ return MAIL_NO_ERROR;
+
+ free:
+ mailsession_free(session);
+ err:
+ return res;
+}
+
+static int
+db_mailstorage_get_folder_session(struct mailstorage * storage,
+ char * pathname, mailsession ** result)
+{
+ * result = storage->sto_session;
+
+ return MAIL_NO_ERROR;
+}
+
diff --git a/libetpan/src/driver/implementation/db/dbstorage.h b/libetpan/src/driver/implementation/db/dbstorage.h
new file mode 100644
index 0000000..5fa9659
--- a/dev/null
+++ b/libetpan/src/driver/implementation/db/dbstorage.h
@@ -0,0 +1,61 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef DBSTORAGE_H
+
+#define DBSTORAGE_H
+
+#include <libetpan/dbdriver_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ db_mailstorage_init is the constructor for a DB storage.
+
+ @param storage this is the storage to initialize.
+
+ @param pathname is the directory that contains the mailbox.
+*/
+
+int db_mailstorage_init(struct mailstorage * storage,
+ char * db_pathname);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/implementation/hotmail/hotmailstorage.c b/libetpan/src/driver/implementation/hotmail/hotmailstorage.c
new file mode 100644
index 0000000..0d1503b
--- a/dev/null
+++ b/libetpan/src/driver/implementation/hotmail/hotmailstorage.c
@@ -0,0 +1,62 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "hotmailstorage.h"
+
+#include "pop3storage.h"
+#include "pop3driver_types.h"
+
+/*
+ hotway is a gateway from hotmail to POP3
+
+ http://hotwayd.sourceforge.net/
+*/
+
+static char hotway_command[512] = "/usr/bin/hotwayd";
+
+int hotmail_mailstorage_init(struct mailstorage * storage,
+ char * hotmail_login, char * hotmail_password,
+ int hotmail_cached, char * hotmail_cache_directory,
+ char * hotmail_flags_directory)
+{
+ return pop3_mailstorage_init(storage,
+ "hotmail.dummy", 0,
+ hotway_command,
+ CONNECTION_TYPE_COMMAND, POP3_AUTH_TYPE_PLAIN,
+ hotmail_login, hotmail_password,
+ hotmail_cached, hotmail_cache_directory,
+ hotmail_flags_directory);
+}
+
diff --git a/libetpan/src/driver/implementation/hotmail/hotmailstorage.h b/libetpan/src/driver/implementation/hotmail/hotmailstorage.h
new file mode 100644
index 0000000..05d6385
--- a/dev/null
+++ b/libetpan/src/driver/implementation/hotmail/hotmailstorage.h
@@ -0,0 +1,56 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef HOTMAILSTORAGE_H
+
+#define HOTMAILSTORAGE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mailstorage_types.h"
+
+int hotmail_mailstorage_init(struct mailstorage * storage,
+ char * hotmail_login, char * hotmail_password,
+ int hotmail_cached, char * hotmail_cache_directory,
+ char * hotmail_flags_directory);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/libetpan/src/driver/implementation/imap/imapdriver.c b/libetpan/src/driver/implementation/imap/imapdriver.c
new file mode 100644
index 0000000..815e077
--- a/dev/null
+++ b/libetpan/src/driver/implementation/imap/imapdriver.c
@@ -0,0 +1,1226 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "imapdriver.h"
+
+#include "mail.h"
+#include "imapdriver_tools.h"
+#include "mailmessage.h"
+#include "imapdriver_message.h"
+#include "imapdriver_types.h"
+#include "maildriver.h"
+#include "maildriver_tools.h"
+#include "generic_cache.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+static int imapdriver_initialize(mailsession * session);
+
+static void imapdriver_uninitialize(mailsession * session);
+
+static int imapdriver_connect_stream(mailsession * session, mailstream * s);
+
+static int imapdriver_starttls(mailsession * session);
+
+static int imapdriver_login(mailsession * session,
+ char * userid, char * password);
+
+static int imapdriver_logout(mailsession * session);
+
+static int imapdriver_noop(mailsession * session);
+
+static int imapdriver_build_folder_name(mailsession * session, char * mb,
+ char * name, char ** result);
+
+static int imapdriver_create_folder(mailsession * session, char * mb);
+
+static int imapdriver_delete_folder(mailsession * session, char * mb);
+
+static int imapdriver_rename_folder(mailsession * session, char * mb,
+ char * new_name);
+
+static int imapdriver_check_folder(mailsession * session);
+
+static int imapdriver_examine_folder(mailsession * session, char * mb);
+
+static int imapdriver_select_folder(mailsession * session, char * mb);
+static int imapdriver_expunge_folder(mailsession * session);
+
+static int imapdriver_status_folder(mailsession * session, char * mb,
+ uint32_t * result_messages, uint32_t * result_recent,
+ uint32_t * result_unseen);
+
+static int imapdriver_messages_number(mailsession * session, char * mb,
+ uint32_t * result);
+
+static int imapdriver_recent_number(mailsession * session, char * mb,
+ uint32_t * result);
+
+static int imapdriver_unseen_number(mailsession * session, char * mb,
+ uint32_t * result);
+
+static int imapdriver_list_folders(mailsession * session, char * mb,
+ struct mail_list ** result);
+static int imapdriver_lsub_folders(mailsession * session, char * mb,
+ struct mail_list ** result);
+static int imapdriver_subscribe_folder(mailsession * session, char * mb);
+static int imapdriver_unsubscribe_folder(mailsession * session, char * mb);
+static int imapdriver_append_message(mailsession * session,
+ char * message, size_t size);
+static int imapdriver_append_message_flags(mailsession * session,
+ char * message, size_t size, struct mail_flags * flags);
+static int imapdriver_copy_message(mailsession * session,
+ uint32_t num, char * mb);
+
+static int imapdriver_get_messages_list(mailsession * session,
+ struct mailmessage_list ** result);
+
+static int
+imapdriver_get_envelopes_list(mailsession * session,
+ struct mailmessage_list * env_list);
+
+
+#if 0
+static int imapdriver_search_messages(mailsession * session, char * charset,
+ struct mail_search_key * key,
+ struct mail_search_result ** result);
+#endif
+
+static int imapdriver_get_message(mailsession * session,
+ uint32_t num, mailmessage ** result);
+
+static int imapdriver_get_message_by_uid(mailsession * session,
+ const char * uid,
+ mailmessage ** result);
+
+static mailsession_driver local_imap_session_driver = {
+ .sess_name = "imap",
+
+ .sess_initialize = imapdriver_initialize,
+ .sess_uninitialize = imapdriver_uninitialize,
+
+ .sess_parameters = NULL,
+
+ .sess_connect_stream = imapdriver_connect_stream,
+ .sess_connect_path = NULL,
+ .sess_starttls = imapdriver_starttls,
+ .sess_login = imapdriver_login,
+ .sess_logout = imapdriver_logout,
+ .sess_noop = imapdriver_noop,
+
+ .sess_build_folder_name = imapdriver_build_folder_name,
+ .sess_create_folder = imapdriver_create_folder,
+ .sess_delete_folder = imapdriver_delete_folder,
+ .sess_rename_folder = imapdriver_rename_folder,
+ .sess_check_folder = imapdriver_check_folder,
+ .sess_examine_folder = imapdriver_examine_folder,
+ .sess_select_folder = imapdriver_select_folder,
+ .sess_expunge_folder = imapdriver_expunge_folder,
+ .sess_status_folder = imapdriver_status_folder,
+ .sess_messages_number = imapdriver_messages_number,
+ .sess_recent_number = imapdriver_recent_number,
+ .sess_unseen_number = imapdriver_unseen_number,
+ .sess_list_folders = imapdriver_list_folders,
+ .sess_lsub_folders = imapdriver_lsub_folders,
+ .sess_subscribe_folder = imapdriver_subscribe_folder,
+ .sess_unsubscribe_folder = imapdriver_unsubscribe_folder,
+
+ .sess_append_message = imapdriver_append_message,
+ .sess_append_message_flags = imapdriver_append_message_flags,
+ .sess_copy_message = imapdriver_copy_message,
+ .sess_move_message = NULL,
+
+ .sess_get_messages_list = imapdriver_get_messages_list,
+ .sess_get_envelopes_list = imapdriver_get_envelopes_list,
+ .sess_remove_message = NULL,
+#if 0
+ .sess_search_messages = imapdriver_search_messages,
+#endif
+
+ .sess_get_message = imapdriver_get_message,
+ .sess_get_message_by_uid = imapdriver_get_message_by_uid,
+};
+
+mailsession_driver * imap_session_driver = &local_imap_session_driver;
+
+static inline struct imap_session_state_data * get_data(mailsession * session)
+{
+ return session->sess_data;
+}
+
+static mailimap * get_imap_session(mailsession * session)
+{
+ return get_data(session)->imap_session;
+}
+
+static int imapdriver_initialize(mailsession * session)
+{
+ struct imap_session_state_data * data;
+ mailimap * imap;
+ struct mail_flags_store * flags_store;
+
+ imap = mailimap_new(0, NULL);
+ if (imap == NULL)
+ goto err;
+
+ flags_store = mail_flags_store_new();
+ if (flags_store == NULL)
+ goto free_session;
+
+ data = malloc(sizeof(* data));
+ if (data == NULL)
+ goto free_flags_store;
+
+ data->imap_mailbox = NULL;
+ data->imap_session = imap;
+ data->imap_flags_store = flags_store;
+
+ session->sess_data = data;
+
+ return MAIL_NO_ERROR;
+
+ free_flags_store:
+ mail_flags_store_free(flags_store);
+ free_session:
+ mailimap_free(imap);
+ err:
+ return MAIL_ERROR_MEMORY;
+}
+
+static void imap_flags_store_process(mailimap * imap,
+ struct mail_flags_store * flags_store)
+{
+ unsigned int i;
+ int r;
+ mailmessage * first;
+ mailmessage * last;
+
+ mail_flags_store_sort(flags_store);
+
+ if (carray_count(flags_store->fls_tab) == 0)
+ return;
+
+ first = carray_get(flags_store->fls_tab, 0);
+ last = first;
+
+ for(i = 1 ; i < carray_count(flags_store->fls_tab) ; i ++) {
+ mailmessage * msg;
+
+ msg = carray_get(flags_store->fls_tab, i);
+
+ if (last->msg_index + 1 == msg->msg_index) {
+ r = mail_flags_compare(first->msg_flags, msg->msg_flags);
+ if (r == 0) {
+ last = msg;
+ continue;
+ }
+ }
+
+ r = imap_store_flags(imap, first->msg_index,
+ last->msg_index, first->msg_flags);
+
+ first = msg;
+ last = msg;
+ }
+
+ r = imap_store_flags(imap, first->msg_index, last->msg_index,
+ first->msg_flags);
+
+ mail_flags_store_clear(flags_store);
+}
+
+static void imapdriver_uninitialize(mailsession * session)
+{
+ struct imap_session_state_data * data;
+
+ data = get_data(session);
+
+ imap_flags_store_process(data->imap_session,
+ data->imap_flags_store);
+ mail_flags_store_free(data->imap_flags_store);
+
+ mailimap_free(data->imap_session);
+ if (data->imap_mailbox != NULL)
+ free(data->imap_mailbox);
+ free(data);
+
+ session->sess_data = NULL;
+}
+
+static int imapdriver_connect_stream(mailsession * session, mailstream * s)
+{
+ int r;
+
+ r = mailimap_connect(get_imap_session(session), s);
+
+ return imap_error_to_mail_error(r);
+}
+
+static int imapdriver_login(mailsession * session,
+ char * userid, char * password)
+{
+ int r;
+
+ r = mailimap_login(get_imap_session(session), userid, password);
+
+ return imap_error_to_mail_error(r);
+}
+
+static int imapdriver_logout(mailsession * session)
+{
+ int r;
+
+ imap_flags_store_process(get_imap_session(session),
+ get_data(session)->imap_flags_store);
+
+ r = mailimap_logout(get_imap_session(session));
+
+ return imap_error_to_mail_error(r);
+}
+
+static int imapdriver_noop(mailsession * session)
+{
+ int r;
+
+ r = mailimap_noop(get_imap_session(session));
+
+ return imap_error_to_mail_error(r);
+}
+
+static int imapdriver_build_folder_name(mailsession * session, char * mb,
+ char * name, char ** result)
+{
+ char delimiter[2] = "X";
+ char * folder_name;
+ mailimap * imap;
+ struct mailimap_mailbox_list * mb_list;
+ int r;
+ clist * imap_list;
+
+ imap = get_imap_session(session);
+
+ r = mailimap_list(imap, mb, "", &imap_list);
+ if (r != MAILIMAP_NO_ERROR)
+ return r;
+
+ if (clist_begin(imap_list) == NULL)
+ return MAIL_ERROR_LIST;
+
+ mb_list = clist_begin(imap_list)->data;
+ delimiter[0] = mb_list->mb_delimiter;
+
+ folder_name = malloc(strlen(mb) + strlen(delimiter) + strlen(name) + 1);
+ if (folder_name == NULL)
+ return MAIL_ERROR_MEMORY;
+
+ strcpy(folder_name, mb);
+ strcat(folder_name, delimiter);
+ strcat(folder_name, name);
+
+ * result = folder_name;
+
+ return MAIL_NO_ERROR;
+}
+
+/* folders operations */
+
+static int imapdriver_create_folder(mailsession * session, char * mb)
+{
+ int r;
+
+ r = mailimap_create(get_imap_session(session), mb);
+
+ return imap_error_to_mail_error(r);
+}
+
+static int imapdriver_delete_folder(mailsession * session, char * mb)
+{
+ int r;
+
+ r = mailimap_delete(get_imap_session(session), mb);
+
+ return imap_error_to_mail_error(r);
+}
+
+static int imapdriver_rename_folder(mailsession * session, char * mb,
+ char * new_name)
+{
+ int r;
+
+ r = mailimap_rename(get_imap_session(session), mb, new_name);
+
+ return imap_error_to_mail_error(r);
+}
+
+static int imapdriver_check_folder(mailsession * session)
+{
+ int r;
+
+ imap_flags_store_process(get_imap_session(session),
+ get_data(session)->imap_flags_store);
+
+ r = mailimap_check(get_imap_session(session));
+
+ return imap_error_to_mail_error(r);
+}
+
+static int imapdriver_examine_folder(mailsession * session, char * mb)
+{
+ int r;
+
+ r = mailimap_examine(get_imap_session(session), mb);
+
+ return imap_error_to_mail_error(r);
+}
+
+static int imapdriver_select_folder(mailsession * session, char * mb)
+{
+ int r;
+ char * new_mb;
+ char * old_mb;
+
+ old_mb = get_data(session)->imap_mailbox;
+ if (old_mb != NULL)
+ if (strcmp(mb, old_mb) == 0)
+ return MAIL_NO_ERROR;
+
+ imap_flags_store_process(get_imap_session(session),
+ get_data(session)->imap_flags_store);
+
+ r = mailimap_select(get_imap_session(session), mb);
+
+ switch (r) {
+ case MAILIMAP_NO_ERROR:
+ new_mb = strdup(mb);
+ if (new_mb == NULL) {
+ if (old_mb != NULL)
+ free(old_mb);
+ get_data(session)->imap_mailbox = NULL;
+ return MAIL_ERROR_MEMORY;
+ }
+
+ get_data(session)->imap_mailbox = new_mb;
+
+ return MAIL_NO_ERROR;
+ default:
+ return imap_error_to_mail_error(r);
+ }
+}
+
+static int imapdriver_expunge_folder(mailsession * session)
+{
+ int r;
+
+ imap_flags_store_process(get_imap_session(session),
+ get_data(session)->imap_flags_store);
+
+ r = mailimap_expunge(get_imap_session(session));
+
+ return imap_error_to_mail_error(r);
+}
+
+static int status_selected_folder(mailsession * session, char * mb,
+ uint32_t * result_messages, uint32_t * result_recent,
+ uint32_t * result_unseen)
+{
+ int r;
+ int res;
+ mailimap * imap;
+ uint32_t exists;
+ uint32_t unseen;
+ uint32_t recent;
+ struct mailimap_search_key * search_key;
+ clist * search_result;
+
+ imap = get_imap_session(session);
+
+ exists = imap->imap_selection_info->sel_exists;
+ recent = imap->imap_selection_info->sel_recent;
+
+ search_key = mailimap_search_key_new(MAILIMAP_SEARCH_KEY_UNSEEN,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, 0,
+ NULL, NULL, NULL, NULL, NULL,
+ NULL, 0, NULL, NULL, NULL);
+ if (search_key == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ /* default : use the RECENT count if search fails */
+ unseen = recent;
+ r = mailimap_search(imap, NULL, search_key, &search_result);
+ mailimap_search_key_free(search_key);
+ if (r == MAILIMAP_NO_ERROR) {
+ /* if this succeed, we use the real count */
+ unseen = clist_count(search_result);
+ mailimap_mailbox_data_search_free(search_result);
+ }
+
+ * result_messages = exists;
+ * result_unseen = unseen;
+ * result_recent = recent;
+
+ return MAIL_NO_ERROR;
+
+ err:
+ return res;
+}
+
+static int status_unselected_folder(mailsession * session, char * mb,
+ uint32_t * result_messages, uint32_t * result_recent,
+ uint32_t * result_unseen)
+{
+ struct mailimap_status_att_list * att_list;
+ struct mailimap_mailbox_data_status * status;
+ int r;
+ int res;
+ clistiter * cur;
+ mailimap * imap;
+
+ imap = get_imap_session(session);
+
+ att_list = mailimap_status_att_list_new_empty();
+ if (att_list == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ r = mailimap_status_att_list_add(att_list, MAILIMAP_STATUS_ATT_MESSAGES);
+ switch (r) {
+ case MAILIMAP_NO_ERROR:
+ break;
+ default:
+ res = MAIL_ERROR_MEMORY;
+ goto free;
+ }
+
+ r = mailimap_status_att_list_add(att_list, MAILIMAP_STATUS_ATT_RECENT);
+ switch (r) {
+ case MAILIMAP_NO_ERROR:
+ break;
+ default:
+ res = MAIL_ERROR_MEMORY;
+ goto free;
+ }
+
+ r = mailimap_status_att_list_add(att_list, MAILIMAP_STATUS_ATT_UNSEEN);
+ switch (r) {
+ case MAILIMAP_NO_ERROR:
+ break;
+ default:
+ res = MAIL_ERROR_MEMORY;
+ goto free;
+ }
+
+ r = mailimap_status(imap, mb, att_list, &status);
+
+ switch (r) {
+ case MAILIMAP_NO_ERROR:
+ break;
+ default:
+ res = imap_error_to_mail_error(r);
+ goto free;
+ }
+
+ * result_messages = 0;
+ * result_recent = 0;
+ * result_unseen = 0;
+
+ for (cur = clist_begin(status->st_info_list);
+ cur != NULL ; cur = clist_next(cur)) {
+ struct mailimap_status_info * status_info;
+
+ status_info = clist_content(cur);
+ switch (status_info->st_att) {
+ case MAILIMAP_STATUS_ATT_MESSAGES:
+ * result_messages = status_info->st_value;
+ break;
+ case MAILIMAP_STATUS_ATT_RECENT:
+ * result_recent = status_info->st_value;
+ break;
+ case MAILIMAP_STATUS_ATT_UNSEEN:
+ * result_unseen = status_info->st_value;
+ break;
+ }
+ }
+
+ mailimap_mailbox_data_status_free(status);
+ mailimap_status_att_list_free(att_list);
+
+ return MAIL_NO_ERROR;
+
+ free:
+ mailimap_status_att_list_free(att_list);
+ err:
+ return res;
+}
+
+static int imapdriver_status_folder(mailsession * session, char * mb,
+ uint32_t * result_messages, uint32_t * result_recent,
+ uint32_t * result_unseen)
+{
+ int res;
+ int current_folder;
+ char * current_mb;
+
+ if (mb == NULL) {
+ mb = get_data(session)->imap_mailbox;
+ if (mb == NULL) {
+ res = MAIL_ERROR_BAD_STATE;
+ goto err;
+ }
+ }
+
+ current_mb = get_data(session)->imap_mailbox;
+ if (strcmp(mb, current_mb) == 0)
+ current_folder = 1;
+ else
+ current_folder = 0;
+
+ if (current_folder)
+ return status_selected_folder(session, mb, result_messages,
+ result_recent, result_unseen);
+ else
+ return status_unselected_folder(session, mb, result_messages,
+ result_recent, result_unseen);
+
+ err:
+ return res;
+}
+
+/* TODO : more efficient functions */
+
+static int imapdriver_messages_number(mailsession * session, char * mb,
+ uint32_t * result)
+{
+ uint32_t messages;
+ uint32_t recent;
+ uint32_t unseen;
+ int r;
+
+ r = imapdriver_status_folder(session, mb, &messages, &recent, &unseen);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ * result = messages;
+
+ return MAIL_NO_ERROR;
+}
+
+static int imapdriver_recent_number(mailsession * session, char * mb,
+ uint32_t * result)
+{
+ uint32_t messages;
+ uint32_t recent;
+ uint32_t unseen;
+ int r;
+
+ r = imapdriver_status_folder(session, mb, &messages, &recent, &unseen);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ * result = recent;
+
+ return MAIL_NO_ERROR;
+}
+
+static int imapdriver_unseen_number(mailsession * session, char * mb,
+ uint32_t * result)
+{
+ uint32_t messages;
+ uint32_t recent;
+ uint32_t unseen;
+ int r;
+
+ r = imapdriver_status_folder(session, mb, &messages, &recent, &unseen);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ * result = unseen;
+
+ return MAIL_NO_ERROR;
+}
+
+enum {
+ IMAP_LIST, IMAP_LSUB
+};
+
+static int imapdriver_list_lsub_folders(mailsession * session, int type,
+ char * mb,
+ struct mail_list ** result)
+{
+ clist * imap_list;
+ struct mail_list * resp;
+ int r;
+ int res;
+
+ switch (type) {
+ case IMAP_LIST:
+ r = mailimap_list(get_imap_session(session), mb,
+ "*", &imap_list);
+ break;
+ case IMAP_LSUB:
+ r = mailimap_lsub(get_imap_session(session), mb,
+ "*", &imap_list);
+ break;
+ default:
+ res = MAIL_ERROR_LIST;
+ goto err;
+ }
+
+ switch (r) {
+ case MAILIMAP_NO_ERROR:
+ break;
+ default:
+ res = imap_error_to_mail_error(r);
+ goto err;
+ }
+
+ r = imap_list_to_list(imap_list, &resp);
+ if (r != MAIL_NO_ERROR) {
+ mailimap_list_result_free(imap_list);
+ res = r;
+ goto err;
+ }
+
+ mailimap_list_result_free(imap_list);
+
+ * result = resp;
+
+ return MAIL_NO_ERROR;
+
+ err:
+ return res;
+}
+
+static int imapdriver_list_folders(mailsession * session, char * mb,
+ struct mail_list ** result)
+{
+ return imapdriver_list_lsub_folders(session, IMAP_LIST, mb,
+ result);
+}
+
+static int imapdriver_lsub_folders(mailsession * session, char * mb,
+ struct mail_list ** result)
+{
+ return imapdriver_list_lsub_folders(session, IMAP_LSUB, mb,
+ result);
+}
+
+static int imapdriver_subscribe_folder(mailsession * session, char * mb)
+{
+ int r;
+
+ r = mailimap_subscribe(get_imap_session(session), mb);
+
+ return imap_error_to_mail_error(r);
+}
+
+static int imapdriver_unsubscribe_folder(mailsession * session, char * mb)
+{
+ int r;
+
+ r = mailimap_unsubscribe(get_imap_session(session), mb);
+
+ return imap_error_to_mail_error(r);
+}
+
+/* messages operations */
+
+static int imapdriver_append_message(mailsession * session,
+ char * message, size_t size)
+{
+ int r;
+
+ r = mailimap_append_simple(get_imap_session(session),
+ get_data(session)->imap_mailbox,
+ message, size);
+
+ return imap_error_to_mail_error(r);
+}
+
+static int imapdriver_append_message_flags(mailsession * session,
+ char * message, size_t size, struct mail_flags * flags)
+{
+ struct mailimap_flag_list * flag_list;
+ int r;
+
+ if (flags != NULL) {
+ r = imap_flags_to_imap_flags(flags, &flag_list);
+ if (r != MAIL_NO_ERROR)
+ return r;
+ }
+ else {
+ flag_list = NULL;
+ }
+
+ r = mailimap_append(get_imap_session(session),
+ get_data(session)->imap_mailbox,
+ flag_list, NULL, message, size);
+
+ if (flag_list != NULL)
+ mailimap_flag_list_free(flag_list);
+
+ return imap_error_to_mail_error(r);
+}
+
+static int imapdriver_copy_message(mailsession * session,
+ uint32_t num, char * mb)
+{
+ int r;
+ struct mailimap_set * set;
+ int res;
+
+ set = mailimap_set_new_single(num);
+ if (set == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ r = mailimap_uid_copy(get_imap_session(session), set, mb);
+
+ mailimap_set_free(set);
+
+ return imap_error_to_mail_error(r);
+
+ err:
+ return res;
+}
+
+static int imapdriver_get_messages_list(mailsession * session,
+ struct mailmessage_list ** result)
+{
+ return imap_get_messages_list(get_imap_session(session),
+ session, imap_message_driver, 1,
+ result);
+}
+
+
+
+#define IMAP_SET_MAX_COUNT 100
+
+static int
+imapdriver_get_envelopes_list(mailsession * session,
+ struct mailmessage_list * env_list)
+{
+ struct mailimap_set * set;
+ struct mailimap_fetch_att * fetch_att;
+ struct mailimap_fetch_type * fetch_type;
+ int res;
+ clist * fetch_result;
+ int r;
+ uint32_t exists;
+ clist * msg_list;
+ clistiter * set_iter;
+
+ if (get_imap_session(session)->imap_selection_info == NULL) {
+ res = MAIL_ERROR_BAD_STATE;
+ goto err;
+ }
+
+ imap_flags_store_process(get_imap_session(session),
+ get_data(session)->imap_flags_store);
+
+ exists = get_imap_session(session)->imap_selection_info->sel_exists;
+
+ if (exists == 0)
+ return MAIL_NO_ERROR;
+
+ fetch_type = mailimap_fetch_type_new_fetch_att_list_empty();
+ if (fetch_type == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ fetch_att = mailimap_fetch_att_new_uid();
+ if (fetch_att == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_fetch_type;
+ }
+
+ r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
+ if (r != MAILIMAP_NO_ERROR) {
+ mailimap_fetch_att_free(fetch_att);
+ res = MAIL_ERROR_MEMORY;
+ goto free_fetch_type;
+ }
+
+ fetch_att = mailimap_fetch_att_new_flags();
+ if (fetch_att == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_fetch_type;
+ }
+
+ r = mailimap_fetch_type_new_fetch_att_list_add(fetch_type, fetch_att);
+ if (r != MAILIMAP_NO_ERROR) {
+ mailimap_fetch_att_free(fetch_att);
+ res = MAIL_ERROR_MEMORY;
+ goto free_fetch_type;
+ }
+
+ r = imap_add_envelope_fetch_att(fetch_type);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free_fetch_type;
+ }
+
+ r = maildriver_env_list_to_msg_list(env_list, &msg_list);
+ if (r != MAIL_NO_ERROR) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_fetch_type;
+ }
+
+ if (clist_begin(msg_list) == NULL) {
+ /* no need to fetch envelopes */
+
+ mailimap_fetch_type_free(fetch_type);
+ clist_free(msg_list);
+ return MAIL_NO_ERROR;
+ }
+
+ r = msg_list_to_imap_set(msg_list, &set);
+ if (r != MAIL_NO_ERROR) {
+ clist_foreach(msg_list, (clist_func) free, NULL);
+ clist_free(msg_list);
+ res = MAIL_ERROR_MEMORY;
+ goto free_fetch_type;
+ }
+ clist_foreach(msg_list, (clist_func) free, NULL);
+ clist_free(msg_list);
+
+ set_iter = clist_begin(set->set_list);
+ while (set_iter != NULL) {
+ struct mailimap_set * subset;
+ unsigned int count;
+
+ subset = mailimap_set_new_empty();
+ if (subset == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ mailimap_fetch_type_free(fetch_type);
+ mailimap_set_free(set);
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ count = 0;
+ while (count < IMAP_SET_MAX_COUNT) {
+ struct mailimap_set_item * item;
+
+ item = clist_content(set_iter);
+ set_iter = clist_delete(set->set_list, set_iter);
+
+ r = mailimap_set_add(subset, item);
+ if (r != MAILIMAP_NO_ERROR) {
+ mailimap_set_item_free(item);
+ mailimap_set_free(subset);
+ mailimap_fetch_type_free(fetch_type);
+ mailimap_set_free(set);
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ count ++;
+
+ if (set_iter == NULL)
+ break;
+ }
+
+ r = mailimap_uid_fetch(get_imap_session(session), subset,
+ fetch_type, &fetch_result);
+
+ mailimap_set_free(subset);
+
+ switch (r) {
+ case MAILIMAP_NO_ERROR:
+ break;
+ default:
+ mailimap_fetch_type_free(fetch_type);
+ mailimap_set_free(set);
+ return imap_error_to_mail_error(r);
+ }
+
+ if (clist_begin(fetch_result) == NULL) {
+ res = MAIL_ERROR_FETCH;
+ goto err;
+ }
+
+ r = imap_fetch_result_to_envelop_list(fetch_result, env_list);
+ mailimap_fetch_list_free(fetch_result);
+
+ if (r != MAIL_NO_ERROR) {
+ mailimap_fetch_type_free(fetch_type);
+ mailimap_set_free(set);
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+ }
+
+#if 0
+ r = mailimap_uid_fetch(get_imap_session(session), set,
+ fetch_type, &fetch_result);
+#endif
+
+ mailimap_fetch_type_free(fetch_type);
+ mailimap_set_free(set);
+#if 0
+ switch (r) {
+ case MAILIMAP_NO_ERROR:
+ break;
+ default:
+ return imap_error_to_mail_error(r);
+ }
+
+ r = imap_fetch_result_to_envelop_list(fetch_result, env_list);
+ mailimap_fetch_list_free(fetch_result);
+
+ if (r != MAIL_NO_ERROR) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+#endif
+
+ return MAIL_NO_ERROR;
+
+ free_fetch_type:
+ mailimap_fetch_type_free(fetch_type);
+ err:
+ return res;
+}
+
+
+#if 0
+static int imapdriver_search_messages(mailsession * session, char * charset,
+ struct mail_search_key * key,
+ struct mail_search_result ** result)
+{
+ struct mailimap_search_key * imap_key;
+ int r;
+ clist * imap_result;
+ clist * result_list;
+ struct mail_search_result * search_result;
+ clistiter * cur;
+
+ r = mail_search_to_imap_search(key, &imap_key);
+ if (r != MAIL_NO_ERROR)
+ return MAIL_ERROR_MEMORY;
+
+ r = mailimap_uid_search(get_imap_session(session), charset, imap_key,
+ &imap_result);
+
+ mailimap_search_key_free(imap_key);
+
+ switch (r) {
+ case MAILIMAP_NO_ERROR:
+ break;
+ default:
+ return imap_error_to_mail_error(r);
+ }
+
+ result_list = clist_new();
+ if (result_list == NULL)
+ return MAIL_ERROR_MEMORY;
+
+ for(cur = clist_begin(imap_result) ; cur != NULL ; cur = clist_next(cur)) {
+ uint32_t val = * (uint32_t *) clist_content(cur);
+ uint32_t * new;
+
+ new = malloc(sizeof(* new));
+ if (new == NULL) {
+ goto free_imap_result;
+ }
+
+ * new = val;
+
+ r = clist_append(result_list, new);
+ if (r != 0) {
+ free(new);
+ goto free_imap_result;
+ }
+ }
+
+ search_result = mail_search_result_new(result_list);
+ if (search_result == NULL)
+ goto free_imap_result;
+
+ mailimap_search_result_free(imap_result);
+
+ * result = search_result;
+
+ return MAIL_NO_ERROR;
+
+ free_imap_result:
+ mailimap_search_result_free(imap_result);
+ return MAIL_ERROR_MEMORY;
+}
+#endif
+
+static int imapdriver_starttls(mailsession * session)
+{
+ mailimap * imap;
+ int r;
+ struct mailimap_capability_data * cap_data;
+ clistiter * cur;
+ int starttls;
+ int fd;
+ mailstream_low * low;
+ mailstream_low * new_low;
+ int capability_available;
+
+ imap = get_imap_session(session);
+
+ capability_available = FALSE;
+ if (imap->imap_connection_info != NULL)
+ if (imap->imap_connection_info->imap_capability != NULL) {
+ capability_available = TRUE;
+ cap_data = imap->imap_connection_info->imap_capability;
+ }
+
+ if (!capability_available) {
+ r = mailimap_capability(imap, &cap_data);
+ switch (r) {
+ case MAILIMAP_NO_ERROR:
+ break;
+ default:
+ return imap_error_to_mail_error(r);
+ }
+ }
+
+ starttls = FALSE;
+ for(cur = clist_begin(cap_data->cap_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailimap_capability * cap;
+
+ cap = clist_content(cur);
+
+ if (cap->cap_type == MAILIMAP_CAPABILITY_NAME)
+ if (strcasecmp(cap->cap_data.cap_name, "STARTTLS") == 0) {
+ starttls = TRUE;
+ break;
+ }
+ }
+
+ if (!capability_available)
+ mailimap_capability_data_free(cap_data);
+
+ if (!starttls)
+ return MAIL_ERROR_NO_TLS;
+
+ r = mailimap_starttls(imap);
+
+ switch (r) {
+ case MAILIMAP_NO_ERROR:
+ break;
+ default:
+ return imap_error_to_mail_error(r);
+ }
+
+ low = mailstream_get_low(imap->imap_stream);
+ fd = mailstream_low_get_fd(low);
+ if (fd == -1)
+ return MAIL_ERROR_STREAM;
+
+ new_low = mailstream_low_ssl_open(fd);
+ if (new_low == NULL)
+ return MAIL_ERROR_STREAM;
+
+ mailstream_low_free(low);
+ mailstream_set_low(imap->imap_stream, new_low);
+
+ return MAIL_NO_ERROR;
+}
+
+static int imapdriver_get_message(mailsession * session,
+ uint32_t num, mailmessage ** result)
+{
+ mailmessage * msg_info;
+ int r;
+
+ msg_info = mailmessage_new();
+ if (msg_info == NULL)
+ return MAIL_ERROR_MEMORY;
+
+ r = mailmessage_init(msg_info, session, imap_message_driver, num, 0);
+ if (r != MAIL_NO_ERROR) {
+ mailmessage_free(msg_info);
+ return r;
+ }
+
+ * result = msg_info;
+
+ return MAIL_NO_ERROR;
+}
+
+/* Retrieve a message by UID
+
+ libEtPan! uid format for IMAP is "UIDVALIDITY-UID"
+ where UIDVALIDITY and UID are decimal representation of
+ respectively uidvalidity and uid numbers.
+
+ Return value:
+ MAIL_ERROR_INVAL if uid is NULL or has an incorrect format.
+ MAIL_ERROR_MSG_NOT_FOUND if uidvalidity has changed or uid was not found
+ MAIL_NO_ERROR if message was found. Result is in result
+*/
+
+static int imapdriver_get_message_by_uid(mailsession * session,
+ const char * uid,
+ mailmessage ** result)
+{
+ uint32_t uidvalidity;
+ uint32_t num;
+ char * p1, * p2;
+ mailimap * imap;
+
+ if (uid == NULL)
+ return MAIL_ERROR_INVAL;
+
+ uidvalidity = strtoul(uid, &p1, 10);
+ if (p1 == uid || * p1 != '-')
+ return MAIL_ERROR_INVAL;
+
+ p1++;
+ num = strtoul(p1, &p2, 10);
+ if (p2 == p1 || * p2 != '\0')
+ return MAIL_ERROR_INVAL;
+
+ imap = get_imap_session(session);
+ if (imap->imap_selection_info->sel_uidvalidity != uidvalidity)
+ return MAIL_ERROR_MSG_NOT_FOUND;
+
+ return imapdriver_get_message(session, num, result);
+}
diff --git a/libetpan/src/driver/implementation/imap/imapdriver.h b/libetpan/src/driver/implementation/imap/imapdriver.h
new file mode 100644
index 0000000..cbc0c51
--- a/dev/null
+++ b/libetpan/src/driver/implementation/imap/imapdriver.h
@@ -0,0 +1,52 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef IMAPDRIVER_H
+
+#define IMAPDRIVER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libetpan/imapdriver_types.h>
+
+extern mailsession_driver * imap_session_driver;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/implementation/imap/imapdriver_cached.c b/libetpan/src/driver/implementation/imap/imapdriver_cached.c
new file mode 100644
index 0000000..806b282
--- a/dev/null
+++ b/libetpan/src/driver/implementation/imap/imapdriver_cached.c
@@ -0,0 +1,1370 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "imapdriver_cached.h"
+
+#include "libetpan-config.h"
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "mail.h"
+#include "imapdriver_tools.h"
+#include "mail_cache_db.h"
+#include "mailmessage.h"
+#include "imapdriver_cached_message.h"
+#include "maildriver.h"
+#include "imapdriver_types.h"
+#include "generic_cache.h"
+#include "imfcache.h"
+#include "maildriver_tools.h"
+#include "imapdriver.h"
+
+static int imapdriver_cached_initialize(mailsession * session);
+static void imapdriver_cached_uninitialize(mailsession * session);
+
+static int imapdriver_cached_parameters(mailsession * session,
+ int id, void * value);
+
+static int imapdriver_cached_connect_stream(mailsession * session,
+ mailstream * s);
+
+static int imapdriver_cached_starttls(mailsession * session);
+
+static int imapdriver_cached_login(mailsession * session,
+ char * userid, char * password);
+static int imapdriver_cached_logout(mailsession * session);
+static int imapdriver_cached_noop(mailsession * session);
+static int imapdriver_cached_build_folder_name(mailsession * session,
+ char * mb,
+ char * name, char ** result);
+static int imapdriver_cached_create_folder(mailsession * session, char * mb);
+static int imapdriver_cached_delete_folder(mailsession * session, char * mb);
+static int imapdriver_cached_rename_folder(mailsession * session, char * mb,
+ char * new_name);
+static int imapdriver_cached_check_folder(mailsession * session);
+static int imapdriver_cached_examine_folder(mailsession * session,
+ char * mb);
+static int imapdriver_cached_select_folder(mailsession * session, char * mb);
+static int imapdriver_cached_expunge_folder(mailsession * session);
+static int imapdriver_cached_status_folder(mailsession * session, char * mb,
+ uint32_t * result_messages,
+ uint32_t * result_recent,
+ uint32_t * result_unseen);
+static int imapdriver_cached_messages_number(mailsession * session,
+ char * mb,
+ uint32_t * result);
+static int imapdriver_cached_recent_number(mailsession * session, char * mb,
+ uint32_t * result);
+static int imapdriver_cached_unseen_number(mailsession * session, char * mb,
+ uint32_t * result);
+static int imapdriver_cached_list_folders(mailsession * session, char * mb,
+ struct mail_list ** result);
+static int imapdriver_cached_lsub_folders(mailsession * session, char * mb,
+ struct mail_list ** result);
+static int imapdriver_cached_subscribe_folder(mailsession * session,
+ char * mb);
+static int imapdriver_cached_unsubscribe_folder(mailsession * session,
+ char * mb);
+static int imapdriver_cached_append_message(mailsession * session,
+ char * message, size_t size);
+static int imapdriver_cached_append_message_flags(mailsession * session,
+ char * message, size_t size, struct mail_flags * flags);
+static int imapdriver_cached_copy_message(mailsession * session,
+ uint32_t num, char * mb);
+
+static int imapdriver_cached_get_messages_list(mailsession * session,
+ struct mailmessage_list **
+ result);
+static int
+imapdriver_cached_get_envelopes_list(mailsession * session,
+ struct mailmessage_list * env_list);
+static int imapdriver_cached_remove_message(mailsession * session,
+ uint32_t num);
+
+#if 0
+static int imapdriver_cached_search_messages(mailsession * session,
+ char * charset,
+ struct mail_search_key * key,
+ struct mail_search_result **
+ result);
+#endif
+
+static int imapdriver_cached_get_message(mailsession * session,
+ uint32_t num, mailmessage ** result);
+
+static int imapdriver_cached_get_message_by_uid(mailsession * session,
+ const char * uid,
+ mailmessage ** result);
+
+static mailsession_driver local_imap_cached_session_driver = {
+ .sess_name = "imap-cached",
+
+ .sess_initialize = imapdriver_cached_initialize,
+ .sess_uninitialize = imapdriver_cached_uninitialize,
+
+ .sess_parameters = imapdriver_cached_parameters,
+
+ .sess_connect_stream = imapdriver_cached_connect_stream,
+ .sess_connect_path = NULL,
+ .sess_starttls = imapdriver_cached_starttls,
+ .sess_login = imapdriver_cached_login,
+ .sess_logout = imapdriver_cached_logout,
+ .sess_noop = imapdriver_cached_noop,
+
+ .sess_build_folder_name = imapdriver_cached_build_folder_name,
+ .sess_create_folder = imapdriver_cached_create_folder,
+ .sess_delete_folder = imapdriver_cached_delete_folder,
+ .sess_rename_folder = imapdriver_cached_rename_folder,
+ .sess_check_folder = imapdriver_cached_check_folder,
+ .sess_examine_folder = imapdriver_cached_examine_folder,
+ .sess_select_folder = imapdriver_cached_select_folder,
+ .sess_expunge_folder = imapdriver_cached_expunge_folder,
+ .sess_status_folder = imapdriver_cached_status_folder,
+ .sess_messages_number = imapdriver_cached_messages_number,
+ .sess_recent_number = imapdriver_cached_recent_number,
+ .sess_unseen_number = imapdriver_cached_unseen_number,
+ .sess_list_folders = imapdriver_cached_list_folders,
+ .sess_lsub_folders = imapdriver_cached_lsub_folders,
+ .sess_subscribe_folder = imapdriver_cached_subscribe_folder,
+ .sess_unsubscribe_folder = imapdriver_cached_unsubscribe_folder,
+
+ .sess_append_message = imapdriver_cached_append_message,
+ .sess_append_message_flags = imapdriver_cached_append_message_flags,
+ .sess_copy_message = imapdriver_cached_copy_message,
+ .sess_move_message = NULL,
+
+ .sess_get_messages_list = imapdriver_cached_get_messages_list,
+ .sess_get_envelopes_list = imapdriver_cached_get_envelopes_list,
+ .sess_remove_message = imapdriver_cached_remove_message,
+#if 0
+ .sess_search_messages = imapdriver_cached_search_messages,
+#endif
+
+ .sess_get_message = imapdriver_cached_get_message,
+ .sess_get_message_by_uid = imapdriver_cached_get_message_by_uid,
+};
+
+mailsession_driver * imap_cached_session_driver =
+&local_imap_cached_session_driver;
+
+#define CACHE_MESSAGE_LIST
+
+static inline struct imap_cached_session_state_data *
+get_cached_data(mailsession * session)
+{
+ return session->sess_data;
+}
+
+static inline mailsession * get_ancestor(mailsession * s)
+{
+ return get_cached_data(s)->imap_ancestor;
+}
+
+static inline
+struct imap_session_state_data * get_ancestor_data(mailsession * s)
+{
+ return get_ancestor(s)->sess_data;
+}
+
+static inline mailimap * get_imap_session(mailsession * session)
+{
+ return get_ancestor_data(session)->imap_session;
+}
+
+static int imapdriver_cached_initialize(mailsession * session)
+{
+ struct imap_cached_session_state_data * data;
+
+ data = malloc(sizeof(* data));
+ if (data == NULL)
+ goto err;
+
+ data->imap_ancestor = mailsession_new(imap_session_driver);
+ if (data->imap_ancestor == NULL)
+ goto free_data;
+ data->imap_quoted_mb = NULL;
+ data->imap_cache_directory[0] = '\0';
+ data->imap_uid_list = carray_new(128);
+ if (data->imap_uid_list == NULL)
+ goto free_session;
+
+ session->sess_data = data;
+
+ return MAIL_NO_ERROR;
+
+ free_session:
+ mailsession_free(data->imap_ancestor);
+ free_data:
+ free(data);
+ err:
+ return MAIL_ERROR_MEMORY;
+}
+
+static void
+free_quoted_mb(struct imap_cached_session_state_data * imap_cached_data)
+{
+ if (imap_cached_data->imap_quoted_mb != NULL) {
+ free(imap_cached_data->imap_quoted_mb);
+ imap_cached_data->imap_quoted_mb = NULL;
+ }
+}
+
+struct uid_cache_item {
+ uint32_t uid;
+ uint32_t size;
+};
+
+static int update_uid_cache(mailsession * session,
+ struct mailmessage_list * env_list)
+{
+ unsigned int i;
+ int r;
+ struct imap_cached_session_state_data * data;
+ int res;
+
+ data = get_cached_data(session);
+
+ /* free all UID cache */
+ for(i = 0 ; i < carray_count(data->imap_uid_list) ; i ++) {
+ struct uid_cache_item * cache_item;
+
+ cache_item = carray_get(data->imap_uid_list, i);
+ free(cache_item);
+ }
+
+ /* build UID cache */
+ r = carray_set_size(data->imap_uid_list,
+ carray_count(env_list->msg_tab));
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
+ struct uid_cache_item * cache_item;
+ mailmessage * msg;
+
+ cache_item = malloc(sizeof(* cache_item));
+ if (cache_item == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+ msg = carray_get(env_list->msg_tab, i);
+ cache_item->uid = msg->msg_index;
+ cache_item->size = msg->msg_size;
+
+ carray_set(data->imap_uid_list, i, cache_item);
+ }
+
+ return MAIL_NO_ERROR;
+
+ err:
+ return res;
+}
+
+static void check_for_uid_cache(mailsession * session)
+{
+#if 0
+ mailsession * imap;
+#endif
+ mailimap * imap;
+#if 0
+ struct imap_session_state_data * imap_data;
+#endif
+ clist * list;
+ clistiter * cur;
+ struct imap_cached_session_state_data * data;
+ unsigned int i;
+ unsigned dest;
+
+ data = get_cached_data(session);
+#if 0
+ imap = get_ancestor(session);
+
+ imap_data = imap->data;
+#endif
+
+ imap = get_imap_session(session);
+
+ if (imap->imap_response_info == NULL)
+ return;
+
+ list = imap->imap_response_info->rsp_expunged;
+ if (list == NULL)
+ return;
+
+ dest = 0;
+ i = 0;
+ /* remove expunged */
+ for(cur = clist_begin(list) ; cur != NULL ; cur = clist_next(cur)) {
+ uint32_t expunged;
+
+ expunged = * (uint32_t *) clist_content(cur);
+
+ while (i < carray_count(data->imap_uid_list)) {
+ struct uid_cache_item * cache_item;
+
+ if (dest + 1 == expunged) {
+ cache_item = carray_get(data->imap_uid_list, i);
+ free(cache_item);
+ i ++;
+ break;
+ }
+ else {
+ cache_item = carray_get(data->imap_uid_list, i);
+ carray_set(data->imap_uid_list, dest, cache_item);
+ i ++;
+ dest ++;
+ }
+ }
+ }
+ /* complete list */
+ while (i < carray_count(data->imap_uid_list)) {
+ struct uid_cache_item * cache_item;
+
+ cache_item = carray_get(data->imap_uid_list, i);
+ carray_set(data->imap_uid_list, dest, cache_item);
+ i ++;
+ dest ++;
+ }
+ carray_set_size(data->imap_uid_list, dest);
+}
+
+static void imapdriver_cached_uninitialize(mailsession * session)
+{
+ struct imap_cached_session_state_data * data;
+ unsigned int i;
+
+ data = get_cached_data(session);
+
+ for(i = 0 ; i < carray_count(data->imap_uid_list) ; i ++) {
+ struct uid_cache_item * cache_item;
+
+ cache_item = carray_get(data->imap_uid_list, i);
+ free(cache_item);
+ }
+ carray_free(data->imap_uid_list);
+ free_quoted_mb(data);
+ mailsession_free(data->imap_ancestor);
+ free(data);
+
+ session->sess_data = NULL;
+}
+
+
+static int imapdriver_cached_parameters(mailsession * session,
+ int id, void * value)
+{
+ struct imap_cached_session_state_data * data;
+ int r;
+
+ data = get_cached_data(session);
+
+ switch (id) {
+ case IMAPDRIVER_CACHED_SET_CACHE_DIRECTORY:
+ strncpy(data->imap_cache_directory, value, PATH_MAX);
+ data->imap_cache_directory[PATH_MAX - 1] = '\0';
+
+ r = generic_cache_create_dir(data->imap_cache_directory);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ return MAIL_NO_ERROR;
+ }
+
+ return MAIL_ERROR_INVAL;
+}
+
+
+static int imapdriver_cached_connect_stream(mailsession * session,
+ mailstream * s)
+{
+ int r;
+
+ check_for_uid_cache(session);
+
+ r = mailsession_connect_stream(get_ancestor(session), s);
+
+ check_for_uid_cache(session);
+
+ return r;
+}
+
+static int imapdriver_cached_starttls(mailsession * session)
+{
+ int r;
+
+ r = mailsession_starttls(get_ancestor(session));
+
+ check_for_uid_cache(session);
+
+ return r;
+}
+
+static int imapdriver_cached_login(mailsession * session,
+ char * userid, char * password)
+{
+ int r;
+
+ r = mailsession_login(get_ancestor(session), userid, password);
+
+ check_for_uid_cache(session);
+
+ return r;
+}
+
+static int imapdriver_cached_logout(mailsession * session)
+{
+ int r;
+
+ r = mailsession_logout(get_ancestor(session));
+
+ check_for_uid_cache(session);
+
+ if (r == MAIL_NO_ERROR) {
+ struct imap_cached_session_state_data * imap_cached_data;
+
+ imap_cached_data = get_cached_data(session);
+
+ free_quoted_mb(imap_cached_data);
+ }
+
+ return r;
+}
+
+static int imapdriver_cached_noop(mailsession * session)
+{
+ int r;
+
+ r = mailsession_noop(get_ancestor(session));
+
+ check_for_uid_cache(session);
+
+ return r;
+}
+
+static int imapdriver_cached_build_folder_name(mailsession * session,
+ char * mb,
+ char * name, char ** result)
+{
+ int r;
+
+ r = mailsession_build_folder_name(get_ancestor(session), mb,
+ name, result);
+
+ check_for_uid_cache(session);
+
+ return r;
+}
+
+static int imapdriver_cached_create_folder(mailsession * session, char * mb)
+{
+ int r;
+
+ r = mailsession_create_folder(get_ancestor(session), mb);
+
+ check_for_uid_cache(session);
+
+ return r;
+}
+
+static int imapdriver_cached_delete_folder(mailsession * session, char * mb)
+{
+ int r;
+
+ r = mailsession_delete_folder(get_ancestor(session), mb);
+
+ check_for_uid_cache(session);
+
+ return r;
+}
+
+static int imapdriver_cached_rename_folder(mailsession * session, char * mb,
+ char * new_name)
+{
+ int r;
+
+ r = mailsession_rename_folder(get_ancestor(session), mb, new_name);
+
+ check_for_uid_cache(session);
+
+ return r;
+}
+
+static int imapdriver_cached_check_folder(mailsession * session)
+{
+ int r;
+
+ r = mailsession_check_folder(get_ancestor(session));
+
+ check_for_uid_cache(session);
+
+ return r;
+}
+
+static int imapdriver_cached_examine_folder(mailsession * session,
+ char * mb)
+{
+ int r;
+
+ r = mailsession_examine_folder(get_ancestor(session), mb);
+
+ check_for_uid_cache(session);
+
+ return r;
+}
+
+static int get_cache_folder(mailsession * session, char ** result)
+{
+#if 0
+ mailsession * imap_session;
+#endif
+ mailimap * imap;
+ char * mb;
+ char * cache_dir;
+ char * dirname;
+ char * quoted_mb;
+ int res;
+ int r;
+ char key[PATH_MAX];
+#if 0
+ struct imap_session_state_data * imap_data;
+ struct imap_cached_session_state_data * cached_data;
+#endif
+
+#if 0
+ imap_session = get_ancestor(session);
+ imap_data = imap_session->data;
+ imap = imap_data->session;
+#endif
+ imap = get_imap_session(session);
+
+ mb = get_ancestor_data(session)->imap_mailbox;
+
+ cache_dir = get_cached_data(session)->imap_cache_directory;
+
+ if (imap->imap_state != MAILIMAP_STATE_SELECTED)
+ return MAIL_ERROR_BAD_STATE;
+
+ if (imap->imap_selection_info == NULL)
+ return MAIL_ERROR_BAD_STATE;
+
+ quoted_mb = maildriver_quote_mailbox(mb);
+ if (quoted_mb == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ snprintf(key, PATH_MAX, "%s/%s", cache_dir, quoted_mb);
+
+ dirname = strdup(key);
+ if (dirname == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_mb;
+ }
+
+ r = generic_cache_create_dir(dirname);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free_dirname;
+ }
+
+ free(quoted_mb);
+
+ * result = dirname;
+
+ return MAIL_NO_ERROR;
+
+ free_dirname:
+ free(dirname);
+ free_mb:
+ free(quoted_mb);
+ err:
+ return res;
+}
+
+static int imapdriver_cached_select_folder(mailsession * session, char * mb)
+{
+ int r;
+ char * quoted_mb;
+ struct imap_cached_session_state_data * data;
+ mailsession * imap;
+ char * old_mb;
+
+ imap = get_ancestor(session);
+
+ old_mb = get_ancestor_data(session)->imap_mailbox;
+ if (old_mb != NULL)
+ if (strcmp(mb, old_mb) == 0)
+ return MAIL_NO_ERROR;
+
+ r = mailsession_select_folder(get_ancestor(session), mb);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ check_for_uid_cache(session);
+
+ r = get_cache_folder(session, &quoted_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, &section);
+ 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, &section);
+ 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, &section);
+ 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, &section);
+ 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, &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, &quoted_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 = &num;
+ 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, &quoted_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 = &num;
+ 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 = &num;
+ 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 = &num;
+ 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 = &num;
+ 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, &quoted_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 = &num;
+ 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 = &num;
+ 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 = &num;
+ key.len = sizeof(num);
+ r = chash_get(folder->fl_msgs_hash, &key, &data);
+ if (r < 0)
+ return MAIL_ERROR_CACHE_MISS;
+ msg_info = data.data;
+
+ snprintf(keyname, PATH_MAX, "%u-%lu-%lu-flags",
+ num, (unsigned long) msg_info->msg_mtime,
+ (unsigned long) msg_info->msg_size);
+
+ r = generic_cache_flags_read(cache_db, mmapstr, keyname, &flags);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ * result = flags;
+
+ return MAIL_NO_ERROR;
+
+ err:
+ return res;
+}
+
+int
+mhdriver_write_cached_flags(struct mail_cache_db * cache_db,
+ MMAPString * mmapstr,
+ char * uid,
+ struct mail_flags * flags)
+{
+ int r;
+ char keyname[PATH_MAX];
+ int res;
+
+ snprintf(keyname, PATH_MAX, "%s-flags", uid);
+
+ r = generic_cache_flags_write(cache_db, mmapstr, keyname, flags);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ return MAIL_NO_ERROR;
+
+ err:
+ return res;
+}
+
+
+int mh_get_messages_list(struct mailmh_folder * folder,
+ mailsession * session, mailmessage_driver * driver,
+ struct mailmessage_list ** result)
+{
+ unsigned int i;
+ struct mailmessage_list * env_list;
+ int r;
+ carray * tab;
+ int res;
+
+ tab = carray_new(128);
+ if (tab == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ for(i = 0 ; i < carray_count(folder->fl_msgs_tab) ; i++) {
+ struct mailmh_msg_info * mh_info;
+ mailmessage * msg;
+
+ mh_info = carray_get(folder->fl_msgs_tab, i);
+ if (mh_info == NULL)
+ continue;
+
+ msg = mailmessage_new();
+ if (msg == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ r = mailmessage_init(msg, session, driver,
+ mh_info->msg_index, mh_info->msg_size);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free_list;
+ }
+
+ r = carray_add(tab, msg, NULL);
+ if (r < 0) {
+ mailmessage_free(msg);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+ }
+
+ env_list = mailmessage_list_new(tab);
+ if (env_list == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ * result = env_list;
+
+ return MAIL_NO_ERROR;
+
+ free_list:
+ for(i = 0 ; i < carray_count(tab) ; i ++)
+ mailmessage_free(carray_get(tab, i));
+ carray_free(tab);
+ err:
+ return res;
+}
diff --git a/libetpan/src/driver/implementation/mh/mhdriver_tools.h b/libetpan/src/driver/implementation/mh/mhdriver_tools.h
new file mode 100644
index 0000000..7b8928e
--- a/dev/null
+++ b/libetpan/src/driver/implementation/mh/mhdriver_tools.h
@@ -0,0 +1,80 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef MHDRIVER_TOOLS_H
+
+#define MHDRIVER_TOOLS_H
+
+#include "maildriver_types.h"
+#include "mail_cache_db_types.h"
+#include "mailmh.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int mhdriver_mh_error_to_mail_error(int error);
+
+int mhdriver_fetch_message(mailsession * session, uint32_t index,
+ char ** result, size_t * result_len);
+
+int mhdriver_fetch_header(mailsession * session, uint32_t index,
+ char ** result, size_t * result_len);
+
+int mhdriver_fetch_size(mailsession * session, uint32_t index,
+ size_t * result);
+
+int
+mhdriver_get_cached_flags(struct mail_cache_db * cache_db,
+ MMAPString * mmapstr,
+ mailsession * session,
+ uint32_t num,
+ struct mail_flags ** result);
+
+int
+mhdriver_write_cached_flags(struct mail_cache_db * cache_db,
+ MMAPString * mmapstr,
+ char * uid,
+ struct mail_flags * flags);
+
+int mh_get_messages_list(struct mailmh_folder * folder,
+ mailsession * session, mailmessage_driver * driver,
+ struct mailmessage_list ** result);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/implementation/mh/mhdriver_types.h b/libetpan/src/driver/implementation/mh/mhdriver_types.h
new file mode 100644
index 0000000..45afb64
--- a/dev/null
+++ b/libetpan/src/driver/implementation/mh/mhdriver_types.h
@@ -0,0 +1,100 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef MHDRIVER_TYPES_H
+
+#define MHDRIVER_TYPES_H
+
+#include <libetpan/libetpan-config.h>
+
+#include <libetpan/maildriver_types.h>
+#include <libetpan/mailmh.h>
+#include <libetpan/clist.h>
+#include <libetpan/generic_cache_types.h>
+#include <libetpan/mailstorage_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct mh_session_state_data {
+ struct mailmh * mh_session;
+
+ struct mailmh_folder * mh_cur_folder;
+
+ clist * mh_subscribed_list;
+};
+
+enum {
+ MHDRIVER_CACHED_SET_CACHE_DIRECTORY = 1,
+ MHDRIVER_CACHED_SET_FLAGS_DIRECTORY,
+};
+
+struct mh_cached_session_state_data {
+ mailsession * mh_ancestor;
+ char * mh_quoted_mb;
+ char mh_cache_directory[PATH_MAX];
+ char mh_flags_directory[PATH_MAX];
+ struct mail_flags_store * mh_flags_store;
+};
+
+/* mh storage */
+
+/*
+ mh_mailstorage is the state data specific to the MH storage.
+
+ - pathname is the root path of the MH storage.
+
+ - cached if this value is != 0, a persistant cache will be
+ stored on local system.
+
+ - cache_directory is the location of the cache.
+
+ - flags_directory is the location of the flags.
+*/
+
+struct mh_mailstorage {
+ char * mh_pathname;
+
+ int mh_cached;
+ char * mh_cache_directory;
+ char * mh_flags_directory;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/implementation/mh/mhstorage.c b/libetpan/src/driver/implementation/mh/mhstorage.c
new file mode 100644
index 0000000..e7fc2f0
--- a/dev/null
+++ b/libetpan/src/driver/implementation/mh/mhstorage.c
@@ -0,0 +1,192 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "mhstorage.h"
+
+#include "mhdriver.h"
+#include "mhdriver_cached.h"
+#include "mail.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/* mh storage */
+
+static int mh_mailstorage_connect(struct mailstorage * storage);
+static int mh_mailstorage_get_folder_session(struct mailstorage * storage,
+ char * pathname, mailsession ** result);
+static void mh_mailstorage_uninitialize(struct mailstorage * storage);
+
+static mailstorage_driver mh_mailstorage_driver = {
+ .sto_name = "mh",
+ .sto_connect = mh_mailstorage_connect,
+ .sto_get_folder_session = mh_mailstorage_get_folder_session,
+ .sto_uninitialize = mh_mailstorage_uninitialize,
+};
+
+int mh_mailstorage_init(struct mailstorage * storage,
+ char * mh_pathname, int mh_cached,
+ char * mh_cache_directory, char * mh_flags_directory)
+{
+ struct mh_mailstorage * mh_storage;
+
+ mh_storage = malloc(sizeof(* mh_storage));
+ if (mh_storage == NULL)
+ goto err;
+
+ mh_storage->mh_pathname = strdup(mh_pathname);
+ if (mh_storage->mh_pathname == NULL)
+ goto free;
+
+ mh_storage->mh_cached = mh_cached;
+
+ if (mh_cached && (mh_cache_directory != NULL) &&
+ (mh_flags_directory != NULL)) {
+ mh_storage->mh_cache_directory = strdup(mh_cache_directory);
+ if (mh_storage->mh_cache_directory == NULL)
+ goto free_pathname;
+ mh_storage->mh_flags_directory = strdup(mh_flags_directory);
+ if (mh_storage->mh_flags_directory == NULL)
+ goto free_cache_directory;
+ }
+ else {
+ mh_storage->mh_cached = FALSE;
+ mh_storage->mh_cache_directory = NULL;
+ mh_storage->mh_flags_directory = NULL;
+ }
+
+ storage->sto_data = mh_storage;
+ storage->sto_driver = &mh_mailstorage_driver;
+
+ return MAIL_NO_ERROR;
+
+ free_cache_directory:
+ free(mh_storage->mh_cache_directory);
+ free_pathname:
+ free(mh_storage->mh_pathname);
+ free:
+ free(mh_storage);
+ err:
+ return MAIL_ERROR_MEMORY;
+}
+
+static void mh_mailstorage_uninitialize(struct mailstorage * storage)
+{
+ struct mh_mailstorage * mh_storage;
+
+ mh_storage = storage->sto_data;
+ if (mh_storage->mh_flags_directory != NULL)
+ free(mh_storage->mh_flags_directory);
+ if (mh_storage->mh_cache_directory != NULL)
+ free(mh_storage->mh_cache_directory);
+ free(mh_storage->mh_pathname);
+ free(mh_storage);
+
+ storage->sto_data = NULL;
+}
+
+static int mh_mailstorage_connect(struct mailstorage * storage)
+{
+ struct mh_mailstorage * mh_storage;
+ mailsession_driver * driver;
+ int r;
+ int res;
+ mailsession * session;
+
+ mh_storage = storage->sto_data;
+
+ if (mh_storage->mh_cached)
+ driver = mh_cached_session_driver;
+ else
+ driver = mh_session_driver;
+
+ session = mailsession_new(driver);
+ if (session == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ if (mh_storage->mh_cached) {
+ r = mailsession_parameters(session,
+ MHDRIVER_CACHED_SET_CACHE_DIRECTORY,
+ mh_storage->mh_cache_directory);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+
+ r = mailsession_parameters(session,
+ MHDRIVER_CACHED_SET_FLAGS_DIRECTORY,
+ mh_storage->mh_flags_directory);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+ }
+
+ r = mailsession_connect_path(session, mh_storage->mh_pathname);
+ switch (r) {
+ case MAIL_NO_ERROR_NON_AUTHENTICATED:
+ case MAIL_NO_ERROR_AUTHENTICATED:
+ case MAIL_NO_ERROR:
+ break;
+ default:
+ res = r;
+ goto free;
+ }
+
+ storage->sto_session = session;
+
+ return MAIL_NO_ERROR;
+
+ free:
+ mailsession_free(session);
+ err:
+ return res;
+}
+
+static int mh_mailstorage_get_folder_session(struct mailstorage * storage,
+ char * pathname, mailsession ** result)
+{
+ int r;
+
+ r = mailsession_select_folder(storage->sto_session, pathname);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ * result = storage->sto_session;
+
+ return MAIL_NO_ERROR;
+}
diff --git a/libetpan/src/driver/implementation/mh/mhstorage.h b/libetpan/src/driver/implementation/mh/mhstorage.h
new file mode 100644
index 0000000..be86007
--- a/dev/null
+++ b/libetpan/src/driver/implementation/mh/mhstorage.h
@@ -0,0 +1,67 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef MHSTORAGE_H
+
+#define MHSTORAGE_H
+
+#include <libetpan/mhdriver_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ mh_mailstorage_init is the constructor for a MH storage
+
+ @param pathname is the filename the root path of the MH storage.
+
+ @param cached if this value is != 0, a persistant cache will be
+ stored on local system.
+
+ @param cache_directory is the location of the cache.
+
+ @param flags_directory is the location of the flags.
+*/
+
+int mh_mailstorage_init(struct mailstorage * storage,
+ char * mh_pathname, int mh_cached,
+ char * mh_cache_directory, char * mh_flags_directory);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/implementation/mime-message/mime_message_driver.c b/libetpan/src/driver/implementation/mime-message/mime_message_driver.c
new file mode 100644
index 0000000..06defbd
--- a/dev/null
+++ b/libetpan/src/driver/implementation/mime-message/mime_message_driver.c
@@ -0,0 +1,914 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "mime_message_driver.h"
+
+#include "libetpan-config.h"
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "mailmessage.h"
+#include "mailmessage_tools.h"
+#include "maildriver_tools.h"
+
+#if 0
+static FILE * get_mime_tmp_file(mailmessage * msg,
+ char * filename, size_t size)
+{
+ int fd;
+ mode_t old_mask;
+ FILE * f;
+
+ if (msg->msg_data == NULL)
+ return NULL;
+
+ snprintf(filename, size, "%s/libetpan-mime-XXXXXX",
+ (char *) msg->msg_data);
+
+ old_mask = umask(0077);
+ fd = mkstemp(filename);
+ umask(old_mask);
+ if (fd == -1)
+ return NULL;
+
+ f = fdopen(fd, "r+");
+ if (f == NULL) {
+ close(fd);
+ unlink(filename);
+ }
+
+ return f;
+}
+#endif
+
+int mime_message_set_tmpdir(mailmessage * msg, char * tmpdir)
+{
+#if 0
+ if (msg->msg_data != NULL)
+ free(msg->msg_data);
+
+ msg->msg_data = strdup(tmpdir);
+ if (msg->msg_data == NULL)
+ return MAIL_ERROR_MEMORY;
+
+#endif
+ return MAIL_NO_ERROR;
+}
+
+void mime_message_detach_mime(mailmessage * msg)
+{
+ msg->msg_mime = NULL;
+}
+
+mailmessage * mime_message_init(struct mailmime * mime)
+{
+ mailmessage * msg;
+ int r;
+
+ msg = mailmessage_new();
+ if (msg == NULL)
+ goto err;
+
+ r = mailmessage_init(msg, NULL, mime_message_driver, 0, 0);
+ if (r != MAIL_NO_ERROR)
+ goto free;
+
+ if (mime != NULL) {
+ mailmime_free(msg->msg_mime);
+ msg->msg_mime = mime;
+ }
+
+ return msg;
+
+ free:
+ mailmessage_free(msg);
+ err:
+ return NULL;
+}
+
+static int initialize(mailmessage * msg)
+{
+ struct mailmime * mime;
+ int res;
+
+ mime = mailmime_new_message_data(NULL);
+ if (mime == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ msg->msg_mime = mime;
+
+ return MAIL_NO_ERROR;
+
+ err:
+ return res;
+}
+
+static void uninitialize(mailmessage * msg)
+{
+ /* tmp dir name */
+ if (msg->msg_data != NULL)
+ free(msg->msg_data);
+
+ if (msg->msg_mime != NULL)
+ mailmime_free(msg->msg_mime);
+ msg->msg_mime = NULL;
+}
+
+static void flush(mailmessage * msg)
+{
+ /* do nothing */
+}
+
+static void check(mailmessage * msg)
+{
+ /* do nothing */
+}
+
+static void fetch_result_free(mailmessage * msg_info, char * content)
+{
+ mmap_string_unref(content);
+}
+
+#if 0
+static int file_to_mmapstr(FILE * f,
+ char ** result, size_t * result_len)
+{
+ int fd;
+ char * data;
+ struct stat buf;
+ MMAPString * mmapstr;
+ int res;
+ int r;
+
+ fd = fileno(f);
+ if (fd == -1) {
+ res = MAIL_ERROR_FILE;
+
+ goto err;
+ }
+
+ fflush(f);
+ r = fstat(fd, &buf);
+ if (r == -1) {
+ res = MAIL_ERROR_FILE;
+
+ goto err;
+ }
+
+ data = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (data == MAP_FAILED) {
+ res = MAIL_ERROR_FILE;
+
+ goto err;
+ }
+
+ mmapstr = mmap_string_new_len(data, buf.st_size);
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+
+ goto unmap;
+ }
+
+ munmap(data, buf.st_size);
+
+ r = mmap_string_ref(mmapstr);
+ if (r != 0) {
+ res = MAIL_ERROR_MEMORY;
+
+ goto err;
+ }
+
+ * result = mmapstr->str;
+ * result_len = mmapstr->len;
+
+ return MAIL_NO_ERROR;
+
+ unmap:
+ munmap(data, buf.st_size);
+ err:
+ return res;
+}
+#endif
+
+#if 0
+static int file_body_to_mmapstr(FILE * f,
+ char ** result, size_t * result_len)
+{
+ int fd;
+ char * data;
+ struct stat buf;
+ MMAPString * mmapstr;
+ size_t cur_token;
+ int res;
+ int r;
+
+ fd = fileno(f);
+ if (fd == -1) {
+ res = MAIL_ERROR_FILE;
+
+ goto err;
+ }
+
+ fflush(f);
+ r = fstat(fd, &buf);
+ if (r == -1) {
+ res = MAIL_ERROR_FILE;
+
+ goto err;
+ }
+
+ data = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (data == MAP_FAILED) {
+ res = MAIL_ERROR_FILE;
+
+ goto err;
+ }
+
+ cur_token = 0;
+
+ /* skip header */
+
+ while (1) {
+ r = mailimf_ignore_field_parse(data,
+ buf.st_size, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else
+ break;
+ }
+
+ r = mailimf_crlf_parse(data, buf.st_size, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = maildriver_imf_error_to_mail_error(r);
+ goto unmap;
+ }
+
+ mmapstr = mmap_string_new_len(data + cur_token, buf.st_size - cur_token);
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+
+ goto unmap;
+ }
+
+ munmap(data, buf.st_size);
+
+ r = mmap_string_ref(mmapstr);
+ if (r != 0) {
+ res = MAIL_ERROR_MEMORY;
+
+ goto err;
+ }
+
+ * result = mmapstr->str;
+ * result_len = mmapstr->len;
+
+ return MAIL_NO_ERROR;
+
+ unmap:
+ munmap(data, buf.st_size);
+ err:
+ return res;
+}
+#endif
+
+
+static int body_to_mmapstr(char * data, size_t size,
+ char ** result, size_t * result_len)
+{
+ MMAPString * mmapstr;
+ size_t cur_token;
+ int res;
+ int r;
+
+ cur_token = 0;
+
+ /* skip header */
+
+ while (1) {
+ r = mailimf_ignore_field_parse(data, size, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else
+ break;
+ }
+
+ r = mailimf_crlf_parse(data, size, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = maildriver_imf_error_to_mail_error(r);
+ goto err;
+ }
+
+ mmapstr = mmap_string_new_len(data + cur_token, size - cur_token);
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+
+ goto err;
+ }
+
+ r = mmap_string_ref(mmapstr);
+ if (r != 0) {
+ mmap_string_free(mmapstr);
+ res = MAIL_ERROR_MEMORY;
+
+ goto err;
+ }
+
+ * result = mmapstr->str;
+ * result_len = mmapstr->len;
+
+ return MAIL_NO_ERROR;
+
+ err:
+ return res;
+}
+
+
+#if 0
+static int file_body_body_to_mmapstr(FILE * f,
+ char ** result, size_t * result_len)
+{
+ int fd;
+ char * data;
+ struct stat buf;
+ MMAPString * mmapstr;
+ size_t cur_token;
+ int res;
+ int r;
+
+ fd = fileno(f);
+ if (fd == -1) {
+ res = MAIL_ERROR_FILE;
+
+ goto err;
+ }
+
+ fflush(f);
+ r = fstat(fd, &buf);
+ if (r == -1) {
+ res = MAIL_ERROR_FILE;
+
+ goto err;
+ }
+
+ data = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (data == MAP_FAILED) {
+ res = MAIL_ERROR_FILE;
+
+ goto err;
+ }
+
+ cur_token = 0;
+
+ /* skip header */
+
+ /* MIME header */
+
+ while (1) {
+ r = mailimf_ignore_field_parse(data,
+ buf.st_size, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else
+ break;
+ }
+
+ r = mailimf_crlf_parse(data, buf.st_size, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = maildriver_imf_error_to_mail_error(r);
+ goto unmap;
+ }
+
+ /* headers */
+
+ while (1) {
+ r = mailimf_ignore_field_parse(data,
+ buf.st_size, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else
+ break;
+ }
+
+ r = mailimf_crlf_parse(data, buf.st_size, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = maildriver_imf_error_to_mail_error(r);
+ goto unmap;
+ }
+
+ mmapstr = mmap_string_new_len(data + cur_token, buf.st_size - cur_token);
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+
+ goto unmap;
+ }
+
+ munmap(data, buf.st_size);
+
+ r = mmap_string_ref(mmapstr);
+ if (r != 0) {
+ res = MAIL_ERROR_MEMORY;
+
+ goto err;
+ }
+
+ * result = mmapstr->str;
+ * result_len = mmapstr->len;
+
+ return MAIL_NO_ERROR;
+
+ unmap:
+ munmap(data, buf.st_size);
+ err:
+ return res;
+}
+#endif
+
+static int body_body_to_mmapstr(char * data, size_t size,
+ char ** result, size_t * result_len)
+{
+ MMAPString * mmapstr;
+ size_t cur_token;
+ int res;
+ int r;
+
+ cur_token = 0;
+
+ /* skip header */
+
+ /* MIME header */
+
+ while (1) {
+ r = mailimf_ignore_field_parse(data, size, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else
+ break;
+ }
+
+ r = mailimf_crlf_parse(data, size, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = maildriver_imf_error_to_mail_error(r);
+ goto err;
+ }
+
+ return body_to_mmapstr(data + cur_token, size - cur_token,
+ result, result_len);
+
+ err:
+ return res;
+}
+
+
+static int fetch_section(mailmessage * msg_info,
+ struct mailmime * mime,
+ char ** result, size_t * result_len)
+{
+ int r;
+#if 0
+ FILE * f;
+#endif
+ int res;
+ int col;
+#if 0
+ char filename[PATH_MAX];
+#endif
+ MMAPString * str;
+
+ if (msg_info->msg_mime == NULL)
+ return MAIL_ERROR_INVAL;
+
+#if 0
+ f = get_mime_tmp_file(msg_info, filename, sizeof(filename));
+ if (f == NULL) {
+ res = MAIL_ERROR_FILE;
+ goto err;
+ }
+#endif
+
+ str = mmap_string_new("");
+ if (str == NULL) {
+ res = MAILIMF_ERROR_MEMORY;
+ goto err;
+ }
+
+ col = 0;
+ r = mailmime_write_mem(str, &col, mime);
+ if (r != MAILIMF_NO_ERROR) {
+ res = maildriver_imf_error_to_mail_error(r);
+ goto free;
+ }
+
+#if 0
+ if (mime->mm_parent == NULL)
+ r = file_to_mmapstr(f, result, result_len);
+ else
+ r = file_body_to_mmapstr(f, result, result_len);
+#endif
+ if (mime->mm_parent == NULL) {
+ r = mmap_string_ref(str);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free;
+ }
+
+ * result = str->str;
+ * result_len = str->len;
+
+ r = MAIL_NO_ERROR;
+ }
+ else {
+ r = body_to_mmapstr(str->str, str->len, result, result_len);
+ if (r == MAIL_NO_ERROR) {
+ mmap_string_free(str);
+ }
+ }
+
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+
+#if 0
+ fclose(f);
+ unlink(filename);
+#endif
+
+ return MAIL_NO_ERROR;
+
+ free:
+#if 0
+ fclose(f);
+ unlink(filename);
+#endif
+ mmap_string_free(str);
+ err:
+ return res;
+}
+
+
+static int fetch_section_header(mailmessage * msg_info,
+ struct mailmime * mime,
+ char ** result, size_t * result_len)
+{
+ int r;
+#if 0
+ FILE * f;
+#endif
+ int res;
+ int col;
+#if 0
+ char filename[PATH_MAX];
+#endif
+ MMAPString * str;
+
+ if (msg_info->msg_mime == NULL)
+ return MAIL_ERROR_INVAL;
+
+#if 0
+ f = get_mime_tmp_file(msg_info, filename, sizeof(filename));
+ if (f == NULL) {
+ res = MAIL_ERROR_FILE;
+ goto err;
+ }
+#endif
+
+ str = mmap_string_new("");
+ if (str == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ col = 0;
+ if (mime->mm_type == MAILMIME_MESSAGE) {
+ if (mime->mm_data.mm_message.mm_fields != NULL) {
+#if 0
+ r = mailimf_fields_write(f, &col, mime->mm_data.mm_message.mm_fields);
+#endif
+ r = mailimf_fields_write_mem(str, &col, mime->mm_data.mm_message.mm_fields);
+ if (r != MAILIMF_NO_ERROR) {
+ res = maildriver_imf_error_to_mail_error(r);
+ goto free;
+ }
+#if 0
+ mailimf_string_write(f, &col, "\r\n", 2);
+#endif
+ mailimf_string_write_mem(str, &col, "\r\n", 2);
+ }
+ }
+
+ r = mmap_string_ref(str);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free;
+ }
+
+#if 0
+ r = file_to_mmapstr(f, result, result_len);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+#endif
+ * result = str->str;
+ * result_len = str->len;
+
+#if 0
+ fclose(f);
+ unlink(filename);
+#endif
+
+ return MAIL_NO_ERROR;
+
+#if 0
+ close:
+ fclose(f);
+ unlink(filename);
+#endif
+ free:
+ mmap_string_free(str);
+ err:
+ return res;
+}
+
+
+static int fetch_section_mime(mailmessage * msg_info,
+ struct mailmime * mime,
+ char ** result, size_t * result_len)
+{
+ int r;
+#if 0
+ FILE * f;
+#endif
+ int res;
+ int col;
+#if 0
+ char filename[PATH_MAX];
+#endif
+ MMAPString * str;
+
+ if (msg_info->msg_mime == NULL)
+ return MAIL_ERROR_INVAL;
+
+ str = mmap_string_new("");
+ if (str == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+#if 0
+ f = get_mime_tmp_file(msg_info, filename, sizeof(filename));
+ if (f == NULL) {
+ res = MAIL_ERROR_FILE;
+ goto err;
+ }
+#endif
+
+ col = 0;
+ if (mime->mm_content_type != NULL) {
+#if 0
+ r = mailmime_content_write(f, &col, mime->mm_content_type);
+#endif
+ r = mailmime_content_write_mem(str, &col, mime->mm_content_type);
+ if (r != MAILIMF_NO_ERROR) {
+ res = maildriver_imf_error_to_mail_error(r);
+ goto free;
+ }
+ }
+ if (mime->mm_mime_fields != NULL) {
+ r = mailmime_fields_write_mem(str, &col, mime->mm_mime_fields);
+ if (r != MAILIMF_NO_ERROR) {
+ res = maildriver_imf_error_to_mail_error(r);
+ goto free;
+ }
+ }
+ mailimf_string_write_mem(str, &col, "\r\n", 2);
+
+#if 0
+ r = file_to_mmapstr(f, result, result_len);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+
+ fclose(f);
+ unlink(filename);
+#endif
+
+ r = mmap_string_ref(str);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free;
+ }
+
+ * result = str->str;
+ * result_len = str->len;
+
+ return MAIL_NO_ERROR;
+
+#if 0
+ close:
+ fclose(f);
+ unlink(filename);
+#endif
+ free:
+ mmap_string_free(str);
+ err:
+ return res;
+}
+
+
+
+static int fetch_section_body(mailmessage * msg_info,
+ struct mailmime * mime,
+ char ** result, size_t * result_len)
+{
+ int r;
+#if 0
+ FILE * f;
+#endif
+ int res;
+ int col;
+#if 0
+ char filename[PATH_MAX];
+#endif
+ MMAPString * str;
+
+ if (msg_info->msg_mime == NULL)
+ return MAIL_ERROR_INVAL;
+
+ str = mmap_string_new("");
+ if (str == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+#if 0
+ f = get_mime_tmp_file(msg_info, filename, sizeof(filename));
+ if (f == NULL) {
+ res = MAIL_ERROR_FILE;
+ goto err;
+ }
+#endif
+
+ col = 0;
+ if (mime->mm_mime_fields != NULL) {
+#if 0
+ r = mailmime_write(f, &col, mime);
+#endif
+ r = mailmime_write_mem(str, &col, mime);
+ if (r != MAILIMF_NO_ERROR) {
+ res = maildriver_imf_error_to_mail_error(r);
+ goto free;
+ }
+ }
+
+ if (mime->mm_type == MAILMIME_MESSAGE)
+ r = body_body_to_mmapstr(str->str, str->len, result, result_len);
+ else
+ r = body_to_mmapstr(str->str, str->len, result, result_len);
+
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+
+ mmap_string_free(str);
+
+#if 0
+ fclose(f);
+ unlink(filename);
+#endif
+
+ return MAIL_NO_ERROR;
+
+#if 0
+ close:
+ fclose(f);
+ unlink(filename);
+#endif
+ free:
+ mmap_string_free(str);
+ err:
+ return res;
+}
+
+
+static int get_bodystructure(mailmessage * msg_info,
+ struct mailmime ** result)
+{
+ if (msg_info->msg_mime == NULL)
+ return MAIL_ERROR_INVAL;
+
+ * result = msg_info->msg_mime;
+
+ return MAIL_NO_ERROR;
+}
+
+
+static int fetch(mailmessage * msg_info,
+ char ** result, size_t * result_len)
+{
+ return fetch_section(msg_info, msg_info->msg_mime, result, result_len);
+}
+
+static int fetch_header(mailmessage * msg_info,
+ char ** result, size_t * result_len)
+{
+ return fetch_section_header(msg_info,
+ msg_info->msg_mime, result, result_len);
+}
+
+static int fetch_body(mailmessage * msg_info,
+ char ** result, size_t * result_len)
+{
+ return fetch_section_body(msg_info, msg_info->msg_mime, result, result_len);
+}
+
+
+static int fetch_size(mailmessage * msg_info,
+ size_t * result)
+{
+ char * msg;
+ int r;
+
+ r = fetch(msg_info, &msg, result);
+ if (r != MAIL_NO_ERROR) {
+ return r;
+ }
+
+ fetch_result_free(msg_info, msg);
+
+ return MAIL_NO_ERROR;
+}
+
+
+static mailmessage_driver local_mime_message_driver = {
+ .msg_name = "mime",
+
+ .msg_initialize = initialize,
+ .msg_uninitialize = uninitialize,
+
+ .msg_flush = flush,
+ .msg_check = check,
+
+ .msg_fetch_result_free = fetch_result_free,
+
+ .msg_fetch = fetch,
+ .msg_fetch_header = fetch_header,
+ .msg_fetch_body = fetch_body,
+ .msg_fetch_size = fetch_size,
+ .msg_get_bodystructure = get_bodystructure,
+ .msg_fetch_section = fetch_section,
+ .msg_fetch_section_header = fetch_section_header,
+ .msg_fetch_section_mime = fetch_section_mime,
+ .msg_fetch_section_body = fetch_section_body,
+ .msg_fetch_envelope = mailmessage_generic_fetch_envelope,
+
+ .msg_get_flags = NULL,
+};
+
+mailmessage_driver * mime_message_driver = &local_mime_message_driver;
diff --git a/libetpan/src/driver/implementation/mime-message/mime_message_driver.h b/libetpan/src/driver/implementation/mime-message/mime_message_driver.h
new file mode 100644
index 0000000..6cc3c5b
--- a/dev/null
+++ b/libetpan/src/driver/implementation/mime-message/mime_message_driver.h
@@ -0,0 +1,53 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef MIME_MESSAGE_DRIVER_H
+
+#define MIME_MESSAGE_DRIVER_H
+
+#include <libetpan/mailmessage.h>
+
+#define LIBETPAN_MIME_MESSAGE
+
+extern mailmessage_driver * mime_message_driver;
+
+mailmessage * mime_message_init(struct mailmime * mime);
+
+void mime_message_detach_mime(mailmessage * msg);
+
+/* deprecated */
+int mime_message_set_tmpdir(mailmessage * msg, char * tmpdir);
+
+#endif
diff --git a/libetpan/src/driver/implementation/nntp/nntpdriver.c b/libetpan/src/driver/implementation/nntp/nntpdriver.c
new file mode 100644
index 0000000..15b764f
--- a/dev/null
+++ b/libetpan/src/driver/implementation/nntp/nntpdriver.c
@@ -0,0 +1,1180 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "nntpdriver.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "mail.h"
+#include "mailmessage.h"
+#include "nntpdriver_tools.h"
+#include "maildriver_tools.h"
+#include "nntpdriver_message.h"
+
+static int nntpdriver_initialize(mailsession * session);
+
+static void nntpdriver_uninitialize(mailsession * session);
+
+static int nntpdriver_parameters(mailsession * session,
+ int id, void * value);
+
+static int nntpdriver_connect_stream(mailsession * session, mailstream * s);
+
+static int nntpdriver_login(mailsession * session,
+ char * userid, char * password);
+
+static int nntpdriver_logout(mailsession * session);
+
+static int nntpdriver_status_folder(mailsession * session, char * mb,
+ uint32_t * result_messages,
+ uint32_t * result_recent,
+ uint32_t * result_unseen);
+
+static int nntpdriver_messages_number(mailsession * session, char * mb,
+ uint32_t * result);
+
+static int nntpdriver_append_message(mailsession * session,
+ char * message, size_t size);
+
+static int nntpdriver_append_message_flags(mailsession * session,
+ char * message, size_t size, struct mail_flags * flags);
+
+static int
+nntpdriver_get_envelopes_list(mailsession * session,
+ struct mailmessage_list * env_list);
+
+
+static int nntpdriver_get_messages_list(mailsession * session,
+ struct mailmessage_list ** result);
+
+static int nntpdriver_list_folders(mailsession * session, char * mb,
+ struct mail_list ** result);
+
+static int nntpdriver_lsub_folders(mailsession * session, char * mb,
+ struct mail_list ** result);
+
+static int nntpdriver_subscribe_folder(mailsession * session, char * mb);
+
+static int nntpdriver_unsubscribe_folder(mailsession * session, char * mb);
+
+static int nntpdriver_get_message(mailsession * session,
+ uint32_t num, mailmessage ** result);
+
+static int nntpdriver_get_message_by_uid(mailsession * session,
+ const char * uid,
+ mailmessage ** result);
+
+static int nntpdriver_noop(mailsession * session);
+
+static mailsession_driver local_nntp_session_driver = {
+ .sess_name = "nntp",
+
+ .sess_initialize = nntpdriver_initialize,
+ .sess_uninitialize = nntpdriver_uninitialize,
+
+ .sess_parameters = nntpdriver_parameters,
+
+ .sess_connect_stream = nntpdriver_connect_stream,
+ .sess_connect_path = NULL,
+ .sess_starttls = NULL,
+ .sess_login = nntpdriver_login,
+ .sess_logout = nntpdriver_logout,
+ .sess_noop = nntpdriver_noop,
+
+ .sess_build_folder_name = NULL,
+ .sess_create_folder = NULL,
+ .sess_delete_folder = NULL,
+ .sess_rename_folder = NULL,
+ .sess_check_folder = NULL,
+ .sess_examine_folder = NULL,
+ .sess_select_folder = nntpdriver_select_folder,
+ .sess_expunge_folder = NULL,
+ .sess_status_folder = nntpdriver_status_folder,
+ .sess_messages_number = nntpdriver_messages_number,
+ .sess_recent_number = nntpdriver_messages_number,
+ .sess_unseen_number = nntpdriver_messages_number,
+ .sess_list_folders = nntpdriver_list_folders,
+ .sess_lsub_folders = nntpdriver_lsub_folders,
+ .sess_subscribe_folder = nntpdriver_subscribe_folder,
+ .sess_unsubscribe_folder = nntpdriver_unsubscribe_folder,
+
+ .sess_append_message = nntpdriver_append_message,
+ .sess_append_message_flags = nntpdriver_append_message_flags,
+ .sess_copy_message = NULL,
+ .sess_move_message = NULL,
+
+ .sess_get_messages_list = nntpdriver_get_messages_list,
+ .sess_get_envelopes_list = nntpdriver_get_envelopes_list,
+ .sess_remove_message = NULL,
+#if 0
+ .sess_search_messages = maildriver_generic_search_messages,
+#endif
+
+ .sess_get_message = nntpdriver_get_message,
+ .sess_get_message_by_uid = nntpdriver_get_message_by_uid,
+};
+
+
+mailsession_driver * nntp_session_driver = &local_nntp_session_driver;
+
+static inline struct nntp_session_state_data *
+get_data(mailsession * session)
+{
+ return session->sess_data;
+}
+
+static inline newsnntp * get_nntp_session(mailsession * session)
+{
+ return get_data(session)->nntp_session;
+}
+
+static int nntpdriver_initialize(mailsession * session)
+{
+ struct nntp_session_state_data * data;
+ newsnntp * nntp;
+
+ nntp = newsnntp_new(0, NULL);
+ if (nntp == NULL)
+ goto err;
+
+ data = malloc(sizeof(* data));
+ if (data == NULL)
+ goto free;
+
+ data->nntp_session = nntp;
+
+ data->nntp_userid = NULL;
+ data->nntp_password = NULL;
+
+ data->nntp_group_info = NULL;
+ data->nntp_group_name = NULL;
+
+ data->nntp_subscribed_list = clist_new();
+ if (data->nntp_subscribed_list == NULL)
+ goto free_data;
+
+ data->nntp_max_articles = 0;
+
+ data->nntp_mode_reader = FALSE;
+
+ session->sess_data = data;
+
+ return MAIL_NO_ERROR;
+
+ free_data:
+ free(data);
+ free:
+ newsnntp_free(nntp);
+ err:
+ return MAIL_ERROR_MEMORY;
+}
+
+static void nntpdriver_uninitialize(mailsession * session)
+{
+ struct nntp_session_state_data * data;
+
+ data = get_data(session);
+
+ clist_foreach(data->nntp_subscribed_list, (clist_func) free, NULL);
+ clist_free(data->nntp_subscribed_list);
+
+ if (data->nntp_group_info != NULL)
+ newsnntp_group_free(data->nntp_group_info);
+
+ if (data->nntp_group_name != NULL)
+ free(data->nntp_group_name);
+
+ if (data->nntp_userid != NULL)
+ free(data->nntp_userid);
+
+ if (data->nntp_password != NULL)
+ free(data->nntp_password);
+
+ newsnntp_free(data->nntp_session);
+ free(data);
+
+ session->sess_data = NULL;
+}
+
+
+static int nntpdriver_parameters(mailsession * session,
+ int id, void * value)
+{
+ struct nntp_session_state_data * data;
+
+ data = get_data(session);
+
+ switch (id) {
+ case NNTPDRIVER_SET_MAX_ARTICLES:
+ {
+ uint32_t * param;
+
+ param = value;
+
+ data->nntp_max_articles = * param;
+ return MAIL_NO_ERROR;
+ }
+ }
+
+ return MAIL_ERROR_INVAL;
+}
+
+
+static int add_to_list(mailsession * session, char * mb)
+{
+ char * new_mb;
+ int r;
+ struct nntp_session_state_data * data;
+
+ data = get_data(session);
+
+ new_mb = strdup(mb);
+ if (new_mb == NULL)
+ return -1;
+
+ r = clist_append(data->nntp_subscribed_list, new_mb);
+ if (r < 0) {
+ free(mb);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int remove_from_list(mailsession * session, char * mb)
+{
+ clistiter * cur;
+ struct nntp_session_state_data * data;
+
+ data = get_data(session);
+
+ for(cur = clist_begin(data->nntp_subscribed_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ char * cur_name;
+
+ cur_name = clist_content(cur);
+ if (strcmp(cur_name, mb) == 0) {
+ clist_delete(data->nntp_subscribed_list, cur);
+ free(cur_name);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
+
+static int nntpdriver_connect_stream(mailsession * session, mailstream * s)
+{
+ int r;
+
+ r = newsnntp_connect(get_nntp_session(session), s);
+
+ switch (r) {
+ case NEWSNNTP_NO_ERROR:
+ return MAIL_NO_ERROR_NON_AUTHENTICATED;
+
+ default:
+ return nntpdriver_nntp_error_to_mail_error(r);
+ }
+}
+
+static int nntpdriver_login(mailsession * session,
+ char * userid, char * password)
+{
+ struct nntp_session_state_data * data;
+ char * new_userid;
+ char * new_password;
+
+ data = get_data(session);
+
+ if (userid != NULL) {
+ new_userid = strdup(userid);
+ if (new_userid == NULL)
+ goto err;
+ }
+ else
+ new_userid = NULL;
+
+ if (password != NULL) {
+ new_password = strdup(password);
+ if (new_password == NULL)
+ goto free_uid;
+ }
+ else
+ new_password = NULL;
+
+ data->nntp_userid = new_userid;
+ data->nntp_password = new_password;
+
+ return MAIL_NO_ERROR;
+
+ free_uid:
+ if (new_userid != NULL)
+ free(new_userid);
+ err:
+ return MAIL_ERROR_MEMORY;
+}
+
+static int nntpdriver_logout(mailsession * session)
+{
+ int r;
+
+ r = newsnntp_quit(get_nntp_session(session));
+
+ return nntpdriver_nntp_error_to_mail_error(r);
+}
+
+
+static int nntpdriver_status_folder(mailsession * session, char * mb,
+ uint32_t * result_messages,
+ uint32_t * result_recent,
+ uint32_t * result_unseen)
+{
+ uint32_t count;
+ int r;
+
+ r = nntpdriver_select_folder(session, mb);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ r = nntpdriver_messages_number(session, mb, &count);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ * result_messages = count;
+ * result_recent = count;
+ * result_unseen = count;
+
+ return MAIL_NO_ERROR;
+}
+
+static int nntpdriver_messages_number(mailsession * session, char * mb,
+ uint32_t * result)
+{
+ int r;
+ struct nntp_session_state_data * data;
+
+ if (mb != NULL) {
+ r = nntpdriver_select_folder(session, mb);
+ if (r != MAIL_NO_ERROR)
+ return r;
+ }
+
+ data = get_data(session);
+
+ if (data->nntp_group_info == NULL)
+ return MAIL_ERROR_FOLDER_NOT_FOUND;
+
+ * result = data->nntp_group_info->grp_last -
+ data->nntp_group_info->grp_first + 1;
+
+ return MAIL_NO_ERROR;
+}
+
+static int nntpdriver_list_folders(mailsession * session, char * mb,
+ struct mail_list ** result)
+{
+ int r;
+ clist * group_list;
+ newsnntp * nntp;
+ clistiter * cur;
+ char * new_mb;
+ int done;
+ clist * list;
+ struct mail_list * ml;
+ int res;
+
+ nntp = get_nntp_session(session);
+
+ new_mb = NULL;
+ if ((mb != NULL) && (*mb != '\0')) {
+ new_mb = malloc(strlen(mb) + 3);
+ if (new_mb == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+ strcpy(new_mb, mb);
+ strcat(new_mb, ".*");
+ }
+
+ done = FALSE;
+ do {
+ if (new_mb != NULL)
+ r = newsnntp_list_active(nntp, new_mb, &group_list);
+ else
+ r = newsnntp_list(nntp, &group_list);
+
+ switch (r) {
+ case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME:
+ r = nntpdriver_authenticate_user(session);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+ break;
+
+ case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD:
+ r = nntpdriver_authenticate_password(session);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+ break;
+
+ case NEWSNNTP_NO_ERROR:
+ if (new_mb != NULL)
+ free(new_mb);
+ done = TRUE;
+ break;
+
+ default:
+ if (new_mb != NULL)
+ free(new_mb);
+ return nntpdriver_nntp_error_to_mail_error(r);
+ }
+ }
+ while (!done);
+
+ list = clist_new();
+ if (list == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ for(cur = clist_begin(group_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct newsnntp_group_info * info;
+ char * new_name;
+
+ info = clist_content(cur);
+ new_name = strdup(info->grp_name);
+ if (new_name == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ r = clist_append(list, new_name);
+ if (r < 0) {
+ free(new_name);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+ }
+
+ ml = mail_list_new(list);
+ if (ml == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ newsnntp_list_free(group_list);
+
+ * result = ml;
+
+ return MAIL_NO_ERROR;
+
+ free_list:
+ clist_foreach(list, (clist_func) free, NULL);
+ clist_free(list);
+ newsnntp_list_free(group_list);
+ err:
+ return res;
+}
+
+static int nntpdriver_lsub_folders(mailsession * session, char * mb,
+ struct mail_list ** result)
+{
+ clist * subscribed;
+ clist * lsub_result;
+ clistiter * cur;
+ struct mail_list * lsub;
+ size_t length;
+ int res;
+ int r;
+ struct nntp_session_state_data * data;
+
+ length = strlen(mb);
+
+ data = get_data(session);
+
+ subscribed = data->nntp_subscribed_list;
+ lsub_result = clist_new();
+ if (lsub_result == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ for(cur = clist_begin(subscribed) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ char * cur_mb;
+ char * new_mb;
+
+ cur_mb = clist_content(cur);
+
+ if (strncmp(mb, cur_mb, length) == 0) {
+ new_mb = strdup(cur_mb);
+ if (new_mb == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ r = clist_append(lsub_result, new_mb);
+ if (r < 0) {
+ free(new_mb);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+ }
+ }
+
+ lsub = mail_list_new(lsub_result);
+ if (lsub == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ * result = lsub;
+
+ return MAIL_NO_ERROR;
+
+ free_list:
+ clist_foreach(lsub_result, (clist_func) free, NULL);
+ clist_free(lsub_result);
+ err:
+ return res;
+}
+
+static int nntpdriver_subscribe_folder(mailsession * session, char * mb)
+{
+ int r;
+
+ r = add_to_list(session, mb);
+ if (r < 0)
+ return MAIL_ERROR_SUBSCRIBE;
+
+ return MAIL_NO_ERROR;
+}
+
+static int nntpdriver_unsubscribe_folder(mailsession * session, char * mb)
+{
+ int r;
+
+ r = remove_from_list(session, mb);
+ if (r < 0)
+ return MAIL_ERROR_UNSUBSCRIBE;
+
+ return MAIL_NO_ERROR;
+}
+
+
+
+/* messages operations */
+
+static int nntpdriver_append_message(mailsession * session,
+ char * message, size_t size)
+{
+ int r;
+ struct nntp_session_state_data * data;
+
+ data = get_data(session);
+
+ do {
+ r = newsnntp_post(get_nntp_session(session), message, size);
+ switch (r) {
+ case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME:
+ r = nntpdriver_authenticate_user(session);
+ if (r != MAIL_NO_ERROR)
+ return r;
+ break;
+
+ case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD:
+ r = nntpdriver_authenticate_password(session);
+ if (r != MAIL_NO_ERROR)
+ return r;
+ break;
+
+ default:
+ return nntpdriver_nntp_error_to_mail_error(r);
+ }
+ }
+ while (1);
+}
+
+static int nntpdriver_append_message_flags(mailsession * session,
+ char * message, size_t size, struct mail_flags * flags)
+{
+ return nntpdriver_append_message(session, message, size);
+}
+
+
+static int xover_resp_to_fields(struct newsnntp_xover_resp_item * item,
+ struct mailimf_fields ** result);
+
+
+static int
+nntpdriver_get_envelopes_list(mailsession * session,
+ struct mailmessage_list * env_list)
+{
+ newsnntp * nntp;
+ int r;
+ struct nntp_session_state_data * data;
+ clist * list;
+ int done;
+ clistiter * cur;
+ uint32_t first_seq;
+ unsigned int i;
+
+ nntp = get_nntp_session(session);
+
+ data = get_data(session);
+
+ if (data->nntp_group_info == NULL)
+ return MAIL_ERROR_BAD_STATE;
+
+ first_seq = data->nntp_group_info->grp_first;
+
+ if (carray_count(env_list->msg_tab) > 0) {
+ mailmessage * msg;
+
+ msg = carray_get(env_list->msg_tab, 0);
+
+ first_seq = msg->msg_index;
+ }
+
+ if (carray_count(env_list->msg_tab) > 0) {
+ i = carray_count(env_list->msg_tab) - 1;
+ while (1) {
+ mailmessage * msg;
+
+ msg = carray_get(env_list->msg_tab, i);
+
+ if (msg->msg_fields != NULL) {
+ first_seq = msg->msg_index + 1;
+ break;
+ }
+
+ if (i == 0)
+ break;
+
+ i --;
+ }
+ }
+
+ if (first_seq > data->nntp_group_info->grp_last) {
+ list = NULL;
+ }
+ else {
+ done = FALSE;
+ do {
+ r = newsnntp_xover_range(nntp, first_seq,
+ data->nntp_group_info->grp_last, &list);
+
+ switch (r) {
+ case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME:
+ r = nntpdriver_authenticate_user(session);
+ if (r != MAIL_NO_ERROR)
+ return r;
+ break;
+
+ case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD:
+ r = nntpdriver_authenticate_password(session);
+ if (r != MAIL_NO_ERROR)
+ return r;
+ break;
+
+ case NEWSNNTP_NO_ERROR:
+ done = TRUE;
+ break;
+
+ default:
+ return nntpdriver_nntp_error_to_mail_error(r);
+ }
+ }
+ while (!done);
+ }
+
+#if 0
+ i = 0;
+ j = 0;
+
+ if (list != NULL) {
+ for(cur = clist_begin(list) ; cur != NULL ; cur = clist_next(cur)) {
+ struct newsnntp_xover_resp_item * item;
+ struct mailimf_fields * fields;
+
+ item = clist_content(cur);
+
+ while (i < carray_count(env_list->msg_tab)) {
+ mailmessage * info;
+
+ info = carray_get(env_list->msg_tab, i);
+
+ if (item->ovr_article == info->msg_index) {
+
+ if (info->fields == NULL) {
+ r = xover_resp_to_fields(item, &fields);
+ if (r == MAIL_NO_ERROR) {
+ info->fields = fields;
+ }
+
+ info->size = item->ovr_size;
+
+ carray_set(env_list->msg_tab, j, info);
+ j ++;
+ i ++;
+ break;
+ }
+ else {
+ carray_set(env_list->msg_tab, j, info);
+ j ++;
+ }
+ }
+ else {
+ if (info->fields != NULL) {
+ carray_set(env_list->msg_tab, j, info);
+ j ++;
+ }
+ else {
+ if (info->flags != NULL) {
+ info->flags->flags &= ~MAIL_FLAG_NEW;
+ info->flags->flags |= MAIL_FLAG_SEEN | MAIL_FLAG_DELETED;
+ mailmessage_check(info);
+ }
+ mailmessage_free(info);
+ carray_set(env_list->msg_tab, i, NULL);
+ }
+ }
+
+ i ++;
+ }
+ }
+ }
+
+ while (i < carray_count(env_list->msg_tab)) {
+ mailmessage * info;
+
+ info = carray_get(env_list->msg_tab, i);
+ if (info->fields != NULL) {
+ carray_set(env_list->msg_tab, j, info);
+ j ++;
+ }
+ else {
+ if (info->flags != NULL) {
+ info->flags->flags &= ~MAIL_FLAG_NEW;
+ info->flags->flags |= MAIL_FLAG_SEEN | MAIL_FLAG_DELETED;
+ mailmessage_check(info);
+ }
+ mailmessage_free(info);
+ carray_set(env_list->msg_tab, i, NULL);
+ }
+
+ i ++;
+ }
+
+ r = carray_set_size(env_list->msg_tab, j);
+ if (r < 0) {
+ if (list != NULL)
+ newsnntp_xover_resp_list_free(list);
+ return MAIL_ERROR_MEMORY;
+ }
+#endif
+ i = 0;
+
+ if (list != NULL) {
+ for(cur = clist_begin(list) ; cur != NULL ; cur = clist_next(cur)) {
+ struct newsnntp_xover_resp_item * item;
+ struct mailimf_fields * fields;
+
+ item = clist_content(cur);
+
+ while (i < carray_count(env_list->msg_tab)) {
+ mailmessage * info;
+
+ info = carray_get(env_list->msg_tab, i);
+
+ if (item->ovr_article == info->msg_index) {
+
+ if (info->msg_fields == NULL) {
+ r = xover_resp_to_fields(item, &fields);
+ if (r == MAIL_NO_ERROR) {
+ info->msg_fields = fields;
+ }
+
+ info->msg_size = item->ovr_size;
+
+ i ++;
+ break;
+ }
+ }
+#if 0
+ else if ((info->fields == NULL) && (info->flags != NULL)) {
+ info->flags->flags &= ~MAIL_FLAG_NEW;
+ info->flags->flags |= MAIL_FLAG_CANCELLED;
+ mailmessage_check(info);
+ }
+#endif
+
+ i ++;
+ }
+ }
+ }
+
+#if 0
+ while (i < env_list->msg_tab->len) {
+ mailmessage * info;
+
+ info = carray_get(env_list->msg_tab, i);
+ if ((info->fields == NULL) && (info->flags != NULL)) {
+ info->flags->flags &= ~MAIL_FLAG_NEW;
+ info->flags->flags |= MAIL_FLAG_CANCELLED;
+ mailmessage_check(info);
+ }
+
+ i ++;
+ }
+#endif
+
+ if (list != NULL)
+ newsnntp_xover_resp_list_free(list);
+
+ return MAIL_NO_ERROR;
+}
+
+
+static int xover_resp_to_fields(struct newsnntp_xover_resp_item * item,
+ struct mailimf_fields ** result)
+{
+ size_t cur_token;
+ clist * list;
+ int r;
+ struct mailimf_fields * fields;
+ int res;
+
+ list = clist_new();
+ if (list == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ if (item->ovr_subject != NULL) {
+ char * subject_str;
+ struct mailimf_subject * subject;
+ struct mailimf_field * field;
+
+ subject_str = strdup(item->ovr_subject);
+ if (subject_str == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ subject = mailimf_subject_new(subject_str);
+ if (subject == NULL) {
+ free(subject_str);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ field = mailimf_field_new(MAILIMF_FIELD_SUBJECT,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, subject, NULL, NULL, NULL);
+ if (field == NULL) {
+ mailimf_subject_free(subject);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ r = clist_append(list, field);
+ if (r < 0) {
+ mailimf_field_free(field);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+ }
+
+ if (item->ovr_author != NULL) {
+ struct mailimf_mailbox_list * mb_list;
+ struct mailimf_from * from;
+ struct mailimf_field * field;
+
+ cur_token = 0;
+ r = mailimf_mailbox_list_parse(item->ovr_author, strlen(item->ovr_author),
+ &cur_token, &mb_list);
+ switch (r) {
+ case MAILIMF_NO_ERROR:
+ from = mailimf_from_new(mb_list);
+ if (from == NULL) {
+ mailimf_mailbox_list_free(mb_list);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ field = mailimf_field_new(MAILIMF_FIELD_FROM,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, from,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL);
+ if (field == NULL) {
+ mailimf_from_free(from);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ r = clist_append(list, field);
+ if (r < 0) {
+ mailimf_field_free(field);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+ break;
+
+ case MAILIMF_ERROR_PARSE:
+ break;
+
+ default:
+ res = maildriver_imf_error_to_mail_error(r);
+ goto free_list;
+ }
+ }
+
+ if (item->ovr_date != NULL) {
+ struct mailimf_date_time * date_time;
+ struct mailimf_orig_date * orig_date;
+ struct mailimf_field * field;
+
+ cur_token = 0;
+ r = mailimf_date_time_parse(item->ovr_date, strlen(item->ovr_date),
+ &cur_token, &date_time);
+ switch (r) {
+ case MAILIMF_NO_ERROR:
+ orig_date = mailimf_orig_date_new(date_time);
+ if (orig_date == NULL) {
+ mailimf_date_time_free(date_time);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ field = mailimf_field_new(MAILIMF_FIELD_ORIG_DATE,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, orig_date, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL);
+ if (field == NULL) {
+ mailimf_orig_date_free(orig_date);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ r = clist_append(list, field);
+ if (r < 0) {
+ mailimf_field_free(field);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+ break;
+
+ case MAILIMF_ERROR_PARSE:
+ break;
+
+ default:
+ res = maildriver_imf_error_to_mail_error(r);
+ goto free_list;
+ }
+ }
+
+ if (item->ovr_message_id != NULL) {
+ char * msgid_str;
+ struct mailimf_message_id * msgid;
+ struct mailimf_field * field;
+
+ cur_token = 0;
+ r = mailimf_msg_id_parse(item->ovr_message_id, strlen(item->ovr_message_id),
+ &cur_token, &msgid_str);
+
+ switch (r) {
+ case MAILIMF_NO_ERROR:
+ msgid = mailimf_message_id_new(msgid_str);
+ if (msgid == NULL) {
+ mailimf_msg_id_free(msgid_str);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ field = mailimf_field_new(MAILIMF_FIELD_MESSAGE_ID,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, msgid, NULL,
+ NULL, NULL, NULL, NULL, NULL);
+
+ r = clist_append(list, field);
+ if (r < 0) {
+ mailimf_field_free(field);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+ break;
+
+ case MAILIMF_ERROR_PARSE:
+ break;
+
+ default:
+ res = maildriver_imf_error_to_mail_error(r);
+ goto free_list;
+ }
+ }
+
+ if (item->ovr_references != NULL) {
+ clist * msgid_list;
+ struct mailimf_references * references;
+ struct mailimf_field * field;
+
+ cur_token = 0;
+
+ r = mailimf_msg_id_list_parse(item->ovr_references, strlen(item->ovr_references),
+ &cur_token, &msgid_list);
+
+ switch (r) {
+ case MAILIMF_NO_ERROR:
+ references = mailimf_references_new(msgid_list);
+ if (references == NULL) {
+ clist_foreach(msgid_list,
+ (clist_func) mailimf_msg_id_free, NULL);
+ clist_free(msgid_list);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ field = mailimf_field_new(MAILIMF_FIELD_REFERENCES,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ references, NULL, NULL, NULL, NULL);
+
+ r = clist_append(list, field);
+ if (r < 0) {
+ mailimf_field_free(field);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ case MAILIMF_ERROR_PARSE:
+ break;
+
+ default:
+ res = maildriver_imf_error_to_mail_error(r);
+ goto free_list;
+ }
+ }
+
+ fields = mailimf_fields_new(list);
+ if (fields == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ * result = fields;
+
+ return MAIL_NO_ERROR;
+
+ free_list:
+ clist_foreach(list, (clist_func) mailimf_field_free, NULL);
+ clist_free(list);
+ err:
+ return res;
+}
+
+
+/* get messages list with group info */
+
+static int nntpdriver_get_messages_list(mailsession * session,
+ struct mailmessage_list ** result)
+{
+ return nntp_get_messages_list(session, session, nntp_message_driver, result);
+
+}
+
+static int nntpdriver_get_message(mailsession * session,
+ uint32_t num, mailmessage ** result)
+{
+ mailmessage * msg_info;
+ int r;
+
+ msg_info = mailmessage_new();
+ if (msg_info == NULL)
+ return MAIL_ERROR_MEMORY;
+
+ r = mailmessage_init(msg_info, session, nntp_message_driver, num, 0);
+ if (r != MAIL_NO_ERROR) {
+ mailmessage_free(msg_info);
+ return r;
+ }
+
+ * result = msg_info;
+
+ return MAIL_NO_ERROR;
+}
+
+static int nntpdriver_noop(mailsession * session)
+{
+ newsnntp * nntp;
+ int r;
+ struct tm tm;
+
+ nntp = get_nntp_session(session);
+
+ r = newsnntp_date(nntp, &tm);
+
+ return nntpdriver_nntp_error_to_mail_error(r);
+}
+
+static int nntpdriver_get_message_by_uid(mailsession * session,
+ const char * uid,
+ mailmessage ** result)
+{
+ uint32_t num;
+ char * p;
+
+ if (uid == NULL)
+ return MAIL_ERROR_INVAL;
+
+ num = strtoul(uid, &p, 10);
+ if ((p == uid) || (* p != '\0'))
+ return MAIL_ERROR_INVAL;
+
+ return nntpdriver_get_message(session, num, result);
+ }
diff --git a/libetpan/src/driver/implementation/nntp/nntpdriver.h b/libetpan/src/driver/implementation/nntp/nntpdriver.h
new file mode 100644
index 0000000..56aaa39
--- a/dev/null
+++ b/libetpan/src/driver/implementation/nntp/nntpdriver.h
@@ -0,0 +1,52 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef NNTPDRIVER_H
+
+#define NNTPDRIVER_H
+
+#include <libetpan/nntpdriver_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern mailsession_driver * nntp_session_driver;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/implementation/nntp/nntpdriver_cached.c b/libetpan/src/driver/implementation/nntp/nntpdriver_cached.c
new file mode 100644
index 0000000..5c29b7b
--- a/dev/null
+++ b/libetpan/src/driver/implementation/nntp/nntpdriver_cached.c
@@ -0,0 +1,1059 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "nntpdriver_cached.h"
+
+#include "libetpan-config.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "mail_cache_db.h"
+
+#include "mail.h"
+#include "mailmessage.h"
+#include "maildriver_tools.h"
+#include "nntpdriver.h"
+#include "maildriver.h"
+#include "newsnntp.h"
+#include "generic_cache.h"
+#include "imfcache.h"
+#include "maillock.h"
+#include "nntpdriver_cached_message.h"
+#include "nntpdriver_tools.h"
+
+static int nntpdriver_cached_initialize(mailsession * session);
+
+static void nntpdriver_cached_uninitialize(mailsession * session);
+
+static int nntpdriver_cached_parameters(mailsession * session,
+ int id, void * value);
+
+static int nntpdriver_cached_connect_stream(mailsession * session,
+ mailstream * s);
+
+static int nntpdriver_cached_login(mailsession * session,
+ char * userid, char * password);
+
+static int nntpdriver_cached_logout(mailsession * session);
+
+static int nntpdriver_cached_check_folder(mailsession * session);
+
+static int nntpdriver_cached_select_folder(mailsession * session, char * mb);
+
+static int nntpdriver_cached_status_folder(mailsession * session,
+ char * mb,
+ uint32_t * result_messages,
+ uint32_t * result_recent,
+ uint32_t * result_unseen);
+
+static int nntpdriver_cached_messages_number(mailsession * session, char * mb,
+ uint32_t * result);
+
+static int nntpdriver_cached_recent_number(mailsession * session, char * mb,
+ uint32_t * result);
+
+static int nntpdriver_cached_unseen_number(mailsession * session, char * mb,
+ uint32_t * result);
+
+static int nntpdriver_cached_append_message(mailsession * session,
+ char * message, size_t size);
+
+static int nntpdriver_cached_append_message_flags(mailsession * session,
+ char * message, size_t size, struct mail_flags * flags);
+
+static int
+nntpdriver_cached_get_envelopes_list(mailsession * session,
+ struct mailmessage_list * env_list);
+
+
+static int
+nntpdriver_cached_get_messages_list(mailsession * session,
+ struct mailmessage_list ** result);
+
+static int nntpdriver_cached_list_folders(mailsession * session, char * mb,
+ struct mail_list ** result);
+
+static int nntpdriver_cached_lsub_folders(mailsession * session, char * mb,
+ struct mail_list ** result);
+
+static int nntpdriver_cached_subscribe_folder(mailsession * session,
+ char * mb);
+
+static int nntpdriver_cached_unsubscribe_folder(mailsession * session,
+ char * mb);
+
+static int nntpdriver_cached_get_message(mailsession * session,
+ uint32_t num, mailmessage ** result);
+
+static int nntpdriver_cached_noop(mailsession * session);
+
+static int nntpdriver_cached_get_message_by_uid(mailsession * session,
+ const char * uid,
+ mailmessage ** result);
+
+static mailsession_driver local_nntp_cached_session_driver = {
+ .sess_name = "nntp-cached",
+
+ .sess_initialize = nntpdriver_cached_initialize,
+ .sess_uninitialize = nntpdriver_cached_uninitialize,
+
+ .sess_parameters = nntpdriver_cached_parameters,
+
+ .sess_connect_stream = nntpdriver_cached_connect_stream,
+ .sess_connect_path = NULL,
+ .sess_starttls = NULL,
+ .sess_login = nntpdriver_cached_login,
+ .sess_logout = nntpdriver_cached_logout,
+ .sess_noop = nntpdriver_cached_noop,
+
+ .sess_build_folder_name = NULL,
+ .sess_create_folder = NULL,
+ .sess_delete_folder = NULL,
+ .sess_rename_folder = NULL,
+ .sess_check_folder = nntpdriver_cached_check_folder,
+ .sess_examine_folder = NULL,
+ .sess_select_folder = nntpdriver_cached_select_folder,
+ .sess_expunge_folder = NULL,
+ .sess_status_folder = nntpdriver_cached_status_folder,
+ .sess_messages_number = nntpdriver_cached_messages_number,
+ .sess_recent_number = nntpdriver_cached_recent_number,
+ .sess_unseen_number = nntpdriver_cached_unseen_number,
+ .sess_list_folders = nntpdriver_cached_list_folders,
+ .sess_lsub_folders = nntpdriver_cached_lsub_folders,
+ .sess_subscribe_folder = nntpdriver_cached_subscribe_folder,
+ .sess_unsubscribe_folder = nntpdriver_cached_unsubscribe_folder,
+
+ .sess_append_message = nntpdriver_cached_append_message,
+ .sess_append_message_flags = nntpdriver_cached_append_message_flags,
+ .sess_copy_message = NULL,
+ .sess_move_message = NULL,
+
+ .sess_get_messages_list = nntpdriver_cached_get_messages_list,
+ .sess_get_envelopes_list = nntpdriver_cached_get_envelopes_list,
+ .sess_remove_message = NULL,
+#if 0
+ .sess_search_messages = maildriver_generic_search_messages,
+#endif
+
+ .sess_get_message = nntpdriver_cached_get_message,
+ .sess_get_message_by_uid = nntpdriver_cached_get_message_by_uid,
+};
+
+
+mailsession_driver * nntp_cached_session_driver =
+&local_nntp_cached_session_driver;
+
+#define ENV_NAME "env.db"
+#define FLAGS_NAME "flags.db"
+
+
+
+static void read_article_seq(mailsession * session,
+ uint32_t * pfirst, uint32_t * plast);
+
+static void write_article_seq(mailsession * session,
+ uint32_t first, uint32_t last);
+
+
+static inline struct nntp_cached_session_state_data *
+get_cached_data(mailsession * session)
+{
+ return session->sess_data;
+}
+
+static inline mailsession * get_ancestor(mailsession * session)
+{
+ return get_cached_data(session)->nntp_ancestor;
+}
+
+static inline struct nntp_session_state_data *
+get_ancestor_data(mailsession * session)
+{
+ return get_ancestor(session)->sess_data;
+}
+
+static inline newsnntp * get_nntp_session(mailsession * session)
+{
+ return get_ancestor_data(session)->nntp_session;
+}
+
+static int nntpdriver_cached_initialize(mailsession * session)
+{
+ struct nntp_cached_session_state_data * data;
+
+ data = malloc(sizeof(* data));
+ if (data == NULL)
+ goto err;
+
+ data->nntp_flags_store = mail_flags_store_new();
+ if (data->nntp_flags_store == NULL)
+ goto free;
+
+ data->nntp_ancestor = mailsession_new(nntp_session_driver);
+ if (data->nntp_ancestor == NULL)
+ goto free_store;
+
+ session->sess_data = data;
+
+ return MAIL_NO_ERROR;
+
+ free_store:
+ mail_flags_store_free(data->nntp_flags_store);
+ free:
+ free(data);
+ err:
+ return MAIL_ERROR_MEMORY;
+}
+
+static int nntp_flags_store_process(char * flags_directory, char * group_name,
+ struct mail_flags_store * flags_store)
+{
+ char filename_flags[PATH_MAX];
+ struct mail_cache_db * cache_db_flags;
+ MMAPString * mmapstr;
+ unsigned int i;
+ int r;
+ int res;
+
+ if (carray_count(flags_store->fls_tab) == 0)
+ return MAIL_NO_ERROR;
+
+ if (group_name == NULL)
+ return MAIL_NO_ERROR;
+
+ snprintf(filename_flags, PATH_MAX, "%s/%s/%s",
+ flags_directory, group_name, FLAGS_NAME);
+
+ r = mail_cache_db_open_lock(filename_flags, &cache_db_flags);
+ if (r < 0) {
+ res = MAIL_ERROR_FILE;
+ goto err;
+ }
+
+ mmapstr = mmap_string_new("");
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto close_db_flags;
+ }
+
+ for(i = 0 ; i < carray_count(flags_store->fls_tab) ; i ++) {
+ mailmessage * msg;
+
+ msg = carray_get(flags_store->fls_tab, i);
+
+ r = nntpdriver_write_cached_flags(cache_db_flags, mmapstr,
+ msg->msg_index, msg->msg_flags);
+ }
+
+ mmap_string_free(mmapstr);
+ mail_cache_db_close_unlock(filename_flags, cache_db_flags);
+
+ mail_flags_store_clear(flags_store);
+
+ return MAIL_NO_ERROR;
+
+ close_db_flags:
+ mail_cache_db_close_unlock(filename_flags, cache_db_flags);
+ err:
+ return res;
+}
+
+static void nntpdriver_cached_uninitialize(mailsession * session)
+{
+ struct nntp_cached_session_state_data * cached_data;
+ struct nntp_session_state_data * ancestor_data;
+
+ cached_data = get_cached_data(session);
+ ancestor_data = get_ancestor_data(session);
+
+ nntp_flags_store_process(cached_data->nntp_flags_directory,
+ ancestor_data->nntp_group_name,
+ cached_data->nntp_flags_store);
+
+ mail_flags_store_free(cached_data->nntp_flags_store);
+
+ mailsession_free(cached_data->nntp_ancestor);
+ free(cached_data);
+
+ session->sess_data = NULL;
+}
+
+static int nntpdriver_cached_parameters(mailsession * session,
+ int id, void * value)
+{
+ struct nntp_cached_session_state_data * cached_data;
+ int r;
+
+ cached_data = get_cached_data(session);
+
+ switch (id) {
+ case NNTPDRIVER_CACHED_SET_CACHE_DIRECTORY:
+ strncpy(cached_data->nntp_cache_directory, value, PATH_MAX);
+ cached_data->nntp_cache_directory[PATH_MAX - 1] = '\0';
+
+ r = generic_cache_create_dir(cached_data->nntp_cache_directory);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ return MAIL_NO_ERROR;
+
+ case NNTPDRIVER_CACHED_SET_FLAGS_DIRECTORY:
+ strncpy(cached_data->nntp_flags_directory, value, PATH_MAX);
+ cached_data->nntp_flags_directory[PATH_MAX - 1] = '\0';
+
+ r = generic_cache_create_dir(cached_data->nntp_flags_directory);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ return MAIL_NO_ERROR;
+
+ default:
+ return mailsession_parameters(get_ancestor(session), id, value);
+ }
+}
+
+static int nntpdriver_cached_connect_stream(mailsession * session,
+ mailstream * s)
+{
+ return mailsession_connect_stream(get_ancestor(session), s);
+}
+
+static int nntpdriver_cached_login(mailsession * session,
+ char * userid, char * password)
+{
+ return mailsession_login(get_ancestor(session), userid, password);
+}
+
+static int nntpdriver_cached_logout(mailsession * session)
+{
+ struct nntp_cached_session_state_data * cached_data;
+ struct nntp_session_state_data * ancestor_data;
+
+ cached_data = get_cached_data(session);
+ ancestor_data = get_ancestor_data(session);
+
+ nntp_flags_store_process(cached_data->nntp_flags_directory,
+ ancestor_data->nntp_group_name,
+ cached_data->nntp_flags_store);
+
+ return mailsession_logout(get_ancestor(session));
+}
+
+static int nntpdriver_cached_select_folder(mailsession * session, char * mb)
+{
+ int r;
+ struct nntp_session_state_data * ancestor_data;
+ struct nntp_cached_session_state_data * cached_data;
+ int res;
+ char key[PATH_MAX];
+
+ cached_data = get_cached_data(session);
+ ancestor_data = get_ancestor_data(session);
+
+ nntp_flags_store_process(cached_data->nntp_flags_directory,
+ ancestor_data->nntp_group_name,
+ cached_data->nntp_flags_store);
+
+ r = mailsession_select_folder(get_ancestor(session), mb);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ if (ancestor_data->nntp_group_name == NULL)
+ return MAIL_ERROR_BAD_STATE;
+
+ snprintf(key, PATH_MAX, "%s/%s", cached_data->nntp_cache_directory,
+ ancestor_data->nntp_group_name);
+
+ r = generic_cache_create_dir(key);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ snprintf(key, PATH_MAX, "%s/%s", cached_data->nntp_flags_directory,
+ ancestor_data->nntp_group_name);
+
+ r = generic_cache_create_dir(key);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ return MAIL_NO_ERROR;
+
+ err:
+ return res;
+}
+
+static int nntpdriver_cached_check_folder(mailsession * session)
+{
+ struct nntp_session_state_data * ancestor_data;
+ struct nntp_cached_session_state_data * cached_data;
+
+ cached_data = get_cached_data(session);
+ ancestor_data = get_ancestor_data(session);
+
+ nntp_flags_store_process(cached_data->nntp_flags_directory,
+ ancestor_data->nntp_group_name,
+ cached_data->nntp_flags_store);
+
+ return MAIL_NO_ERROR;
+}
+
+
+static int nntpdriver_cached_status_folder(mailsession * session,
+ char * mb, uint32_t * result_messages, uint32_t * result_recent,
+ uint32_t * result_unseen)
+{
+ int res;
+ struct nntp_cached_session_state_data * cached_data;
+ struct nntp_session_state_data * ancestor_data;
+ char filename_flags[PATH_MAX];
+ struct mail_cache_db * cache_db_flags;
+ MMAPString * mmapstr;
+ uint32_t i;
+ int r;
+ uint32_t recent;
+ uint32_t unseen;
+ uint32_t first;
+ uint32_t last;
+ uint32_t count;
+ uint32_t additionnal;
+
+ r = nntpdriver_cached_select_folder(session, mb);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ read_article_seq(session, &first, &last);
+
+ count = 0;
+ recent = 0;
+ unseen = 0;
+
+ ancestor_data = get_ancestor_data(session);
+ cached_data = get_cached_data(session);
+ if (ancestor_data->nntp_group_name == NULL) {
+ res = MAIL_ERROR_BAD_STATE;
+ goto err;
+ }
+
+ if (ancestor_data->nntp_group_info->grp_first > first)
+ first = ancestor_data->nntp_group_info->grp_first;
+ if (last < first)
+ last = ancestor_data->nntp_group_info->grp_last;
+
+ snprintf(filename_flags, PATH_MAX, "%s/%s/%s",
+ cached_data->nntp_flags_directory,
+ ancestor_data->nntp_group_name, FLAGS_NAME);
+
+ r = mail_cache_db_open_lock(filename_flags, &cache_db_flags);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ mmapstr = mmap_string_new("");
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto close_db_flags;
+ }
+
+ for(i = first ; i <= last ; i++) {
+ struct mail_flags * flags;
+
+ r = nntpdriver_get_cached_flags(cache_db_flags, mmapstr,
+ i, &flags);
+ if (r == MAIL_NO_ERROR) {
+ if ((flags->fl_flags & MAIL_FLAG_CANCELLED) != 0) {
+ mail_flags_free(flags);
+ continue;
+ }
+
+ count ++;
+ if ((flags->fl_flags & MAIL_FLAG_NEW) != 0) {
+ recent ++;
+ }
+ if ((flags->fl_flags & MAIL_FLAG_SEEN) == 0) {
+ unseen ++;
+ }
+ mail_flags_free(flags);
+ }
+ }
+
+ if ((count == 0) && (first != last)) {
+ count = last - first + 1;
+ recent = count;
+ unseen = count;
+ }
+
+ additionnal = ancestor_data->nntp_group_info->grp_last - last;
+ recent += additionnal;
+ unseen += additionnal;
+
+ mmap_string_free(mmapstr);
+ mail_cache_db_close_unlock(filename_flags, cache_db_flags);
+
+ * result_messages = count;
+ * result_recent = recent;
+ * result_unseen = unseen;
+
+ return MAIL_NO_ERROR;
+
+ close_db_flags:
+ mail_cache_db_close_unlock(filename_flags, cache_db_flags);
+ err:
+ return res;
+}
+
+static int nntpdriver_cached_messages_number(mailsession * session,
+ char * mb,
+ uint32_t * result)
+{
+ uint32_t messages;
+ uint32_t recent;
+ uint32_t unseen;
+ int r;
+
+ r = nntpdriver_cached_status_folder(session, mb,
+ &messages, &recent, &unseen);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ * result = messages;
+
+ return MAIL_NO_ERROR;
+}
+
+static int nntpdriver_cached_recent_number(mailsession * session,
+ char * mb,
+ uint32_t * result)
+{
+ uint32_t messages;
+ uint32_t recent;
+ uint32_t unseen;
+ int r;
+
+ r = nntpdriver_cached_status_folder(session, mb,
+ &messages, &recent, &unseen);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ * result = recent;
+
+ return MAIL_NO_ERROR;
+}
+
+static int nntpdriver_cached_unseen_number(mailsession * session,
+ char * mb,
+ uint32_t * result)
+{
+ uint32_t messages;
+ uint32_t recent;
+ uint32_t unseen;
+ int r;
+
+ r = nntpdriver_cached_status_folder(session, mb,
+ &messages, &recent, &unseen);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ * result = unseen;
+
+ return MAIL_NO_ERROR;
+}
+
+static int nntpdriver_cached_list_folders(mailsession * session, char * mb,
+ struct mail_list ** result)
+{
+ return mailsession_list_folders(get_ancestor(session), mb, result);
+}
+
+static int nntpdriver_cached_lsub_folders(mailsession * session, char * mb,
+ struct mail_list ** result)
+{
+ return mailsession_lsub_folders(get_ancestor(session), mb, result);
+}
+
+static int nntpdriver_cached_subscribe_folder(mailsession * session,
+ char * mb)
+{
+ return mailsession_subscribe_folder(get_ancestor(session), mb);
+}
+
+static int nntpdriver_cached_unsubscribe_folder(mailsession * session,
+ char * mb)
+{
+ return mailsession_unsubscribe_folder(get_ancestor(session), mb);
+}
+
+
+
+/* messages operations */
+
+static int nntpdriver_cached_append_message(mailsession * session,
+ char * message, size_t size)
+{
+ return mailsession_append_message(get_ancestor(session), message, size);
+}
+
+static int nntpdriver_cached_append_message_flags(mailsession * session,
+ char * message, size_t size, struct mail_flags * flags)
+{
+ return nntpdriver_cached_append_message(session, message, size);
+}
+
+
+
+static int
+get_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr,
+ mailsession * session, uint32_t num,
+ struct mailimf_fields ** result)
+{
+ char keyname[PATH_MAX];
+ int r;
+ struct mailimf_fields * fields;
+ int res;
+
+ snprintf(keyname, PATH_MAX, "%i-envelope", num);
+
+ r = generic_cache_fields_read(cache_db, mmapstr, keyname, &fields);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ * result = fields;
+
+ return MAIL_NO_ERROR;
+
+ err:
+ return res;
+}
+
+static int
+write_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr,
+ mailsession * session, uint32_t num,
+ struct mailimf_fields * fields)
+{
+ int r;
+ int res;
+ char keyname[PATH_MAX];
+
+ snprintf(keyname, PATH_MAX, "%i-envelope", num);
+
+ r = generic_cache_fields_write(cache_db, mmapstr, keyname, fields);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ return MAIL_NO_ERROR;
+
+ err:
+ return res;
+}
+
+#define SEQ_FILENAME "articles-seq"
+
+static void read_article_seq(mailsession * session,
+ uint32_t * pfirst, uint32_t * plast)
+{
+ FILE * f;
+ struct nntp_session_state_data * ancestor_data;
+ uint32_t first;
+ uint32_t last;
+ char seq_filename[PATH_MAX];
+ struct nntp_cached_session_state_data * cached_data;
+ int r;
+
+ first = 0;
+ last = 0;
+
+ cached_data = get_cached_data(session);
+ ancestor_data = get_ancestor_data(session);
+
+ if (ancestor_data->nntp_group_name == NULL)
+ return;
+
+ snprintf(seq_filename, PATH_MAX, "%s/%s/%s",
+ cached_data->nntp_cache_directory,
+ ancestor_data->nntp_group_name, SEQ_FILENAME);
+ f = fopen(seq_filename, "r");
+
+ if (f != NULL) {
+ int fd;
+
+ fd = fileno(f);
+
+ r = maillock_read_lock(seq_filename, fd);
+ if (r == 0) {
+ MMAPString * mmapstr;
+ size_t cur_token;
+ char buf[sizeof(uint32_t) * 2];
+ size_t read_size;
+
+ read_size = fread(buf, 1, sizeof(uint32_t) * 2, f);
+ mmapstr = mmap_string_new_len(buf, read_size);
+ if (mmapstr != NULL) {
+ cur_token = 0;
+ r = mailimf_cache_int_read(mmapstr, &cur_token, &first);
+ r = mailimf_cache_int_read(mmapstr, &cur_token, &last);
+
+ mmap_string_free(mmapstr);
+ }
+
+ maillock_read_unlock(seq_filename, fd);
+ }
+ fclose(f);
+ }
+
+ * pfirst = first;
+ * plast = last;
+}
+
+static void write_article_seq(mailsession * session,
+ uint32_t first, uint32_t last)
+{
+ FILE * f;
+ struct nntp_session_state_data * ancestor_data;
+ char seq_filename[PATH_MAX];
+ struct nntp_cached_session_state_data * cached_data;
+ int r;
+ int fd;
+
+ cached_data = get_cached_data(session);
+ ancestor_data = get_ancestor_data(session);
+
+ if (ancestor_data->nntp_group_name == NULL)
+ return;
+
+ snprintf(seq_filename, PATH_MAX, "%s/%s/%s",
+ cached_data->nntp_cache_directory,
+ ancestor_data->nntp_group_name, SEQ_FILENAME);
+
+ fd = creat(seq_filename, S_IRUSR | S_IWUSR);
+ if (fd < 0)
+ return;
+
+ f = fdopen(fd, "w");
+ if (f != NULL) {
+ r = maillock_write_lock(seq_filename, fd);
+ if (r == 0) {
+ MMAPString * mmapstr;
+ size_t cur_token;
+
+ mmapstr = mmap_string_new("");
+ if (mmapstr != NULL) {
+ r = mail_serialize_clear(mmapstr, &cur_token);
+ if (r == MAIL_NO_ERROR) {
+ r = mailimf_cache_int_write(mmapstr, &cur_token, first);
+ r = mailimf_cache_int_write(mmapstr, &cur_token, last);
+
+ fwrite(mmapstr->str, 1, mmapstr->len, f);
+ }
+
+ mmap_string_free(mmapstr);
+ }
+
+ maillock_write_unlock(seq_filename, fd);
+ }
+ fclose(f);
+ }
+ else
+ close(fd);
+}
+
+
+static void get_uid_from_filename(char * filename)
+{
+ char * p;
+
+ if (strcmp(filename, SEQ_FILENAME) == 0)
+ * filename = 0;
+
+ p = strstr(filename, "-header");
+ if (p != NULL)
+ * p = 0;
+}
+
+static int
+nntpdriver_cached_get_envelopes_list(mailsession * session,
+ struct mailmessage_list * env_list)
+{
+ int r;
+ unsigned int i;
+ struct nntp_cached_session_state_data * cached_data;
+ uint32_t first;
+ uint32_t last;
+ struct nntp_session_state_data * ancestor_data;
+ char filename_env[PATH_MAX];
+ char filename_flags[PATH_MAX];
+ struct mail_cache_db * cache_db_env;
+ struct mail_cache_db * cache_db_flags;
+ MMAPString * mmapstr;
+ int res;
+ char cache_dir[PATH_MAX];
+
+ cached_data = get_cached_data(session);
+ ancestor_data = get_ancestor_data(session);
+
+ nntp_flags_store_process(cached_data->nntp_flags_directory,
+ ancestor_data->nntp_group_name,
+ cached_data->nntp_flags_store);
+
+ if (ancestor_data->nntp_group_name == NULL) {
+ res = MAIL_ERROR_BAD_STATE;
+ goto err;
+ }
+
+ /* read articles sequence */
+
+ read_article_seq(session, &first, &last);
+
+ mmapstr = mmap_string_new("");
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ snprintf(filename_env, PATH_MAX, "%s/%s/%s",
+ cached_data->nntp_cache_directory,
+ ancestor_data->nntp_group_name, ENV_NAME);
+
+ r = mail_cache_db_open_lock(filename_env, &cache_db_env);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_mmapstr;
+ }
+
+ snprintf(filename_flags, PATH_MAX, "%s/%s/%s",
+ cached_data->nntp_flags_directory,
+ ancestor_data->nntp_group_name, FLAGS_NAME);
+
+ /* fill with cached */
+
+ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
+ mailmessage * msg;
+ struct mailimf_fields * fields;
+
+ msg = carray_get(env_list->msg_tab, i);
+
+ if ((msg->msg_index < first) || (msg->msg_index > last))
+ continue;
+
+ if (msg->msg_fields == NULL) {
+ r = get_cached_envelope(cache_db_env, mmapstr,
+ session, msg->msg_index, &fields);
+ if (r == MAIL_NO_ERROR) {
+ msg->msg_fields = fields;
+ msg->msg_cached = TRUE;
+ }
+ }
+ }
+
+ mail_cache_db_close_unlock(filename_env, cache_db_env);
+
+ r = mailsession_get_envelopes_list(get_ancestor(session), env_list);
+
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free_mmapstr;
+ }
+
+ r = mail_cache_db_open_lock(filename_flags, &cache_db_flags);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_mmapstr;
+ }
+
+ /* add flags */
+
+ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
+ mailmessage * msg;
+
+ msg = carray_get(env_list->msg_tab, i);
+
+ if (msg->msg_flags == NULL) {
+ struct mail_flags * flags;
+
+ r = nntpdriver_get_cached_flags(cache_db_flags, mmapstr,
+ msg->msg_index, &flags);
+ if (r == MAIL_NO_ERROR) {
+ msg->msg_flags = flags;
+ }
+ else {
+ msg->msg_flags = mail_flags_new_empty();
+ if (msg->msg_fields == NULL) {
+ msg->msg_flags->fl_flags |= MAIL_FLAG_CANCELLED;
+ mailmessage_check(msg);
+ }
+ }
+ }
+ }
+
+ mail_cache_db_close_unlock(filename_flags, cache_db_flags);
+
+ r = mail_cache_db_open_lock(filename_env, &cache_db_env);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_mmapstr;
+ }
+
+ r = mail_cache_db_open_lock(filename_flags, &cache_db_flags);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto close_db_env;
+ }
+
+ /* must write cache */
+
+ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
+ mailmessage * msg;
+
+ msg = carray_get(env_list->msg_tab, i);
+
+ if (msg->msg_fields != NULL) {
+ if (!msg->msg_cached) {
+ r = write_cached_envelope(cache_db_env, mmapstr,
+ session, msg->msg_index, msg->msg_fields);
+ }
+ }
+
+ if (msg->msg_flags != NULL) {
+ r = nntpdriver_write_cached_flags(cache_db_flags, mmapstr,
+ msg->msg_index, msg->msg_flags);
+ }
+ }
+
+ first = 0;
+ last = 0;
+ if (carray_count(env_list->msg_tab) > 0) {
+ mailmessage * msg;
+
+ msg = carray_get(env_list->msg_tab, 0);
+ first = msg->msg_index;
+
+ msg = carray_get(env_list->msg_tab, carray_count(env_list->msg_tab) - 1);
+ last = msg->msg_index;
+ }
+
+ /* write articles sequence */
+
+ write_article_seq(session, first, last);
+
+ /* flush cache */
+
+ maildriver_cache_clean_up(cache_db_env, cache_db_flags, env_list);
+
+ /* remove cache files */
+
+ snprintf(cache_dir, PATH_MAX, "%s/%s",
+ cached_data->nntp_cache_directory, ancestor_data->nntp_group_name);
+
+ mail_cache_db_close_unlock(filename_flags, cache_db_flags);
+ mail_cache_db_close_unlock(filename_env, cache_db_env);
+ mmap_string_free(mmapstr);
+
+ maildriver_message_cache_clean_up(cache_dir, env_list,
+ get_uid_from_filename);
+
+ return MAIL_NO_ERROR;
+
+ close_db_env:
+ mail_cache_db_close_unlock(filename_env, cache_db_env);
+ free_mmapstr:
+ mmap_string_free(mmapstr);
+ err:
+ return res;
+}
+
+static int
+nntpdriver_cached_get_messages_list(mailsession * session,
+ struct mailmessage_list ** result)
+{
+ return nntp_get_messages_list(get_ancestor(session), session,
+ nntp_cached_message_driver, result);
+}
+
+static int nntpdriver_cached_get_message(mailsession * session,
+ uint32_t num, mailmessage ** result)
+{
+ mailmessage * msg_info;
+ int r;
+
+ msg_info = mailmessage_new();
+ if (msg_info == NULL)
+ return MAIL_ERROR_MEMORY;
+
+ r = mailmessage_init(msg_info, session, nntp_cached_message_driver, num, 0);
+ if (r != MAIL_NO_ERROR) {
+ mailmessage_free(msg_info);
+ return r;
+ }
+
+ * result = msg_info;
+
+ return MAIL_NO_ERROR;
+}
+
+static int nntpdriver_cached_noop(mailsession * session)
+{
+ return mailsession_noop(get_ancestor(session));
+}
+
+static int nntpdriver_cached_get_message_by_uid(mailsession * session,
+ const char * uid,
+ mailmessage ** result)
+{
+ uint32_t num;
+ char * p;
+
+ if (uid == NULL)
+ return MAIL_ERROR_INVAL;
+
+ num = strtoul(uid, &p, 10);
+ if ((p == uid) || (* p != '\0'))
+ return MAIL_ERROR_INVAL;
+
+ return nntpdriver_cached_get_message(session, num, result);
+}
diff --git a/libetpan/src/driver/implementation/nntp/nntpdriver_cached.h b/libetpan/src/driver/implementation/nntp/nntpdriver_cached.h
new file mode 100644
index 0000000..c0264de
--- a/dev/null
+++ b/libetpan/src/driver/implementation/nntp/nntpdriver_cached.h
@@ -0,0 +1,52 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef NNTPDRIVER_CACHED_H
+
+#define NNTPDRIVER_CACHED_H
+
+#include <libetpan/nntpdriver_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern mailsession_driver * nntp_cached_session_driver;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/implementation/nntp/nntpdriver_cached_message.c b/libetpan/src/driver/implementation/nntp/nntpdriver_cached_message.c
new file mode 100644
index 0000000..131b689
--- a/dev/null
+++ b/libetpan/src/driver/implementation/nntp/nntpdriver_cached_message.c
@@ -0,0 +1,365 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "nntpdriver_cached_message.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "mail_cache_db.h"
+
+#include "mailmessage.h"
+#include "mailmessage_tools.h"
+#include "nntpdriver.h"
+#include "nntpdriver_tools.h"
+#include "nntpdriver_cached.h"
+#include "nntpdriver_message.h"
+#include "generic_cache.h"
+
+static int nntp_prefetch(mailmessage * msg_info);
+
+static void nntp_prefetch_free(struct generic_message_t * msg);
+
+static int nntp_initialize(mailmessage * msg_info);
+
+static int nntp_fetch_header(mailmessage * msg_info,
+ char ** result,
+ size_t * result_len);
+
+static int nntp_fetch_size(mailmessage * msg_info,
+ size_t * result);
+
+static void nntp_uninitialize(mailmessage * msg_info);
+
+static void nntp_flush(mailmessage * msg_info);
+
+static void nntp_check(mailmessage * msg_info);
+
+static int nntp_get_flags(mailmessage * msg_info,
+ struct mail_flags ** result);
+
+static mailmessage_driver local_nntp_cached_message_driver = {
+ .msg_name = "nntp-cached",
+
+ .msg_initialize = nntp_initialize,
+ .msg_uninitialize = nntp_uninitialize,
+
+ .msg_flush = nntp_flush,
+ .msg_check = nntp_check,
+
+ .msg_fetch_result_free = mailmessage_generic_fetch_result_free,
+
+ .msg_fetch = mailmessage_generic_fetch,
+ .msg_fetch_header = nntp_fetch_header,
+ .msg_fetch_body = mailmessage_generic_fetch_body,
+ .msg_fetch_size = nntp_fetch_size,
+ .msg_get_bodystructure = mailmessage_generic_get_bodystructure,
+ .msg_fetch_section = mailmessage_generic_fetch_section,
+ .msg_fetch_section_header = mailmessage_generic_fetch_section_header,
+ .msg_fetch_section_mime = mailmessage_generic_fetch_section_mime,
+ .msg_fetch_section_body = mailmessage_generic_fetch_section_body,
+ .msg_fetch_envelope = mailmessage_generic_fetch_envelope,
+
+ .msg_get_flags = nntp_get_flags,
+};
+
+mailmessage_driver * nntp_cached_message_driver =
+&local_nntp_cached_message_driver;
+
+static inline struct nntp_cached_session_state_data *
+get_cached_session_data(mailmessage * msg)
+{
+ return msg->msg_session->sess_data;
+}
+
+static inline mailsession * get_ancestor_session(mailmessage * msg)
+{
+ return get_cached_session_data(msg)->nntp_ancestor;
+}
+
+static inline struct nntp_session_state_data *
+get_ancestor_session_data(mailmessage * msg)
+{
+ return get_ancestor_session(msg)->sess_data;
+}
+
+static inline newsnntp *
+get_nntp_session(mailmessage * msg)
+{
+ return get_ancestor_session_data(msg)->nntp_session;
+}
+
+static int nntp_prefetch(mailmessage * msg_info)
+{
+ char * msg_content;
+ size_t msg_length;
+ struct generic_message_t * msg;
+ int r;
+ struct nntp_cached_session_state_data * cached_data;
+ struct nntp_session_state_data * ancestor_data;
+ char filename[PATH_MAX];
+
+ /* we try the cached message */
+
+ cached_data = get_cached_session_data(msg_info);
+
+ ancestor_data = get_ancestor_session_data(msg_info);
+
+ snprintf(filename, PATH_MAX, "%s/%s/%i", cached_data->nntp_cache_directory,
+ ancestor_data->nntp_group_name, msg_info->msg_index);
+
+ r = generic_cache_read(filename, &msg_content, &msg_length);
+ if (r == MAIL_NO_ERROR) {
+ msg = msg_info->msg_data;
+
+ msg->msg_message = msg_content;
+ msg->msg_length = msg_length;
+
+ return MAIL_NO_ERROR;
+ }
+
+ /* we get the message through the network */
+
+ r = nntpdriver_article(get_ancestor_session(msg_info),
+ msg_info->msg_index, &msg_content,
+ &msg_length);
+
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ /* we write the message cache */
+
+ generic_cache_store(filename, msg_content, msg_length);
+
+ msg = msg_info->msg_data;
+
+ msg->msg_message = msg_content;
+ msg->msg_length = msg_length;
+
+ return MAIL_NO_ERROR;
+}
+
+static void nntp_prefetch_free(struct generic_message_t * msg)
+{
+ if (msg->msg_message != NULL) {
+ mmap_string_unref(msg->msg_message);
+ msg->msg_message = NULL;
+ }
+}
+
+static int nntp_initialize(mailmessage * msg_info)
+{
+ struct generic_message_t * msg;
+ int r;
+ char * uid;
+ char static_uid[20];
+
+ snprintf(static_uid, 20, "%u", msg_info->msg_index);
+ uid = strdup(static_uid);
+ if (uid == NULL)
+ return MAIL_ERROR_MEMORY;
+
+ r = mailmessage_generic_initialize(msg_info);
+ if (r != MAIL_NO_ERROR) {
+ free(uid);
+ return r;
+ }
+
+ msg = msg_info->msg_data;
+ msg->msg_prefetch = nntp_prefetch;
+ msg->msg_prefetch_free = nntp_prefetch_free;
+ msg_info->msg_uid = uid;
+
+ return MAIL_NO_ERROR;
+}
+
+
+static void nntp_uninitialize(mailmessage * msg_info)
+{
+ mailmessage_generic_uninitialize(msg_info);
+}
+
+#define FLAGS_NAME "flags.db"
+
+static void nntp_flush(mailmessage * msg_info)
+{
+ mailmessage_generic_flush(msg_info);
+}
+
+
+static void nntp_check(mailmessage * msg_info)
+{
+ int r;
+
+ if (msg_info->msg_flags != NULL) {
+ r = mail_flags_store_set(get_cached_session_data(msg_info)->nntp_flags_store,
+ msg_info);
+ /* ignore errors */
+ }
+}
+
+static int nntp_fetch_header(mailmessage * msg_info,
+ char ** result,
+ size_t * result_len)
+{
+ struct generic_message_t * msg;
+ char * headers;
+ size_t headers_length;
+ struct nntp_cached_session_state_data * cached_data;
+ struct nntp_session_state_data * ancestor_data;
+ int r;
+ char filename[PATH_MAX];
+
+ msg = msg_info->msg_data;
+
+ if (msg->msg_message != NULL)
+ return mailmessage_generic_fetch_header(msg_info,
+ result, result_len);
+
+ /* we try the cached message */
+
+ cached_data = get_cached_session_data(msg_info);
+
+ ancestor_data = get_ancestor_session_data(msg_info);
+
+ snprintf(filename, PATH_MAX, "%s/%s/%i-header",
+ cached_data->nntp_cache_directory,
+ ancestor_data->nntp_group_name, msg_info->msg_index);
+
+ r = generic_cache_read(filename, &headers, &headers_length);
+ if (r == MAIL_NO_ERROR) {
+ * result = headers;
+ * result_len = headers_length;
+
+ return MAIL_NO_ERROR;
+ }
+
+ /* we get the message through the network */
+
+ r = nntpdriver_head(get_ancestor_session(msg_info), msg_info->msg_index,
+ &headers, &headers_length);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ /* we write the message cache */
+
+ generic_cache_store(filename, headers, headers_length);
+
+ * result = headers;
+ * result_len = headers_length;
+
+ return MAIL_NO_ERROR;
+}
+
+static int nntp_fetch_size(mailmessage * msg_info,
+ size_t * result)
+{
+ return nntpdriver_size(get_ancestor_session(msg_info),
+ msg_info->msg_index, result);
+}
+
+static int nntp_get_flags(mailmessage * msg_info,
+ struct mail_flags ** result)
+{
+ int r;
+ struct mail_flags * flags;
+ struct mail_cache_db * cache_db_flags;
+ char filename_flags[PATH_MAX];
+ int res;
+ MMAPString * mmapstr;
+
+ if (msg_info->msg_flags != NULL) {
+ * result = msg_info->msg_flags;
+
+ return MAIL_NO_ERROR;
+ }
+
+ flags = mail_flags_store_get(get_cached_session_data(msg_info)->nntp_flags_store, msg_info->msg_index);
+
+ if (flags == NULL) {
+ struct nntp_cached_session_state_data * cached_data;
+ struct nntp_session_state_data * ancestor_data;
+
+ cached_data = get_cached_session_data(msg_info);
+
+ ancestor_data = get_ancestor_session_data(msg_info);
+ if (ancestor_data->nntp_group_name == NULL) {
+ res = MAIL_ERROR_BAD_STATE;
+ goto err;
+ }
+
+ snprintf(filename_flags, PATH_MAX, "%s/%s/%s",
+ cached_data->nntp_flags_directory,
+ ancestor_data->nntp_group_name, FLAGS_NAME);
+
+ r = mail_cache_db_open_lock(filename_flags, &cache_db_flags);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ mmapstr = mmap_string_new("");
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto close_db_flags;
+ }
+
+ r = nntpdriver_get_cached_flags(cache_db_flags, mmapstr,
+ msg_info->msg_index, &flags);
+ if (r != MAIL_NO_ERROR) {
+ flags = mail_flags_new_empty();
+ if (flags == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_mmapstr;
+ }
+ }
+
+ mmap_string_free(mmapstr);
+ mail_cache_db_close_unlock(filename_flags, cache_db_flags);
+ }
+
+ msg_info->msg_flags = flags;
+
+ * result = flags;
+
+ return MAIL_NO_ERROR;
+
+ free_mmapstr:
+ mmap_string_free(mmapstr);
+ close_db_flags:
+ mail_cache_db_close_unlock(filename_flags, cache_db_flags);
+ err:
+ return res;
+}
diff --git a/libetpan/src/driver/implementation/nntp/nntpdriver_cached_message.h b/libetpan/src/driver/implementation/nntp/nntpdriver_cached_message.h
new file mode 100644
index 0000000..f515d48
--- a/dev/null
+++ b/libetpan/src/driver/implementation/nntp/nntpdriver_cached_message.h
@@ -0,0 +1,52 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include <libetpan/mailmessage_types.h>
+
+#ifndef NNTPDRIVER_CACHED_MESSAGE_H
+
+#define NNTPDRIVER_CACHED_MESSAGE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern mailmessage_driver * nntp_cached_message_driver;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/implementation/nntp/nntpdriver_message.c b/libetpan/src/driver/implementation/nntp/nntpdriver_message.c
new file mode 100644
index 0000000..117bc56
--- a/dev/null
+++ b/libetpan/src/driver/implementation/nntp/nntpdriver_message.c
@@ -0,0 +1,169 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "nntpdriver_message.h"
+
+#include "mailmessage_tools.h"
+#include "nntpdriver_tools.h"
+#include "nntpdriver.h"
+#include "newsnntp.h"
+#include <string.h>
+#include <stdlib.h>
+
+static int nntp_prefetch(mailmessage * msg_info);
+
+static void nntp_prefetch_free(struct generic_message_t * msg);
+
+static int nntp_initialize(mailmessage * msg_info);
+
+static int nntp_fetch_header(mailmessage * msg_info,
+ char ** result,
+ size_t * result_len);
+
+static int nntp_fetch_size(mailmessage * msg_info,
+ size_t * result);
+
+static mailmessage_driver local_nntp_message_driver = {
+ .msg_name = "nntp",
+
+ .msg_initialize = nntp_initialize,
+ .msg_uninitialize = mailmessage_generic_uninitialize,
+
+ .msg_flush = mailmessage_generic_flush,
+ .msg_check = NULL,
+
+ .msg_fetch_result_free = mailmessage_generic_fetch_result_free,
+
+ .msg_fetch = mailmessage_generic_fetch,
+ .msg_fetch_header = nntp_fetch_header,
+ .msg_fetch_body = mailmessage_generic_fetch_body,
+ .msg_fetch_size = nntp_fetch_size,
+ .msg_get_bodystructure = mailmessage_generic_get_bodystructure,
+ .msg_fetch_section = mailmessage_generic_fetch_section,
+ .msg_fetch_section_header = mailmessage_generic_fetch_section_header,
+ .msg_fetch_section_mime = mailmessage_generic_fetch_section_mime,
+ .msg_fetch_section_body = mailmessage_generic_fetch_section_body,
+ .msg_fetch_envelope = mailmessage_generic_fetch_envelope,
+
+ .msg_get_flags = NULL,
+};
+
+mailmessage_driver * nntp_message_driver = &local_nntp_message_driver;
+
+static int nntp_prefetch(mailmessage * msg_info)
+{
+ char * msg_content;
+ size_t msg_length;
+ struct generic_message_t * msg;
+ int r;
+
+ r = nntpdriver_article(msg_info->msg_session, msg_info->msg_index,
+ &msg_content, &msg_length);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ msg = msg_info->msg_data;
+
+ msg->msg_message = msg_content;
+ msg->msg_length = msg_length;
+
+ return MAIL_NO_ERROR;
+}
+
+static void nntp_prefetch_free(struct generic_message_t * msg)
+{
+ if (msg->msg_message != NULL) {
+ mmap_string_unref(msg->msg_message);
+ msg->msg_message = NULL;
+ }
+}
+
+static int nntp_initialize(mailmessage * msg_info)
+{
+ struct generic_message_t * msg;
+ int r;
+ char * uid;
+ char static_uid[20];
+
+ snprintf(static_uid, 20, "%u", msg_info->msg_index);
+ uid = strdup(static_uid);
+ if (uid == NULL)
+ return MAIL_ERROR_MEMORY;
+
+ r = mailmessage_generic_initialize(msg_info);
+ if (r != MAIL_NO_ERROR) {
+ free(uid);
+ return r;
+ }
+
+ msg = msg_info->msg_data;
+ msg->msg_prefetch = nntp_prefetch;
+ msg->msg_prefetch_free = nntp_prefetch_free;
+ msg_info->msg_uid = uid;
+
+ return MAIL_NO_ERROR;
+}
+
+static int nntp_fetch_header(mailmessage * msg_info,
+ char ** result,
+ size_t * result_len)
+{
+ struct generic_message_t * msg;
+ char * headers;
+ size_t headers_length;
+ int r;
+
+ msg = msg_info->msg_data;
+
+ if (msg->msg_message != NULL)
+ return mailmessage_generic_fetch_header(msg_info,
+ result, result_len);
+
+ r = nntpdriver_head(msg_info->msg_session, msg_info->msg_index,
+ &headers, &headers_length);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ * result = headers;
+ * result_len = headers_length;
+
+ return MAIL_NO_ERROR;
+}
+
+static int nntp_fetch_size(mailmessage * msg_info,
+ size_t * result)
+{
+ return nntpdriver_size(msg_info->msg_session, msg_info->msg_index, result);
+}
diff --git a/libetpan/src/driver/implementation/nntp/nntpdriver_message.h b/libetpan/src/driver/implementation/nntp/nntpdriver_message.h
new file mode 100644
index 0000000..15e80b7
--- a/dev/null
+++ b/libetpan/src/driver/implementation/nntp/nntpdriver_message.h
@@ -0,0 +1,52 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef NNTPDRIVER_MESSAGE_H
+
+#define NNTPDRIVER_MESSAGE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libetpan/nntpdriver_types.h>
+
+extern mailmessage_driver * nntp_message_driver;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/implementation/nntp/nntpdriver_tools.c b/libetpan/src/driver/implementation/nntp/nntpdriver_tools.c
new file mode 100644
index 0000000..eef0953
--- a/dev/null
+++ b/libetpan/src/driver/implementation/nntp/nntpdriver_tools.c
@@ -0,0 +1,563 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "nntpdriver_tools.h"
+
+#include "mail.h"
+#include "nntpdriver.h"
+#include "nntpdriver_cached.h"
+#include "newsnntp.h"
+#include "maildriver_types.h"
+#include "generic_cache.h"
+#include "imfcache.h"
+#include "mailmessage.h"
+#include "mail_cache_db.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+
+int nntpdriver_nntp_error_to_mail_error(int error)
+{
+ switch (error) {
+ case NEWSNNTP_NO_ERROR:
+ return MAIL_NO_ERROR;
+
+ case NEWSNNTP_ERROR_STREAM:
+ return MAIL_ERROR_STREAM;
+
+ case NEWSNNTP_ERROR_UNEXPECTED:
+ return MAIL_ERROR_PROGRAM_ERROR;
+
+ case NEWSNNTP_ERROR_NO_NEWSGROUP_SELECTED:
+ return MAIL_ERROR_FOLDER_NOT_FOUND;
+
+ case NEWSNNTP_ERROR_NO_ARTICLE_SELECTED:
+ case NEWSNNTP_ERROR_INVALID_ARTICLE_NUMBER:
+ case NEWSNNTP_ERROR_ARTICLE_NOT_FOUND:
+ return MAIL_ERROR_MSG_NOT_FOUND;
+
+ case NEWSNNTP_ERROR_UNEXPECTED_RESPONSE:
+ case NEWSNNTP_ERROR_INVALID_RESPONSE:
+ return MAIL_ERROR_PARSE;
+
+ case NEWSNNTP_ERROR_NO_SUCH_NEWS_GROUP:
+ return MAIL_ERROR_FOLDER_NOT_FOUND;
+
+ case NEWSNNTP_ERROR_POSTING_NOT_ALLOWED:
+ return MAIL_ERROR_READONLY;
+
+ case NEWSNNTP_ERROR_POSTING_FAILED:
+ return MAIL_ERROR_APPEND;
+
+ case NEWSNNTP_ERROR_PROGRAM_ERROR:
+ return MAIL_ERROR_PROGRAM_ERROR;
+
+ case NEWSNNTP_ERROR_NO_PERMISSION:
+ return MAIL_ERROR_NO_PERMISSION;
+
+ case NEWSNNTP_ERROR_COMMAND_NOT_UNDERSTOOD:
+ case NEWSNNTP_ERROR_COMMAND_NOT_SUPPORTED:
+ return MAIL_ERROR_COMMAND_NOT_SUPPORTED;
+
+ case NEWSNNTP_ERROR_CONNECTION_REFUSED:
+ return MAIL_ERROR_CONNECT;
+
+ case NEWSNNTP_ERROR_MEMORY:
+ return MAIL_ERROR_MEMORY;
+
+ case NEWSNNTP_ERROR_AUTHENTICATION_REJECTED:
+ return MAIL_ERROR_LOGIN;
+
+ case NEWSNNTP_ERROR_BAD_STATE:
+ return MAIL_ERROR_BAD_STATE;
+
+ case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME:
+ case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD:
+ default:
+ return MAIL_ERROR_INVAL;
+ }
+}
+
+static inline struct nntp_session_state_data *
+session_get_data(mailsession * session)
+{
+ return session->sess_data;
+}
+
+static inline newsnntp * session_get_nntp_session(mailsession * session)
+{
+ return session_get_data(session)->nntp_session;
+}
+
+static inline struct nntp_cached_session_state_data *
+cached_session_get_data(mailsession * session)
+{
+ return session->sess_data;
+}
+
+static inline mailsession * cached_session_get_ancestor(mailsession * session)
+{
+ return cached_session_get_data(session)->nntp_ancestor;
+}
+
+static inline struct nntp_session_state_data *
+cached_session_get_ancestor_data(mailsession * session)
+{
+ return session_get_data(cached_session_get_ancestor(session));
+}
+
+static inline newsnntp * cached_session_get_nntp_session(mailsession * session)
+{
+ return session_get_nntp_session(cached_session_get_ancestor(session));
+}
+
+
+int nntpdriver_authenticate_password(mailsession * session)
+{
+ struct nntp_session_state_data * data;
+ int r;
+
+ data = session_get_data(session);
+
+ if (data->nntp_password == NULL)
+ return MAIL_ERROR_LOGIN;
+
+ r = newsnntp_authinfo_password(session_get_nntp_session(session),
+ data->nntp_password);
+
+ return nntpdriver_nntp_error_to_mail_error(r);
+}
+
+int nntpdriver_mode_reader(mailsession * session)
+{
+ int done;
+ int r;
+
+ done = FALSE;
+
+ do {
+ r = newsnntp_mode_reader(session_get_nntp_session(session));
+
+ switch (r) {
+ case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME:
+ r = nntpdriver_authenticate_user(session);
+ if (r != MAIL_NO_ERROR)
+ return r;
+ break;
+
+ case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD:
+ r = nntpdriver_authenticate_password(session);
+ if (r != MAIL_NO_ERROR)
+ return r;
+ break;
+
+ case NEWSNNTP_NO_ERROR:
+ done = TRUE;
+ break;
+
+ default:
+ done = TRUE;
+ break;
+ }
+ }
+ while (!done);
+
+ return MAIL_NO_ERROR;
+}
+
+int nntpdriver_authenticate_user(mailsession * session)
+{
+ struct nntp_session_state_data * data;
+ int r;
+
+ data = session_get_data(session);
+
+ if (data->nntp_userid == NULL)
+ return MAIL_ERROR_LOGIN;
+
+ r = newsnntp_authinfo_username(session_get_nntp_session(session),
+ data->nntp_userid);
+
+ switch (r) {
+ case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD:
+ return nntpdriver_authenticate_password(session);
+
+ default:
+ return nntpdriver_nntp_error_to_mail_error(r);
+ }
+}
+
+int nntpdriver_article(mailsession * session, uint32_t index,
+ char ** result,
+ size_t * result_len)
+{
+ char * msg_content;
+ size_t msg_length;
+ int r;
+ int done;
+
+ done = FALSE;
+ do {
+ r = newsnntp_article(session_get_nntp_session(session),
+ index, &msg_content, &msg_length);
+
+ switch (r) {
+ case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME:
+ r = nntpdriver_authenticate_user(session);
+ if (r != MAIL_NO_ERROR)
+ return r;
+ break;
+
+ case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD:
+ r = nntpdriver_authenticate_password(session);
+ if (r != MAIL_NO_ERROR)
+ return r;
+ break;
+
+ case NEWSNNTP_NO_ERROR:
+ done = TRUE;
+ break;
+
+ default:
+ return nntpdriver_nntp_error_to_mail_error(r);
+ }
+ }
+ while (!done);
+
+ * result = msg_content;
+ * result_len = msg_length;
+
+ return MAIL_NO_ERROR;
+}
+
+int nntpdriver_head(mailsession * session, uint32_t index,
+ char ** result,
+ size_t * result_len)
+{
+ char * headers;
+ size_t headers_length;
+ int r;
+ int done;
+
+ done = FALSE;
+ do {
+ r = newsnntp_head(session_get_nntp_session(session),
+ index, &headers, &headers_length);
+
+ switch (r) {
+ case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME:
+ r = nntpdriver_authenticate_user(session);
+ if (r != MAIL_NO_ERROR)
+ return r;
+ break;
+
+ case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD:
+ r = nntpdriver_authenticate_password(session);
+ if (r != MAIL_NO_ERROR)
+ return r;
+ break;
+
+ case NEWSNNTP_NO_ERROR:
+ done = TRUE;
+ break;
+
+ default:
+ return nntpdriver_nntp_error_to_mail_error(r);
+ }
+ }
+ while (!done);
+
+ * result = headers;
+ * result_len = headers_length;
+
+ return MAIL_NO_ERROR;
+}
+
+int nntpdriver_size(mailsession * session, uint32_t index,
+ size_t * result)
+{
+ newsnntp * nntp;
+ struct newsnntp_xover_resp_item * item;
+ int r;
+ int done;
+
+ nntp = session_get_nntp_session(session);
+
+ done = FALSE;
+ do {
+ r = newsnntp_xover_single(nntp, index, &item);
+ switch (r) {
+ case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME:
+ r = nntpdriver_authenticate_user(session);
+ if (r != MAIL_NO_ERROR)
+ return r;
+ break;
+
+ case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD:
+ r = nntpdriver_authenticate_password(session);
+ if (r != MAIL_NO_ERROR)
+ return r;
+ break;
+
+ case NEWSNNTP_NO_ERROR:
+ done = TRUE;
+ break;
+
+ default:
+ return nntpdriver_nntp_error_to_mail_error(r);
+ }
+ }
+ while (!done);
+
+ * result = item->ovr_size;
+
+ xover_resp_item_free(item);
+
+ return MAIL_NO_ERROR;
+}
+
+int
+nntpdriver_get_cached_flags(struct mail_cache_db * cache_db,
+ MMAPString * mmapstr,
+ uint32_t num,
+ struct mail_flags ** result)
+{
+ int r;
+ char keyname[PATH_MAX];
+ struct mail_flags * flags;
+ int res;
+
+ snprintf(keyname, PATH_MAX, "%u-flags", num);
+
+ r = generic_cache_flags_read(cache_db, mmapstr, keyname, &flags);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ * result = flags;
+
+ return MAIL_NO_ERROR;
+
+ err:
+ return res;
+}
+
+int
+nntpdriver_write_cached_flags(struct mail_cache_db * cache_db,
+ MMAPString * mmapstr,
+ uint32_t num,
+ struct mail_flags * flags)
+{
+ int r;
+ char keyname[PATH_MAX];
+ int res;
+
+ snprintf(keyname, PATH_MAX, "%u-flags", num);
+
+ r = generic_cache_flags_write(cache_db, mmapstr, keyname, flags);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ return MAIL_NO_ERROR;
+
+ err:
+ return res;
+}
+
+
+
+int nntpdriver_select_folder(mailsession * session, char * mb)
+{
+ int r;
+ struct newsnntp_group_info * info;
+ newsnntp * nntp_session;
+ struct nntp_session_state_data * data;
+ char * new_name;
+ int done;
+
+ data = session_get_data(session);
+
+ if (!data->nntp_mode_reader) {
+ r = nntpdriver_mode_reader(session);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ data->nntp_mode_reader = TRUE;
+ }
+
+ if (data->nntp_group_name != NULL)
+ if (strcmp(data->nntp_group_name, mb) == 0)
+ return MAIL_NO_ERROR;
+
+ nntp_session = session_get_nntp_session(session);
+
+ done = FALSE;
+ do {
+ r = newsnntp_group(nntp_session, mb, &info);
+
+ switch (r) {
+ case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_USERNAME:
+ r = nntpdriver_authenticate_user(session);
+ if (r != MAIL_NO_ERROR)
+ return r;
+ break;
+
+ case NEWSNNTP_WARNING_REQUEST_AUTHORIZATION_PASSWORD:
+ r = nntpdriver_authenticate_password(session);
+ if (r != MAIL_NO_ERROR)
+ return r;
+ break;
+
+ case NEWSNNTP_NO_ERROR:
+ done = TRUE;
+ break;
+
+ default:
+ return nntpdriver_nntp_error_to_mail_error(r);
+ }
+
+ }
+ while (!done);
+
+ new_name = strdup(mb);
+ if (new_name == NULL)
+ return MAIL_ERROR_MEMORY;
+
+ if (data->nntp_group_name != NULL)
+ free(data->nntp_group_name);
+ data->nntp_group_name = new_name;
+ if (data->nntp_group_info != NULL)
+ newsnntp_group_free(data->nntp_group_info);
+ data->nntp_group_info = info;
+
+ return MAIL_NO_ERROR;
+}
+
+
+int nntp_get_messages_list(mailsession * nntp_session,
+ mailsession * session,
+ mailmessage_driver * driver,
+ struct mailmessage_list ** result)
+{
+ carray * tab;
+ struct mailmessage_list * env_list;
+ uint32_t i;
+ int res;
+ int r;
+ struct nntp_session_state_data * data;
+ struct newsnntp_group_info * group_info;
+ uint32_t max;
+ unsigned int cur;
+
+ data = session_get_data(nntp_session);
+
+ if (data->nntp_group_name == NULL) {
+ res = MAIL_ERROR_BAD_STATE;
+ goto err;
+ }
+
+ r = nntpdriver_select_folder(nntp_session, data->nntp_group_name);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ group_info = data->nntp_group_info;
+
+ if (group_info == NULL) {
+ res = MAIL_ERROR_BAD_STATE;
+ goto err;
+ }
+
+ max = group_info->grp_first;
+ if (data->nntp_max_articles != 0) {
+ if (group_info->grp_last - data->nntp_max_articles + 1 > max)
+ max = group_info->grp_last - data->nntp_max_articles + 1;
+ }
+
+ tab = carray_new(128);
+ if (tab == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ for(i = max ; i <= group_info->grp_last ; i++) {
+ mailmessage * msg;
+
+ msg = mailmessage_new();
+ if (msg == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ r = mailmessage_init(msg, session, driver, i, 0);
+ if (r != MAIL_NO_ERROR) {
+ mailmessage_free(msg);
+ res = r;
+ goto free_list;
+ }
+
+ r = carray_add(tab, msg, NULL);
+ if (r < 0) {
+ mailmessage_free(msg);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+ }
+
+ env_list = mailmessage_list_new(tab);
+ if (env_list == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ * result = env_list;
+
+ return MAIL_NO_ERROR;
+
+ free_list:
+ for(cur = 0 ; cur < carray_count(tab) ; cur ++)
+ mailmessage_free(carray_get(tab, cur));
+ carray_free(tab);
+ err:
+ return res;
+}
diff --git a/libetpan/src/driver/implementation/nntp/nntpdriver_tools.h b/libetpan/src/driver/implementation/nntp/nntpdriver_tools.h
new file mode 100644
index 0000000..8ca9d16
--- a/dev/null
+++ b/libetpan/src/driver/implementation/nntp/nntpdriver_tools.h
@@ -0,0 +1,88 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef NNTPDRIVER_TOOLS_H
+
+#define NNTPDRIVER_TOOLS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "mail_cache_db_types.h"
+#include "nntpdriver_types.h"
+
+int nntpdriver_nntp_error_to_mail_error(int error);
+
+int nntpdriver_authenticate_password(mailsession * session);
+
+int nntpdriver_authenticate_user(mailsession * session);
+
+int nntpdriver_article(mailsession * session, uint32_t index,
+ char ** result, size_t * result_len);
+
+int nntpdriver_head(mailsession * session, uint32_t index,
+ char ** result,
+ size_t * result_len);
+
+int nntpdriver_size(mailsession * session, uint32_t index,
+ size_t * result);
+
+int
+nntpdriver_get_cached_flags(struct mail_cache_db * cache_db,
+ MMAPString * mmapstr,
+ uint32_t num,
+ struct mail_flags ** result);
+
+int
+nntpdriver_write_cached_flags(struct mail_cache_db * cache_db,
+ MMAPString * mmapstr,
+ uint32_t num,
+ struct mail_flags * flags);
+
+int nntpdriver_select_folder(mailsession * session, char * mb);
+
+int nntp_get_messages_list(mailsession * nntp_session,
+ mailsession * session,
+ mailmessage_driver * driver,
+ struct mailmessage_list ** result);
+
+int nntpdriver_mode_reader(mailsession * session);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/implementation/nntp/nntpdriver_types.h b/libetpan/src/driver/implementation/nntp/nntpdriver_types.h
new file mode 100644
index 0000000..7d4b74d
--- a/dev/null
+++ b/libetpan/src/driver/implementation/nntp/nntpdriver_types.h
@@ -0,0 +1,146 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef NNTPDRIVER_TYPES_H
+
+#define NNTPDRIVER_TYPES_H
+
+#include <libetpan/libetpan-config.h>
+
+#include <libetpan/maildriver_types.h>
+#include <libetpan/newsnntp.h>
+#include <libetpan/clist.h>
+#include <libetpan/generic_cache_types.h>
+#include <libetpan/mailstorage_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* NNTP driver for session */
+
+enum {
+ NNTPDRIVER_SET_MAX_ARTICLES = 1,
+};
+
+struct nntp_session_state_data {
+ newsnntp * nntp_session;
+ char * nntp_userid;
+ char * nntp_password;
+
+ struct newsnntp_group_info * nntp_group_info;
+ char * nntp_group_name;
+
+ clist * nntp_subscribed_list;
+
+ uint32_t nntp_max_articles;
+
+ int nntp_mode_reader;
+};
+
+/* cached NNTP driver for session */
+
+enum {
+ /* the mapping of the parameters should be the same as for nntp */
+ NNTPDRIVER_CACHED_SET_MAX_ARTICLES = 1,
+ /* cache specific */
+ NNTPDRIVER_CACHED_SET_CACHE_DIRECTORY,
+ NNTPDRIVER_CACHED_SET_FLAGS_DIRECTORY,
+};
+
+struct nntp_cached_session_state_data {
+ mailsession * nntp_ancestor;
+ char nntp_cache_directory[PATH_MAX];
+ char nntp_flags_directory[PATH_MAX];
+ struct mail_flags_store * nntp_flags_store;
+};
+
+
+/* nntp storage */
+
+/*
+ nntp_mailstorage is the state data specific to the IMAP4rev1 storage.
+
+ - storage this is the storage to initialize.
+
+ - servername this is the name of the NNTP server
+
+ - port is the port to connect to, on the server.
+ you give 0 to use the default port.
+
+ - connection_type is the type of socket layer to use.
+ The value can be CONNECTION_TYPE_PLAIN or CONNECTION_TYPE_TLS.
+
+ - auth_type is the authenticate mechanism to use.
+ The value can be NNTP_AUTH_TYPE_PLAIN.
+
+ - login is the login of the POP3 account.
+
+ - password is the password of the POP3 account.
+
+ - cached if this value is != 0, a persistant cache will be
+ stored on local system.
+
+ - cache_directory is the location of the cache
+
+ - flags_directory is the location of the flags
+*/
+
+struct nntp_mailstorage {
+ char * nntp_servername;
+ uint16_t nntp_port;
+ char * nntp_command;
+ int nntp_connection_type;
+
+ int nntp_auth_type;
+ char * nntp_login;
+ char * nntp_password;
+
+ int nntp_cached;
+ char * nntp_cache_directory;
+ char * nntp_flags_directory;
+};
+
+/* this is the type of NNTP authentication */
+
+enum {
+ NNTP_AUTH_TYPE_PLAIN, /* plain text authentication */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/implementation/nntp/nntpstorage.c b/libetpan/src/driver/implementation/nntp/nntpstorage.c
new file mode 100644
index 0000000..8d0e4ff
--- a/dev/null
+++ b/libetpan/src/driver/implementation/nntp/nntpstorage.c
@@ -0,0 +1,267 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "nntpstorage.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "maildriver.h"
+#include "nntpdriver.h"
+#include "nntpdriver_cached.h"
+#include "mailstorage_tools.h"
+#include "mail.h"
+
+/* nntp storage */
+
+#define NNTP_DEFAULT_PORT 119
+#define NNTPS_DEFAULT_PORT 563
+
+static int nntp_mailstorage_connect(struct mailstorage * storage);
+static int nntp_mailstorage_get_folder_session(struct mailstorage * storage,
+ char * pathname, mailsession ** result);
+static void nntp_mailstorage_uninitialize(struct mailstorage * storage);
+
+static mailstorage_driver nntp_mailstorage_driver = {
+ .sto_name = "nntp",
+ .sto_connect = nntp_mailstorage_connect,
+ .sto_get_folder_session = nntp_mailstorage_get_folder_session,
+ .sto_uninitialize = nntp_mailstorage_uninitialize,
+};
+
+int nntp_mailstorage_init(struct mailstorage * storage,
+ char * nn_servername, uint16_t nn_port,
+ char * nn_command,
+ int nn_connection_type, int nn_auth_type,
+ char * nn_login, char * nn_password,
+ int nn_cached, char * nn_cache_directory, char * nn_flags_directory)
+{
+ struct nntp_mailstorage * nntp_storage;
+ int res;
+
+ nntp_storage = malloc(sizeof(* nntp_storage));
+ if (nntp_storage == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ nntp_storage->nntp_servername = strdup(nn_servername);
+ if (nntp_storage->nntp_servername == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free;
+ }
+
+ nntp_storage->nntp_connection_type = nn_connection_type;
+
+ if (nn_port == 0) {
+ switch (nn_connection_type) {
+ case CONNECTION_TYPE_PLAIN:
+ case CONNECTION_TYPE_COMMAND:
+ nn_port = NNTP_DEFAULT_PORT;
+ break;
+
+ case CONNECTION_TYPE_TLS:
+ case CONNECTION_TYPE_COMMAND_TLS:
+ nn_port = NNTPS_DEFAULT_PORT;
+ break;
+
+ default:
+ res = MAIL_ERROR_INVAL;
+ goto free_servername;
+ }
+ }
+
+ nntp_storage->nntp_port = nn_port;
+
+ if (nn_command != NULL) {
+ nntp_storage->nntp_command = strdup(nn_command);
+ if (nntp_storage->nntp_command == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_servername;
+ }
+ }
+ else
+ nntp_storage->nntp_command = NULL;
+
+ nntp_storage->nntp_auth_type = nn_auth_type;
+
+ if (nn_login != NULL) {
+ nntp_storage->nntp_login = strdup(nn_login);
+ if (nntp_storage->nntp_login == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_command;
+ }
+ }
+ else
+ nntp_storage->nntp_login = NULL;
+
+ if (nn_password != NULL) {
+ nntp_storage->nntp_password = strdup(nn_password);
+ if (nntp_storage->nntp_password == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_login;
+ }
+ }
+ else
+ nntp_storage->nntp_password = NULL;
+
+ nntp_storage->nntp_cached = nn_cached;
+
+ if (nn_cached && (nn_cache_directory != NULL) &&
+ (nn_flags_directory != NULL)) {
+ nntp_storage->nntp_cache_directory = strdup(nn_cache_directory);
+ if (nntp_storage->nntp_cache_directory == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_password;
+ }
+ nntp_storage->nntp_flags_directory = strdup(nn_flags_directory);
+ if (nntp_storage->nntp_flags_directory == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_cache_directory;
+ }
+ }
+ else {
+ nntp_storage->nntp_cached = FALSE;
+ nntp_storage->nntp_cache_directory = NULL;
+ nntp_storage->nntp_flags_directory = NULL;
+ }
+
+ storage->sto_data = nntp_storage;
+ storage->sto_driver = &nntp_mailstorage_driver;
+
+ return MAIL_NO_ERROR;
+
+ free_cache_directory:
+ free(nntp_storage->nntp_cache_directory);
+ free_password:
+ free(nntp_storage->nntp_password);
+ free_login:
+ free(nntp_storage->nntp_login);
+ free_command:
+ free(nn_command);
+ free_servername:
+ free(nntp_storage->nntp_servername);
+ free:
+ free(nntp_storage);
+ err:
+ return res;
+}
+
+static void nntp_mailstorage_uninitialize(struct mailstorage * storage)
+{
+ struct nntp_mailstorage * nntp_storage;
+
+ nntp_storage = storage->sto_data;
+
+ if (nntp_storage->nntp_flags_directory != NULL)
+ free(nntp_storage->nntp_flags_directory);
+ if (nntp_storage->nntp_cache_directory != NULL)
+ free(nntp_storage->nntp_cache_directory);
+ if (nntp_storage->nntp_password != NULL)
+ free(nntp_storage->nntp_password);
+ if (nntp_storage->nntp_login != NULL)
+ free(nntp_storage->nntp_login);
+ if (nntp_storage->nntp_command != NULL)
+ free(nntp_storage->nntp_command);
+ free(nntp_storage->nntp_servername);
+ free(nntp_storage);
+
+ storage->sto_data = NULL;
+}
+
+static int nntp_mailstorage_connect(struct mailstorage * storage)
+{
+ struct nntp_mailstorage * nntp_storage;
+ mailsession_driver * driver;
+ int r;
+ int res;
+ mailsession * session;
+
+ nntp_storage = storage->sto_data;
+
+ if (nntp_storage->nntp_cached)
+ driver = nntp_cached_session_driver;
+ else
+ driver = nntp_session_driver;
+
+ r = mailstorage_generic_connect(driver,
+ nntp_storage->nntp_servername,
+ nntp_storage->nntp_port, nntp_storage->nntp_command,
+ nntp_storage->nntp_connection_type,
+ NNTPDRIVER_CACHED_SET_CACHE_DIRECTORY,
+ nntp_storage->nntp_cache_directory,
+ NNTPDRIVER_CACHED_SET_FLAGS_DIRECTORY,
+ nntp_storage->nntp_flags_directory,
+ &session);
+ switch (r) {
+ case MAIL_NO_ERROR_NON_AUTHENTICATED:
+ case MAIL_NO_ERROR_AUTHENTICATED:
+ case MAIL_NO_ERROR:
+ break;
+ default:
+ res = r;
+ goto err;
+ }
+
+ r = mailstorage_generic_auth(session, r,
+ nntp_storage->nntp_connection_type,
+ nntp_storage->nntp_login,
+ nntp_storage->nntp_password);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+
+ storage->sto_session = session;
+
+ return MAIL_NO_ERROR;
+
+ free:
+ mailsession_free(session);
+ err:
+ return res;
+}
+
+static int nntp_mailstorage_get_folder_session(struct mailstorage * storage,
+ char * pathname, mailsession ** result)
+{
+ int r;
+
+ r = mailsession_select_folder(storage->sto_session, pathname);
+
+ * result = storage->sto_session;
+
+ return MAIL_NO_ERROR;
+}
diff --git a/libetpan/src/driver/implementation/nntp/nntpstorage.h b/libetpan/src/driver/implementation/nntp/nntpstorage.h
new file mode 100644
index 0000000..7b046f4
--- a/dev/null
+++ b/libetpan/src/driver/implementation/nntp/nntpstorage.h
@@ -0,0 +1,93 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef NNTPSTORAGE_H
+
+#define NNTPSTORAGE_H
+
+#include <libetpan/nntpdriver_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ nntp_mailstorage_init is the constructor for a NNTP storage
+
+ @param storage this is the storage to initialize.
+
+ @param servername this is the name of the NNTP server
+
+ @param port is the port to connect to, on the server.
+ you give 0 to use the default port.
+
+ @param command the command used to connect to the server instead of
+ allowing normal TCP connections to be used.
+
+ @param connection_type is the type of socket layer to use.
+ The value can be CONNECTION_TYPE_PLAIN, CONNECTION_TYPE_STARTTLS,
+ CONNECTION_TYPE_TRY_STARTTLS, CONNECTION_TYPE_TLS,
+ CONNECTION_TYPE_COMMAND, CONNECTION_TYPE_COMMAND_STARTTLS,
+ CONNECTION_TYPE_COMMAND_TRY_STARTTLS, CONNECTION_TYPE_COMMAND_TLS,.
+
+ @param auth_type is the authenticate mechanism to use.
+ The value can be NNTP_AUTH_TYPE_PLAIN.
+
+ @param login is the login of the POP3 account.
+
+ @param password is the password of the POP3 account.
+
+ @param cached if this value is != 0, a persistant cache will be
+ stored on local system.
+
+ @param cache_directory is the location of the cache
+
+ @param flags_directory is the location of the flags
+*/
+
+int nntp_mailstorage_init(struct mailstorage * storage,
+ char * nntp_servername, uint16_t nntp_port,
+ char * nntp_command,
+ int nntp_connection_type, int nntp_auth_type,
+ char * nntp_login, char * nntp_password,
+ int nntp_cached, char * nntp_cache_directory,
+ char * nntp_flags_directory);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/implementation/pop3/pop3driver.c b/libetpan/src/driver/implementation/pop3/pop3driver.c
new file mode 100644
index 0000000..ea69923
--- a/dev/null
+++ b/libetpan/src/driver/implementation/pop3/pop3driver.c
@@ -0,0 +1,388 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "pop3driver.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "pop3driver_message.h"
+#include "maildriver_tools.h"
+#include "pop3driver_tools.h"
+#include "mailmessage.h"
+
+static int pop3driver_initialize(mailsession * session);
+
+static void pop3driver_uninitialize(mailsession * session);
+
+static int pop3driver_parameters(mailsession * session,
+ int id, void * value);
+
+static int pop3driver_connect_stream(mailsession * session, mailstream * s);
+
+static int pop3driver_starttls(mailsession * session);
+
+static int pop3driver_login(mailsession * session,
+ char * userid, char * password);
+
+static int pop3driver_logout(mailsession * session);
+
+static int pop3driver_noop(mailsession * session);
+
+static int pop3driver_status_folder(mailsession * session, char * mb,
+ uint32_t * result_messages, uint32_t * result_recent,
+ uint32_t * result_unseen);
+
+static int pop3driver_messages_number(mailsession * session, char * mb,
+ uint32_t * result);
+
+static int pop3driver_remove_message(mailsession * session, uint32_t num);
+
+static int pop3driver_get_messages_list(mailsession * session,
+ struct mailmessage_list ** result);
+
+static int pop3driver_get_message(mailsession * session,
+ uint32_t num, mailmessage ** result);
+
+static mailsession_driver local_pop3_session_driver = {
+ .sess_name = "pop3",
+
+ .sess_initialize = pop3driver_initialize,
+ .sess_uninitialize = pop3driver_uninitialize,
+
+ .sess_parameters = pop3driver_parameters,
+
+ .sess_connect_stream = pop3driver_connect_stream,
+ .sess_connect_path = NULL,
+ .sess_starttls = pop3driver_starttls,
+ .sess_login = pop3driver_login,
+ .sess_logout = pop3driver_logout,
+ .sess_noop = pop3driver_noop,
+
+ .sess_build_folder_name = NULL,
+ .sess_create_folder = NULL,
+ .sess_delete_folder = NULL,
+ .sess_rename_folder = NULL,
+ .sess_check_folder = NULL,
+ .sess_examine_folder = NULL,
+ .sess_select_folder = NULL,
+ .sess_expunge_folder = NULL,
+ .sess_status_folder = pop3driver_status_folder,
+ .sess_messages_number = pop3driver_messages_number,
+ .sess_recent_number = pop3driver_messages_number,
+ .sess_unseen_number = pop3driver_messages_number,
+ .sess_list_folders = NULL,
+ .sess_lsub_folders = NULL,
+ .sess_subscribe_folder = NULL,
+ .sess_unsubscribe_folder = NULL,
+
+ .sess_append_message = NULL,
+ .sess_append_message_flags = NULL,
+ .sess_copy_message = NULL,
+ .sess_move_message = NULL,
+
+ .sess_get_messages_list = pop3driver_get_messages_list,
+ .sess_get_envelopes_list = maildriver_generic_get_envelopes_list,
+ .sess_remove_message = pop3driver_remove_message,
+#if 0
+ .sess_search_messages = maildriver_generic_search_messages,
+#endif
+
+ .sess_get_message = pop3driver_get_message,
+ .sess_get_message_by_uid = NULL,
+};
+
+mailsession_driver * pop3_session_driver = &local_pop3_session_driver;
+
+static inline struct pop3_session_state_data *
+get_data(mailsession * session)
+{
+ return session->sess_data;
+}
+
+static mailpop3 * get_pop3_session(mailsession * session)
+{
+ return get_data(session)->pop3_session;
+}
+
+static int pop3driver_initialize(mailsession * session)
+{
+ struct pop3_session_state_data * data;
+ mailpop3 * pop3;
+
+ pop3 = mailpop3_new(0, NULL);
+ if (session == NULL)
+ goto err;
+
+ data = malloc(sizeof(* data));
+ if (data == NULL)
+ goto free;
+
+ data->pop3_session = pop3;
+ data->pop3_auth_type = POP3DRIVER_AUTH_TYPE_PLAIN;
+
+ session->sess_data = data;
+
+ return MAIL_NO_ERROR;
+
+ free:
+ mailpop3_free(pop3);
+ err:
+ return MAIL_ERROR_MEMORY;
+}
+
+static void pop3driver_uninitialize(mailsession * session)
+{
+ struct pop3_session_state_data * data;
+
+ data = get_data(session);
+
+ mailpop3_free(data->pop3_session);
+ free(data);
+
+ session->sess_data = data;
+}
+
+static int pop3driver_connect_stream(mailsession * session, mailstream * s)
+{
+ int r;
+
+ r = mailpop3_connect(get_pop3_session(session), s);
+
+ switch (r) {
+ case MAILPOP3_NO_ERROR:
+ return MAIL_NO_ERROR_NON_AUTHENTICATED;
+
+ default:
+ return pop3driver_pop3_error_to_mail_error(r);
+ }
+}
+
+static int pop3driver_starttls(mailsession * session)
+{
+ int r;
+ int fd;
+ mailstream_low * low;
+ mailstream_low * new_low;
+ mailpop3 * pop3;
+
+ pop3 = get_pop3_session(session);
+
+ r = mailpop3_stls(pop3);
+
+ switch (r) {
+ case MAILPOP3_NO_ERROR:
+ break;
+ default:
+ return pop3driver_pop3_error_to_mail_error(r);
+ }
+
+ low = mailstream_get_low(pop3->pop3_stream);
+ fd = mailstream_low_get_fd(low);
+ if (fd == -1)
+ return MAIL_ERROR_STREAM;
+
+ new_low = mailstream_low_ssl_open(fd);
+ if (new_low == NULL)
+ return MAIL_ERROR_STREAM;
+ mailstream_low_free(low);
+ mailstream_set_low(pop3->pop3_stream, new_low);
+
+ return MAIL_NO_ERROR;
+}
+
+static int pop3driver_parameters(mailsession * session,
+ int id, void * value)
+{
+ struct pop3_session_state_data * data;
+
+ data = get_data(session);
+
+ switch (id) {
+ case POP3DRIVER_SET_AUTH_TYPE:
+ {
+ int * param;
+
+ param = value;
+
+ data->pop3_auth_type = * param;
+ return MAIL_NO_ERROR;
+ }
+ }
+
+ return MAIL_ERROR_INVAL;
+}
+
+static int pop3driver_login(mailsession * session,
+ char * userid, char * password)
+{
+ int r;
+ carray * msg_tab;
+ struct pop3_session_state_data * data;
+
+ data = get_data(session);
+
+ switch (data->pop3_auth_type) {
+ case POP3DRIVER_AUTH_TYPE_TRY_APOP:
+ r = mailpop3_login_apop(get_pop3_session(session), userid, password);
+ if (r != MAILPOP3_NO_ERROR)
+ r = mailpop3_login(get_pop3_session(session), userid, password);
+ break;
+
+ case POP3DRIVER_AUTH_TYPE_APOP:
+ r = mailpop3_login_apop(get_pop3_session(session), userid, password);
+ break;
+
+ default:
+ case POP3DRIVER_AUTH_TYPE_PLAIN:
+ r = mailpop3_login(get_pop3_session(session), userid, password);
+ break;
+ }
+
+ mailpop3_list(get_pop3_session(session), &msg_tab);
+
+ return pop3driver_pop3_error_to_mail_error(r);
+}
+
+static int pop3driver_logout(mailsession * session)
+{
+ int r;
+
+ r = mailpop3_quit(get_pop3_session(session));
+
+ return pop3driver_pop3_error_to_mail_error(r);
+}
+
+static int pop3driver_noop(mailsession * session)
+{
+ int r;
+
+ r = mailpop3_noop(get_pop3_session(session));
+
+ return pop3driver_pop3_error_to_mail_error(r);
+}
+
+static int pop3driver_status_folder(mailsession * session, char * mb,
+ uint32_t * result_messages,
+ uint32_t * result_recent,
+ uint32_t * result_unseen)
+{
+ uint32_t count;
+ int r;
+
+ r = pop3driver_messages_number(session, mb, &count);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ * result_messages = count;
+ * result_recent = count;
+ * result_unseen = count;
+
+ return MAIL_NO_ERROR;
+}
+
+static int pop3driver_messages_number(mailsession * session, char * mb,
+ uint32_t * result)
+{
+ carray * msg_tab;
+
+ mailpop3_list(get_pop3_session(session), &msg_tab);
+
+ * result = carray_count(msg_tab) -
+ get_pop3_session(session)->pop3_deleted_count;
+
+ return MAIL_NO_ERROR;
+}
+
+
+/* messages operations */
+
+static int pop3driver_remove_message(mailsession * session, uint32_t num)
+{
+ mailpop3 * pop3;
+ int r;
+
+ pop3 = get_pop3_session(session);
+
+ r = mailpop3_dele(pop3, num);
+ switch (r) {
+ case MAILPOP3_ERROR_BAD_STATE:
+ return MAIL_ERROR_BAD_STATE;
+
+ case MAILPOP3_ERROR_NO_SUCH_MESSAGE:
+ return MAIL_ERROR_MSG_NOT_FOUND;
+
+ case MAILPOP3_ERROR_STREAM:
+ return MAIL_ERROR_STREAM;
+
+ case MAILPOP3_NO_ERROR:
+ return MAIL_NO_ERROR;
+
+ default:
+ return MAIL_ERROR_REMOVE;
+ }
+}
+
+static int pop3driver_get_messages_list(mailsession * session,
+ struct mailmessage_list ** result)
+{
+ mailpop3 * pop3;
+
+ pop3 = get_pop3_session(session);
+
+ return pop3_get_messages_list(pop3, session,
+ pop3_message_driver, result);
+}
+
+static int pop3driver_get_message(mailsession * session,
+ uint32_t num, mailmessage ** result)
+{
+ mailmessage * msg_info;
+ int r;
+
+ msg_info = mailmessage_new();
+ if (msg_info == NULL)
+ return MAIL_ERROR_MEMORY;
+
+ r = mailmessage_init(msg_info, session, pop3_message_driver, num, 0);
+ if (r != MAIL_NO_ERROR) {
+ mailmessage_free(msg_info);
+ return r;
+ }
+
+ * result = msg_info;
+
+ return MAIL_NO_ERROR;
+}
diff --git a/libetpan/src/driver/implementation/pop3/pop3driver.h b/libetpan/src/driver/implementation/pop3/pop3driver.h
new file mode 100644
index 0000000..b70f69e
--- a/dev/null
+++ b/libetpan/src/driver/implementation/pop3/pop3driver.h
@@ -0,0 +1,52 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef POP3DRIVER_H
+
+#define POP3DRIVER_H
+
+#include <libetpan/pop3driver_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern mailsession_driver * pop3_session_driver;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/implementation/pop3/pop3driver_cached.c b/libetpan/src/driver/implementation/pop3/pop3driver_cached.c
new file mode 100644
index 0000000..d3cc98e
--- a/dev/null
+++ b/libetpan/src/driver/implementation/pop3/pop3driver_cached.c
@@ -0,0 +1,899 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "pop3driver_cached.h"
+
+#include "libetpan-config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "mail.h"
+#include "mail_cache_db.h"
+
+#include "maildriver.h"
+#include "mailmessage.h"
+#include "pop3driver.h"
+#include "mailpop3.h"
+#include "generic_cache.h"
+#include "imfcache.h"
+#include "pop3driver_cached_message.h"
+#include "pop3driver_tools.h"
+#include "maildriver_tools.h"
+
+static int pop3driver_cached_initialize(mailsession * session);
+
+static void pop3driver_cached_uninitialize(mailsession * session);
+
+static int pop3driver_cached_parameters(mailsession * session,
+ int id, void * value);
+
+static int pop3driver_cached_connect_stream(mailsession * session,
+ mailstream * s);
+
+static int pop3driver_cached_starttls(mailsession * session);
+
+static int pop3driver_cached_login(mailsession * session,
+ char * userid, char * password);
+
+static int pop3driver_cached_logout(mailsession * session);
+
+static int pop3driver_cached_check_folder(mailsession * session);
+
+static int pop3driver_cached_noop(mailsession * session);
+
+static int pop3driver_cached_expunge_folder(mailsession * session);
+
+static int pop3driver_cached_status_folder(mailsession * session,
+ char * mb, uint32_t * result_messages, uint32_t * result_recent,
+ uint32_t * result_unseen);
+
+static int pop3driver_cached_messages_number(mailsession * session,
+ char * mb,
+ uint32_t * result);
+
+static int pop3driver_cached_recent_number(mailsession * session,
+ char * mb,
+ uint32_t * result);
+
+static int pop3driver_cached_unseen_number(mailsession * session,
+ char * mb,
+ uint32_t * result);
+
+static int pop3driver_cached_remove_message(mailsession * session,
+ uint32_t num);
+
+static int
+pop3driver_cached_get_messages_list(mailsession * session,
+ struct mailmessage_list ** result);
+
+static int
+pop3driver_cached_get_envelopes_list(mailsession * session,
+ struct mailmessage_list * env_list);
+
+static int pop3driver_cached_get_message(mailsession * session,
+ uint32_t num, mailmessage ** result);
+
+static int pop3driver_cached_get_message_by_uid(mailsession * session,
+ const char * uid, mailmessage ** result);
+
+static mailsession_driver local_pop3_cached_session_driver = {
+ .sess_name = "pop3-cached",
+
+ .sess_initialize = pop3driver_cached_initialize,
+ .sess_uninitialize = pop3driver_cached_uninitialize,
+
+ .sess_parameters = pop3driver_cached_parameters,
+
+ .sess_connect_stream = pop3driver_cached_connect_stream,
+ .sess_connect_path = NULL,
+ .sess_starttls = pop3driver_cached_starttls,
+ .sess_login = pop3driver_cached_login,
+ .sess_logout = pop3driver_cached_logout,
+ .sess_noop = pop3driver_cached_noop,
+
+ .sess_build_folder_name = NULL,
+ .sess_create_folder = NULL,
+ .sess_delete_folder = NULL,
+ .sess_rename_folder = NULL,
+ .sess_check_folder = pop3driver_cached_check_folder,
+ .sess_examine_folder = NULL,
+ .sess_select_folder = NULL,
+ .sess_expunge_folder = pop3driver_cached_expunge_folder,
+ .sess_status_folder = pop3driver_cached_status_folder,
+ .sess_messages_number = pop3driver_cached_messages_number,
+ .sess_recent_number = pop3driver_cached_recent_number,
+ .sess_unseen_number = pop3driver_cached_unseen_number,
+ .sess_list_folders = NULL,
+ .sess_lsub_folders = NULL,
+ .sess_subscribe_folder = NULL,
+ .sess_unsubscribe_folder = NULL,
+
+ .sess_append_message = NULL,
+ .sess_append_message_flags = NULL,
+ .sess_copy_message = NULL,
+ .sess_move_message = NULL,
+
+ .sess_get_messages_list = pop3driver_cached_get_messages_list,
+ .sess_get_envelopes_list = pop3driver_cached_get_envelopes_list,
+ .sess_remove_message = pop3driver_cached_remove_message,
+#if 0
+ .sess_search_messages = maildriver_generic_search_messages,
+#endif
+
+ .sess_get_message = pop3driver_cached_get_message,
+ .sess_get_message_by_uid = pop3driver_cached_get_message_by_uid,
+};
+
+mailsession_driver * pop3_cached_session_driver =
+&local_pop3_cached_session_driver;
+
+#define ENV_NAME "env.db"
+#define FLAGS_NAME "flags.db"
+
+
+static inline struct pop3_cached_session_state_data *
+get_cached_data(mailsession * session)
+{
+ return session->sess_data;
+}
+
+static inline mailsession * get_ancestor(mailsession * session)
+{
+ return get_cached_data(session)->pop3_ancestor;
+}
+
+static inline struct pop3_session_state_data *
+get_ancestor_data(mailsession * session)
+{
+ return get_ancestor(session)->sess_data;
+}
+
+static inline mailpop3 * get_pop3_session(mailsession * session)
+{
+ return get_ancestor_data(session)->pop3_session;
+}
+
+static int pop3driver_cached_initialize(mailsession * session)
+{
+ struct pop3_cached_session_state_data * data;
+
+ data = malloc(sizeof(* data));
+ if (data == NULL)
+ goto err;
+
+ data->pop3_flags_store = mail_flags_store_new();
+ if (data->pop3_flags_store == NULL)
+ goto free_data;
+
+ data->pop3_ancestor = mailsession_new(pop3_session_driver);
+ if (data->pop3_ancestor == NULL)
+ goto free_store;
+
+ data->pop3_flags_hash = chash_new(128, CHASH_COPYNONE);
+ if (data->pop3_flags_hash == NULL)
+ goto free_session;
+
+ session->sess_data = data;
+
+ return MAIL_NO_ERROR;
+
+ free_session:
+ mailsession_free(data->pop3_ancestor);
+ free_store:
+ mail_flags_store_free(data->pop3_flags_store);
+ free_data:
+ free(data);
+ err:
+ return MAIL_ERROR_MEMORY;
+}
+
+static int pop3_flags_store_process(char * flags_directory,
+ struct mail_flags_store * flags_store)
+{
+ char filename_flags[PATH_MAX];
+ struct mail_cache_db * cache_db_flags;
+ MMAPString * mmapstr;
+ unsigned int i;
+ int r;
+ int res;
+
+ if (carray_count(flags_store->fls_tab) == 0)
+ return MAIL_NO_ERROR;
+
+ snprintf(filename_flags, PATH_MAX, "%s/%s",
+ flags_directory, FLAGS_NAME);
+
+ r = mail_cache_db_open_lock(filename_flags, &cache_db_flags);
+ if (r < 0) {
+ res = MAIL_ERROR_FILE;
+ goto err;
+ }
+
+ mmapstr = mmap_string_new("");
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto close_db_flags;
+ }
+
+ for(i = 0 ; i < carray_count(flags_store->fls_tab) ; i ++) {
+ mailmessage * msg;
+
+ msg = carray_get(flags_store->fls_tab, i);
+
+ r = pop3driver_write_cached_flags(cache_db_flags, mmapstr,
+ msg->msg_uid, msg->msg_flags);
+ }
+
+ mmap_string_free(mmapstr);
+ mail_cache_db_close_unlock(filename_flags, cache_db_flags);
+
+ mail_flags_store_clear(flags_store);
+
+ return MAIL_NO_ERROR;
+
+ close_db_flags:
+ mail_cache_db_close_unlock(filename_flags, cache_db_flags);
+ err:
+ return res;
+}
+
+static void pop3driver_cached_uninitialize(mailsession * session)
+{
+ struct pop3_cached_session_state_data * data;
+
+ data = get_cached_data(session);
+
+ pop3_flags_store_process(data->pop3_flags_directory,
+ data->pop3_flags_store);
+
+ mail_flags_store_free(data->pop3_flags_store);
+
+ chash_free(data->pop3_flags_hash);
+ mailsession_free(data->pop3_ancestor);
+ free(data);
+
+ session->sess_data = data;
+}
+
+static int pop3driver_cached_check_folder(mailsession * session)
+{
+ struct pop3_cached_session_state_data * pop3_data;
+
+ pop3_data = get_cached_data(session);
+
+ pop3_flags_store_process(pop3_data->pop3_flags_directory,
+ pop3_data->pop3_flags_store);
+
+ return MAIL_NO_ERROR;
+}
+
+static int pop3driver_cached_parameters(mailsession * session,
+ int id, void * value)
+{
+ struct pop3_cached_session_state_data * data;
+ int r;
+
+ data = get_cached_data(session);
+
+ switch (id) {
+ case POP3DRIVER_CACHED_SET_CACHE_DIRECTORY:
+ strncpy(data->pop3_cache_directory, value, PATH_MAX);
+ data->pop3_cache_directory[PATH_MAX - 1] = '\0';
+
+ r = generic_cache_create_dir(data->pop3_cache_directory);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ return MAIL_NO_ERROR;
+
+ case POP3DRIVER_CACHED_SET_FLAGS_DIRECTORY:
+ strncpy(data->pop3_flags_directory, value, PATH_MAX);
+ data->pop3_flags_directory[PATH_MAX - 1] = '\0';
+
+ r = generic_cache_create_dir(data->pop3_flags_directory);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ return MAIL_NO_ERROR;
+
+ default:
+ return mailsession_parameters(data->pop3_ancestor, id, value);
+ }
+}
+
+static int pop3driver_cached_connect_stream(mailsession * session,
+ mailstream * s)
+{
+ int r;
+
+ r = mailsession_connect_stream(get_ancestor(session), s);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ return MAIL_NO_ERROR;
+}
+
+static int pop3driver_cached_starttls(mailsession * session)
+{
+ return mailsession_starttls(get_ancestor(session));
+}
+
+
+static int pop3driver_cached_login(mailsession * session,
+ char * userid, char * password)
+{
+ return mailsession_login(get_ancestor(session), userid, password);
+}
+
+static int pop3driver_cached_logout(mailsession * session)
+{
+ struct pop3_cached_session_state_data * cached_data;
+
+ cached_data = get_cached_data(session);
+
+ pop3_flags_store_process(cached_data->pop3_flags_directory,
+ cached_data->pop3_flags_store);
+
+ return mailsession_logout(get_ancestor(session));
+}
+
+static int pop3driver_cached_noop(mailsession * session)
+{
+ return mailsession_noop(get_ancestor(session));
+}
+
+static int pop3driver_cached_expunge_folder(mailsession * session)
+{
+ int res;
+ struct pop3_cached_session_state_data * cached_data;
+ char filename_flags[PATH_MAX];
+ struct mail_cache_db * cache_db_flags;
+ MMAPString * mmapstr;
+ unsigned int i;
+ int r;
+ carray * msg_tab;
+ mailpop3 * pop3;
+
+ pop3 = get_pop3_session(session);
+
+ cached_data = get_cached_data(session);
+
+ pop3_flags_store_process(cached_data->pop3_flags_directory,
+ cached_data->pop3_flags_store);
+
+ snprintf(filename_flags, PATH_MAX, "%s/%s",
+ cached_data->pop3_flags_directory, FLAGS_NAME);
+
+ r = mail_cache_db_open_lock(filename_flags, &cache_db_flags);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ mmapstr = mmap_string_new("");
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto close_db_flags;
+ }
+
+ mailpop3_list(pop3, &msg_tab);
+
+ for(i = 0 ; i < carray_count(msg_tab) ; i++) {
+ struct mailpop3_msg_info * pop3_info;
+ struct mail_flags * flags;
+
+ pop3_info = carray_get(msg_tab, i);
+ if (pop3_info == NULL)
+ continue;
+
+ if (pop3_info->msg_deleted)
+ continue;
+
+ r = pop3driver_get_cached_flags(cache_db_flags, mmapstr,
+ session, pop3_info->msg_index, &flags);
+ if (r != MAIL_NO_ERROR)
+ continue;
+
+ if (flags->fl_flags & MAIL_FLAG_DELETED) {
+ r = mailpop3_dele(pop3, pop3_info->msg_index);
+ }
+
+ mail_flags_free(flags);
+ }
+
+ mmap_string_free(mmapstr);
+ mail_cache_db_close_unlock(filename_flags, cache_db_flags);
+
+ return MAIL_NO_ERROR;
+
+ close_db_flags:
+ mail_cache_db_close_unlock(filename_flags, cache_db_flags);
+ err:
+ return res;
+}
+
+static int pop3driver_cached_status_folder(mailsession * session,
+ char * mb, uint32_t * result_messages, uint32_t * result_recent,
+ uint32_t * result_unseen)
+{
+ int res;
+ struct pop3_cached_session_state_data * cached_data;
+ char filename_flags[PATH_MAX];
+ struct mail_cache_db * cache_db_flags;
+ MMAPString * mmapstr;
+ unsigned int i;
+ int r;
+ carray * msg_tab;
+ mailpop3 * pop3;
+ uint32_t recent;
+ uint32_t unseen;
+
+ recent = 0;
+ unseen = 0;
+
+ pop3 = get_pop3_session(session);
+
+ cached_data = get_cached_data(session);
+
+ pop3_flags_store_process(cached_data->pop3_flags_directory,
+ cached_data->pop3_flags_store);
+
+ snprintf(filename_flags, PATH_MAX, "%s/%s",
+ cached_data->pop3_flags_directory, FLAGS_NAME);
+
+ r = mail_cache_db_open_lock(filename_flags, &cache_db_flags);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ mmapstr = mmap_string_new("");
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto close_db_flags;
+ }
+
+ mailpop3_list(pop3, &msg_tab);
+
+ for(i = 0 ; i < carray_count(msg_tab) ; i++) {
+ struct mailpop3_msg_info * pop3_info;
+ struct mail_flags * flags;
+
+ pop3_info = carray_get(msg_tab, i);
+ if (pop3_info == NULL)
+ continue;
+
+ if (pop3_info->msg_deleted)
+ continue;
+
+ r = pop3driver_get_cached_flags(cache_db_flags, mmapstr,
+ session, pop3_info->msg_index, &flags);
+ if (r != MAIL_NO_ERROR) {
+ recent ++;
+ unseen ++;
+ continue;
+ }
+
+ if ((flags->fl_flags & MAIL_FLAG_NEW) != 0) {
+ recent ++;
+ }
+ if ((flags->fl_flags & MAIL_FLAG_SEEN) == 0) {
+ unseen ++;
+ }
+ mail_flags_free(flags);
+
+ }
+
+ mmap_string_free(mmapstr);
+ mail_cache_db_close_unlock(filename_flags, cache_db_flags);
+
+ * result_messages = carray_count(msg_tab) - pop3->pop3_deleted_count;
+ * result_recent = recent;
+ * result_unseen = unseen;
+
+ return MAIL_NO_ERROR;
+
+ close_db_flags:
+ mail_cache_db_close_unlock(filename_flags, cache_db_flags);
+ err:
+ return res;
+}
+
+static int pop3driver_cached_messages_number(mailsession * session,
+ char * mb,
+ uint32_t * result)
+{
+ return mailsession_messages_number(get_ancestor(session), mb, result);
+}
+
+static int pop3driver_cached_recent_number(mailsession * session,
+ char * mb,
+ uint32_t * result)
+{
+ uint32_t messages;
+ uint32_t recent;
+ uint32_t unseen;
+ int r;
+
+ r = pop3driver_cached_status_folder(session, mb,
+ &messages, &recent, &unseen);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ * result = recent;
+
+ return MAIL_NO_ERROR;
+}
+
+static int pop3driver_cached_unseen_number(mailsession * session,
+ char * mb,
+ uint32_t * result)
+{
+ uint32_t messages;
+ uint32_t recent;
+ uint32_t unseen;
+ int r;
+
+ r = pop3driver_cached_status_folder(session, mb,
+ &messages, &recent, &unseen);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ * result = unseen;
+
+ return MAIL_NO_ERROR;
+}
+
+/* messages operations */
+
+static int pop3driver_cached_remove_message(mailsession * session,
+ uint32_t num)
+{
+ return mailsession_remove_message(get_ancestor(session), num);
+}
+
+static int
+pop3driver_cached_get_messages_list(mailsession * session,
+ struct mailmessage_list ** result)
+{
+ mailpop3 * pop3;
+
+ pop3 = get_pop3_session(session);
+
+ return pop3_get_messages_list(pop3, session,
+ pop3_cached_message_driver, result);
+}
+
+
+static int
+get_cached_envelope(struct mail_cache_db * cache_db, MMAPString * mmapstr,
+ mailsession * session, uint32_t num,
+ struct mailimf_fields ** result)
+{
+ int r;
+ char keyname[PATH_MAX];
+ struct mailpop3_msg_info * info;
+ struct mailimf_fields * fields;
+ int res;
+ mailpop3 * pop3;
+
+ pop3 = get_pop3_session(session);
+
+ r = mailpop3_get_msg_info(pop3, num, &info);
+ switch (r) {
+ case MAILPOP3_ERROR_BAD_STATE:
+ return MAIL_ERROR_BAD_STATE;
+ case MAILPOP3_ERROR_NO_SUCH_MESSAGE:
+ return MAIL_ERROR_MSG_NOT_FOUND;
+ case MAILPOP3_NO_ERROR:
+ break;
+ default:
+ return MAIL_ERROR_FETCH;
+ }
+
+ snprintf(keyname, PATH_MAX, "%s-envelope", info->msg_uidl);
+
+ r = generic_cache_fields_read(cache_db, mmapstr, keyname, &fields);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ * result = fields;
+
+ return MAIL_NO_ERROR;
+
+ err:
+ return res;
+}
+
+static int
+write_cached_envelope(struct mail_cache_db * cache_db,
+ MMAPString * mmapstr,
+ mailsession * session, uint32_t num,
+ struct mailimf_fields * fields)
+{
+ int r;
+ char keyname[PATH_MAX];
+ int res;
+ struct mailpop3_msg_info * info;
+ mailpop3 * pop3;
+
+ pop3 = get_pop3_session(session);
+
+ r = mailpop3_get_msg_info(pop3, num, &info);
+ switch (r) {
+ case MAILPOP3_ERROR_BAD_STATE:
+ return MAIL_ERROR_BAD_STATE;
+ case MAILPOP3_ERROR_NO_SUCH_MESSAGE:
+ return MAIL_ERROR_MSG_NOT_FOUND;
+ case MAILPOP3_NO_ERROR:
+ break;
+ default:
+ return MAIL_ERROR_FETCH;
+ }
+
+ snprintf(keyname, PATH_MAX, "%s-envelope", info->msg_uidl);
+
+ r = generic_cache_fields_write(cache_db, mmapstr, keyname, fields);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ return MAIL_NO_ERROR;
+
+ err:
+ return res;
+}
+
+static void get_uid_from_filename(char * filename)
+{
+ char * p;
+
+ p = strstr(filename, "-header");
+ if (p != NULL)
+ * p = 0;
+}
+
+static int
+pop3driver_cached_get_envelopes_list(mailsession * session,
+ struct mailmessage_list * env_list)
+{
+ int r;
+ unsigned int i;
+ struct pop3_cached_session_state_data * cached_data;
+ char filename_env[PATH_MAX];
+ char filename_flags[PATH_MAX];
+ struct mail_cache_db * cache_db_env;
+ struct mail_cache_db * cache_db_flags;
+ MMAPString * mmapstr;
+ int res;
+
+ cached_data = get_cached_data(session);
+
+ pop3_flags_store_process(cached_data->pop3_flags_directory,
+ cached_data->pop3_flags_store);
+
+ snprintf(filename_env, PATH_MAX, "%s/%s",
+ cached_data->pop3_cache_directory, ENV_NAME);
+
+ mmapstr = mmap_string_new("");
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ r = mail_cache_db_open_lock(filename_env, &cache_db_env);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_mmapstr;
+ }
+
+ snprintf(filename_flags, PATH_MAX, "%s/%s",
+ cached_data->pop3_flags_directory, FLAGS_NAME);
+
+ r = mail_cache_db_open_lock(filename_flags, &cache_db_flags);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto close_db_env;
+ }
+
+ /* fill with cached */
+
+ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
+ mailmessage * msg;
+ struct mailimf_fields * fields;
+ struct mail_flags * flags;
+
+ msg = carray_get(env_list->msg_tab, i);
+
+ if (msg->msg_fields == NULL) {
+ r = get_cached_envelope(cache_db_env, mmapstr,
+ session, msg->msg_index, &fields);
+ if (r == MAIL_NO_ERROR) {
+ msg->msg_cached = TRUE;
+ msg->msg_fields = fields;
+ }
+ }
+
+ if (msg->msg_flags == NULL) {
+ r = pop3driver_get_cached_flags(cache_db_flags, mmapstr,
+ session, msg->msg_index, &flags);
+ if (r == MAIL_NO_ERROR) {
+ msg->msg_flags = flags;
+ }
+ }
+ }
+
+ mail_cache_db_close_unlock(filename_flags, cache_db_flags);
+ mail_cache_db_close_unlock(filename_env, cache_db_env);
+
+ r = maildriver_generic_get_envelopes_list(session, env_list);
+
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free_mmapstr;
+ }
+
+ /* add flags */
+
+ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
+ mailmessage * msg;
+
+ msg = carray_get(env_list->msg_tab, i);
+
+ if (msg->msg_flags == NULL)
+ msg->msg_flags = mail_flags_new_empty();
+ }
+
+ r = mail_cache_db_open_lock(filename_env, &cache_db_env);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_mmapstr;
+ }
+
+ r = mail_cache_db_open_lock(filename_flags, &cache_db_flags);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto close_db_env;
+ }
+
+ /* must write cache */
+
+ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
+ mailmessage * msg;
+
+ msg = carray_get(env_list->msg_tab, i);
+
+ if (msg->msg_fields != NULL) {
+ if (!msg->msg_cached) {
+ r = write_cached_envelope(cache_db_env, mmapstr,
+ session, msg->msg_index, msg->msg_fields);
+ }
+ }
+
+ if (msg->msg_flags != NULL) {
+ r = pop3driver_write_cached_flags(cache_db_flags, mmapstr,
+ msg->msg_uid, msg->msg_flags);
+ }
+ }
+
+ /* flush cache */
+
+ maildriver_cache_clean_up(cache_db_env, cache_db_flags, env_list);
+
+ mail_cache_db_close_unlock(filename_flags, cache_db_flags);
+ mail_cache_db_close_unlock(filename_env, cache_db_env);
+ mmap_string_free(mmapstr);
+
+ /* remove cache files */
+
+ maildriver_message_cache_clean_up(cached_data->pop3_cache_directory,
+ env_list, get_uid_from_filename);
+
+ return MAIL_NO_ERROR;
+
+ close_db_env:
+ mail_cache_db_close_unlock(filename_env, cache_db_env);
+ free_mmapstr:
+ mmap_string_free(mmapstr);
+ err:
+ return res;
+}
+
+static int pop3driver_cached_get_message(mailsession * session,
+ uint32_t num, mailmessage ** result)
+{
+ mailmessage * msg_info;
+ int r;
+
+ msg_info = mailmessage_new();
+ if (msg_info == NULL)
+ return MAIL_ERROR_MEMORY;
+
+ r = mailmessage_init(msg_info, session, pop3_cached_message_driver, num, 0);
+ if (r != MAIL_NO_ERROR) {
+ mailmessage_free(msg_info);
+ return r;
+ }
+
+ * result = msg_info;
+
+ return MAIL_NO_ERROR;
+}
+
+static int pop3driver_cached_get_message_by_uid(mailsession * session,
+ const char * uid, mailmessage ** result)
+{
+ mailpop3 * pop3;
+ struct mailpop3_msg_info * msg_info;
+ int found;
+ unsigned int i;
+
+ if (uid == NULL)
+ return MAIL_ERROR_INVAL;
+
+ pop3 = get_pop3_session(session);
+
+ found = 0;
+
+ /* iterate all messages and look for uid */
+ for(i = 0 ; i < carray_count(pop3->pop3_msg_tab) ; i++) {
+ msg_info = carray_get(pop3->pop3_msg_tab, i);
+
+ if (msg_info == NULL)
+ continue;
+
+ if (msg_info->msg_deleted)
+ continue;
+
+ /* uid found, stop looking */
+ if (strcmp(msg_info->msg_uidl, uid) == 0) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ return MAIL_ERROR_MSG_NOT_FOUND;
+
+ return pop3driver_cached_get_message(session, msg_info->msg_index, result);
+}
diff --git a/libetpan/src/driver/implementation/pop3/pop3driver_cached.h b/libetpan/src/driver/implementation/pop3/pop3driver_cached.h
new file mode 100644
index 0000000..4f4b6c9
--- a/dev/null
+++ b/libetpan/src/driver/implementation/pop3/pop3driver_cached.h
@@ -0,0 +1,52 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef POP3DRIVER_CACHED_H
+
+#define POP3DRIVER_CACHED_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libetpan/pop3driver_types.h>
+
+extern mailsession_driver * pop3_cached_session_driver;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/implementation/pop3/pop3driver_cached_message.c b/libetpan/src/driver/implementation/pop3/pop3driver_cached_message.c
new file mode 100644
index 0000000..4eed0db
--- a/dev/null
+++ b/libetpan/src/driver/implementation/pop3/pop3driver_cached_message.c
@@ -0,0 +1,355 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "pop3driver_cached_message.h"
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "mail_cache_db.h"
+
+#include "mailmessage.h"
+#include "mailmessage_tools.h"
+#include "pop3driver.h"
+#include "pop3driver_tools.h"
+#include "pop3driver_cached.h"
+#include "pop3driver_message.h"
+#include "generic_cache.h"
+
+static int pop3_prefetch(mailmessage * msg_info);
+
+static void pop3_prefetch_free(struct generic_message_t * msg);
+
+static int pop3_initialize(mailmessage * msg_info);
+
+static void pop3_flush(mailmessage * msg_info);
+
+static void pop3_check(mailmessage * msg_info);
+
+static int pop3_fetch_header(mailmessage * msg_info,
+ char ** result,
+ size_t * result_len);
+
+static int pop3_fetch_size(mailmessage * msg_info,
+ size_t * result);
+
+static int pop3_get_flags(mailmessage * msg_info,
+ struct mail_flags ** result);
+
+static void pop3_uninitialize(mailmessage * msg_info);
+
+static mailmessage_driver local_pop3_cached_message_driver = {
+ .msg_name = "pop3-cached",
+
+ .msg_initialize = pop3_initialize,
+ .msg_uninitialize = pop3_uninitialize,
+
+ .msg_flush = pop3_flush,
+ .msg_check = pop3_check,
+
+ .msg_fetch_result_free = mailmessage_generic_fetch_result_free,
+
+ .msg_fetch = mailmessage_generic_fetch,
+ .msg_fetch_header = pop3_fetch_header,
+ .msg_fetch_body = mailmessage_generic_fetch_body,
+ .msg_fetch_size = pop3_fetch_size,
+ .msg_get_bodystructure = mailmessage_generic_get_bodystructure,
+ .msg_fetch_section = mailmessage_generic_fetch_section,
+ .msg_fetch_section_header = mailmessage_generic_fetch_section_header,
+ .msg_fetch_section_mime = mailmessage_generic_fetch_section_mime,
+ .msg_fetch_section_body = mailmessage_generic_fetch_section_body,
+ .msg_fetch_envelope = mailmessage_generic_fetch_envelope,
+
+ .msg_get_flags = pop3_get_flags,
+};
+
+mailmessage_driver * pop3_cached_message_driver =
+&local_pop3_cached_message_driver;
+
+
+static inline struct pop3_cached_session_state_data *
+get_cached_session_data(mailmessage * msg)
+{
+ return msg->msg_session->sess_data;
+}
+
+static inline mailsession * get_ancestor_session(mailmessage * msg)
+{
+ return get_cached_session_data(msg)->pop3_ancestor;
+}
+
+static inline struct pop3_session_state_data *
+get_ancestor_session_data(mailmessage * msg)
+{
+ return get_ancestor_session(msg)->sess_data;
+}
+
+static inline mailpop3 * get_pop3_session(mailmessage * msg)
+{
+ return get_ancestor_session_data(msg)->pop3_session;
+}
+
+
+static int pop3_prefetch(mailmessage * msg_info)
+{
+ char * msg_content;
+ size_t msg_length;
+ struct generic_message_t * msg;
+ int r;
+ struct pop3_cached_session_state_data * cached_data;
+ char filename[PATH_MAX];
+
+ /* we try the cached message */
+
+ cached_data = get_cached_session_data(msg_info);
+
+ snprintf(filename, PATH_MAX, "%s/%s",
+ cached_data->pop3_cache_directory, msg_info->msg_uid);
+
+ r = generic_cache_read(filename, &msg_content, &msg_length);
+ if (r == MAIL_NO_ERROR) {
+ msg = msg_info->msg_data;
+
+ msg->msg_message = msg_content;
+ msg->msg_length = msg_length;
+
+ return MAIL_NO_ERROR;
+ }
+
+ /* we get the message through the network */
+
+ r = pop3driver_retr(get_ancestor_session(msg_info), msg_info->msg_index,
+ &msg_content, &msg_length);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ /* we write the message cache */
+
+ generic_cache_store(filename, msg_content, msg_length);
+
+ msg = msg_info->msg_data;
+
+ msg->msg_message = msg_content;
+ msg->msg_length = msg_length;
+
+ return MAIL_NO_ERROR;
+}
+
+static void pop3_prefetch_free(struct generic_message_t * msg)
+{
+ if (msg->msg_message != NULL) {
+ mmap_string_unref(msg->msg_message);
+ msg->msg_message = NULL;
+ }
+}
+
+static int pop3_initialize(mailmessage * msg_info)
+{
+ struct generic_message_t * msg;
+ int r;
+ char * uid;
+ struct mailpop3_msg_info * info;
+ mailpop3 * pop3;
+
+ pop3 = get_pop3_session(msg_info);
+
+ r = mailpop3_get_msg_info(pop3, msg_info->msg_index, &info);
+ switch (r) {
+ case MAILPOP3_NO_ERROR:
+ break;
+ default:
+ return pop3driver_pop3_error_to_mail_error(r);
+ }
+
+ uid = strdup(info->msg_uidl);
+ if (uid == NULL)
+ return MAIL_ERROR_MEMORY;
+
+ r = mailmessage_generic_initialize(msg_info);
+ if (r != MAIL_NO_ERROR) {
+ free(uid);
+ return r;
+ }
+
+ msg = msg_info->msg_data;
+ msg->msg_prefetch = pop3_prefetch;
+ msg->msg_prefetch_free = pop3_prefetch_free;
+ msg_info->msg_uid = uid;
+
+ return MAIL_NO_ERROR;
+}
+
+static void pop3_uninitialize(mailmessage * msg_info)
+{
+ mailmessage_generic_uninitialize(msg_info);
+}
+
+#define FLAGS_NAME "flags.db"
+
+static void pop3_flush(mailmessage * msg_info)
+{
+ mailmessage_generic_flush(msg_info);
+}
+
+static void pop3_check(mailmessage * msg_info)
+{
+ int r;
+
+ if (msg_info->msg_flags != NULL) {
+ r = mail_flags_store_set(get_cached_session_data(msg_info)->pop3_flags_store,
+ msg_info);
+ }
+}
+
+
+static int pop3_fetch_header(mailmessage * msg_info,
+ char ** result,
+ size_t * result_len)
+{
+ struct generic_message_t * msg;
+ char * headers;
+ size_t headers_length;
+ int r;
+ struct pop3_cached_session_state_data * cached_data;
+ char filename[PATH_MAX];
+
+ msg = msg_info->msg_data;
+
+ if (msg->msg_message != NULL)
+ return mailmessage_generic_fetch_header(msg_info,
+ result, result_len);
+
+ /* we try the cached message */
+
+ cached_data = get_cached_session_data(msg_info);
+
+ snprintf(filename, PATH_MAX, "%s/%s-header",
+ cached_data->pop3_cache_directory, msg_info->msg_uid);
+
+ r = generic_cache_read(filename, &headers, &headers_length);
+ if (r == MAIL_NO_ERROR) {
+ * result = headers;
+ * result_len = headers_length;
+
+ return MAIL_NO_ERROR;
+ }
+
+ /* we get the message trough the network */
+
+ r = pop3driver_header(get_ancestor_session(msg_info), msg_info->msg_index,
+ &headers, &headers_length);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ generic_cache_store(filename, headers, headers_length);
+
+ * result = headers;
+ * result_len = headers_length;
+
+ return MAIL_NO_ERROR;
+}
+
+static int pop3_fetch_size(mailmessage * msg_info,
+ size_t * result)
+{
+ return pop3driver_size(get_ancestor_session(msg_info),
+ msg_info->msg_index, result);
+}
+
+static int pop3_get_flags(mailmessage * msg_info,
+ struct mail_flags ** result)
+{
+ int r;
+ struct mail_flags * flags;
+ struct mail_cache_db * cache_db_flags;
+ char filename_flags[PATH_MAX];
+ int res;
+ struct pop3_cached_session_state_data * cached_data;
+ MMAPString * mmapstr;
+
+ if (msg_info->msg_flags != NULL) {
+ * result = msg_info->msg_flags;
+
+ return MAIL_NO_ERROR;
+ }
+
+ cached_data = get_cached_session_data(msg_info);
+
+ flags = mail_flags_store_get(cached_data->pop3_flags_store,
+ msg_info->msg_index);
+
+ if (flags == NULL) {
+ snprintf(filename_flags, PATH_MAX, "%s/%s",
+ cached_data->pop3_flags_directory, FLAGS_NAME);
+
+ r = mail_cache_db_open_lock(filename_flags, &cache_db_flags);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ mmapstr = mmap_string_new("");
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto close_db_flags;
+ }
+
+ r = pop3driver_get_cached_flags(cache_db_flags, mmapstr,
+ msg_info->msg_session, msg_info->msg_index, &flags);
+ if (r != MAIL_NO_ERROR) {
+ flags = mail_flags_new_empty();
+ if (flags == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_mmapstr;
+ }
+ }
+
+ mmap_string_free(mmapstr);
+ mail_cache_db_close_unlock(filename_flags, cache_db_flags);
+ }
+
+ msg_info->msg_flags = flags;
+
+ * result = flags;
+
+ return MAIL_NO_ERROR;
+
+ free_mmapstr:
+ mmap_string_free(mmapstr);
+ close_db_flags:
+ mail_cache_db_close_unlock(filename_flags, cache_db_flags);
+ err:
+ return res;
+}
diff --git a/libetpan/src/driver/implementation/pop3/pop3driver_cached_message.h b/libetpan/src/driver/implementation/pop3/pop3driver_cached_message.h
new file mode 100644
index 0000000..f13cec7
--- a/dev/null
+++ b/libetpan/src/driver/implementation/pop3/pop3driver_cached_message.h
@@ -0,0 +1,52 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef POP3DRIVER_CACHED_MESSAGE_H
+
+#define POP3DRIVER_CACHED_MESSAGE_H
+
+#include <libetpan/pop3driver_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern mailmessage_driver * pop3_cached_message_driver;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/implementation/pop3/pop3driver_message.c b/libetpan/src/driver/implementation/pop3/pop3driver_message.c
new file mode 100644
index 0000000..6ea8979
--- a/dev/null
+++ b/libetpan/src/driver/implementation/pop3/pop3driver_message.c
@@ -0,0 +1,193 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "pop3driver_message.h"
+
+#include "mailmessage_tools.h"
+#include "pop3driver_tools.h"
+#include "pop3driver.h"
+#include "mailpop3.h"
+#include <stdlib.h>
+#include <string.h>
+
+static int pop3_prefetch(mailmessage * msg_info);
+
+static void pop3_prefetch_free(struct generic_message_t * msg);
+
+static int pop3_initialize(mailmessage * msg_info);
+
+static int pop3_fetch_header(mailmessage * msg_info,
+ char ** result,
+ size_t * result_len);
+
+static int pop3_fetch_size(mailmessage * msg_info,
+ size_t * result);
+
+static mailmessage_driver local_pop3_message_driver = {
+ .msg_name = "pop3",
+
+ .msg_initialize = pop3_initialize,
+ .msg_uninitialize = mailmessage_generic_uninitialize,
+
+ .msg_flush = mailmessage_generic_flush,
+ .msg_check = NULL,
+
+ .msg_fetch_result_free = mailmessage_generic_fetch_result_free,
+
+ .msg_fetch = mailmessage_generic_fetch,
+ .msg_fetch_header = pop3_fetch_header,
+ .msg_fetch_body = mailmessage_generic_fetch_body,
+ .msg_fetch_size = pop3_fetch_size,
+ .msg_get_bodystructure = mailmessage_generic_get_bodystructure,
+ .msg_fetch_section = mailmessage_generic_fetch_section,
+ .msg_fetch_section_header = mailmessage_generic_fetch_section_header,
+ .msg_fetch_section_mime = mailmessage_generic_fetch_section_mime,
+ .msg_fetch_section_body = mailmessage_generic_fetch_section_body,
+ .msg_fetch_envelope = mailmessage_generic_fetch_envelope,
+
+ .msg_get_flags = NULL,
+};
+
+mailmessage_driver * pop3_message_driver = &local_pop3_message_driver;
+
+static inline struct pop3_session_state_data *
+get_data(mailsession * session)
+{
+ return session->sess_data;
+}
+
+
+static mailpop3 * get_pop3_session(mailsession * session)
+{
+ return get_data(session)->pop3_session;
+}
+
+
+static int pop3_prefetch(mailmessage * msg_info)
+{
+ char * msg_content;
+ size_t msg_length;
+ struct generic_message_t * msg;
+ int r;
+
+ r = pop3driver_retr(msg_info->msg_session, msg_info->msg_index,
+ &msg_content, &msg_length);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ msg = msg_info->msg_data;
+
+ msg->msg_message = msg_content;
+ msg->msg_length = msg_length;
+
+ return MAIL_NO_ERROR;
+}
+
+static void pop3_prefetch_free(struct generic_message_t * msg)
+{
+ if (msg->msg_message != NULL) {
+ mmap_string_unref(msg->msg_message);
+ msg->msg_message = NULL;
+ }
+}
+
+static int pop3_initialize(mailmessage * msg_info)
+{
+ struct generic_message_t * msg;
+ int r;
+ char * uid;
+ struct mailpop3_msg_info * info;
+ mailpop3 * pop3;
+
+ pop3 = get_pop3_session(msg_info->msg_session);
+
+ r = mailpop3_get_msg_info(pop3, msg_info->msg_index, &info);
+ switch (r) {
+ case MAILPOP3_NO_ERROR:
+ break;
+ default:
+ return pop3driver_pop3_error_to_mail_error(r);
+ }
+
+ uid = strdup(info->msg_uidl);
+ if (uid == NULL)
+ return MAIL_ERROR_MEMORY;
+
+ r = mailmessage_generic_initialize(msg_info);
+ if (r != MAIL_NO_ERROR) {
+ free(uid);
+ return r;
+ }
+
+ msg = msg_info->msg_data;
+ msg->msg_prefetch = pop3_prefetch;
+ msg->msg_prefetch_free = pop3_prefetch_free;
+ msg_info->msg_uid = uid;
+
+ return MAIL_NO_ERROR;
+}
+
+
+static int pop3_fetch_header(mailmessage * msg_info,
+ char ** result,
+ size_t * result_len)
+{
+ struct generic_message_t * msg;
+ char * headers;
+ size_t headers_length;
+ int r;
+
+ msg = msg_info->msg_data;
+
+ if (msg->msg_message != NULL)
+ return mailmessage_generic_fetch_header(msg_info,
+ result, result_len);
+
+ r = pop3driver_header(msg_info->msg_session, msg_info->msg_index,
+ &headers, &headers_length);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ * result = headers;
+ * result_len = headers_length;
+
+ return MAIL_NO_ERROR;
+}
+
+static int pop3_fetch_size(mailmessage * msg_info,
+ size_t * result)
+{
+ return pop3driver_size(msg_info->msg_session, msg_info->msg_index, result);
+}
diff --git a/libetpan/src/driver/implementation/pop3/pop3driver_message.h b/libetpan/src/driver/implementation/pop3/pop3driver_message.h
new file mode 100644
index 0000000..ad0a01b
--- a/dev/null
+++ b/libetpan/src/driver/implementation/pop3/pop3driver_message.h
@@ -0,0 +1,52 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef POP3DRIVER_MESSAGE_H
+
+#define POP3DRIVER_MESSAGE_H
+
+#include <libetpan/pop3driver_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern mailmessage_driver * pop3_message_driver;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/implementation/pop3/pop3driver_tools.c b/libetpan/src/driver/implementation/pop3/pop3driver_tools.c
new file mode 100644
index 0000000..73dd22a
--- a/dev/null
+++ b/libetpan/src/driver/implementation/pop3/pop3driver_tools.c
@@ -0,0 +1,344 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "pop3driver_tools.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "maildriver_types.h"
+#include "mailpop3.h"
+#include "pop3driver.h"
+#include "pop3driver_cached.h"
+#include "generic_cache.h"
+#include "imfcache.h"
+#include "mailmessage.h"
+#include "mail_cache_db.h"
+
+int pop3driver_pop3_error_to_mail_error(int error)
+{
+ switch (error) {
+ case MAILPOP3_NO_ERROR:
+ return MAIL_NO_ERROR;
+
+ case MAILPOP3_ERROR_BAD_STATE:
+ return MAIL_ERROR_BAD_STATE;
+
+ case MAILPOP3_ERROR_UNAUTHORIZED:
+ return MAIL_ERROR_CONNECT;
+
+ case MAILPOP3_ERROR_STREAM:
+ return MAIL_ERROR_STREAM;
+
+ case MAILPOP3_ERROR_DENIED:
+ return MAIL_ERROR_CONNECT;
+
+ case MAILPOP3_ERROR_BAD_USER:
+ case MAILPOP3_ERROR_BAD_PASSWORD:
+ return MAIL_ERROR_LOGIN;
+
+ case MAILPOP3_ERROR_CANT_LIST:
+ return MAIL_ERROR_LIST;
+
+ case MAILPOP3_ERROR_NO_SUCH_MESSAGE:
+ return MAIL_ERROR_MSG_NOT_FOUND;
+
+ case MAILPOP3_ERROR_MEMORY:
+ return MAIL_ERROR_MEMORY;
+
+ case MAILPOP3_ERROR_CONNECTION_REFUSED:
+ return MAIL_ERROR_CONNECT;
+
+ case MAILPOP3_ERROR_APOP_NOT_SUPPORTED:
+ return MAIL_ERROR_NO_APOP;
+
+ case MAILPOP3_ERROR_CAPA_NOT_SUPPORTED:
+ return MAIL_ERROR_CAPABILITY;
+
+ case MAILPOP3_ERROR_STLS_NOT_SUPPORTED:
+ return MAIL_ERROR_NO_TLS;
+
+ default:
+ return MAIL_ERROR_INVAL;
+ }
+};
+
+static inline struct pop3_session_state_data *
+session_get_data(mailsession * session)
+{
+ return session->sess_data;
+}
+
+static inline mailpop3 * session_get_pop3_session(mailsession * session)
+{
+ return session_get_data(session)->pop3_session;
+}
+
+static inline struct pop3_cached_session_state_data *
+cached_session_get_data(mailsession * session)
+{
+ return session->sess_data;
+}
+
+static inline mailsession *
+cached_session_get_ancestor(mailsession * session)
+{
+ return cached_session_get_data(session)->pop3_ancestor;
+}
+
+static inline struct pop3_session_state_data *
+cached_session_get_ancestor_data(mailsession * session)
+{
+ return session_get_data(cached_session_get_ancestor(session));
+}
+
+static inline mailpop3 *
+cached_session_get_pop3_session(mailsession * session)
+{
+ return session_get_pop3_session(cached_session_get_ancestor(session));
+}
+
+
+int pop3driver_retr(mailsession * session, uint32_t index,
+ char ** result, size_t * result_len)
+{
+ char * msg_content;
+ size_t msg_length;
+ int r;
+
+ r = mailpop3_retr(session_get_pop3_session(session), index,
+ &msg_content, &msg_length);
+
+ switch (r) {
+ case MAILPOP3_NO_ERROR:
+ break;
+ default:
+ return pop3driver_pop3_error_to_mail_error(r);
+ }
+
+ * result = msg_content;
+ * result_len = msg_length;
+
+ return MAIL_NO_ERROR;
+}
+
+int pop3driver_header(mailsession * session, uint32_t index,
+ char ** result,
+ size_t * result_len)
+{
+ char * headers;
+ size_t headers_length;
+ int r;
+
+ r = mailpop3_header(session_get_pop3_session(session),
+ index, &headers, &headers_length);
+
+ switch (r) {
+ case MAILPOP3_NO_ERROR:
+ break;
+ default:
+ return pop3driver_pop3_error_to_mail_error(r);
+ }
+
+ * result = headers;
+ * result_len = headers_length;
+
+ return MAIL_NO_ERROR;
+}
+
+int pop3driver_size(mailsession * session, uint32_t index,
+ size_t * result)
+{
+ mailpop3 * pop3;
+ carray * msg_tab;
+ struct mailpop3_msg_info * info;
+ int r;
+
+ pop3 = session_get_pop3_session(session);
+
+ mailpop3_list(pop3, &msg_tab);
+
+ r = mailpop3_get_msg_info(pop3, index, &info);
+ switch (r) {
+ case MAILPOP3_NO_ERROR:
+ break;
+ default:
+ return pop3driver_pop3_error_to_mail_error(r);
+ }
+
+ * result = info->msg_size;
+
+ return MAIL_NO_ERROR;
+}
+
+int
+pop3driver_get_cached_flags(struct mail_cache_db * cache_db,
+ MMAPString * mmapstr,
+ mailsession * session,
+ uint32_t num,
+ struct mail_flags ** result)
+{
+ int r;
+ char keyname[PATH_MAX];
+ struct mail_flags * flags;
+ int res;
+ struct mailpop3_msg_info * info;
+
+ r = mailpop3_get_msg_info(cached_session_get_pop3_session(session),
+ num, &info);
+ switch (r) {
+ case MAILPOP3_ERROR_BAD_STATE:
+ return MAIL_ERROR_BAD_STATE;
+ case MAILPOP3_ERROR_NO_SUCH_MESSAGE:
+ return MAIL_ERROR_MSG_NOT_FOUND;
+ case MAILPOP3_NO_ERROR:
+ break;
+ default:
+ return MAIL_ERROR_FETCH;
+ }
+
+ snprintf(keyname, PATH_MAX, "%s-flags", info->msg_uidl);
+
+ r = generic_cache_flags_read(cache_db, mmapstr, keyname, &flags);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ * result = flags;
+
+ return MAIL_NO_ERROR;
+
+ err:
+ return res;
+}
+
+int
+pop3driver_write_cached_flags(struct mail_cache_db * cache_db,
+ MMAPString * mmapstr,
+ char * uid,
+ struct mail_flags * flags)
+{
+ int r;
+ char keyname[PATH_MAX];
+ int res;
+
+ snprintf(keyname, PATH_MAX, "%s-flags", uid);
+
+ r = generic_cache_flags_write(cache_db, mmapstr, keyname, flags);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ return MAIL_NO_ERROR;
+
+ err:
+ return res;
+}
+
+int pop3_get_messages_list(mailpop3 * pop3,
+ mailsession * session,
+ mailmessage_driver * driver,
+ struct mailmessage_list ** result)
+{
+ carray * msg_tab;
+ carray * tab;
+ struct mailmessage_list * env_list;
+ unsigned int i;
+ int res;
+ int r;
+
+ mailpop3_list(pop3, &msg_tab);
+
+ tab = carray_new(128);
+ if (tab == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ for(i = 0 ; i < carray_count(msg_tab) ; i++) {
+ struct mailpop3_msg_info * pop3_info;
+ mailmessage * msg;
+
+ pop3_info = carray_get(msg_tab, i);
+
+ if (pop3_info == NULL)
+ continue;
+
+ if (pop3_info->msg_deleted)
+ continue;
+
+ msg = mailmessage_new();
+ if (msg == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ r = mailmessage_init(msg, session, driver,
+ (uint32_t) pop3_info->msg_index, pop3_info->msg_size);
+ if (r != MAIL_NO_ERROR) {
+ mailmessage_free(msg);
+ res = r;
+ goto free_list;
+ }
+
+ r = carray_add(tab, msg, NULL);
+ if (r < 0) {
+ mailmessage_free(msg);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+ }
+
+ env_list = mailmessage_list_new(/*list*/ tab);
+ if (env_list == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ * result = env_list;
+
+ return MAIL_NO_ERROR;
+
+ free_list:
+ for(i = 0 ; i < carray_count(tab) ; i ++)
+ mailmessage_free(carray_get(tab, i));
+ carray_free(tab);
+ err:
+ return res;
+}
diff --git a/libetpan/src/driver/implementation/pop3/pop3driver_tools.h b/libetpan/src/driver/implementation/pop3/pop3driver_tools.h
new file mode 100644
index 0000000..e6413aa
--- a/dev/null
+++ b/libetpan/src/driver/implementation/pop3/pop3driver_tools.h
@@ -0,0 +1,82 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef POP3DRIVER_TOOLS_H
+
+#define POP3DRIVER_TOOLS_H
+
+#include "mail_cache_db_types.h"
+#include "pop3driver_types.h"
+#include "mailpop3.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int pop3driver_pop3_error_to_mail_error(int error);
+
+int pop3driver_retr(mailsession * session, uint32_t index,
+ char ** result, size_t * result_len);
+
+int pop3driver_header(mailsession * session, uint32_t index,
+ char ** result,
+ size_t * result_len);
+
+int pop3driver_size(mailsession * session, uint32_t index,
+ size_t * result);
+
+int
+pop3driver_get_cached_flags(struct mail_cache_db * cache_db,
+ MMAPString * mmapstr,
+ mailsession * session,
+ uint32_t num,
+ struct mail_flags ** result);
+
+int
+pop3driver_write_cached_flags(struct mail_cache_db * cache_db,
+ MMAPString * mmapstr,
+ char * uid,
+ struct mail_flags * flags);
+
+int pop3_get_messages_list(mailpop3 * pop3,
+ mailsession * session,
+ mailmessage_driver * driver,
+ struct mailmessage_list ** result);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/implementation/pop3/pop3driver_types.h b/libetpan/src/driver/implementation/pop3/pop3driver_types.h
new file mode 100644
index 0000000..4bb872c
--- a/dev/null
+++ b/libetpan/src/driver/implementation/pop3/pop3driver_types.h
@@ -0,0 +1,153 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef POP3DRIVER_TYPES_H
+
+#define POP3DRIVER_TYPES_H
+
+#include <libetpan/libetpan-config.h>
+
+#include <libetpan/maildriver_types.h>
+#include <libetpan/mailpop3.h>
+#include <libetpan/maildriver_types.h>
+#include <libetpan/chash.h>
+#include <libetpan/mailstorage_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* POP3 driver for session */
+
+enum {
+ POP3DRIVER_SET_AUTH_TYPE = 1,
+};
+
+enum {
+ POP3DRIVER_AUTH_TYPE_PLAIN = 0,
+ POP3DRIVER_AUTH_TYPE_APOP,
+ POP3DRIVER_AUTH_TYPE_TRY_APOP,
+};
+
+struct pop3_session_state_data {
+ int pop3_auth_type;
+ mailpop3 * pop3_session;
+};
+
+/* cached POP3 driver for session */
+
+enum {
+ /* the mapping of the parameters should be the same as for pop3 */
+ POP3DRIVER_CACHED_SET_AUTH_TYPE = 1,
+ /* cache specific */
+ POP3DRIVER_CACHED_SET_CACHE_DIRECTORY,
+ POP3DRIVER_CACHED_SET_FLAGS_DIRECTORY,
+};
+
+struct pop3_cached_session_state_data {
+ mailsession * pop3_ancestor;
+ char pop3_cache_directory[PATH_MAX];
+ char pop3_flags_directory[PATH_MAX];
+ chash * pop3_flags_hash;
+ carray * pop3_flags_array;
+ struct mail_flags_store * pop3_flags_store;
+};
+
+/* pop3 storage */
+
+/*
+ pop3_mailstorage is the state data specific to the POP3 storage.
+
+ - servername this is the name of the POP3 server
+
+ - port is the port to connect to, on the server.
+ you give 0 to use the default port.
+
+ - connection_type is the type of socket layer to use.
+ The value can be CONNECTION_TYPE_PLAIN, CONNECTION_TYPE_STARTTLS,
+ CONNECTION_TYPE_TRY_STARTTLS or CONNECTION_TYPE_TLS.
+
+ - auth_type is the authenticate mechanism to use.
+ The value can be POP3_AUTH_TYPE_PLAIN, POP3_AUTH_TYPE_APOP
+ or POP3_AUTH_TYPE_TRY_APOP. Other values are not yet implemented.
+
+ - login is the login of the POP3 account.
+
+ - password is the password of the POP3 account.
+
+ - cached if this value is != 0, a persistant cache will be
+ stored on local system.
+
+ - cache_directory is the location of the cache.
+
+ - flags_directory is the location of the flags.
+*/
+
+struct pop3_mailstorage {
+ char * pop3_servername;
+ uint16_t pop3_port;
+ char * pop3_command;
+ int pop3_connection_type;
+
+ int pop3_auth_type;
+ char * pop3_login;
+ char * pop3_password;
+
+ int pop3_cached;
+ char * pop3_cache_directory;
+ char * pop3_flags_directory;
+};
+
+/* this is the type of POP3 authentication */
+
+enum {
+ POP3_AUTH_TYPE_PLAIN, /* plain text authentication */
+ POP3_AUTH_TYPE_APOP, /* APOP authentication */
+ POP3_AUTH_TYPE_TRY_APOP, /* first, try APOP, if it fails,
+ try plain text */
+ POP3_AUTH_TYPE_SASL_ANONYMOUS, /* SASL anonymous */
+ POP3_AUTH_TYPE_SASL_CRAM_MD5, /* SASL CRAM MD5 */
+ POP3_AUTH_TYPE_SASL_KERBEROS_V4, /* SASL KERBEROS V4 */
+ POP3_AUTH_TYPE_SASL_PLAIN, /* SASL plain */
+ POP3_AUTH_TYPE_SASL_SCRAM_MD5, /* SASL SCRAM MD5 */
+ POP3_AUTH_TYPE_SASL_GSSAPI, /* SASL GSSAPI */
+ POP3_AUTH_TYPE_SASL_DIGEST_MD5, /* SASL digest MD5 */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/implementation/pop3/pop3storage.c b/libetpan/src/driver/implementation/pop3/pop3storage.c
new file mode 100644
index 0000000..1cff650
--- a/dev/null
+++ b/libetpan/src/driver/implementation/pop3/pop3storage.c
@@ -0,0 +1,284 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "pop3storage.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "mail.h"
+#include "mailstorage_tools.h"
+#include "maildriver.h"
+
+/* pop3 storage */
+
+#define POP3_DEFAULT_PORT 110
+#define POP3S_DEFAULT_PORT 995
+
+static int pop3_mailstorage_connect(struct mailstorage * storage);
+static int pop3_mailstorage_get_folder_session(struct mailstorage * storage,
+ char * pathname, mailsession ** result);
+static void pop3_mailstorage_uninitialize(struct mailstorage * storage);
+
+static mailstorage_driver pop3_mailstorage_driver = {
+ .sto_name = "pop3",
+ .sto_connect = pop3_mailstorage_connect,
+ .sto_get_folder_session = pop3_mailstorage_get_folder_session,
+ .sto_uninitialize = pop3_mailstorage_uninitialize,
+};
+
+int pop3_mailstorage_init(struct mailstorage * storage,
+ char * pop3_servername, uint16_t pop3_port,
+ char * pop3_command,
+ int pop3_connection_type, int pop3_auth_type,
+ char * pop3_login, char * pop3_password,
+ int pop3_cached, char * pop3_cache_directory, char * pop3_flags_directory)
+{
+ struct pop3_mailstorage * pop3_storage;
+
+ pop3_storage = malloc(sizeof(* pop3_storage));
+ if (pop3_storage == NULL)
+ goto err;
+
+ pop3_storage->pop3_servername = strdup(pop3_servername);
+ if (pop3_storage->pop3_servername == NULL)
+ goto free;
+
+ pop3_storage->pop3_connection_type = pop3_connection_type;
+
+ if (pop3_port == 0) {
+ switch (pop3_connection_type) {
+ case CONNECTION_TYPE_PLAIN:
+ case CONNECTION_TYPE_TRY_STARTTLS:
+ case CONNECTION_TYPE_STARTTLS:
+ case CONNECTION_TYPE_COMMAND:
+ case CONNECTION_TYPE_COMMAND_TRY_STARTTLS:
+ case CONNECTION_TYPE_COMMAND_STARTTLS:
+ pop3_port = POP3_DEFAULT_PORT;
+ break;
+
+ case CONNECTION_TYPE_TLS:
+ case CONNECTION_TYPE_COMMAND_TLS:
+ pop3_port = POP3S_DEFAULT_PORT;
+ break;
+ }
+ }
+
+ pop3_storage->pop3_port = pop3_port;
+
+ if (pop3_command != NULL) {
+ pop3_storage->pop3_command = strdup(pop3_command);
+ if (pop3_storage->pop3_command == NULL)
+ goto free_servername;
+ }
+ else
+ pop3_storage->pop3_command = NULL;
+
+ pop3_storage->pop3_auth_type = pop3_auth_type;
+
+ if (pop3_login != NULL) {
+ pop3_storage->pop3_login = strdup(pop3_login);
+ if (pop3_storage->pop3_login == NULL)
+ goto free_command;
+ }
+ else
+ pop3_storage->pop3_login = NULL;
+
+ if (pop3_password != NULL) {
+ pop3_storage->pop3_password = strdup(pop3_password);
+ if (pop3_storage->pop3_password == NULL)
+ goto free_login;
+ }
+ else
+ pop3_storage->pop3_password = NULL;
+
+ pop3_storage->pop3_cached = pop3_cached;
+
+ if (pop3_cached && (pop3_cache_directory != NULL) &&
+ (pop3_flags_directory != NULL)) {
+ pop3_storage->pop3_cache_directory = strdup(pop3_cache_directory);
+ if (pop3_storage->pop3_cache_directory == NULL)
+ goto free_password;
+ pop3_storage->pop3_flags_directory = strdup(pop3_flags_directory);
+ if (pop3_storage->pop3_flags_directory == NULL)
+ goto free_cache_directory;
+ }
+ else {
+ pop3_storage->pop3_cached = FALSE;
+ pop3_storage->pop3_cache_directory = NULL;
+ pop3_storage->pop3_flags_directory = NULL;
+ }
+
+ storage->sto_data = pop3_storage;
+ storage->sto_driver = &pop3_mailstorage_driver;
+
+ return MAIL_NO_ERROR;
+
+ free_cache_directory:
+ free(pop3_storage->pop3_cache_directory);
+ free_password:
+ if (pop3_storage->pop3_password != NULL)
+ free(pop3_storage->pop3_password);
+ free_login:
+ if (pop3_storage->pop3_login != NULL)
+ free(pop3_storage->pop3_login);
+ free_command:
+ if (pop3_storage->pop3_command != NULL)
+ free(pop3_storage->pop3_command);
+ free_servername:
+ if (pop3_storage->pop3_servername != NULL)
+ free(pop3_storage->pop3_servername);
+ free:
+ free(pop3_storage);
+ err:
+ return MAIL_ERROR_MEMORY;
+}
+
+static void pop3_mailstorage_uninitialize(struct mailstorage * storage)
+{
+ struct pop3_mailstorage * pop3_storage;
+
+ pop3_storage = storage->sto_data;
+
+ if (pop3_storage->pop3_flags_directory != NULL)
+ free(pop3_storage->pop3_flags_directory);
+ if (pop3_storage->pop3_cache_directory != NULL)
+ free(pop3_storage->pop3_cache_directory);
+ if (pop3_storage->pop3_password != NULL)
+ free(pop3_storage->pop3_password);
+ if (pop3_storage->pop3_login != NULL)
+ free(pop3_storage->pop3_login);
+ if (pop3_storage->pop3_command != NULL)
+ free(pop3_storage->pop3_command);
+ free(pop3_storage->pop3_servername);
+ free(pop3_storage);
+
+ storage->sto_data = pop3_storage;
+}
+
+static int pop3_mailstorage_connect(struct mailstorage * storage)
+{
+ struct pop3_mailstorage * pop3_storage;
+ mailsession_driver * driver;
+ int r;
+ int res;
+ mailsession * session;
+ int auth_type;
+
+ pop3_storage = storage->sto_data;
+
+ if (pop3_storage->pop3_cached)
+ driver = pop3_cached_session_driver;
+ else
+ driver = pop3_session_driver;
+
+ r = mailstorage_generic_connect(driver,
+ pop3_storage->pop3_servername,
+ pop3_storage->pop3_port, pop3_storage->pop3_command,
+ pop3_storage->pop3_connection_type,
+ POP3DRIVER_CACHED_SET_CACHE_DIRECTORY,
+ pop3_storage->pop3_cache_directory,
+ POP3DRIVER_CACHED_SET_FLAGS_DIRECTORY,
+ pop3_storage->pop3_flags_directory,
+ &session);
+ switch (r) {
+ case MAIL_NO_ERROR_NON_AUTHENTICATED:
+ case MAIL_NO_ERROR_AUTHENTICATED:
+ case MAIL_NO_ERROR:
+ break;
+ default:
+ res = r;
+ goto err;
+ }
+
+ auth_type = -1;
+ switch (pop3_storage->pop3_auth_type) {
+ case POP3_AUTH_TYPE_PLAIN:
+ auth_type = POP3DRIVER_AUTH_TYPE_PLAIN;
+ break;
+ case POP3_AUTH_TYPE_APOP:
+ auth_type = POP3DRIVER_AUTH_TYPE_APOP;
+ break;
+ case POP3_AUTH_TYPE_TRY_APOP:
+ auth_type = POP3DRIVER_AUTH_TYPE_TRY_APOP;
+ break;
+ }
+
+ if (auth_type != -1) {
+ mailsession_parameters(session, POP3DRIVER_SET_AUTH_TYPE, &auth_type);
+ }
+
+ r = mailstorage_generic_auth(session, r,
+ pop3_storage->pop3_auth_type,
+ pop3_storage->pop3_login,
+ pop3_storage->pop3_password);
+ if (r != MAIL_NO_ERROR) {
+ if (pop3_storage->pop3_auth_type == POP3_AUTH_TYPE_TRY_APOP) {
+ /* try in clear authentication */
+ mailsession_free(session);
+
+ pop3_storage->pop3_auth_type = POP3_AUTH_TYPE_PLAIN;
+ r = mailstorage_connect(storage);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ return res;
+ }
+ pop3_storage->pop3_auth_type = POP3_AUTH_TYPE_TRY_APOP;
+
+ return MAIL_NO_ERROR;
+ }
+
+ res = r;
+ goto free;
+ }
+
+ storage->sto_session = session;
+
+ return MAIL_NO_ERROR;
+
+ free:
+ mailsession_free(session);
+ err:
+ return res;
+}
+
+static int pop3_mailstorage_get_folder_session(struct mailstorage * storage,
+ char * pathname, mailsession ** result)
+{
+ * result = storage->sto_session;
+
+ return MAIL_NO_ERROR;
+}
+
diff --git a/libetpan/src/driver/implementation/pop3/pop3storage.h b/libetpan/src/driver/implementation/pop3/pop3storage.h
new file mode 100644
index 0000000..e8cd513
--- a/dev/null
+++ b/libetpan/src/driver/implementation/pop3/pop3storage.h
@@ -0,0 +1,95 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef POP3STORAGE_H
+
+#define POP3STORAGE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libetpan/pop3driver_types.h>
+#include <libetpan/pop3driver.h>
+#include <libetpan/pop3driver_cached.h>
+
+/*
+ pop3_mailstorage_init is the constructor for a POP3 storage
+
+ @param storage this is the storage to initialize.
+
+ @param servername this is the name of the POP3 server
+
+ @param port is the port to connect to, on the server.
+ you give 0 to use the default port.
+
+ @param command the command used to connect to the server instead of
+ allowing normal TCP connections to be used.
+
+ @param connection_type is the type of socket layer to use.
+ The value can be CONNECTION_TYPE_PLAIN, CONNECTION_TYPE_STARTTLS,
+ CONNECTION_TYPE_TRY_STARTTLS, CONNECTION_TYPE_TLS,
+ CONNECTION_TYPE_COMMAND, CONNECTION_TYPE_COMMAND_STARTTLS,
+ CONNECTION_TYPE_COMMAND_TRY_STARTTLS, CONNECTION_TYPE_COMMAND_TLS,.
+
+ @param auth_type is the authenticate mechanism to use.
+ The value can be POP3_AUTH_TYPE_PLAIN, POP3_AUTH_TYPE_APOP
+ or POP3_AUTH_TYPE_TRY_APOP. Other values are not yet implemented.
+
+ @param login is the login of the POP3 account.
+
+ @param password is the password of the POP3 account.
+
+ @param cached if this value is != 0, a persistant cache will be
+ stored on local system.
+
+ @param cache_directory is the location of the cache
+
+ @param flags_directory is the location of the flags
+*/
+
+int pop3_mailstorage_init(struct mailstorage * storage,
+ char * pop3_servername, uint16_t pop3_port,
+ char * pop3_command,
+ int pop3_connection_type, int pop3_auth_type,
+ char * pop3_login, char * pop3_password,
+ int pop3_cached, char * pop3_cache_directory,
+ char * pop3_flags_directory);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/interface/maildriver.c b/libetpan/src/driver/interface/maildriver.c
new file mode 100644
index 0000000..5b6c4f2
--- a/dev/null
+++ b/libetpan/src/driver/interface/maildriver.c
@@ -0,0 +1,383 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "maildriver.h"
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+
+/* *********************************************************************** */
+/* mail session */
+
+mailsession * mailsession_new(mailsession_driver * sess_driver)
+{
+ mailsession * session;
+ int r;
+
+ session = malloc(sizeof(* session));
+
+ session->sess_data = NULL;
+
+ if (sess_driver->sess_initialize != NULL) {
+ r = sess_driver->sess_initialize(session);
+ if (r != MAIL_NO_ERROR)
+ goto free;
+ }
+
+ session->sess_driver = sess_driver;
+
+ return session;
+
+ free:
+ free(session);
+ return NULL;
+}
+
+void mailsession_free(mailsession * session)
+{
+ if (session->sess_driver->sess_uninitialize != NULL)
+ session->sess_driver->sess_uninitialize(session);
+ free(session);
+}
+
+int mailsession_parameters(mailsession * session,
+ int id, void * value)
+{
+ if (session->sess_driver->sess_parameters == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_parameters(session, id, value);
+}
+
+int mailsession_connect_stream(mailsession * session, mailstream * s)
+{
+ if (session->sess_driver->sess_connect_stream == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_connect_stream(session, s);
+}
+
+int mailsession_connect_path(mailsession * session, char * path)
+{
+ if (session->sess_driver->sess_connect_path == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_connect_path(session, path);
+}
+
+int mailsession_starttls(mailsession * session)
+{
+ if (session->sess_driver->sess_starttls == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_starttls(session);
+}
+
+int mailsession_login(mailsession * session,
+ char * userid, char * password)
+{
+ if (session->sess_driver->sess_login == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_login(session, userid, password);
+}
+
+int mailsession_logout(mailsession * session)
+{
+ if (session->sess_driver->sess_logout == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_logout(session);
+}
+
+int mailsession_noop(mailsession * session)
+{
+ if (session->sess_driver->sess_noop == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_noop(session);
+}
+
+/* folders operations */
+
+int mailsession_build_folder_name(mailsession * session, char * mb,
+ char * name, char ** result)
+{
+ if (session->sess_driver->sess_build_folder_name == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_build_folder_name(session,
+ mb, name, result);
+}
+
+int mailsession_create_folder(mailsession * session, char * mb)
+{
+ if (session->sess_driver->sess_create_folder == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_create_folder(session, mb);
+}
+
+int mailsession_delete_folder(mailsession * session, char * mb)
+{
+ if (session->sess_driver->sess_delete_folder == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_delete_folder(session, mb);
+}
+
+int mailsession_rename_folder(mailsession * session,
+ char * mb, char * new_name)
+{
+ if (session->sess_driver->sess_rename_folder == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_rename_folder(session, mb, new_name);
+}
+
+int mailsession_check_folder(mailsession * session)
+{
+ if (session->sess_driver->sess_check_folder == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_check_folder(session);
+}
+
+int mailsession_examine_folder(mailsession * session, char * mb)
+{
+ if (session->sess_driver->sess_examine_folder == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_examine_folder(session, mb);
+}
+
+int mailsession_select_folder(mailsession * session, char * mb)
+{
+ if (session->sess_driver->sess_select_folder == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_select_folder(session, mb);
+}
+
+int mailsession_expunge_folder(mailsession * session)
+{
+ if (session->sess_driver->sess_expunge_folder == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_expunge_folder(session);
+}
+
+int mailsession_status_folder(mailsession * session, char * mb,
+ uint32_t * result_messages, uint32_t * result_recent,
+ uint32_t * result_unseen)
+{
+ if (session->sess_driver->sess_status_folder == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_status_folder(session, mb,
+ result_messages, result_recent, result_unseen);
+}
+
+int mailsession_messages_number(mailsession * session, char * mb,
+ uint32_t * result)
+{
+ if (session->sess_driver->sess_messages_number == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_messages_number(session, mb, result);
+}
+
+int mailsession_recent_number(mailsession * session, char * mb,
+ uint32_t * result)
+{
+ if (session->sess_driver->sess_recent_number == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_recent_number(session, mb, result);
+}
+
+int mailsession_unseen_number(mailsession * session, char * mb,
+ uint32_t * result)
+{
+ if (session->sess_driver->sess_unseen_number == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_recent_number(session, mb, result);
+}
+
+int mailsession_list_folders(mailsession * session, char * mb,
+ struct mail_list ** result)
+{
+ if (session->sess_driver->sess_list_folders == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_list_folders(session, mb, result);
+}
+
+int mailsession_lsub_folders(mailsession * session, char * mb,
+ struct mail_list ** result)
+{
+ if (session->sess_driver->sess_lsub_folders == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_lsub_folders(session, mb, result);
+}
+
+int mailsession_subscribe_folder(mailsession * session, char * mb)
+{
+ if (session->sess_driver->sess_subscribe_folder == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_subscribe_folder(session, mb);
+}
+
+int mailsession_unsubscribe_folder(mailsession * session, char * mb)
+{
+ if (session->sess_driver->sess_unsubscribe_folder == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_unsubscribe_folder(session, mb);
+}
+
+/* message */
+
+int mailsession_append_message(mailsession * session,
+ char * message, size_t size)
+{
+ if (session->sess_driver->sess_append_message == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_append_message(session, message, size);
+}
+
+int mailsession_append_message_flags(mailsession * session,
+ char * message, size_t size, struct mail_flags * flags)
+{
+ if (session->sess_driver->sess_append_message_flags == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_append_message_flags(session,
+ message, size, flags);
+}
+
+int mailsession_copy_message(mailsession * session,
+ uint32_t num, char * mb)
+{
+ if (session->sess_driver->sess_copy_message == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_copy_message(session, num, mb);
+}
+
+int mailsession_move_message(mailsession * session,
+ uint32_t num, char * mb)
+{
+ if (session->sess_driver->sess_move_message == NULL) {
+ int r;
+
+ if ((session->sess_driver->sess_copy_message == NULL) &&
+ (session->sess_driver->sess_remove_message == NULL))
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ r = mailsession_copy_message(session, num, mb);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ r = mailsession_remove_message(session, num);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ return MAIL_NO_ERROR;
+ }
+
+ return session->sess_driver->sess_move_message(session, num, mb);
+}
+
+int mailsession_get_envelopes_list(mailsession * session,
+ struct mailmessage_list * env_list)
+{
+ if (session->sess_driver->sess_get_envelopes_list == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_get_envelopes_list(session, env_list);
+}
+
+int mailsession_get_messages_list(mailsession * session,
+ struct mailmessage_list ** result)
+{
+ if (session->sess_driver->sess_get_messages_list == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_get_messages_list(session, result);
+}
+
+int mailsession_remove_message(mailsession * session, uint32_t num)
+{
+ if (session->sess_driver->sess_remove_message == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_remove_message(session, num);
+}
+
+#if 0
+int mailsession_search_messages(mailsession * session, char * charset,
+ struct mail_search_key * key,
+ struct mail_search_result ** result)
+{
+ if (session->sess_driver->sess_search_messages == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_search_messages(session,
+ charset, key, result);
+}
+#endif
+
+int mailsession_get_message(mailsession * session,
+ uint32_t num, mailmessage ** result)
+{
+ if (session->sess_driver->sess_get_message == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_get_message(session, num, result);
+}
+
+int mailsession_get_message_by_uid(mailsession * session,
+ const char * uid, mailmessage ** result)
+{
+ if (session->sess_driver->sess_get_message_by_uid == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return session->sess_driver->sess_get_message_by_uid(session, uid, result);
+}
diff --git a/libetpan/src/driver/interface/maildriver.h b/libetpan/src/driver/interface/maildriver.h
new file mode 100644
index 0000000..16e830b
--- a/dev/null
+++ b/libetpan/src/driver/interface/maildriver.h
@@ -0,0 +1,546 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef MAILDRIVER_H
+
+#define MAILDRIVER_H
+
+#include <libetpan/maildriver_types.h>
+#include <libetpan/maildriver_types_helper.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* mailsession */
+
+/*
+ mailsession_new creates a new session, using the given driver
+
+ @return the created session is returned
+*/
+
+mailsession * mailsession_new(mailsession_driver * sess_driver);
+
+/*
+ mailsession_free release the memory used by the session
+*/
+
+void mailsession_free(mailsession * session);
+
+/*
+ mailsession_parameters is used to make calls specific to the driver
+
+ @param id is the command to send to the driver,
+ usually, commands can be found in the header of the driver
+
+ @param value is the parameter of the specific call
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_parameters(mailsession * session,
+ int id, void * value);
+
+/*
+ There are drivers of two kinds : stream drivers (driver that connects
+ to servers through TCP or other means of connection) and file drivers
+ (driver that are based on filesystem)
+
+ The following function can only be used by stream drivers.
+ mailsession_connect_stream connects a stream to the session
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_connect_stream(mailsession * session, mailstream * s);
+
+/*
+ The following function can only be used by file drivers.
+ mailsession_connect_path selects the main path of the session
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_connect_path(mailsession * session, char * path);
+
+/*
+ NOTE: works only on stream drivers
+
+ mailsession_starttls switches the current connection to TLS (secure layer)
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_starttls(mailsession * session);
+
+/*
+ mailsession_login notifies the login and the password to authenticate
+ to the session
+
+ @param userid the given string is only needed at this function call
+ (it will be duplicated if necessary)
+ @param password the given string is only needed at this function call
+ (it will be duplicated if necessary)
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_login(mailsession * session,
+ char * userid, char * password);
+
+/*
+ NOTE: this function doesn't often work on filsystem drivers
+
+ mailsession_logout deconnects the session and closes the stream.
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_logout(mailsession * session);
+
+/*
+ mailsession_noop does no operation on the session, but it can be
+ used to poll for the status of the connection.
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_noop(mailsession * session);
+
+/*
+ NOTE: driver's specific should be used
+
+ mailsession_build_folder_name will return an allocated string with
+ that contains the complete path of the folder to create
+
+ @param session the sesion
+ @param mb is the parent mailbox
+ @param name is the name of the folder to create
+ @param result the complete path of the folder to create will be
+ stored in (* result), this name have to be freed with free()
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_build_folder_name(mailsession * session, char * mb,
+ char * name, char ** result);
+
+/*
+ NOTE: driver's specific should be used
+
+ mailsession_create_folder creates the folder that corresponds to the
+ given name
+
+ @param session the session
+ @param mb is the name of the mailbox
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_create_folder(mailsession * session, char * mb);
+
+
+/*
+ NOTE: driver's specific should be used
+
+ mailsession_delete_folder deletes the folder that corresponds to the
+ given name
+
+ @param session the session
+ @param mb is the name of the mailbox
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_delete_folder(mailsession * session, char * mb);
+
+
+/*
+ mailsession_rename_folder changes the name of the folder
+
+ @param session the session
+ @param mb is the name of the mailbox whose name has to be changed
+ @param new_name is the destination name (the parent
+ of the new folder folder can be other)
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_rename_folder(mailsession * session,
+ char * mb, char * new_name);
+
+/*
+ mailsession_check_folder makes a checkpoint of the session
+
+ @param session the session
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_check_folder(mailsession * session);
+
+
+/*
+ NOTE: this function is not implemented in most drivers
+
+ mailsession_examine_folder selects a mailbox as readonly
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_examine_folder(mailsession * session, char * mb);
+
+
+/*
+ mailsession_select_folder selects a mailbox
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_select_folder(mailsession * session, char * mb);
+
+
+/*
+ mailsession_expunge_folder deletes all messages marked \Deleted
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_expunge_folder(mailsession * session);
+
+
+/*
+ mailsession_status_folder queries the status of the folder
+ (number of messages, number of recent messages, number of unseen messages)
+
+ @param session the session
+ @param mb mailbox to query
+ @param result_messages the number of messages is stored
+ in (* result_messages)
+ @param result_recent the number of messages is stored
+ in (* result_recent)
+ @param result_unseen the number of messages is stored
+ in (* result_unseen)
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_status_folder(mailsession * session, char * mb,
+ uint32_t * result_messages, uint32_t * result_recent,
+ uint32_t * result_unseen);
+
+
+/*
+ mailsession_messages_number queries the number of messages in the folder
+
+ @param session the session
+ @param mb mailbox to query
+ @param result the number of messages is stored in (* result)
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_messages_number(mailsession * session, char * mb,
+ uint32_t * result);
+
+/*
+ mailsession_recent_number queries the number of recent messages in the folder
+
+ @param session the session
+ @param mb mailbox to query
+ @param result the number of recent messages is stored in (* result)
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_recent_number(mailsession * session,
+ char * mb, uint32_t * result);
+
+/*
+ mailsession_unseen_number queries the number of unseen messages in the folder
+
+ @param session the session
+ @param mb mailbox to query
+ @param result the number of unseen messages is stored in (* result)
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_unseen_number(mailsession * session, char * mb,
+ uint32_t * result);
+
+/*
+ NOTE: driver's specific should be used
+
+ mailsession_list_folders returns the list of all sub-mailboxes
+ of the given mailbox
+
+ @param session the session
+ @param mb the mailbox
+ @param result list of mailboxes if stored in (* result),
+ this structure have to be freed with mail_list_free()
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_list_folders(mailsession * session, char * mb,
+ struct mail_list ** result);
+
+/*
+ NOTE: driver's specific should be used
+
+ mailsession_lsub_folders returns the list of subscribed
+ sub-mailboxes of the given mailbox
+
+ @param session the session
+ @param mb the mailbox
+ @param result list of mailboxes if stored in (* result),
+ this structure have to be freed with mail_list_free()
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_lsub_folders(mailsession * session, char * mb,
+ struct mail_list ** result);
+
+/*
+ NOTE: driver's specific should be used
+
+ mailsession_subscribe_folder subscribes to the given mailbox
+
+ @param session the session
+ @param mb the mailbox
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_subscribe_folder(mailsession * session, char * mb);
+
+/*
+ NOTE: driver's specific should be used
+
+ mailsession_unsubscribe_folder unsubscribes to the given mailbox
+
+ @param session the session
+ @param mb the mailbox
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_unsubscribe_folder(mailsession * session, char * mb);
+
+/*
+ mailsession_append_message adds a RFC 2822 message to the current
+ given mailbox
+
+ @param session the session
+ @param message is a string that contains the RFC 2822 message
+ @param size this is the size of the message
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_append_message(mailsession * session,
+ char * message, size_t size);
+
+int mailsession_append_message_flags(mailsession * session,
+ char * message, size_t size, struct mail_flags * flags);
+
+/*
+ NOTE: some drivers does not implement this
+
+ mailsession_copy_message copies a message whose number is given to
+ a given mailbox. The mailbox must be accessible from the same session.
+
+ @param session the session
+ @param num the message number
+ @param mb the destination mailbox
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_copy_message(mailsession * session,
+ uint32_t num, char * mb);
+
+/*
+ NOTE: some drivers does not implement this
+
+ mailsession_move_message copies a message whose number is given to
+ a given mailbox. The mailbox must be accessible from the same session.
+
+ @param session the session
+ @param num the message number
+ @param mb the destination mailbox
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_move_message(mailsession * session,
+ uint32_t num, char * mb);
+
+/*
+ mailsession_get_messages_list returns the list of message numbers
+ of the current mailbox.
+
+ @param session the session
+ @param result the list of message numbers will be stored in (* result),
+ this structure have to be freed with mailmessage_list_free()
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_get_messages_list(mailsession * session,
+ struct mailmessage_list ** result);
+
+/*
+ mailsession_get_envelopes_list fills the parsed fields in the
+ mailmessage structures of the mailmessage_list.
+
+ @param session the session
+ @param result this is the list of mailmessage structures
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_get_envelopes_list(mailsession * session,
+ struct mailmessage_list * result);
+
+/*
+ NOTE: some drivers does not implement this
+
+ mailsession_remove_message removes the given message from the mailbox.
+ The message is permanently deleted.
+
+ @param session the session
+ @param num is the message number
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_remove_message(mailsession * session, uint32_t num);
+
+
+/*
+ NOTE: this function is not implemented in most drivers
+
+ mailsession_search_message returns a list of message numbers that
+ corresponds to the given criteria.
+
+ @param session the session
+ @param charset is the charset to use (it can be NULL)
+ @param key is the list of criteria
+ @param result the search result is stored in (* result),
+ this structure have to be freed with mail_search_result_free()
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+#if 0
+int mailsession_search_messages(mailsession * session, char * charset,
+ struct mail_search_key * key,
+ struct mail_search_result ** result);
+#endif
+
+/*
+ mailsession_get_message returns a mailmessage structure that corresponds
+ to the given message number.
+ * WARNING * mailsession_get_message_by_uid() should be used instead.
+
+ @param session the session
+ @param num the message number
+ @param result the allocated mailmessage structure will be stored
+ in (* result), this structure have to be freed with mailmessage_free()
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_get_message(mailsession * session,
+ uint32_t num, mailmessage ** result);
+
+/*
+ mailsession_get_message_by_uid returns a mailmessage structure
+ that corresponds to the given message unique identifier.
+ This is currently implemented only for cached drivers.
+ * WARNING * That will deprecates the use of mailsession_get_message()
+
+ @param session the session
+ @param uid the message unique identifier
+ @param result the allocated mailmessage structure will be stored
+ in (* result), this structure have to be freed with mailmessage_free()
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailsession_get_message_by_uid(mailsession * session,
+ const char * uid, mailmessage ** result);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/interface/maildriver_errors.h b/libetpan/src/driver/interface/maildriver_errors.h
new file mode 100644
index 0000000..99ec25c
--- a/dev/null
+++ b/libetpan/src/driver/interface/maildriver_errors.h
@@ -0,0 +1,102 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef MAILDRIVER_ERRORS_H
+
+#define MAILDRIVER_ERRORS_H
+
+enum {
+ MAIL_NO_ERROR = 0,
+ MAIL_NO_ERROR_AUTHENTICATED,
+ MAIL_NO_ERROR_NON_AUTHENTICATED,
+ MAIL_ERROR_NOT_IMPLEMENTED,
+ MAIL_ERROR_UNKNOWN,
+ MAIL_ERROR_CONNECT,
+ MAIL_ERROR_BAD_STATE,
+ MAIL_ERROR_FILE,
+ MAIL_ERROR_STREAM,
+ MAIL_ERROR_LOGIN,
+ MAIL_ERROR_CREATE, /* 10 */
+ MAIL_ERROR_DELETE,
+ MAIL_ERROR_LOGOUT,
+ MAIL_ERROR_NOOP,
+ MAIL_ERROR_RENAME,
+ MAIL_ERROR_CHECK,
+ MAIL_ERROR_EXAMINE,
+ MAIL_ERROR_SELECT,
+ MAIL_ERROR_MEMORY,
+ MAIL_ERROR_STATUS,
+ MAIL_ERROR_SUBSCRIBE, /* 20 */
+ MAIL_ERROR_UNSUBSCRIBE,
+ MAIL_ERROR_LIST,
+ MAIL_ERROR_LSUB,
+ MAIL_ERROR_APPEND,
+ MAIL_ERROR_COPY,
+ MAIL_ERROR_FETCH,
+ MAIL_ERROR_STORE,
+ MAIL_ERROR_SEARCH,
+ MAIL_ERROR_DISKSPACE,
+ MAIL_ERROR_MSG_NOT_FOUND, /* 30 */
+ MAIL_ERROR_PARSE,
+ MAIL_ERROR_INVAL,
+ MAIL_ERROR_PART_NOT_FOUND,
+ MAIL_ERROR_REMOVE,
+ MAIL_ERROR_FOLDER_NOT_FOUND,
+ MAIL_ERROR_MOVE,
+ MAIL_ERROR_STARTTLS,
+ MAIL_ERROR_CACHE_MISS,
+ MAIL_ERROR_NO_TLS,
+ MAIL_ERROR_EXPUNGE, /* 40 */
+ /* misc errors */
+ MAIL_ERROR_MISC,
+ MAIL_ERROR_PROTOCOL,
+ MAIL_ERROR_CAPABILITY,
+ MAIL_ERROR_CLOSE,
+ MAIL_ERROR_FATAL,
+ MAIL_ERROR_READONLY,
+ MAIL_ERROR_NO_APOP,
+ MAIL_ERROR_COMMAND_NOT_SUPPORTED,
+ MAIL_ERROR_NO_PERMISSION,
+ MAIL_ERROR_PROGRAM_ERROR, /* 50 */
+ MAIL_ERROR_SUBJECT_NOT_FOUND,
+ MAIL_ERROR_CHAR_ENCODING_FAILED,
+ MAIL_ERROR_SEND,
+ MAIL_ERROR_COMMAND,
+ MAIL_ERROR_SYSTEM,
+ MAIL_ERROR_UNABLE,
+ MAIL_ERROR_FOLDER,
+};
+
+#endif
diff --git a/libetpan/src/driver/interface/maildriver_tools.c b/libetpan/src/driver/interface/maildriver_tools.c
new file mode 100644
index 0000000..4501b23
--- a/dev/null
+++ b/libetpan/src/driver/interface/maildriver_tools.c
@@ -0,0 +1,841 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "maildriver_tools.h"
+
+#include "libetpan-config.h"
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <dirent.h>
+#include <unistd.h>
+
+#include "maildriver.h"
+#include "mailmessage.h"
+#include "mailstream.h"
+#include "mailmime.h"
+#include "mail_cache_db.h"
+
+/* ********************************************************************* */
+/* tools */
+
+
+int
+maildriver_generic_get_envelopes_list(mailsession * session,
+ struct mailmessage_list * env_list)
+{
+ int r;
+ unsigned i;
+#if 0
+ uint32_t j;
+ uint32_t last_msg;
+
+ last_msg = 0;
+#endif
+
+#if 0
+ j = 0;
+ i = 0;
+ while (i < env_list->tab->len) {
+ mailmessage * msg;
+ uint32_t index;
+
+ msg = carray_get(env_list->tab, i);
+
+ index = msg->index;
+
+ if (msg->fields == NULL) {
+ struct mailimf_fields * fields;
+
+ r = mailmessage_fetch_envelope(msg, &fields);
+ if (r != MAIL_NO_ERROR) {
+ /* do nothing */
+ }
+ else {
+ msg->fields = fields;
+
+ carray_set(env_list->tab, j, msg);
+
+ j ++;
+ last_msg = i + 1;
+ }
+ mailmessage_flush(msg);
+ }
+ else {
+ j ++;
+ last_msg = i + 1;
+ }
+
+ i ++;
+ }
+
+ for(i = last_msg ; i < env_list->tab->len ; i ++) {
+ mailmessage_free(carray_get(env_list->tab, i));
+ carray_set(env_list->tab, i, NULL);
+ }
+
+ r = carray_set_size(env_list->tab, j);
+ if (r < 0)
+ return MAIL_ERROR_MEMORY;
+#endif
+
+ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
+ mailmessage * msg;
+
+ msg = carray_get(env_list->msg_tab, i);
+
+ if (msg->msg_fields == NULL) {
+ struct mailimf_fields * fields;
+
+ r = mailmessage_fetch_envelope(msg, &fields);
+ if (r != MAIL_NO_ERROR) {
+ /* do nothing */
+ }
+ else {
+ msg->msg_fields = fields;
+ }
+ mailmessage_flush(msg);
+ }
+ }
+
+ return MAIL_NO_ERROR;
+}
+
+
+#if 0
+static int is_search_header_only(struct mail_search_key * key)
+{
+ clistiter * cur;
+ int result;
+
+ switch (key->type) {
+ case MAIL_SEARCH_KEY_ANSWERED:
+ case MAIL_SEARCH_KEY_BCC:
+ case MAIL_SEARCH_KEY_BEFORE:
+ case MAIL_SEARCH_KEY_CC:
+ case MAIL_SEARCH_KEY_DELETED:
+ case MAIL_SEARCH_KEY_FLAGGED:
+ case MAIL_SEARCH_KEY_FROM:
+ case MAIL_SEARCH_KEY_NEW:
+ case MAIL_SEARCH_KEY_OLD:
+ case MAIL_SEARCH_KEY_ON:
+ case MAIL_SEARCH_KEY_RECENT:
+ case MAIL_SEARCH_KEY_SEEN:
+ case MAIL_SEARCH_KEY_SINCE:
+ case MAIL_SEARCH_KEY_SUBJECT:
+ case MAIL_SEARCH_KEY_TO:
+ case MAIL_SEARCH_KEY_UNANSWERED:
+ case MAIL_SEARCH_KEY_UNDELETED:
+ case MAIL_SEARCH_KEY_UNFLAGGED:
+ case MAIL_SEARCH_KEY_UNSEEN:
+ case MAIL_SEARCH_KEY_HEADER:
+ case MAIL_SEARCH_KEY_LARGER:
+ case MAIL_SEARCH_KEY_NOT:
+ case MAIL_SEARCH_KEY_SMALLER:
+ case MAIL_SEARCH_KEY_ALL:
+ return TRUE;
+
+ case MAIL_SEARCH_KEY_BODY:
+ case MAIL_SEARCH_KEY_TEXT:
+ return FALSE;
+
+ case MAIL_SEARCH_KEY_OR:
+ return (is_search_header_only(key->or1) &&
+ is_search_header_only(key->or2));
+
+ case MAIL_SEARCH_KEY_MULTIPLE:
+ result = TRUE;
+ for (cur = clist_begin(key->multiple) ; cur != NULL ;
+ cur = clist_next(cur))
+ result = result && is_search_header_only(clist_content(cur));
+ return result;
+
+ default:
+ return TRUE;
+ }
+}
+
+static int match_header(struct mailimf_fields * fields,
+ char * name, char * value)
+{
+ clistiter * cur;
+
+ for(cur = clist_begin(fields->list) ; cur != NULL ;
+ cur = clist_content(cur)) {
+ struct mailimf_field * field;
+ struct mailimf_optional_field * opt_field;
+
+ field = clist_content(cur);
+ opt_field = field->optional_field;
+ if ((char) toupper((unsigned char) opt_field->name[0]) ==
+ (char) toupper((unsigned char) name[0])) {
+ if (strcasecmp(opt_field->name, name) == 0)
+ if (strstr(opt_field->value, value) != NULL)
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+static int comp_date(struct mailimf_fields * fields,
+ struct mailimf_date_time * ref_date)
+{
+ clistiter * cur;
+ struct mailimf_date_time * date;
+ int r;
+
+ date = NULL;
+ for(cur = clist_begin(fields->list) ; cur != NULL ;
+ cur = clist_content(cur)) {
+ struct mailimf_field * field;
+ struct mailimf_optional_field * opt_field;
+
+ field = clist_content(cur);
+ opt_field = field->optional_field;
+ if ((char) toupper((unsigned char) opt_field->name[0]) == 'D') {
+ if (strcasecmp(opt_field->name, "Date") == 0) {
+ size_t cur_token;
+
+ cur_token = 0;
+ r = mailimf_date_time_parse(opt_field->value, strlen(opt_field->value),
+ &cur_token, &date);
+ if (r == MAILIMF_NO_ERROR)
+ break;
+ else if (r == MAILIMF_ERROR_PARSE) {
+ /* do nothing */
+ }
+ else
+ break;
+ }
+ }
+ }
+
+ if (date == NULL)
+ return 0;
+
+ return mailimf_date_time_comp(date, ref_date);
+}
+
+static int match_messages(char * message,
+ size_t size,
+ struct mailimf_fields * fields,
+ int32_t flags,
+ char * charset,
+ struct mail_search_key * key)
+{
+ clistiter * cur;
+ size_t length;
+ size_t cur_token;
+ int r;
+
+ switch (key->type) {
+
+ /* flags */
+ case MAIL_SEARCH_KEY_ANSWERED:
+ return ((flags & MAIL_FLAG_ANSWERED) != 0);
+
+ case MAIL_SEARCH_KEY_FLAGGED:
+ return ((flags & MAIL_FLAG_FLAGGED) != 0);
+
+ case MAIL_SEARCH_KEY_DELETED:
+ return ((flags & MAIL_FLAG_DELETED) != 0);
+
+ case MAIL_SEARCH_KEY_RECENT:
+ return ((flags & MAIL_FLAG_NEW) != 0) &&
+ ((flags & MAIL_FLAG_SEEN) == 0);
+
+ case MAIL_SEARCH_KEY_SEEN:
+ return ((flags & MAIL_FLAG_SEEN) != 0);
+
+ case MAIL_SEARCH_KEY_NEW:
+ return ((flags & MAIL_FLAG_NEW) != 0);
+
+ case MAIL_SEARCH_KEY_OLD:
+ return ((flags & MAIL_FLAG_NEW) == 0);
+
+ case MAIL_SEARCH_KEY_UNANSWERED:
+ return ((flags & MAIL_FLAG_ANSWERED) == 0);
+
+ case MAIL_SEARCH_KEY_UNDELETED:
+ return ((flags & MAIL_FLAG_DELETED) == 0);
+
+ case MAIL_SEARCH_KEY_UNFLAGGED:
+ return ((flags & MAIL_FLAG_FLAGGED) == 0);
+
+ case MAIL_SEARCH_KEY_UNSEEN:
+ return ((flags & MAIL_FLAG_SEEN) == 0);
+
+ /* headers */
+ case MAIL_SEARCH_KEY_BCC:
+ return match_header(fields, "Bcc", key->bcc);
+
+ case MAIL_SEARCH_KEY_CC:
+ return match_header(fields, "Cc", key->cc);
+
+ case MAIL_SEARCH_KEY_FROM:
+ return match_header(fields, "From", key->from);
+
+ case MAIL_SEARCH_KEY_SUBJECT:
+ return match_header(fields, "Subject", key->subject);
+
+ case MAIL_SEARCH_KEY_TO:
+ return match_header(fields, "To", key->to);
+
+ case MAIL_SEARCH_KEY_HEADER:
+ return match_header(fields, key->header_name, key->header_value);
+
+ /* date */
+ case MAIL_SEARCH_KEY_BEFORE:
+ return (comp_date(fields, key->before) <= 0);
+
+ case MAIL_SEARCH_KEY_ON:
+ return (comp_date(fields, key->before) == 0);
+
+ case MAIL_SEARCH_KEY_SINCE:
+ return (comp_date(fields, key->before) >= 0);
+
+ /* boolean */
+ case MAIL_SEARCH_KEY_NOT:
+ return (!match_messages(message, size, fields, flags, charset, key->not));
+ case MAIL_SEARCH_KEY_OR:
+ return (match_messages(message, size, fields, flags, charset, key->or1) ||
+ match_messages(message, size, fields, flags, charset, key->or2));
+
+ case MAIL_SEARCH_KEY_MULTIPLE:
+ for(cur = clist_begin(key->multiple) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ if (!match_messages(message, size, fields, flags, charset,
+ clist_content(cur)))
+ return FALSE;
+ }
+
+ return TRUE;
+
+ /* size */
+ case MAIL_SEARCH_KEY_SMALLER:
+ return (size <= key->smaller);
+
+ case MAIL_SEARCH_KEY_LARGER:
+ return (size >= key->larger);
+
+ case MAIL_SEARCH_KEY_BODY:
+ length = strlen(message);
+
+ cur_token = 0;
+ while (1) {
+ r = mailimf_ignore_field_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else
+ break;
+ }
+
+ return (strstr(message + cur_token, key->body) != NULL);
+
+ case MAIL_SEARCH_KEY_TEXT:
+ return (strstr(message, key->body) != NULL);
+
+ case MAIL_SEARCH_KEY_ALL:
+ default:
+ return TRUE;
+ }
+}
+
+int maildriver_generic_search_messages(mailsession * session, char * charset,
+ struct mail_search_key * key,
+ struct mail_search_result ** result)
+{
+ int header;
+ clist * list;
+ struct mail_search_result * search_result;
+ int r;
+ struct mailmessage_list * env_list;
+ int res;
+ unsigned int i;
+
+ header = is_search_header_only(key);
+
+ r = mailsession_get_messages_list(session, &env_list);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ list = NULL;
+ for(i = 0 ; i < carray_count(env_list->tab) ; i ++) {
+ char * message;
+ size_t length;
+ struct mail_info * info;
+ uint32_t flags;
+ struct mailimf_fields * fields;
+ size_t cur_token;
+
+ info = carray_get(env_list->tab, i);
+
+ if (!header) {
+ r = mailsession_fetch_message(session, info->index, &message, &length);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free_list;
+ }
+
+ cur_token = 0;
+ r = mailimf_optional_fields_parse(message, length,
+ &cur_token, &fields);
+ if (r != MAILIMF_NO_ERROR) {
+ res = MAIL_ERROR_PARSE;
+ goto free_list;
+ }
+ }
+ else {
+ char * msg_header;
+ int r;
+ size_t cur_token;
+ size_t header_len;
+
+ r = mailsession_fetch_message_header(session, info->index, &msg_header,
+ &header_len);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free_list;
+ }
+
+ message = NULL;
+ cur_token = 0;
+ r = mailimf_optional_fields_parse(msg_header, header_len,
+ &cur_token, &fields);
+ if (r != MAILIMF_NO_ERROR) {
+ res = MAIL_ERROR_PARSE;
+ goto free_list;
+ }
+
+ mailsession_fetch_result_free(session, msg_header);
+ }
+
+ r = mailsession_get_message_flags(session, info->index, &flags);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free_list;
+ }
+
+ if (match_messages(message, info->size, fields, flags,
+ charset, key)) {
+ uint32_t * pnum;
+
+ pnum = malloc(sizeof(* pnum));
+ if (pnum == NULL) {
+ if (message != NULL)
+ mailsession_fetch_result_free(session, message);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ * pnum = info->index;
+
+ r = clist_append(list, pnum);
+ if (r < 0) {
+ free(pnum);
+ if (message != NULL)
+ mailsession_fetch_result_free(session, message);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+ }
+
+ if (message != NULL)
+ mailsession_fetch_result_free(session, message);
+ }
+
+ search_result = mail_search_result_new(list);
+ if (search_result == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ * result = search_result;
+
+ return MAIL_NO_ERROR;
+
+ free_list:
+ clist_foreach(list, (clist_func) free, NULL);
+ clist_free(list);
+ mailmessage_list_free(env_list);
+ return res;
+}
+#endif
+
+#if 0
+int maildriver_generic_search_messages(mailsession * session, char * charset,
+ struct mail_search_key * key,
+ struct mail_search_result ** result)
+{
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+}
+#endif
+
+int
+maildriver_env_list_to_msg_list(struct mailmessage_list * env_list,
+ clist ** result)
+{
+ clist * msg_list;
+ int r;
+ int res;
+ unsigned int i;
+
+ msg_list = clist_new();
+ if (msg_list == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
+ mailmessage * msg;
+
+ msg = carray_get(env_list->msg_tab, i);
+
+ if (msg->msg_fields == NULL) {
+ uint32_t * pindex;
+
+ pindex = malloc(sizeof(* pindex));
+ if (pindex == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_msg_list;
+ }
+
+ * pindex = msg->msg_index;
+
+ r = clist_append(msg_list, pindex);
+ if (r < 0) {
+ free(pindex);
+ res = MAIL_ERROR_MEMORY;
+ goto free_msg_list;
+ }
+
+ }
+ }
+
+ * result = msg_list;
+
+ return MAIL_NO_ERROR;
+
+ free_msg_list:
+ clist_foreach(msg_list, (clist_func) free, NULL);
+ clist_free(msg_list);
+ err:
+ return res;
+}
+
+
+int
+maildriver_env_list_to_msg_list_no_flags(struct mailmessage_list * env_list,
+ clist ** result)
+{
+ clist * msg_list;
+ int r;
+ int res;
+ unsigned int i;
+
+ msg_list = clist_new();
+ if (msg_list == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
+ mailmessage * msg;
+
+ msg = carray_get(env_list->msg_tab, i);
+
+ if (msg->msg_flags == NULL) {
+ uint32_t * pindex;
+
+ pindex = malloc(sizeof(* pindex));
+ if (pindex == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_msg_list;
+ }
+
+ * pindex = msg->msg_index;
+
+ r = clist_append(msg_list, pindex);
+ if (r < 0) {
+ free(pindex);
+ res = MAIL_ERROR_MEMORY;
+ goto free_msg_list;
+ }
+
+ }
+ }
+
+ * result = msg_list;
+
+ return MAIL_NO_ERROR;
+
+ free_msg_list:
+ clist_foreach(msg_list, (clist_func) free, NULL);
+ clist_free(msg_list);
+ err:
+ return res;
+}
+
+
+
+int maildriver_imf_error_to_mail_error(int error)
+{
+ switch (error) {
+ case MAILIMF_NO_ERROR:
+ return MAIL_NO_ERROR;
+
+ case MAILIMF_ERROR_PARSE:
+ return MAIL_ERROR_PARSE;
+
+ case MAILIMF_ERROR_MEMORY:
+ return MAIL_ERROR_MEMORY;
+
+ case MAILIMF_ERROR_INVAL:
+ return MAIL_ERROR_INVAL;
+
+ case MAILIMF_ERROR_FILE:
+ return MAIL_ERROR_FILE;
+
+ default:
+ return MAIL_ERROR_INVAL;
+ }
+}
+
+char * maildriver_quote_mailbox(char * mb)
+{
+ MMAPString * gstr;
+ char * str;
+
+ gstr = mmap_string_new("");
+ if (gstr == NULL)
+ return NULL;
+
+ while (* mb != 0) {
+ char hex[3];
+
+ if (((* mb >= 'a') && (* mb <= 'z')) ||
+ ((* mb >= 'A') && (* mb <= 'Z')) ||
+ ((* mb >= '0') && (* mb <= '9')))
+ mmap_string_append_c(gstr, * mb);
+ else {
+ if (mmap_string_append_c(gstr, '%') == NULL)
+ goto free;
+ snprintf(hex, 3, "%02x", (unsigned char) (* mb));
+ if (mmap_string_append(gstr, hex) == NULL)
+ goto free;
+ }
+ mb ++;
+ }
+
+ str = strdup(gstr->str);
+ if (str == NULL)
+ goto free;
+
+ mmap_string_free(gstr);
+
+ return str;
+
+ free:
+ mmap_string_free(gstr);
+ return NULL;
+}
+
+
+
+int maildriver_cache_clean_up(struct mail_cache_db * cache_db_env,
+ struct mail_cache_db * cache_db_flags,
+ struct mailmessage_list * env_list)
+{
+ chash * hash_exist;
+ int res;
+ int r;
+ char keyname[PATH_MAX];
+ unsigned int i;
+
+ /* flush cache */
+
+ hash_exist = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYALL);
+ if (hash_exist == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
+ mailmessage * msg;
+ chashdatum key;
+ chashdatum value;
+
+ msg = carray_get(env_list->msg_tab, i);
+
+ value.data = NULL;
+ value.len = 0;
+
+ if (cache_db_env != NULL) {
+ snprintf(keyname, PATH_MAX, "%s-envelope", msg->msg_uid);
+
+ key.data = keyname;
+ key.len = strlen(keyname);
+ r = chash_set(hash_exist, &key, &value, NULL);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free;
+ }
+ }
+
+ if (cache_db_flags != NULL) {
+ snprintf(keyname, PATH_MAX, "%s-flags", msg->msg_uid);
+
+ key.data = keyname;
+ key.len = strlen(keyname);
+ r = chash_set(hash_exist, &key, &value, NULL);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free;
+ }
+ }
+ }
+
+ /* clean up */
+ if (cache_db_env != NULL)
+ mail_cache_db_clean_up(cache_db_env, hash_exist);
+ if (cache_db_flags != NULL)
+ mail_cache_db_clean_up(cache_db_flags, hash_exist);
+
+ chash_free(hash_exist);
+
+ return MAIL_NO_ERROR;
+
+ free:
+ chash_free(hash_exist);
+ err:
+ return res;
+}
+
+
+/*
+ maildriver_message_cache_clean_up()
+
+ remove files in cache_dir that does not correspond to a message.
+
+ get_uid_from_filename() modifies the given filename so that it
+ is a uid when returning from the function. If get_uid_from_filename()
+ clears the content of file (set to empty string), this means that
+ this file should not be deleted.
+*/
+
+int maildriver_message_cache_clean_up(char * cache_dir,
+ struct mailmessage_list * env_list,
+ void (* get_uid_from_filename)(char *))
+{
+ chash * hash_exist;
+ DIR * d;
+ char cached_filename[PATH_MAX];
+ struct dirent * ent;
+ char keyname[PATH_MAX];
+ unsigned int i;
+ int res;
+ int r;
+
+ /* remove files */
+
+ hash_exist = chash_new(CHASH_DEFAULTSIZE, CHASH_COPYALL);
+ if (hash_exist == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
+ mailmessage * msg;
+ chashdatum key;
+ chashdatum value;
+
+ msg = carray_get(env_list->msg_tab, i);
+
+ key.data = msg->msg_uid;
+ key.len = strlen(msg->msg_uid);
+ value.data = NULL;
+ value.len = 0;
+ r = chash_set(hash_exist, &key, &value, NULL);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free;
+ }
+ }
+
+ d = opendir(cache_dir);
+ while ((ent = readdir(d)) != NULL) {
+ chashdatum key;
+ chashdatum value;
+
+ if (strcmp(ent->d_name, ".") == 0)
+ continue;
+
+ if (strcmp(ent->d_name, "..") == 0)
+ continue;
+
+ if (strstr(ent->d_name, ".db") != NULL)
+ continue;
+
+ strncpy(keyname, ent->d_name, sizeof(keyname));
+ keyname[sizeof(keyname) - 1] = '\0';
+
+ get_uid_from_filename(keyname);
+
+ if (* keyname == '\0')
+ continue;
+
+ key.data = keyname;
+ key.len = strlen(keyname);
+
+ r = chash_get(hash_exist, &key, &value);
+ if (r < 0) {
+ snprintf(cached_filename, sizeof(cached_filename),
+ "%s/%s", cache_dir, ent->d_name);
+ unlink(cached_filename);
+ }
+ }
+ closedir(d);
+
+ chash_free(hash_exist);
+
+ return MAIL_NO_ERROR;
+
+ free:
+ chash_free(hash_exist);
+ err:
+ return res;
+}
diff --git a/libetpan/src/driver/interface/maildriver_tools.h b/libetpan/src/driver/interface/maildriver_tools.h
new file mode 100644
index 0000000..a92af42
--- a/dev/null
+++ b/libetpan/src/driver/interface/maildriver_tools.h
@@ -0,0 +1,81 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef MAILDRIVER_TOOLS_H
+
+#define MAILDRIVER_TOOLS_H
+
+#include "maildriver_types.h"
+#include "mail_cache_db_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int
+maildriver_generic_get_envelopes_list(mailsession * session,
+ struct mailmessage_list * env_list);
+
+#if 0
+int maildriver_generic_search_messages(mailsession * session, char * charset,
+ struct mail_search_key * key,
+ struct mail_search_result ** result);
+#endif
+
+int
+maildriver_env_list_to_msg_list(struct mailmessage_list * env_list,
+ clist ** result);
+
+int maildriver_imf_error_to_mail_error(int error);
+
+char * maildriver_quote_mailbox(char * mb);
+
+int
+maildriver_env_list_to_msg_list_no_flags(struct mailmessage_list * env_list,
+ clist ** result);
+
+int maildriver_cache_clean_up(struct mail_cache_db * cache_db_env,
+ struct mail_cache_db * cache_db_flags,
+ struct mailmessage_list * env_list);
+
+int maildriver_message_cache_clean_up(char * cache_dir,
+ struct mailmessage_list * env_list,
+ void (* get_uid_from_filename)(char *));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/interface/maildriver_types.c b/libetpan/src/driver/interface/maildriver_types.c
new file mode 100644
index 0000000..43f5c4f
--- a/dev/null
+++ b/libetpan/src/driver/interface/maildriver_types.c
@@ -0,0 +1,340 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "maildriver_types.h"
+#include <time.h>
+#include <stdlib.h>
+#include "mailmessage.h"
+
+struct mailmessage_list * mailmessage_list_new(carray * msg_tab)
+{
+ struct mailmessage_list * env_list;
+
+ env_list = malloc(sizeof(* env_list));
+ if (env_list == NULL)
+ return NULL;
+
+ env_list->msg_tab = msg_tab;
+
+ return env_list;
+}
+
+void mailmessage_list_free(struct mailmessage_list * env_list)
+{
+ unsigned int i;
+
+ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
+ mailmessage * msg;
+
+ msg = carray_get(env_list->msg_tab, i);
+ if (msg != NULL)
+ mailmessage_free(msg);
+ }
+ carray_free(env_list->msg_tab);
+ free(env_list);
+}
+
+struct mail_list * mail_list_new(clist * list)
+{
+ struct mail_list * resp;
+
+ resp = malloc(sizeof(* resp));
+ if (resp == NULL)
+ return NULL;
+ resp->mb_list = list;
+
+ return resp;
+}
+
+void mail_list_free(struct mail_list * resp)
+{
+ clist_foreach(resp->mb_list, (clist_func) free, NULL);
+ clist_free(resp->mb_list);
+ free(resp);
+}
+
+static int32_t mailimf_date_time_to_int(struct mailimf_date_time * date)
+{
+ return date->dt_year * 12 * 30 * 24 * 60 * 60 +
+ date->dt_month * 30 * 24 * 60 * 60 + date->dt_day * 24 * 60 * 60 +
+ (date->dt_hour - date->dt_zone) * 60 * 60 +
+ date->dt_min * 60 + date->dt_sec;
+}
+
+int32_t mailimf_date_time_comp(struct mailimf_date_time * date1,
+ struct mailimf_date_time * date2)
+{
+ return mailimf_date_time_to_int(date1) - mailimf_date_time_to_int(date2);
+}
+
+
+
+
+
+
+
+#if 0
+struct mail_search_key *
+mail_search_key_new(int sk_type,
+ char * sk_bcc,
+ struct mailimf_date_time * sk_before,
+ char * sk_body,
+ char * sk_cc,
+ char * sk_from,
+ struct mailimf_date_time * sk_on,
+ struct mailimf_date_time * sk_since,
+ char * sk_subject,
+ char * sk_text,
+ char * sk_to,
+ char * sk_header_name,
+ char * sk_header_value,
+ size_t sk_larger,
+ struct mail_search_key * sk_not,
+ struct mail_search_key * sk_or1,
+ struct mail_search_key * sk_or2,
+ size_t sk_smaller,
+ clist * sk_multiple)
+{
+ struct mail_search_key * key;
+
+ key = malloc(sizeof(* key));
+ if (key == NULL)
+ return NULL;
+
+ key->sk_type = sk_type;
+ key->sk_bcc = sk_bcc;
+ key->sk_before = sk_before;
+ key->sk_body = sk_body;
+ key->sk_cc = sk_cc;
+ key->sk_from = sk_from;
+ key->sk_on = sk_on;
+ key->sk_since = sk_since;
+ key->sk_subject = sk_subject;
+ key->sk_text = sk_text;
+ key->sk_to = sk_to;
+ key->sk_header_name = sk_header_name;
+ key->sk_header_value = sk_header_value;
+ key->sk_larger = sk_larger;
+ key->sk_not = sk_not;
+ key->sk_or1 = sk_or1;
+ key->sk_or2 = sk_or2;
+ key->sk_smaller = sk_smaller;
+ key->sk_multiple = sk_multiple;
+
+ return key;
+}
+
+
+void mail_search_key_free(struct mail_search_key * key)
+{
+ if (key->sk_bcc)
+ free(key->sk_bcc);
+ if (key->sk_before)
+ mailimf_date_time_free(key->sk_before);
+ if (key->sk_body)
+ free(key->sk_body);
+ if (key->sk_cc)
+ free(key->sk_cc);
+ if (key->sk_from)
+ free(key->sk_from);
+ if (key->sk_on)
+ mailimf_date_time_free(key->sk_on);
+ if (key->sk_since)
+ mailimf_date_time_free(key->sk_since);
+ if (key->sk_subject)
+ free(key->sk_subject);
+ if (key->sk_text)
+ free(key->sk_text);
+ if (key->sk_to)
+ free(key->sk_to);
+ if (key->sk_header_name)
+ free(key->sk_header_name);
+ if (key->sk_header_value)
+ free(key->sk_header_value);
+ if (key->sk_not)
+ mail_search_key_free(key->sk_not);
+ if (key->sk_or1)
+ mail_search_key_free(key->sk_or1);
+ if (key->sk_or2)
+ mail_search_key_free(key->sk_or2);
+ if (key->sk_multiple) {
+ clist_foreach(key->sk_multiple, (clist_func) mail_search_key_free, NULL);
+ clist_free(key->sk_multiple);
+ }
+
+ free(key);
+}
+
+
+struct mail_search_result * mail_search_result_new(clist * list)
+{
+ struct mail_search_result * search_result;
+
+ search_result = malloc(sizeof(* search_result));
+ if (search_result == NULL)
+ return NULL;
+ search_result->list = list;
+
+ return search_result;
+}
+
+void mail_search_result_free(struct mail_search_result * search_result)
+{
+ clist_foreach(search_result->list, (clist_func) free, NULL);
+ clist_free(search_result->list);
+ free(search_result);
+}
+#endif
+
+struct error_message {
+ int code;
+ char * message;
+};
+
+static struct error_message message_tab[] = {
+{ MAIL_NO_ERROR, "no error" },
+{ MAIL_NO_ERROR_AUTHENTICATED, "no error - authenticated" },
+{ MAIL_NO_ERROR_NON_AUTHENTICATED, "no error - not authenticated" },
+{ MAIL_ERROR_NOT_IMPLEMENTED, "not implemented" },
+{ MAIL_ERROR_UNKNOWN, "unknown"},
+{ MAIL_ERROR_CONNECT, "connect"},
+{ MAIL_ERROR_BAD_STATE, "bad state"},
+{ MAIL_ERROR_FILE, "file error - file could not be accessed" },
+{ MAIL_ERROR_STREAM, "stream error - socket could not be read or written" },
+{ MAIL_ERROR_LOGIN, "login error" },
+{ MAIL_ERROR_CREATE, "create error" },
+{ MAIL_ERROR_DELETE, /* 10 */ "delete error" },
+{ MAIL_ERROR_LOGOUT, "logout error" },
+{ MAIL_ERROR_NOOP, "noop error" },
+{ MAIL_ERROR_RENAME, "rename error" },
+{ MAIL_ERROR_CHECK, "check error" },
+{ MAIL_ERROR_EXAMINE, "examine error" },
+{ MAIL_ERROR_SELECT, "select error - folder does not exist" },
+{ MAIL_ERROR_MEMORY, "not enough memory" },
+{ MAIL_ERROR_STATUS, "status error" },
+{ MAIL_ERROR_SUBSCRIBE, "subscribe error" },
+{ MAIL_ERROR_UNSUBSCRIBE, /* 20 */ "unsubscribe error" },
+{ MAIL_ERROR_LIST, "list error" },
+{ MAIL_ERROR_LSUB, "lsub error" },
+{ MAIL_ERROR_APPEND, "append error - mail could not be appended" },
+{ MAIL_ERROR_COPY, "copy error" },
+{ MAIL_ERROR_FETCH, "fetch error" },
+{ MAIL_ERROR_STORE, "store error" },
+{ MAIL_ERROR_SEARCH, "search error" },
+{ MAIL_ERROR_DISKSPACE, " error: not enough diskspace" },
+{ MAIL_ERROR_MSG_NOT_FOUND, "message not found" },
+{ MAIL_ERROR_PARSE, /* 30 */ "parse error" },
+{ MAIL_ERROR_INVAL, "invalid parameter for the function" },
+{ MAIL_ERROR_PART_NOT_FOUND, "mime part of the message is not found" },
+{ MAIL_ERROR_REMOVE, "remove error - the message did not exist" },
+{ MAIL_ERROR_FOLDER_NOT_FOUND, "folder not found" },
+{ MAIL_ERROR_MOVE, "move error" },
+{ MAIL_ERROR_STARTTLS, "starttls error" },
+{ MAIL_ERROR_CACHE_MISS, "mail cache missed" },
+{ MAIL_ERROR_NO_TLS, "no starttls" },
+{ MAIL_ERROR_EXPUNGE, "expunge error" },
+{ MAIL_ERROR_PROTOCOL, "protocol error - server did not respect the protocol" },
+{ MAIL_ERROR_CAPABILITY, "capability error" },
+{ MAIL_ERROR_CLOSE, "close error" },
+{ MAIL_ERROR_FATAL, "fatal error" },
+{ MAIL_ERROR_READONLY, "mailbox is readonly" },
+{ MAIL_ERROR_NO_APOP, "pop3 error - no apop" },
+{ MAIL_ERROR_COMMAND_NOT_SUPPORTED, "nntp error - command not supported" },
+{ MAIL_ERROR_NO_PERMISSION, "nntp error - no permission" },
+{ MAIL_ERROR_PROGRAM_ERROR, "nntp error - program error" },
+{ MAIL_ERROR_SUBJECT_NOT_FOUND, "internal threading error - subject not found" }};
+
+const char * maildriver_strerror(int err)
+{
+ int count;
+ int i;
+
+ count = sizeof(message_tab) / sizeof(struct error_message);
+
+ for(i = 0 ; i < count ; i++) {
+ if (message_tab[i].code == err) {
+ return message_tab[i].message;
+ }
+ }
+
+ return "unknown error";
+}
+
+
+struct mail_flags * mail_flags_new_empty(void)
+{
+ struct mail_flags * flags;
+
+ flags = malloc(sizeof(* flags));
+ if (flags == NULL)
+ goto err;
+
+ flags->fl_flags = MAIL_FLAG_NEW;
+ flags->fl_extension = clist_new();
+ if (flags->fl_extension == NULL)
+ goto free;
+
+ return flags;
+
+ free:
+ free(flags);
+ err:
+ return NULL;
+}
+
+struct mail_flags * mail_flags_new(uint32_t fl_flags, clist * fl_extension)
+{
+ struct mail_flags * flags;
+
+ flags = malloc(sizeof(* flags));
+ if (flags == NULL)
+ goto err;
+
+ flags->fl_flags = fl_flags;
+ flags->fl_extension = fl_extension;
+
+ return flags;
+
+err:
+ return NULL;
+}
+
+void mail_flags_free(struct mail_flags * flags)
+{
+ clist_foreach(flags->fl_extension, (clist_func) free, NULL);
+ clist_free(flags->fl_extension);
+ free(flags);
+}
+
diff --git a/libetpan/src/driver/interface/maildriver_types.h b/libetpan/src/driver/interface/maildriver_types.h
new file mode 100644
index 0000000..2225236
--- a/dev/null
+++ b/libetpan/src/driver/interface/maildriver_types.h
@@ -0,0 +1,795 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef MAILDRIVER_TYPES_H
+
+#define MAILDRIVER_TYPES_H
+
+#include <inttypes.h>
+#include <sys/types.h>
+
+#include <libetpan/mailstream.h>
+#include <libetpan/mailimf.h>
+#include <libetpan/mailmime.h>
+#include <libetpan/carray.h>
+
+#include <libetpan/mailthread_types.h>
+#include <libetpan/maildriver_errors.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct mailsession_driver mailsession_driver;
+
+typedef struct mailsession mailsession;
+
+typedef struct mailmessage_driver mailmessage_driver;
+
+typedef struct mailmessage mailmessage;
+
+
+/*
+ mailmessage_list is a list of mailmessage
+
+ - tab is an array of mailmessage structures
+*/
+
+struct mailmessage_list {
+ carray * msg_tab; /* elements are (mailmessage *) */
+};
+
+struct mailmessage_list * mailmessage_list_new(carray * msg_tab);
+void mailmessage_list_free(struct mailmessage_list * env_list);
+
+/*
+ mail_list is a list of mailbox names
+
+ - list is a list of mailbox names
+*/
+
+struct mail_list {
+ clist * mb_list; /* elements are (char *) */
+};
+
+struct mail_list * mail_list_new(clist * mb_list);
+void mail_list_free(struct mail_list * resp);
+
+/*
+ This is a flag value.
+ Flags can be combined with OR operation
+*/
+
+enum {
+ MAIL_FLAG_NEW = 1 << 0,
+ MAIL_FLAG_SEEN = 1 << 1,
+ MAIL_FLAG_FLAGGED = 1 << 2,
+ MAIL_FLAG_DELETED = 1 << 3,
+ MAIL_FLAG_ANSWERED = 1 << 4,
+ MAIL_FLAG_FORWARDED = 1 << 5,
+ MAIL_FLAG_CANCELLED = 1 << 6,
+};
+
+/*
+ mail_flags is the value of a flag related to a message.
+
+ - flags is the standard flags value
+
+ - extension is a list of unknown flags for libEtPan!
+*/
+
+struct mail_flags {
+ uint32_t fl_flags;
+ clist * fl_extension; /* elements are (char *) */
+};
+
+struct mail_flags * mail_flags_new(uint32_t fl_flags, clist * fl_ext);
+void mail_flags_free(struct mail_flags * flags);
+
+/*
+ This function creates a flag for a new message
+*/
+
+struct mail_flags * mail_flags_new_empty(void);
+
+
+/*
+ mailimf_date_time_comp compares two dates
+
+
+*/
+
+int32_t mailimf_date_time_comp(struct mailimf_date_time * date1,
+ struct mailimf_date_time * date2);
+
+/*
+ this is type type of the search criteria
+*/
+
+enum {
+ MAIL_SEARCH_KEY_ALL, /* all messages correspond */
+ MAIL_SEARCH_KEY_ANSWERED, /* messages with flag \Answered */
+ MAIL_SEARCH_KEY_BCC, /* messages which Bcc field contains
+ a given string */
+ MAIL_SEARCH_KEY_BEFORE, /* messages which internal date is earlier
+ than the specified date */
+ MAIL_SEARCH_KEY_BODY, /* message that contains the given string
+ (in header and text parts) */
+ MAIL_SEARCH_KEY_CC, /* messages whose Cc field contains the
+ given string */
+ MAIL_SEARCH_KEY_DELETED, /* messages with the flag \Deleted */
+ MAIL_SEARCH_KEY_FLAGGED, /* messages with the flag \Flagged */
+ MAIL_SEARCH_KEY_FROM, /* messages whose From field contains the
+ given string */
+ MAIL_SEARCH_KEY_NEW, /* messages with the flag \Recent and not
+ the \Seen flag */
+ MAIL_SEARCH_KEY_OLD, /* messages that do not have the
+ \Recent flag set */
+ MAIL_SEARCH_KEY_ON, /* messages whose internal date is the
+ specified date */
+ MAIL_SEARCH_KEY_RECENT, /* messages with the flag \Recent */
+ MAIL_SEARCH_KEY_SEEN, /* messages with the flag \Seen */
+ MAIL_SEARCH_KEY_SINCE, /* messages whose internal date is later
+ than specified date */
+ MAIL_SEARCH_KEY_SUBJECT, /* messages whose Subject field contains the
+ given string */
+ MAIL_SEARCH_KEY_TEXT, /* messages whose text part contains the
+ given string */
+ MAIL_SEARCH_KEY_TO, /* messages whose To field contains the
+ given string */
+ MAIL_SEARCH_KEY_UNANSWERED, /* messages with no flag \Answered */
+ MAIL_SEARCH_KEY_UNDELETED, /* messages with no flag \Deleted */
+ MAIL_SEARCH_KEY_UNFLAGGED, /* messages with no flag \Flagged */
+ MAIL_SEARCH_KEY_UNSEEN, /* messages with no flag \Seen */
+ MAIL_SEARCH_KEY_HEADER, /* messages whose given field
+ contains the given string */
+ MAIL_SEARCH_KEY_LARGER, /* messages whose size is larger then
+ the given size */
+ MAIL_SEARCH_KEY_NOT, /* not operation of the condition */
+ MAIL_SEARCH_KEY_OR, /* or operation between two conditions */
+ MAIL_SEARCH_KEY_SMALLER, /* messages whose size is smaller than
+ the given size */
+ MAIL_SEARCH_KEY_MULTIPLE /* the boolean operator between the
+ conditions is AND */
+};
+
+/*
+ mail_search_key is the condition on the messages to return
+
+ - type is the type of the condition
+
+ - bcc is the text to search in the Bcc field when type is
+ MAIL_SEARCH_KEY_BCC, should be allocated with malloc()
+
+ - before is a date when type is MAIL_SEARCH_KEY_BEFORE
+
+ - body is the text to search in the message when type is
+ MAIL_SEARCH_KEY_BODY, should be allocated with malloc()
+
+ - cc is the text to search in the Cc field when type is
+ MAIL_SEARCH_KEY_CC, should be allocated with malloc()
+
+ - from is the text to search in the From field when type is
+ MAIL_SEARCH_KEY_FROM, should be allocated with malloc()
+
+ - on is a date when type is MAIL_SEARCH_KEY_ON
+
+ - since is a date when type is MAIL_SEARCH_KEY_SINCE
+
+ - subject is the text to search in the Subject field when type is
+ MAILIMAP_SEARCH_KEY_SUBJECT, should be allocated with malloc()
+
+ - text is the text to search in the text part of the message when
+ type is MAILIMAP_SEARCH_KEY_TEXT, should be allocated with malloc()
+
+ - to is the text to search in the To field when type is
+ MAILIMAP_SEARCH_KEY_TO, should be allocated with malloc()
+
+ - header_name is the header name when type is MAILIMAP_SEARCH_KEY_HEADER,
+ should be allocated with malloc()
+
+ - header_value is the text to search in the given header when type is
+ MAILIMAP_SEARCH_KEY_HEADER, should be allocated with malloc()
+
+ - larger is a size when type is MAILIMAP_SEARCH_KEY_LARGER
+
+ - not is a condition when type is MAILIMAP_SEARCH_KEY_NOT
+
+ - or1 is a condition when type is MAILIMAP_SEARCH_KEY_OR
+
+ - or2 is a condition when type is MAILIMAP_SEARCH_KEY_OR
+
+ - sentbefore is a date when type is MAILIMAP_SEARCH_KEY_SENTBEFORE
+
+ - senton is a date when type is MAILIMAP_SEARCH_KEY_SENTON
+
+ - sentsince is a date when type is MAILIMAP_SEARCH_KEY_SENTSINCE
+
+ - smaller is a size when type is MAILIMAP_SEARCH_KEY_SMALLER
+
+ - multiple is a set of message when type is MAILIMAP_SEARCH_KEY_MULTIPLE
+*/
+
+#if 0
+struct mail_search_key {
+ int sk_type;
+ union {
+ char * sk_bcc;
+ struct mailimf_date_time * sk_before;
+ char * sk_body;
+ char * sk_cc;
+ char * sk_from;
+ struct mailimf_date_time * sk_on;
+ struct mailimf_date_time * sk_since;
+ char * sk_subject;
+ char * sk_text;
+ char * sk_to;
+ char * sk_header_name;
+ char * sk_header_value;
+ size_t sk_larger;
+ struct mail_search_key * sk_not;
+ struct mail_search_key * sk_or1;
+ struct mail_search_key * sk_or2;
+ size_t sk_smaller;
+ clist * sk_multiple; /* list of (struct mailimap_search_key *) */
+ } sk_data;
+};
+
+
+struct mail_search_key *
+mail_search_key_new(int sk_type,
+ char * sk_bcc, struct mailimf_date_time * sk_before,
+ char * sk_body, char * sk_cc, char * sk_from,
+ struct mailimf_date_time * sk_on, struct mailimf_date_time * sk_since,
+ char * sk_subject, char * sk_text, char * sk_to,
+ char * sk_header_name, char * sk_header_value, size_t sk_larger,
+ struct mail_search_key * sk_not, struct mail_search_key * sk_or1,
+ struct mail_search_key * sk_or2, size_t sk_smaller,
+ clist * sk_multiple);
+
+void mail_search_key_free(struct mail_search_key * key);
+#endif
+
+/*
+ mail_search_result is a list of message numbers that is returned
+ by the mailsession_search_messages function()
+*/
+
+#if 0
+struct mail_search_result {
+ clist * sr_list; /* list of (uint32_t *) */
+};
+
+struct mail_search_result * mail_search_result_new(clist * sr_list);
+
+void mail_search_result_free(struct mail_search_result * search_result);
+#endif
+
+
+/*
+ There is three kinds of identities :
+ - storage
+ - folders
+ - session
+
+ A storage (struct mailstorage) represents whether a server or
+ a main path,
+
+ A storage can be an IMAP server, the root path of a MH or a mbox file.
+
+ Folders (struct mailfolder) are the mailboxes we can
+ choose in the server or as sub-folder of the main path.
+
+ Folders for IMAP are the IMAP mailboxes, for MH this is one of the
+ folder of the MH storage, for mbox, there is only one folder, the
+ mbox file content;
+
+ A mail session (struct mailsession) is whether a connection to a server
+ or a path that is open. It is the abstraction lower folders and storage.
+ It allow us to send commands.
+
+ We have a session driver for mail session for each kind of storage.
+
+ From a session, we can get a message (struct mailmessage) to read.
+ We have a message driver for each kind of storage.
+*/
+
+/*
+ maildriver is the driver structure for mail sessions
+
+ - name is the name of the driver
+
+ - initialize() is the function that will initializes a data structure
+ specific to the driver, it returns a value that will be stored
+ in the field data of the session.
+ The field data of the session is the state of the session,
+ the internal data structure used by the driver.
+ It is called when creating the mailsession structure with
+ mailsession_new().
+
+ - uninitialize() frees the structure created with initialize()
+
+ - parameters() implements functions specific to the given mail access
+
+ - connect_stream() connects a stream to the session
+
+ - connect_path() notify a main path to the session
+
+ - starttls() changes the current stream to a TLS stream
+
+ - login() notifies the user and the password to authenticate to the
+ session
+
+ - logout() exits the session and closes the stream
+
+ - noop() does no operation on the session, but it can be
+ used to poll for the status of the connection.
+
+ - build_folder_name() will return an allocated string with
+ that contains the complete path of the folder to create
+
+ - create_folder() creates the folder that corresponds to the
+ given name
+
+ - delete_folder() deletes the folder that corresponds to the
+ given name
+
+ - rename_folder() change the name of the folder
+
+ - check_folder() makes a checkpoint of the session
+
+ - examine_folder() selects a mailbox as readonly
+
+ - select_folder() selects a mailbox
+
+ - expunge_folder() deletes all messages marked \Deleted
+
+ - status_folder() queries the status of the folder
+ (number of messages, number of recent messages, number of
+ unseen messages)
+
+ - messages_number() queries the number of messages in the folder
+
+ - recent_number() queries the number of recent messages in the folder
+
+ - unseen_number() queries the number of unseen messages in the folder
+
+ - list_folders() returns the list of all sub-mailboxes
+ of the given mailbox
+
+ - lsub_folders() returns the list of subscribed
+ sub-mailboxes of the given mailbox
+
+ - subscribe_folder() subscribes to the given mailbox
+
+ - unsubscribe_folder() unsubscribes to the given mailbox
+
+ - append_message() adds a RFC 2822 message to the current
+ given mailbox
+
+ - copy_message() copies a message whose number is given to
+ a given mailbox. The mailbox must be accessible from
+ the same session.
+
+ - move_message() copies a message whose number is given to
+ a given mailbox. The mailbox must be accessible from the
+ same session.
+
+ - get_messages_list() returns the list of message numbers
+ of the current mailbox.
+
+ - get_envelopes_list() fills the parsed fields in the
+ mailmessage structures of the mailmessage_list.
+
+ - remove_message() removes the given message from the mailbox.
+ The message is permanently deleted.
+
+ - search_message() returns a list of message numbers that
+ corresponds to the given criteria.
+
+ - get_message returns a mailmessage structure that corresponds
+ to the given message number.
+
+ - get_message_by_uid returns a mailmessage structure that corresponds
+ to the given message unique identifier.
+
+ * mandatory functions are the following :
+
+ - connect_stream() of connect_path()
+ - logout()
+ - get_messages_list()
+ - get_envelopes_list()
+
+ * we advise you to implement these functions :
+
+ - select_folder() (in case a session can access several folders)
+ - noop() (to check if the server is responding)
+ - check_folder() (to make a checkpoint of the session)
+ - status_folder(), messages_number(), recent_number(), unseen_number()
+ (to get stat of the folder)
+ - append_message() (but can't be done in the case of POP3 at least)
+ - login() in a case of an authenticated driver.
+ - starttls() in a case of a stream driver, if the procotol supports
+ STARTTLS.
+ - get_message_by_uid() so that the application can remember the message
+ by UID and build its own list of messages.
+
+ * drivers' specific :
+
+ Everything that is specific to the driver will be implemented in this
+ function :
+
+ - parameters()
+*/
+
+struct mailsession_driver {
+ char * sess_name;
+
+ int (* sess_initialize)(mailsession * session);
+ void (* sess_uninitialize)(mailsession * session);
+
+ int (* sess_parameters)(mailsession * session,
+ int id, void * value);
+
+ int (* sess_connect_stream)(mailsession * session, mailstream * s);
+ int (* sess_connect_path)(mailsession * session, char * path);
+
+ int (* sess_starttls)(mailsession * session);
+
+ int (* sess_login)(mailsession * session, char * userid, char * password);
+ int (* sess_logout)(mailsession * session);
+ int (* sess_noop)(mailsession * session);
+
+ /* folders operations */
+
+ int (* sess_build_folder_name)(mailsession * session, char * mb,
+ char * name, char ** result);
+
+ int (* sess_create_folder)(mailsession * session, char * mb);
+ int (* sess_delete_folder)(mailsession * session, char * mb);
+ int (* sess_rename_folder)(mailsession * session, char * mb,
+ char * new_name);
+ int (* sess_check_folder)(mailsession * session);
+ int (* sess_examine_folder)(mailsession * session, char * mb);
+ int (* sess_select_folder)(mailsession * session, char * mb);
+ int (* sess_expunge_folder)(mailsession * session);
+ int (* sess_status_folder)(mailsession * session, char * mb,
+ uint32_t * result_num, uint32_t * result_recent,
+ uint32_t * result_unseen);
+ int (* sess_messages_number)(mailsession * session, char * mb,
+ uint32_t * result);
+ int (* sess_recent_number)(mailsession * session, char * mb,
+ uint32_t * result);
+ int (* sess_unseen_number)(mailsession * session, char * mb,
+ uint32_t * result);
+
+ int (* sess_list_folders)(mailsession * session, char * mb,
+ struct mail_list ** result);
+ int (* sess_lsub_folders)(mailsession * session, char * mb,
+ struct mail_list ** result);
+
+ int (* sess_subscribe_folder)(mailsession * session, char * mb);
+ int (* sess_unsubscribe_folder)(mailsession * session, char * mb);
+
+ /* messages operations */
+
+ int (* sess_append_message)(mailsession * session,
+ char * message, size_t size);
+ int (* sess_append_message_flags)(mailsession * session,
+ char * message, size_t size, struct mail_flags * flags);
+ int (* sess_copy_message)(mailsession * session,
+ uint32_t num, char * mb);
+ int (* sess_move_message)(mailsession * session,
+ uint32_t num, char * mb);
+
+ int (* sess_get_message)(mailsession * session,
+ uint32_t num, mailmessage ** result);
+
+ int (* sess_get_message_by_uid)(mailsession * session,
+ const char * uid, mailmessage ** result);
+
+ int (* sess_get_messages_list)(mailsession * session,
+ struct mailmessage_list ** result);
+ int (* sess_get_envelopes_list)(mailsession * session,
+ struct mailmessage_list * env_list);
+ int (* sess_remove_message)(mailsession * session, uint32_t num);
+#if 0
+ int (* sess_search_messages)(mailsession * session, char * charset,
+ struct mail_search_key * key,
+ struct mail_search_result ** result);
+#endif
+};
+
+
+/*
+ session is the data structure for a mail session.
+
+ - data is the internal data structure used by the driver
+ It is called when initializing the mailsession structure.
+
+ - driver is the driver used for the session
+*/
+
+struct mailsession {
+ void * sess_data;
+ mailsession_driver * sess_driver;
+};
+
+
+
+
+/*
+ mailmessage_driver is the driver structure to get information from messages.
+
+ - name is the name of the driver
+
+ - initialize() is the function that will initializes a data structure
+ specific to the driver, it returns a value that will be stored
+ in the field data of the mailsession.
+ The field data of the session is the state of the session,
+ the internal data structure used by the driver.
+ It is called when initializing the mailmessage structure with
+ mailmessage_init().
+
+ - uninitialize() frees the structure created with initialize().
+ It will be called by mailmessage_free().
+
+ - flush() will free from memory all temporary structures of the message
+ (for example, the MIME structure of the message).
+
+ - fetch_result_free() will free all strings resulted by fetch() or
+ any fetch_xxx() functions that returns a string.
+
+ - fetch() returns the content of the message (headers and text).
+
+ - fetch_header() returns the content of the headers.
+
+ - fetch_body() returns the message text (message content without headers)
+
+ - fetch_size() returns the size of the message content.
+
+ - get_bodystructure() returns the MIME structure of the message.
+
+ - fetch_section() returns the content of a given MIME part
+
+ - fetch_section_header() returns the header of the message
+ contained by the given MIME part.
+
+ - fetch_section_mime() returns the MIME headers of the
+ given MIME part.
+
+ - fetch_section_body() returns the text (if this is a message, this is the
+ message content without headers) of the given MIME part.
+
+ - fetch_envelope() returns a mailimf_fields structure, with a list of
+ fields chosen by the driver.
+
+ - get_flags() returns a the flags related to the message.
+ When you want to get flags of a message, you have to make sure to
+ call get_flags() at least once before using directly message->flags.
+*/
+
+#define LIBETPAN_MAIL_MESSAGE_CHECK
+
+struct mailmessage_driver {
+ char * msg_name;
+
+ int (* msg_initialize)(mailmessage * msg_info);
+
+ void (* msg_uninitialize)(mailmessage * msg_info);
+
+ void (* msg_flush)(mailmessage * msg_info);
+
+ void (* msg_check)(mailmessage * msg_info);
+
+ void (* msg_fetch_result_free)(mailmessage * msg_info,
+ char * msg);
+
+ int (* msg_fetch)(mailmessage * msg_info,
+ char ** result,
+ size_t * result_len);
+
+ int (* msg_fetch_header)(mailmessage * msg_info,
+ char ** result,
+ size_t * result_len);
+
+ int (* msg_fetch_body)(mailmessage * msg_info,
+ char ** result, size_t * result_len);
+
+ int (* msg_fetch_size)(mailmessage * msg_info,
+ size_t * result);
+
+ int (* msg_get_bodystructure)(mailmessage * msg_info,
+ struct mailmime ** result);
+
+ int (* msg_fetch_section)(mailmessage * msg_info,
+ struct mailmime * mime,
+ char ** result, size_t * result_len);
+
+ int (* msg_fetch_section_header)(mailmessage * msg_info,
+ struct mailmime * mime,
+ char ** result,
+ size_t * result_len);
+
+ int (* msg_fetch_section_mime)(mailmessage * msg_info,
+ struct mailmime * mime,
+ char ** result,
+ size_t * result_len);
+
+ int (* msg_fetch_section_body)(mailmessage * msg_info,
+ struct mailmime * mime,
+ char ** result,
+ size_t * result_len);
+
+ int (* msg_fetch_envelope)(mailmessage * msg_info,
+ struct mailimf_fields ** result);
+
+ int (* msg_get_flags)(mailmessage * msg_info,
+ struct mail_flags ** result);
+};
+
+
+/*
+ mailmessage is a data structure to get information from messages
+
+ - session is the session linked to the given message, it can be NULL
+
+ - driver is the message driver
+
+ - index is the message number
+
+ - uid, when it is not NULL, it means that the folder
+ the folder has persistant message numbers, the string is
+ the unique message number in the folder.
+ uid should be implemented if possible.
+ for drivers where we cannot generate real uid,
+ a suggestion is "AAAA-IIII" where AAAA is some
+ random session number and IIII the content of index field.
+
+ - size, when it is not 0, is the size of the message content.
+
+ - fields, when it is not NULL, are the header fields of the message.
+
+ - flags, when it is not NULL, are the flags related to the message.
+
+ - single_fields, when resolved != 0, is filled with the data of fields.
+
+ - mime, when it is not NULL
+
+ - cached is != 0 when the header fields were read from the cache.
+
+ - data is data specific to the driver, this is internal data structure,
+ some state of the message.
+*/
+
+struct mailmessage {
+ mailsession * msg_session;
+ mailmessage_driver * msg_driver;
+ uint32_t msg_index;
+ char * msg_uid;
+
+ size_t msg_size;
+ struct mailimf_fields * msg_fields;
+ struct mail_flags * msg_flags;
+
+ int msg_resolved;
+ struct mailimf_single_fields msg_single_fields;
+ struct mailmime * msg_mime;
+
+ /* internal data */
+
+ int msg_cached;
+ void * msg_data;
+
+ /*
+ msg_folder field :
+ used to reference the mailfolder, this is a workaround due
+ to the problem with initial conception, where folder notion
+ did not exist.
+ */
+ void * msg_folder;
+ /* user data */
+ void * msg_user_data;
+};
+
+
+/*
+ mailmessage_tree is a node in the messages tree (thread)
+
+ - parent is the parent of the message, it is NULL if the message
+ is the root of the message tree.
+
+ - date is the date of the message in number of second elapsed
+ since 00:00:00 on January 1, 1970, Coordinated Universal Time (UTC).
+
+ - msg is the message structure that is stored referenced by the node.
+ is msg is NULL, this is a dummy node.
+
+ - children is an array that contains all the children of the node.
+ children are mailmessage_tree structures.
+
+ - is_reply is != 0 when the message is a reply or a forward
+
+ - base_subject is the extracted subject of the message.
+
+ - index is the message number.
+*/
+
+struct mailmessage_tree {
+ struct mailmessage_tree * node_parent;
+ char * node_msgid;
+ time_t node_date;
+ mailmessage * node_msg;
+ carray * node_children; /* array of (struct mailmessage_tree *) */
+
+ /* private, used for threading */
+ int node_is_reply;
+ char * node_base_subject;
+};
+
+
+struct mailmessage_tree *
+mailmessage_tree_new(char * node_msgid, time_t node_date,
+ mailmessage * node_msg);
+
+void mailmessage_tree_free(struct mailmessage_tree * tree);
+
+/*
+ mailmessage_tree_free_recursive
+
+ if you want to release memory of the given tree and all the sub-trees,
+ you can use this function.
+*/
+
+void mailmessage_tree_free_recursive(struct mailmessage_tree * tree);
+
+
+struct generic_message_t {
+ int (* msg_prefetch)(mailmessage * msg_info);
+ void (* msg_prefetch_free)(struct generic_message_t * msg);
+ int msg_fetched;
+ char * msg_message;
+ size_t msg_length;
+ void * msg_data;
+};
+
+
+const char * maildriver_strerror(int err);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/interface/maildriver_types_helper.c b/libetpan/src/driver/interface/maildriver_types_helper.c
new file mode 100644
index 0000000..6e3abf4
--- a/dev/null
+++ b/libetpan/src/driver/interface/maildriver_types_helper.c
@@ -0,0 +1,104 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 200 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "maildriver_types_helper.h"
+
+#include "mail.h"
+
+#include "clist.h"
+#include <string.h>
+#include <stdlib.h>
+
+int mail_flags_add_extension(struct mail_flags * flags,
+ char * ext_flag)
+{
+ char * str;
+ int r;
+
+ if (mail_flags_has_extension(flags, ext_flag))
+ return MAIL_NO_ERROR;
+
+ str = strdup(ext_flag);
+ if (str == NULL)
+ return MAIL_ERROR_MEMORY;
+
+ r = clist_append(flags->fl_extension, str);
+ if (r < 0) {
+ free(str);
+ return MAIL_ERROR_MEMORY;
+ }
+
+ return MAIL_NO_ERROR;
+}
+
+int mail_flags_remove_extension(struct mail_flags * flags,
+ char * ext_flag)
+{
+ clistiter * cur;
+
+ cur = clist_begin(flags->fl_extension);
+ while (cur != NULL) {
+ char * flag_name;
+
+ flag_name = clist_content(cur);
+
+ if (strcasecmp(flag_name, ext_flag) == 0) {
+ free(flag_name);
+ cur = clist_delete(flags->fl_extension, cur);
+ }
+ else
+ cur = clist_next(cur);
+ }
+
+ return MAIL_NO_ERROR;
+}
+
+int mail_flags_has_extension(struct mail_flags * flags,
+ char * ext_flag)
+{
+ clistiter * cur;
+
+ for(cur = clist_begin(flags->fl_extension) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ char * flag_name;
+
+ flag_name = clist_content(cur);
+
+ if (strcasecmp(flag_name, ext_flag) == 0)
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/libetpan/src/driver/interface/maildriver_types_helper.h b/libetpan/src/driver/interface/maildriver_types_helper.h
new file mode 100644
index 0000000..50ccc70
--- a/dev/null
+++ b/libetpan/src/driver/interface/maildriver_types_helper.h
@@ -0,0 +1,99 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef MAILDRIVER_TYPES_HELPER_H
+
+#define MAILDRIVER_TYPES_HELPER_H
+
+#include <libetpan/maildriver_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ mail_flags_add_extension adds the given flag if it does not exists in
+ the flags.
+
+ @param flags this is the flag to change
+
+ @param ext_flag this is the name of an extension flag
+ the given flag name is duplicated and is no more needed after
+ the function call.
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mail_flags_add_extension(struct mail_flags * flags,
+ char * ext_flag);
+
+/*
+ mail_flags_remove_extension removes the given flag if it does not exists in
+ the flags.
+
+ @param flags this is the flag to change
+
+ @param ext_flag this is the name of an extension flag
+ the given flag name is no more needed after the function call.
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mail_flags_remove_extension(struct mail_flags * flags,
+ char * ext_flag);
+
+/*
+ mail_flags_has_extension returns 1 if the flags is in the given flags,
+ 0 is returned otherwise.
+
+ @param flags this is the flag to change
+
+ @param ext_flag this is the name of an extension flag
+ the given flag name is no more needed after the function call.
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mail_flags_has_extension(struct mail_flags * flags,
+ char * ext_flag);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/interface/mailfolder.c b/libetpan/src/driver/interface/mailfolder.c
new file mode 100644
index 0000000..eb69d7f
--- a/dev/null
+++ b/libetpan/src/driver/interface/mailfolder.c
@@ -0,0 +1,138 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "mailfolder.h"
+
+#include "maildriver.h"
+
+int mailfolder_noop(struct mailfolder * folder)
+{
+ return mailsession_noop(folder->fld_session);
+}
+
+int mailfolder_check(struct mailfolder * folder)
+{
+ return mailsession_check_folder(folder->fld_session);
+}
+
+int mailfolder_expunge(struct mailfolder * folder)
+{
+ return mailsession_expunge_folder(folder->fld_session);
+}
+
+int mailfolder_status(struct mailfolder * folder,
+ uint32_t * result_messages, uint32_t * result_recent,
+ uint32_t * result_unseen)
+{
+ return mailsession_status_folder(folder->fld_session,
+ folder->fld_pathname, result_messages,
+ result_recent, result_unseen);
+}
+
+int mailfolder_append_message(struct mailfolder * folder,
+ char * message, size_t size)
+{
+ return mailsession_append_message(folder->fld_session, message, size);
+}
+
+int mailfolder_append_message_flags(struct mailfolder * folder,
+ char * message, size_t size, struct mail_flags * flags)
+{
+ return mailsession_append_message_flags(folder->fld_session, message,
+ size, flags);
+}
+
+int mailfolder_get_messages_list(struct mailfolder * folder,
+ struct mailmessage_list ** result)
+{
+ int r;
+ struct mailmessage_list * msg_list;
+ unsigned int i;
+
+ r = mailsession_get_messages_list(folder->fld_session, &msg_list);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ for(i = 0 ; i < carray_count(msg_list->msg_tab) ; i ++) {
+ mailmessage * msg;
+
+ msg = carray_get(msg_list->msg_tab, i);
+ msg->msg_folder = folder;
+ }
+
+ * result = msg_list;
+
+ return MAIL_NO_ERROR;
+}
+
+int mailfolder_get_envelopes_list(struct mailfolder * folder,
+ struct mailmessage_list * result)
+{
+ return mailsession_get_envelopes_list(folder->fld_session, result);
+}
+
+int mailfolder_get_message(struct mailfolder * folder,
+ uint32_t num, mailmessage ** result)
+{
+ mailmessage * msg;
+ int r;
+
+ r = mailsession_get_message(folder->fld_session, num, &msg);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ msg->msg_folder = folder;
+
+ * result = msg;
+
+ return MAIL_NO_ERROR;
+}
+
+int mailfolder_get_message_by_uid(struct mailfolder * folder,
+ const char * uid, mailmessage ** result)
+{
+ mailmessage * msg;
+ int r;
+
+ r = mailsession_get_message_by_uid(folder->fld_session, uid, &msg);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ msg->msg_folder = folder;
+
+ * result = msg;
+
+ return MAIL_NO_ERROR;
+}
diff --git a/libetpan/src/driver/interface/mailfolder.h b/libetpan/src/driver/interface/mailfolder.h
new file mode 100644
index 0000000..55ea3be
--- a/dev/null
+++ b/libetpan/src/driver/interface/mailfolder.h
@@ -0,0 +1,70 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef MAILFOLDER_H
+
+#define MAILFOLDER_H
+
+#include "mailstorage_types.h"
+
+int mailfolder_noop(struct mailfolder * folder);
+
+int mailfolder_check(struct mailfolder * folder);
+
+int mailfolder_expunge(struct mailfolder * folder);
+
+int mailfolder_status(struct mailfolder * folder,
+ uint32_t * result_messages, uint32_t * result_recent,
+ uint32_t * result_unseen);
+
+int mailfolder_append_message(struct mailfolder * folder,
+ char * message, size_t size);
+
+int mailfolder_append_message_flags(struct mailfolder * folder,
+ char * message, size_t size, struct mail_flags * flags);
+
+int mailfolder_get_messages_list(struct mailfolder * folder,
+ struct mailmessage_list ** result);
+
+int mailfolder_get_envelopes_list(struct mailfolder * folder,
+ struct mailmessage_list * result);
+
+int mailfolder_get_message(struct mailfolder * folder,
+ uint32_t num, mailmessage ** result);
+
+int mailfolder_get_message_by_uid(struct mailfolder * folder,
+ const char * uid, mailmessage ** result);
+
+#endif
diff --git a/libetpan/src/driver/interface/mailmessage.c b/libetpan/src/driver/interface/mailmessage.c
new file mode 100644
index 0000000..b4921e5
--- a/dev/null
+++ b/libetpan/src/driver/interface/mailmessage.c
@@ -0,0 +1,240 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "mailmessage.h"
+
+#include "mail.h"
+
+#include <string.h>
+
+int mailmessage_init(mailmessage * msg_info,
+ mailsession * msg_session,
+ mailmessage_driver * msg_driver,
+ uint32_t msg_index, size_t msg_size)
+{
+ int r;
+ int res;
+
+ msg_info->msg_driver = msg_driver;
+ msg_info->msg_session = msg_session;
+ msg_info->msg_index = msg_index;
+ msg_info->msg_uid = NULL;
+
+ msg_info->msg_cached = FALSE;
+ msg_info->msg_size = msg_size;
+ msg_info->msg_fields = NULL;
+ memset(&msg_info->msg_single_fields, 0,
+ sizeof(struct mailimf_single_fields));
+ msg_info->msg_resolved = FALSE;
+ msg_info->msg_flags = NULL;
+
+ msg_info->msg_mime = NULL;
+ msg_info->msg_data = NULL;
+ msg_info->msg_folder = NULL;
+ msg_info->msg_user_data = NULL;
+
+ if (msg_driver->msg_initialize != NULL) {
+ r = msg_driver->msg_initialize(msg_info);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+ }
+
+ return MAIL_NO_ERROR;
+
+ err:
+ msg_info->msg_driver = NULL;
+ msg_info->msg_session = NULL;
+ return res;
+}
+
+int mailmessage_flush(mailmessage * msg_info)
+{
+ if (msg_info->msg_driver->msg_flush == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ msg_info->msg_driver->msg_flush(msg_info);
+
+ return MAIL_NO_ERROR;
+}
+
+int mailmessage_check(mailmessage * msg_info)
+{
+ if (msg_info->msg_driver->msg_check == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ msg_info->msg_driver->msg_check(msg_info);
+
+ return MAIL_NO_ERROR;
+}
+
+int mailmessage_fetch_result_free(mailmessage * msg_info,
+ char * msg)
+{
+ if (msg_info->msg_driver->msg_fetch_result_free == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ msg_info->msg_driver->msg_fetch_result_free(msg_info, msg);
+
+ return MAIL_NO_ERROR;
+}
+
+int mailmessage_fetch(mailmessage * msg_info,
+ char ** result,
+ size_t * result_len)
+{
+ if (msg_info->msg_driver->msg_fetch == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return msg_info->msg_driver->msg_fetch(msg_info, result, result_len);
+}
+
+int mailmessage_fetch_header(mailmessage * msg_info,
+ char ** result,
+ size_t * result_len)
+{
+ if (msg_info->msg_driver->msg_fetch_header == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return msg_info->msg_driver->msg_fetch_header(msg_info, result, result_len);
+}
+
+int mailmessage_fetch_body(mailmessage * msg_info,
+ char ** result, size_t * result_len)
+{
+ if (msg_info->msg_driver->msg_fetch_body == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return msg_info->msg_driver->msg_fetch_body(msg_info, result, result_len);
+}
+
+int mailmessage_fetch_size(mailmessage * msg_info,
+ size_t * result)
+{
+ if (msg_info->msg_driver->msg_fetch_size == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return msg_info->msg_driver->msg_fetch_size(msg_info, result);
+}
+
+int mailmessage_get_bodystructure(mailmessage * msg_info,
+ struct mailmime ** result)
+{
+ if (msg_info->msg_driver->msg_get_bodystructure == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return msg_info->msg_driver->msg_get_bodystructure(msg_info, result);
+}
+
+int mailmessage_fetch_section(mailmessage * msg_info,
+ struct mailmime * mime,
+ char ** result, size_t * result_len)
+{
+ if (msg_info->msg_driver->msg_fetch_section == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return msg_info->msg_driver->msg_fetch_section(msg_info, mime, result, result_len);
+}
+
+int mailmessage_fetch_section_header(mailmessage * msg_info,
+ struct mailmime * mime,
+ char ** result,
+ size_t * result_len)
+{
+ if (msg_info->msg_driver->msg_fetch_section_header == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return msg_info->msg_driver->msg_fetch_section_header(msg_info, mime,
+ result, result_len);
+}
+
+int mailmessage_fetch_section_mime(mailmessage * msg_info,
+ struct mailmime * mime,
+ char ** result,
+ size_t * result_len)
+{
+ if (msg_info->msg_driver->msg_fetch_section_mime == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return msg_info->msg_driver->msg_fetch_section_mime(msg_info, mime,
+ result, result_len);
+}
+
+int mailmessage_fetch_section_body(mailmessage * msg_info,
+ struct mailmime * mime,
+ char ** result,
+ size_t * result_len)
+{
+ if (msg_info->msg_driver->msg_fetch_section_body == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return msg_info->msg_driver->msg_fetch_section_body(msg_info, mime,
+ result, result_len);
+}
+
+int mailmessage_fetch_envelope(mailmessage * msg_info,
+ struct mailimf_fields ** result)
+{
+ if (msg_info->msg_driver->msg_fetch_envelope == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return msg_info->msg_driver->msg_fetch_envelope(msg_info, result);
+}
+
+int mailmessage_get_flags(mailmessage * msg_info,
+ struct mail_flags ** result)
+{
+ struct mail_flags * dummy;
+
+ if (msg_info->msg_driver->msg_get_flags == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ if (result != NULL)
+ return msg_info->msg_driver->msg_get_flags(msg_info, result);
+ else
+ return msg_info->msg_driver->msg_get_flags(msg_info, &dummy);
+}
+
+void mailmessage_resolve_single_fields(mailmessage * msg_info)
+{
+ if (!msg_info->msg_resolved) {
+ if (msg_info->msg_fields != NULL) {
+ mailimf_single_fields_init(&msg_info->msg_single_fields,
+ msg_info->msg_fields);
+ msg_info->msg_resolved = TRUE;
+ }
+ }
+}
diff --git a/libetpan/src/driver/interface/mailmessage.h b/libetpan/src/driver/interface/mailmessage.h
new file mode 100644
index 0000000..02b351b
--- a/dev/null
+++ b/libetpan/src/driver/interface/mailmessage.h
@@ -0,0 +1,379 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include <libetpan/mailmessage_types.h>
+
+#ifndef MAILMESSAGE_H
+
+#define MAILMESSAGE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ mailmessage_new
+
+ This function will initializes a new empty message.
+
+ @return a new empty message will be returned.
+*/
+
+mailmessage * mailmessage_new(void);
+
+/*
+ mailmessage_free
+
+ This function will release the memory used by this message.
+*/
+
+void mailmessage_free(mailmessage * info);
+
+/*
+ mailmessage_init
+
+ This function will initializes a mailmessage structure
+ with a message from a given session.
+
+ @param msg_info This is the message to initialize.
+
+ @param session This is the source session of the message. It
+ can be NULL if the message does not get the information
+ through the session.
+
+ @param driver This is the driver to use for the message.
+
+ @param index This is the message number in the session. 0 can
+ be given if the message is not attached to a session.
+
+ @param size is an optional parameter, 0 can be given.
+ This is informational. This is the size of message content.
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mailmessage_init(mailmessage * msg_info,
+ mailsession * session,
+ mailmessage_driver * driver,
+ uint32_t index, size_t size);
+
+/*
+ mailmessage_flush
+
+ This function will release all the temporary resources that are not
+ necessary to use the mailmessage structure from memory. These
+ resources are for example cached information, such as the MIME
+ structure.
+
+ @param info is the message to clean.
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error. We can assume that MAIL_NO_ERROR is always returned.
+*/
+
+int mailmessage_flush(mailmessage * info);
+
+/*
+ mailmessage_check
+
+ This function will notify the new value of the flags to the session,
+ it must be called before mailsession_check_folder() in case the flags have
+ been changed.
+
+ @param info is the message to checkpoint.
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error. We can assume that MAIL_NO_ERROR is always returned.
+*/
+
+int mailmessage_check(mailmessage * info);
+
+/*
+ mailmessage_fetch_result_free
+
+ This function releases the memory used by a message returned
+ by any of the fetch function that returns a (char *).
+
+ @param msg_info is the message which the given buffer is from.
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error. We can assume that MAIL_NO_ERROR is always returned.
+*/
+
+int mailmessage_fetch_result_free(mailmessage * msg_info,
+ char * msg);
+
+/*
+ mailmessage_fetch
+
+ This function returns the content of the message (headers and text).
+
+ @param msg_info is the message from which we want to fetch information.
+
+ @param result The content of the message is returned in (* result)
+
+ @param result_len The length of the returned string is stored
+ in (* result_len).
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error.
+*/
+
+int mailmessage_fetch(mailmessage * msg_info,
+ char ** result,
+ size_t * result_len);
+
+/*
+ mailmessage_fetch_header
+
+ This function returns the header of the message as a string.
+
+ @param msg_info is the message from which we want to fetch information.
+
+ @param result The header of the message is returned in (* result)
+
+ @param result_len The length of the returned string is stored
+ in (* result_len).
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error.
+*/
+
+int mailmessage_fetch_header(mailmessage * msg_info,
+ char ** result,
+ size_t * result_len);
+
+/*
+ mailmessage_fetch_body
+
+ This function returns the content of the message (without headers).
+
+ @param msg_info is the message from which we want to fetch information.
+ @param result The message text (without headers) is returned
+ in (* result)
+ @param result_len The length of the returned string is stored
+ in (* result_len).
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error.
+*/
+
+int mailmessage_fetch_body(mailmessage * msg_info,
+ char ** result, size_t * result_len);
+
+/*
+ mailmessage_fetch_size
+
+ This function returns the size of the message content.
+
+ @param msg_info is the message from which we want to fetch information.
+
+ @param result The length of the message content is stored in (* result).
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error.
+*/
+
+int mailmessage_fetch_size(mailmessage * msg_info,
+ size_t * result);
+
+/*
+ mailmessage_get_bodystructure
+
+ This functions returns the MIME structure of the message.
+ The returned information MUST not be freed by hand. It is freed by
+ mailmessage_flush() or mailmessage_free().
+
+ @param msg_info is the message from which we want to fetch information.
+
+ @param result The MIME structure is stored in (* result).
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error.
+*/
+
+int mailmessage_get_bodystructure(mailmessage * msg_info,
+ struct mailmime ** result);
+
+/*
+ mailmessage_fetch_section
+
+ This function returns the content of a MIME part.
+
+ @param msg_info is the message from which we want to fetch information.
+
+ @param mime is the MIME part identifier.
+
+ @param result The content is returned in (* result)
+
+ @param result_len The length of the returned string is stored
+ in (* result_len).
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error.
+ */
+
+int mailmessage_fetch_section(mailmessage * msg_info,
+ struct mailmime * mime,
+ char ** result, size_t * result_len);
+
+/*
+ mailmessage_fetch_section_header
+
+ This function returns the header of the message contained
+ in the given MIME part.
+
+ @param msg_info is the message from which we want to fetch information.
+
+ @param mime is the MIME part identifier.
+
+ @param result The header is returned in (* result)
+
+ @param result_len The length of the returned string is stored
+ in (* result_len).
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error.
+*/
+
+int mailmessage_fetch_section_header(mailmessage * msg_info,
+ struct mailmime * mime,
+ char ** result,
+ size_t * result_len);
+
+/*
+ mailmessage_fetch_section_mime
+
+ This function returns the MIME header of the given MIME part.
+
+ @param msg_info is the message from which we want to fetch information.
+
+ @param mime is the MIME part identifier.
+
+ @param result The MIME header is returned in (* result)
+
+ @param result_len The length of the returned string is stored
+ in (* result_len).
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error.
+*/
+
+int mailmessage_fetch_section_mime(mailmessage * msg_info,
+ struct mailmime * mime,
+ char ** result,
+ size_t * result_len);
+
+/*
+ mailmessage_fetch_section_body
+
+ This function returns the text part of the message contained
+ in the given MIME part.
+
+ @param msg_info is the message from which we want to fetch information.
+
+ @param mime is the MIME part identifier.
+
+ @param result The message text is returned in (* result)
+
+ @param result_len The length of the returned string is stored
+ in (* result_len).
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error.
+ */
+
+int mailmessage_fetch_section_body(mailmessage * msg_info,
+ struct mailmime * mime,
+ char ** result,
+ size_t * result_len);
+
+/*
+ mailmessage_fetch_envelope
+
+ This function returns a list of parsed fields of the message,
+ chosen by the driver.
+ The returned structure must be freed with mailimf_fields_free().
+
+ @param msg_info is the message from which we want to fetch information.
+
+ @param result The headers list is returned in (* result)
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error.
+ */
+
+int mailmessage_fetch_envelope(mailmessage * msg_info,
+ struct mailimf_fields ** result);
+
+
+/*
+ mailmessage_get_flags
+
+ This function returns the flags related to the message.
+ The returned information MUST not be freed by hand. It is freed by
+ mailmessage_free().
+
+ @param msg_info is the message from which we want to fetch information.
+
+ @param result The flags are stored in (* result).
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error.
+*/
+
+int mailmessage_get_flags(mailmessage * msg_info,
+ struct mail_flags ** result);
+
+/*
+ mailmessage_resolve_single_fields
+
+ This function will use the fields information to fill the single_fields
+ structure in the mailmessage structure.
+
+ @param msg_info This is the msg_info to process.
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error.
+*/
+
+void mailmessage_resolve_single_fields(mailmessage * msg_info);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/interface/mailmessage_tools.c b/libetpan/src/driver/interface/mailmessage_tools.c
new file mode 100644
index 0000000..9e53173
--- a/dev/null
+++ b/libetpan/src/driver/interface/mailmessage_tools.c
@@ -0,0 +1,600 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "mailmessage_tools.h"
+#include "mailmessage.h"
+
+#include <stdlib.h>
+
+#include "maildriver.h"
+#include "maildriver_tools.h"
+
+int
+mailmessage_generic_initialize(mailmessage * msg_info)
+{
+ struct generic_message_t * msg;
+
+ msg = malloc(sizeof(* msg));
+
+ if (msg == NULL) {
+ return MAIL_ERROR_MEMORY;
+ }
+
+ msg->msg_fetched = 0;
+ msg->msg_message = NULL;
+ msg->msg_length = 0;
+
+ msg->msg_prefetch = NULL;
+ msg->msg_prefetch_free = NULL;
+ msg->msg_data = NULL;
+
+ msg_info->msg_data = msg;
+
+ return MAIL_NO_ERROR;
+}
+
+void mailmessage_generic_flush(mailmessage * msg_info)
+{
+ struct generic_message_t * msg;
+
+ if (msg_info->msg_mime != NULL) {
+ mailmime_free(msg_info->msg_mime);
+ msg_info->msg_mime = NULL;
+ }
+ msg = msg_info->msg_data;
+ if (msg != NULL) {
+ if (msg->msg_prefetch_free != NULL)
+ msg->msg_prefetch_free(msg);
+ msg->msg_fetched = 0;
+ }
+}
+
+void mailmessage_generic_uninitialize(mailmessage * msg_info)
+{
+ struct generic_message_t * msg;
+
+ mailmessage_generic_flush(msg_info);
+
+ msg = msg_info->msg_data;
+ msg_info->msg_data = NULL;
+ free(msg);
+}
+
+static inline int
+mailmessage_generic_prefetch(mailmessage * msg_info)
+{
+ struct generic_message_t * msg;
+ int r;
+
+ msg = msg_info->msg_data;
+
+ if (msg->msg_fetched)
+ return MAIL_NO_ERROR;
+
+#if 0
+ if (msg->message != NULL)
+ return MAIL_NO_ERROR;
+#endif
+
+ r = msg->msg_prefetch(msg_info);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ msg->msg_fetched = 1;
+
+ return MAIL_NO_ERROR;
+}
+
+static int
+mailmessage_generic_prefetch_bodystructure(mailmessage * msg_info)
+{
+ size_t length;
+ char * message;
+ size_t cur_token;
+ struct mailmime * mime;
+ int r;
+ int res;
+ struct generic_message_t * msg;
+
+ if (msg_info->msg_mime != NULL) {
+ /* it has already been fetched */
+ return MAIL_NO_ERROR;
+ }
+
+#if 0
+ msg = msg_info->data;
+ if (msg->message == NULL) {
+ r = mailmessage_generic_prefetch(msg_info);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+ }
+#endif
+ r = mailmessage_generic_prefetch(msg_info);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ msg = msg_info->msg_data;
+ message = msg->msg_message;
+ length = msg->msg_length;
+ cur_token = 0;
+ r = mailmime_parse(message, length, &cur_token, &mime);
+ if (r != MAILIMF_NO_ERROR) {
+ res = MAIL_ERROR_PARSE;
+ goto err;
+ }
+
+ msg_info->msg_mime = mime;
+
+ return MAIL_NO_ERROR;
+
+ err:
+ return res;
+}
+
+void
+mailmessage_generic_fetch_result_free(mailmessage * msg_info, char * msg)
+{
+ int r;
+
+ r = mmap_string_unref(msg);
+}
+
+int mailmessage_generic_fetch(mailmessage * msg_info,
+ char ** result,
+ size_t * result_len)
+{
+ int r;
+ char * message;
+ size_t cur_token;
+ size_t length;
+ MMAPString * mmapstr;
+ int res;
+ struct generic_message_t * msg;
+
+ msg = msg_info->msg_data;
+ r = mailmessage_generic_prefetch(msg_info);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ message = msg->msg_message;
+ length = msg->msg_length;
+ cur_token = 0;
+
+ mmapstr = mmap_string_new_len(message, length);
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ r = mmap_string_ref(mmapstr);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_mmap;
+ }
+
+ * result = mmapstr->str;
+ * result_len = length;
+
+ return MAIL_NO_ERROR;
+
+ free_mmap:
+ mmap_string_free(mmapstr);
+ err:
+ return res;
+}
+
+int mailmessage_generic_fetch_header(mailmessage * msg_info,
+ char ** result,
+ size_t * result_len)
+{
+ int r;
+ char * message;
+ size_t cur_token;
+ size_t length;
+ MMAPString * mmapstr;
+ char * headers;
+ int res;
+ struct generic_message_t * msg;
+
+ msg = msg_info->msg_data;
+ r = mailmessage_generic_prefetch(msg_info);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ message = msg->msg_message;
+ length = msg->msg_length;
+ cur_token = 0;
+
+ while (1) {
+ r = mailimf_ignore_field_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else
+ break;
+ }
+ mailimf_crlf_parse(message, length, &cur_token);
+
+ mmapstr = mmap_string_new_len(message, cur_token);
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ r = mmap_string_ref(mmapstr);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_mmap;
+ }
+
+ headers = mmapstr->str;
+
+ * result = headers;
+ * result_len = cur_token;
+
+ return MAIL_NO_ERROR;
+
+ free_mmap:
+ mmap_string_free(mmapstr);
+ err:
+ return res;
+}
+
+int mailmessage_generic_fetch_body(mailmessage * msg_info,
+ char ** result, size_t * result_len)
+{
+ int r;
+ char * message;
+ size_t cur_token;
+ MMAPString * mmapstr;
+ size_t length;
+ int res;
+ struct generic_message_t * msg;
+
+ msg = msg_info->msg_data;
+ r = mailmessage_generic_prefetch(msg_info);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ message = msg->msg_message;
+ length = msg->msg_length;
+ cur_token = 0;
+
+ while (1) {
+ r = mailimf_ignore_field_parse(message, length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else
+ break;
+ }
+ mailimf_crlf_parse(message, length, &cur_token);
+
+ mmapstr = mmap_string_new_len(message + cur_token, length - cur_token);
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ r = mmap_string_ref(mmapstr);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_mmap;
+ }
+
+ * result = mmapstr->str;
+ * result_len = length - cur_token;
+
+ return MAIL_NO_ERROR;
+
+ free_mmap:
+ mmap_string_free(mmapstr);
+ err:
+ return res;
+}
+
+
+
+
+int
+mailmessage_generic_get_bodystructure(mailmessage * msg_info,
+ struct mailmime ** result)
+{
+ int r;
+
+ r = mailmessage_generic_prefetch_bodystructure(msg_info);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ * result = msg_info->msg_mime;
+
+ return MAIL_NO_ERROR;
+}
+
+
+
+
+int
+mailmessage_generic_fetch_section(mailmessage * msg_info,
+ struct mailmime * mime,
+ char ** result, size_t * result_len)
+{
+ MMAPString * mmapstr;
+ int r;
+ int res;
+
+ mmapstr = mmap_string_new_len(mime->mm_body->dt_data.dt_text.dt_data,
+ mime->mm_body->dt_data.dt_text.dt_length);
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ r = mmap_string_ref(mmapstr);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_mmap;
+ }
+
+ * result = mmapstr->str;
+ * result_len = mmapstr->len;
+
+ return MAIL_NO_ERROR;
+
+ free_mmap:
+ mmap_string_free(mmapstr);
+ err:
+ return res;
+}
+
+int
+mailmessage_generic_fetch_section_header(mailmessage * msg_info,
+ struct mailmime * mime,
+ char ** result,
+ size_t * result_len)
+{
+ MMAPString * mmapstr;
+ int r;
+ int res;
+ size_t cur_token;
+
+ /* skip mime */
+
+ cur_token = 0;
+
+ if (mime->mm_type == MAILMIME_MESSAGE) {
+
+ while (1) {
+ r = mailimf_ignore_field_parse(mime->mm_body->dt_data.dt_text.dt_data,
+ mime->mm_body->dt_data.dt_text.dt_length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else
+ break;
+ }
+
+ r = mailimf_crlf_parse(mime->mm_body->dt_data.dt_text.dt_data,
+ mime->mm_body->dt_data.dt_text.dt_length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = maildriver_imf_error_to_mail_error(r);
+ goto err;
+ }
+ }
+
+ mmapstr = mmap_string_new_len(mime->mm_body->dt_data.dt_text.dt_data,
+ cur_token);
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ r = mmap_string_ref(mmapstr);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_mmap;
+ }
+
+ * result = mmapstr->str;
+ * result_len = mmapstr->len;
+
+ return MAIL_NO_ERROR;
+
+ free_mmap:
+ mmap_string_free(mmapstr);
+ err:
+ return res;
+}
+
+int
+mailmessage_generic_fetch_section_mime(mailmessage * msg_info,
+ struct mailmime * mime,
+ char ** result,
+ size_t * result_len)
+{
+ MMAPString * mmapstr;
+ int r;
+ int res;
+ size_t cur_token;
+
+ cur_token = 0;
+
+ /* skip header */
+
+ while (1) {
+ r = mailimf_ignore_field_parse(mime->mm_mime_start,
+ mime->mm_length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else
+ break;
+ }
+
+ r = mailimf_crlf_parse(mime->mm_mime_start, mime->mm_length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = maildriver_imf_error_to_mail_error(r);
+ goto err;
+ }
+
+ mmapstr = mmap_string_new_len(mime->mm_mime_start, cur_token);
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ r = mmap_string_ref(mmapstr);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_mmap;
+ }
+
+ * result = mmapstr->str;
+ * result_len = mmapstr->len;
+
+ return MAIL_NO_ERROR;
+
+ free_mmap:
+ mmap_string_free(mmapstr);
+ err:
+ return res;
+}
+
+int
+mailmessage_generic_fetch_section_body(mailmessage * msg_info,
+ struct mailmime * mime,
+ char ** result,
+ size_t * result_len)
+{
+ MMAPString * mmapstr;
+ int r;
+ int res;
+ size_t cur_token;
+
+ cur_token = 0;
+
+ if (mime->mm_type == MAILMIME_MESSAGE) {
+
+ /* skip header */
+
+ while (1) {
+ r = mailimf_ignore_field_parse(mime->mm_body->dt_data.dt_text.dt_data,
+ mime->mm_body->dt_data.dt_text.dt_length, &cur_token);
+ if (r == MAILIMF_NO_ERROR) {
+ /* do nothing */
+ }
+ else
+ break;
+ }
+
+ r = mailimf_crlf_parse(mime->mm_body->dt_data.dt_text.dt_data,
+ mime->mm_body->dt_data.dt_text.dt_length, &cur_token);
+ if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
+ res = maildriver_imf_error_to_mail_error(r);
+ goto err;
+ }
+ }
+
+ mmapstr = mmap_string_new_len(mime->mm_body->dt_data.dt_text.dt_data +
+ cur_token, mime->mm_body->dt_data.dt_text.dt_length - cur_token);
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ r = mmap_string_ref(mmapstr);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_mmap;
+ }
+
+ * result = mmapstr->str;
+ * result_len = mmapstr->len;
+
+ return MAIL_NO_ERROR;
+
+ free_mmap:
+ mmap_string_free(mmapstr);
+ err:
+ return res;
+}
+
+int mailmessage_generic_fetch_envelope(mailmessage * msg_info,
+ struct mailimf_fields ** result)
+{
+ int r;
+ int res;
+ size_t cur_token;
+ char * header;
+ size_t length;
+ struct mailimf_fields * fields;
+
+ r = mailmessage_fetch_header(msg_info, &header, &length);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ cur_token = 0;
+
+ r = mailimf_envelope_fields_parse(header, length, &cur_token,
+ &fields);
+ if (r != MAILIMF_NO_ERROR) {
+ res = maildriver_imf_error_to_mail_error(r);
+ goto free;
+ /* do nothing */
+ }
+
+ mailmessage_fetch_result_free(msg_info, header);
+
+ * result = fields;
+
+ return MAIL_NO_ERROR;
+
+ free:
+ mailmessage_fetch_result_free(msg_info, header);
+ err:
+ return res;
+}
diff --git a/libetpan/src/driver/interface/mailmessage_tools.h b/libetpan/src/driver/interface/mailmessage_tools.h
new file mode 100644
index 0000000..fd055c7
--- a/dev/null
+++ b/libetpan/src/driver/interface/mailmessage_tools.h
@@ -0,0 +1,103 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef MAILMESSAGE_TOOLS_H
+
+#define MAILMESSAGE_TOOLS_H
+
+#include "mailmessage_types.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int
+mailmessage_generic_initialize(mailmessage *
+ msg_info);
+
+void mailmessage_generic_uninitialize(mailmessage *
+ msg_info);
+
+void mailmessage_generic_flush(mailmessage * msg_info);
+
+void mailmessage_generic_fetch_result_free(mailmessage * msg_info,
+ char * msg);
+
+int mailmessage_generic_fetch(mailmessage * msg_info,
+ char ** result,
+ size_t * result_len);
+
+int mailmessage_generic_fetch_header(mailmessage * msg_info,
+ char ** result,
+ size_t * result_len);
+
+int mailmessage_generic_fetch_body(mailmessage * msg_info,
+ char ** result, size_t * result_len);
+
+int mailmessage_generic_get_bodystructure(mailmessage *
+ msg_info,
+ struct mailmime ** result);
+
+int
+mailmessage_generic_fetch_section(mailmessage * msg_info,
+ struct mailmime * mime,
+ char ** result, size_t * result_len);
+
+int
+mailmessage_generic_fetch_section_header(mailmessage * msg_info,
+ struct mailmime * mime,
+ char ** result,
+ size_t * result_len);
+
+int
+mailmessage_generic_fetch_section_mime(mailmessage * msg_info,
+ struct mailmime * mime,
+ char ** result,
+ size_t * result_len);
+
+int
+mailmessage_generic_fetch_section_body(mailmessage * msg_info,
+ struct mailmime * mime,
+ char ** result,
+ size_t * result_len);
+
+int mailmessage_generic_fetch_envelope(mailmessage * msg_info,
+ struct mailimf_fields ** result);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/interface/mailmessage_types.c b/libetpan/src/driver/interface/mailmessage_types.c
new file mode 100644
index 0000000..e0955e4
--- a/dev/null
+++ b/libetpan/src/driver/interface/mailmessage_types.c
@@ -0,0 +1,92 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "mailmessage_types.h"
+
+#include "mail.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+mailmessage * mailmessage_new(void)
+{
+ mailmessage * msg_info;
+
+ msg_info = malloc(sizeof(* msg_info));
+ if (msg_info == NULL)
+ goto err;
+
+ msg_info->msg_driver = NULL;
+ msg_info->msg_session = NULL;
+ msg_info->msg_index = 0;
+ msg_info->msg_uid = NULL;
+
+ msg_info->msg_cached = FALSE;
+ msg_info->msg_size = 0;
+ msg_info->msg_fields = NULL;
+ memset(&msg_info->msg_single_fields,
+ 0, sizeof(struct mailimf_single_fields));
+ msg_info->msg_resolved = FALSE;
+ msg_info->msg_flags = NULL;
+
+ msg_info->msg_mime = NULL;
+ msg_info->msg_data = NULL;
+
+ msg_info->msg_folder = NULL;
+ msg_info->msg_user_data = NULL;
+
+ return msg_info;
+
+ err:
+ return NULL;
+}
+
+void mailmessage_free(mailmessage * msg_info)
+{
+ if (msg_info->msg_driver != NULL) {
+ if (msg_info->msg_driver->msg_uninitialize != NULL)
+ msg_info->msg_driver->msg_uninitialize(msg_info);
+ }
+
+ if (msg_info->msg_fields != NULL)
+ mailimf_fields_free(msg_info->msg_fields);
+ if (msg_info->msg_mime != NULL)
+ mailmime_free(msg_info->msg_mime);
+ if (msg_info->msg_flags != NULL)
+ mail_flags_free(msg_info->msg_flags);
+ if (msg_info->msg_uid != NULL)
+ free(msg_info->msg_uid);
+ free(msg_info);
+}
diff --git a/libetpan/src/driver/interface/mailmessage_types.h b/libetpan/src/driver/interface/mailmessage_types.h
new file mode 100644
index 0000000..c3ed2c4
--- a/dev/null
+++ b/libetpan/src/driver/interface/mailmessage_types.h
@@ -0,0 +1,50 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef MAILMESSAGE_TYPES_H
+
+#define MAILMESSAGE_TYPES_H
+
+#include <libetpan/maildriver_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/interface/mailstorage.c b/libetpan/src/driver/interface/mailstorage.c
new file mode 100644
index 0000000..2e2ddcb
--- a/dev/null
+++ b/libetpan/src/driver/interface/mailstorage.c
@@ -0,0 +1,341 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "mailstorage.h"
+
+#include "maildriver.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+static int mailstorage_get_folder(struct mailstorage * storage,
+ char * pathname, mailsession ** result);
+
+struct mailfolder * mailfolder_new(struct mailstorage * storage,
+ char * pathname, char * virtual_name)
+{
+ struct mailfolder * folder;
+
+ folder = malloc(sizeof(struct mailfolder));
+ if (folder == NULL)
+ goto err;
+
+ if (pathname != NULL) {
+ folder->fld_pathname = strdup(pathname);
+ if (folder->fld_pathname == NULL)
+ goto free;
+ }
+ else
+ folder->fld_pathname = NULL;
+
+ if (virtual_name != NULL) {
+ folder->fld_virtual_name = strdup(virtual_name);
+ if (folder->fld_virtual_name == NULL)
+ goto free_pathname;
+ }
+ else
+ folder->fld_virtual_name = NULL;
+
+ folder->fld_storage = storage;
+
+ folder->fld_session = NULL;
+ folder->fld_shared_session = 0;
+ folder->fld_pos = NULL;
+
+ folder->fld_parent = NULL;
+ folder->fld_sibling_index = 0;
+ folder->fld_children = carray_new(128);
+ if (folder->fld_children == NULL)
+ goto free_virtualname;
+
+ return folder;
+
+free_virtualname:
+ if (folder->fld_virtual_name != NULL)
+ free(folder->fld_virtual_name);
+free_pathname:
+ if (folder->fld_pathname != NULL)
+ free(folder->fld_pathname);
+free:
+ free(folder);
+err:
+ return NULL;
+}
+
+void mailfolder_free(struct mailfolder * folder)
+{
+ if (folder->fld_parent != NULL)
+ mailfolder_detach_parent(folder);
+
+ while (carray_count(folder->fld_children) > 0) {
+ struct mailfolder * child;
+
+ child = carray_get(folder->fld_children, 0);
+ mailfolder_detach_parent(child);
+ }
+
+ carray_free(folder->fld_children);
+
+ if (folder->fld_session != NULL)
+ mailfolder_disconnect(folder);
+
+ if (folder->fld_virtual_name != NULL)
+ free(folder->fld_virtual_name);
+ if (folder->fld_pathname != NULL)
+ free(folder->fld_pathname);
+ free(folder);
+}
+
+int mailfolder_connect(struct mailfolder * folder)
+{
+ mailsession * session;
+ int res;
+ int r;
+
+ if (folder->fld_storage == NULL) {
+ res = MAIL_ERROR_INVAL;
+ goto err;
+ }
+
+ if (folder->fld_storage->sto_session == NULL) {
+ r = mailstorage_connect(folder->fld_storage);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+ }
+
+ if (folder->fld_session != NULL) {
+ if ((folder->fld_pathname != NULL) && (folder->fld_shared_session)) {
+ if (folder->fld_session->sess_driver->sess_select_folder != NULL) {
+ r = mailsession_select_folder(folder->fld_session,
+ folder->fld_pathname);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+ }
+ }
+
+ return MAIL_NO_ERROR;
+ }
+
+ r = mailstorage_get_folder(folder->fld_storage, folder->fld_pathname,
+ &session);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+ folder->fld_session = session;
+ folder->fld_shared_session = (session == folder->fld_storage->sto_session);
+ if (folder->fld_shared_session) {
+ r = clist_append(folder->fld_storage->sto_shared_folders, folder);
+ if (r < 0) {
+ folder->fld_session = NULL;
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+ folder->fld_pos = clist_end(folder->fld_storage->sto_shared_folders);
+ }
+
+ return MAIL_NO_ERROR;
+
+err:
+ return res;
+}
+
+void mailfolder_disconnect(struct mailfolder * folder)
+{
+ if (folder->fld_session == NULL)
+ return;
+
+ if (folder->fld_shared_session) {
+ clist_delete(folder->fld_storage->sto_shared_folders, folder->fld_pos);
+ folder->fld_pos = NULL;
+ }
+ else {
+ mailsession_logout(folder->fld_session);
+ mailsession_free(folder->fld_session);
+ }
+
+ folder->fld_session = NULL;
+}
+
+int mailfolder_add_child(struct mailfolder * parent,
+ struct mailfolder * child)
+{
+ unsigned int index;
+ int r;
+
+ r = carray_add(parent->fld_children, child, &index);
+ if (r < 0)
+ return MAIL_ERROR_MEMORY;
+
+ child->fld_sibling_index = index;
+ child->fld_parent = parent;
+
+ return MAIL_NO_ERROR;
+}
+
+int mailfolder_detach_parent(struct mailfolder * folder)
+{
+ unsigned int i;
+ int r;
+
+ if (folder->fld_parent == NULL)
+ return MAIL_ERROR_INVAL;
+
+ r = carray_delete_slow(folder->fld_parent->fld_children,
+ folder->fld_sibling_index);
+ if (r < 0)
+ return MAIL_ERROR_INVAL;
+
+ for(i = 0 ; i < carray_count(folder->fld_parent->fld_children) ; i ++) {
+ struct mailfolder * child;
+
+ child = carray_get(folder->fld_parent->fld_children, i);
+ child->fld_sibling_index = i;
+ }
+
+ folder->fld_parent = NULL;
+ folder->fld_sibling_index = 0;
+
+ return MAIL_NO_ERROR;
+}
+
+struct mailstorage * mailstorage_new(char * sto_id)
+{
+ struct mailstorage * storage;
+
+ storage = malloc(sizeof(struct mailstorage));
+ if (storage == NULL)
+ goto err;
+
+ if (sto_id != NULL) {
+ storage->sto_id = strdup(sto_id);
+ if (storage->sto_id == NULL)
+ goto free;
+ }
+ else
+ storage->sto_id = NULL;
+
+ storage->sto_data = NULL;
+ storage->sto_session = NULL;
+ storage->sto_driver = NULL;
+ storage->sto_shared_folders = clist_new();
+ if (storage->sto_shared_folders == NULL)
+ goto free_id;
+
+ return storage;
+
+ free_id:
+ if (storage->sto_id != NULL)
+ free(storage->sto_id);
+ free:
+ free(storage);
+ err:
+ return NULL;
+}
+
+void mailstorage_free(struct mailstorage * storage)
+{
+ if (storage->sto_session != NULL)
+ mailstorage_disconnect(storage);
+
+ if (storage->sto_driver != NULL) {
+ if (storage->sto_driver->sto_uninitialize != NULL)
+ storage->sto_driver->sto_uninitialize(storage);
+ }
+
+ clist_free(storage->sto_shared_folders);
+
+ if (storage->sto_id != NULL)
+ free(storage->sto_id);
+
+ free(storage);
+}
+
+int mailstorage_connect(struct mailstorage * storage)
+{
+ if (storage->sto_session != NULL)
+ return MAIL_NO_ERROR;
+
+ if (!clist_isempty(storage->sto_shared_folders))
+ return MAIL_ERROR_BAD_STATE;
+
+ if (storage->sto_driver->sto_connect == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return storage->sto_driver->sto_connect(storage);
+}
+
+
+void mailstorage_disconnect(struct mailstorage * storage)
+{
+ int r;
+ clistiter * cur;
+
+ while ((cur = clist_begin(storage->sto_shared_folders)) != NULL) {
+ struct mailfolder * folder;
+
+ folder = cur->data;
+ mailfolder_disconnect(folder);
+ }
+
+ if (storage->sto_session == NULL)
+ return;
+
+ r = mailsession_logout(storage->sto_session);
+
+ mailsession_free(storage->sto_session);
+ storage->sto_session = NULL;
+}
+
+
+int mailstorage_noop(struct mailstorage * storage)
+{
+ return mailsession_noop(storage->sto_session);
+}
+
+
+static int mailstorage_get_folder(struct mailstorage * storage,
+ char * pathname, mailsession ** result)
+{
+ if (storage->sto_driver->sto_get_folder_session == NULL)
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+
+ return storage->sto_driver->sto_get_folder_session(storage,
+ pathname, result);
+}
diff --git a/libetpan/src/driver/interface/mailstorage.h b/libetpan/src/driver/interface/mailstorage.h
new file mode 100644
index 0000000..e8cbda3
--- a/dev/null
+++ b/libetpan/src/driver/interface/mailstorage.h
@@ -0,0 +1,99 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef MAIL_STORAGE_H
+
+#define MAIL_STORAGE_H
+
+#include <libetpan/maildriver_types.h>
+#include <libetpan/mailstorage_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* storage */
+
+/*
+ mailstorage_new
+
+ This function creates an empty storage. This storage have to be initialized.
+ The "driver" and "data" fields should be initialized.
+
+ @param id is the name of the storage. It can be NULL.
+ The given parameter is no more needed when the creation is finished.
+ The given string is duplicated.
+
+ @return The mail storage is returned.
+*/
+
+struct mailstorage * mailstorage_new(char * sto_id);
+
+void mailstorage_free(struct mailstorage * storage);
+
+/*
+ session will be initialized on success.
+*/
+
+int mailstorage_connect(struct mailstorage * storage);
+
+void mailstorage_disconnect(struct mailstorage * storage);
+
+int mailstorage_noop(struct mailstorage * storage);
+
+
+/* folder */
+
+struct mailfolder * mailfolder_new(struct mailstorage * fld_storage,
+ char * fld_pathname, char * fld_virtual_name);
+
+void mailfolder_free(struct mailfolder * folder);
+
+int mailfolder_add_child(struct mailfolder * parent,
+ struct mailfolder * child);
+
+int mailfolder_detach_parent(struct mailfolder * folder);
+
+int mailfolder_connect(struct mailfolder * folder);
+
+void mailfolder_disconnect(struct mailfolder * folder);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/libetpan/src/driver/interface/mailstorage_tools.c b/libetpan/src/driver/interface/mailstorage_tools.c
new file mode 100644
index 0000000..9d39cab
--- a/dev/null
+++ b/libetpan/src/driver/interface/mailstorage_tools.c
@@ -0,0 +1,372 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "mailstorage_tools.h"
+
+#include "libetpan-config.h"
+
+#include <sys/types.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include "mail.h"
+#include "mailmessage.h"
+#include "maildriver.h"
+
+/* tools */
+
+/* connection to TCP/IP server */
+
+static int tcp_connect(char * server, uint16_t port)
+{
+ struct hostent * remotehost;
+ struct sockaddr_in sa;
+ int s;
+ int r;
+
+ s = socket(PF_INET, SOCK_STREAM, 0);
+ if (s == -1)
+ goto err;
+
+ remotehost = gethostbyname(server);
+ if (remotehost == NULL)
+ goto close_socket;
+
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons(port);
+ memcpy(&sa.sin_addr, remotehost->h_addr, remotehost->h_length);
+
+ r = connect(s, (struct sockaddr *) &sa, sizeof(struct sockaddr_in));
+ if (r == -1)
+ goto close_socket;
+
+ return s;
+
+ close_socket:
+ close(s);
+ err:
+ return -1;
+}
+
+
+/* connection through a shell command */
+
+static void do_exec_command(int fd, const char *command,
+ char *servername, uint16_t port)
+{
+ int i, maxopen;
+
+ if (fork() > 0) {
+ /* Fork again to become a child of init rather than
+ the etpan client. */
+ exit(0);
+ }
+
+ if (servername)
+ setenv("ETPANSERVER", servername, 1);
+ else
+ unsetenv("ETPANSERVER");
+
+ if (port) {
+ char porttext[20];
+
+ snprintf(porttext, sizeof(porttext), "%d", port);
+ setenv("ETPANPORT", porttext, 1);
+ }
+ else {
+ unsetenv("ETPANPORT");
+ }
+
+ /* Not a lot we can do if there's an error other than bail. */
+ if (dup2(fd, 0) == -1)
+ exit(1);
+ if (dup2(fd, 1) == -1)
+ exit(1);
+
+ /* Should we close stderr and reopen /dev/null? */
+
+ maxopen = sysconf(_SC_OPEN_MAX);
+ for (i=3; i < maxopen; i++)
+ close(i);
+
+#ifdef TIOCNOTTY
+ /* Detach from the controlling tty if we have one. Otherwise,
+ SSH might do something stupid like trying to use it instead
+ of running $SSH_ASKPASS. Doh. */
+ fd = open("/dev/tty", O_RDONLY);
+ if (fd != -1) {
+ ioctl(fd, TIOCNOTTY, NULL);
+ close(fd);
+ }
+#endif /* TIOCNOTTY */
+
+ execl("/bin/sh", "/bin/sh", "-c", command, NULL);
+
+ /* Eep. Shouldn't reach this */
+ exit(1);
+}
+
+static int subcommand_connect(char *command, char *servername, uint16_t port)
+{
+ int sockfds[2];
+ pid_t childpid;
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds))
+ return -1;
+
+ childpid = fork();
+ if (!childpid) {
+ do_exec_command(sockfds[1], command, servername, port);
+ }
+ else if (childpid == -1) {
+ close(sockfds[0]);
+ close(sockfds[1]);
+ return -1;
+ }
+
+ close(sockfds[1]);
+
+ /* Reap child, leaving grandchild process to run */
+ waitpid(childpid, NULL, 0);
+
+ return sockfds[0];
+}
+
+int mailstorage_generic_connect(mailsession_driver * driver,
+ char * servername,
+ uint16_t port,
+ char * command,
+ int connection_type,
+ int cache_function_id,
+ char * cache_directory,
+ int flags_function_id,
+ char * flags_directory,
+ mailsession ** result)
+{
+ int r;
+ int res;
+ mailstream * stream;
+ int fd;
+ mailsession * session;
+ int connect_result;
+
+ switch (connection_type) {
+ case CONNECTION_TYPE_PLAIN:
+ case CONNECTION_TYPE_TRY_STARTTLS:
+ case CONNECTION_TYPE_STARTTLS:
+ case CONNECTION_TYPE_TLS:
+ fd = tcp_connect(servername, port);
+ if (fd == -1) {
+ res = MAIL_ERROR_CONNECT;
+ goto err;
+ }
+ break;
+
+ case CONNECTION_TYPE_COMMAND:
+ case CONNECTION_TYPE_COMMAND_TRY_STARTTLS:
+ case CONNECTION_TYPE_COMMAND_STARTTLS:
+ case CONNECTION_TYPE_COMMAND_TLS:
+ fd = subcommand_connect(command, servername, port);
+ break;
+
+ default:
+ fd = -1;
+ break;
+ }
+
+ if (fd == -1) {
+ res = MAIL_ERROR_INVAL;
+ goto err;
+ }
+
+ switch (connection_type) {
+ case CONNECTION_TYPE_PLAIN:
+ case CONNECTION_TYPE_TRY_STARTTLS:
+ case CONNECTION_TYPE_STARTTLS:
+ case CONNECTION_TYPE_COMMAND:
+ case CONNECTION_TYPE_COMMAND_TRY_STARTTLS:
+ case CONNECTION_TYPE_COMMAND_STARTTLS:
+ stream = mailstream_socket_open(fd);
+ break;
+
+ case CONNECTION_TYPE_TLS:
+ case CONNECTION_TYPE_COMMAND_TLS:
+ stream = mailstream_ssl_open(fd);
+ break;
+
+ default:
+ stream = NULL;
+ break;
+ }
+
+ if (stream == NULL) {
+ res = MAIL_ERROR_STREAM;
+ close(fd);
+ goto err;
+ }
+
+ session = mailsession_new(driver);
+ if (session == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto close_stream;
+ }
+
+ if (cache_directory != NULL) {
+ char cache_directory_server[PATH_MAX];
+
+ snprintf(cache_directory_server, PATH_MAX, "%s/%s",
+ cache_directory, servername);
+
+ r = mailsession_parameters(session,
+ cache_function_id,
+ cache_directory_server);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto close_stream;
+ }
+ }
+
+ if (flags_directory != NULL) {
+ char flags_directory_server[PATH_MAX];
+
+ snprintf(flags_directory_server, PATH_MAX, "%s/%s",
+ flags_directory, servername);
+
+ r = mailsession_parameters(session,
+ flags_function_id,
+ flags_directory_server);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto close_stream;
+ }
+ }
+
+ r = mailsession_connect_stream(session, stream);
+ switch (r) {
+ case MAIL_NO_ERROR_NON_AUTHENTICATED:
+ case MAIL_NO_ERROR_AUTHENTICATED:
+ case MAIL_NO_ERROR:
+ break;
+ default:
+ res = r;
+ goto free;
+ }
+
+ connect_result = r;
+
+ switch (connection_type) {
+ case CONNECTION_TYPE_TRY_STARTTLS:
+ case CONNECTION_TYPE_COMMAND_TRY_STARTTLS:
+ r = mailsession_starttls(session);
+ if ((r != MAIL_NO_ERROR) && (r != MAIL_ERROR_NO_TLS)) {
+ res = r;
+ goto free;
+ }
+ break;
+
+ case CONNECTION_TYPE_STARTTLS:
+ case CONNECTION_TYPE_COMMAND_STARTTLS:
+ r = mailsession_starttls(session);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+ }
+
+ * result = session;
+
+ return connect_result;
+
+ close_stream:
+ mailstream_close(stream);
+ free:
+ mailsession_free(session);
+ err:
+ return res;
+}
+
+
+
+
+
+int mailstorage_generic_auth(mailsession * session,
+ int connect_result,
+ int auth_type,
+ char * login,
+ char * password)
+{
+ int must_auth;
+ int r;
+ int res;
+
+ r = connect_result;
+
+ must_auth = FALSE;
+ switch (r) {
+ case MAIL_NO_ERROR_NON_AUTHENTICATED:
+ must_auth = TRUE;
+ break;
+ case MAIL_NO_ERROR_AUTHENTICATED:
+ case MAIL_NO_ERROR:
+ break;
+ default:
+ res = r;
+ goto err;
+ }
+
+ if ((login == NULL) || (password == NULL))
+ must_auth = FALSE;
+
+ if (must_auth) {
+ r = mailsession_login(session, login, password);
+ if (r != MAIL_NO_ERROR) {
+ mailsession_logout(session);
+ res = r;
+ goto err;
+ }
+ }
+
+ return MAIL_NO_ERROR;
+
+ err:
+ return res;
+}
diff --git a/libetpan/src/driver/interface/mailstorage_tools.h b/libetpan/src/driver/interface/mailstorage_tools.h
new file mode 100644
index 0000000..113dcdf
--- a/dev/null
+++ b/libetpan/src/driver/interface/mailstorage_tools.h
@@ -0,0 +1,67 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "mailstorage.h"
+
+#ifndef MAILSTORAGE_TOOLS_H
+
+#define MAILSTORAGE_TOOLS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int mailstorage_generic_connect(mailsession_driver * driver,
+ char * servername,
+ uint16_t port,
+ char * command,
+ int connection_type,
+ int cache_function_id,
+ char * cache_directory,
+ int flags_function_id,
+ char * flags_directory,
+ mailsession ** result);
+
+int mailstorage_generic_auth(mailsession * session,
+ int connect_result,
+ int auth_type,
+ char * login,
+ char * password);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/interface/mailstorage_types.h b/libetpan/src/driver/interface/mailstorage_types.h
new file mode 100644
index 0000000..d0d18c8
--- a/dev/null
+++ b/libetpan/src/driver/interface/mailstorage_types.h
@@ -0,0 +1,203 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef MAILSTORAGE_TYPES_H
+
+#define MAILSTORAGE_TYPES_H
+
+#include <libetpan/maildriver_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct mailstorage;
+
+typedef struct mailstorage_driver mailstorage_driver;
+
+
+/*
+ There is three kinds of identities :
+ - storage
+ - folders
+ - session
+
+ A storage (struct mailstorage) represents whether a server or
+ a main path,
+
+ A storage can be an IMAP server, the root path of a MH or a mbox file.
+
+ Folders (struct mailfolder) are the mailboxes we can
+ choose in the server or as sub-folder of the main path.
+
+ Folders for IMAP are the IMAP mailboxes, for MH this is one of the
+ folder of the MH storage, for mbox, there is only one folder, the
+ mbox file content;
+
+ A mail session (struct mailsession) is whether a connection to a server
+ or a path that is open. It is the abstraction lower folders and storage.
+ It allow us to send commands.
+
+ We have a session driver for mail session for each kind of storage.
+
+ From a session, we can get a message (struct mailmessage) to read.
+ We have a message driver for each kind of storage.
+*/
+
+/*
+ mailstorage_driver is the driver structure for mail storages
+
+ - name is the name of the driver
+
+ - connect() connects the storage to the remote access or to
+ the path in the local filesystem.
+
+ - get_folder() can have two kinds of behaviour.
+ Either it creates a new session and independant from the session
+ used by the storage and select the given mailbox or
+ it selects the given mailbox in the current session.
+ It depends on the efficiency of the mail driver.
+
+ - uninitialize() frees the data created with mailstorage constructor.
+*/
+
+struct mailstorage_driver {
+ char * sto_name;
+ int (* sto_connect)(struct mailstorage * storage);
+ int (* sto_get_folder_session)(struct mailstorage * storage,
+ char * pathname, mailsession ** result);
+ void (* sto_uninitialize)(struct mailstorage * storage);
+};
+
+/*
+ mailstorage is the data structure for a storage
+
+ - id is the name of the storage, it can be NULL.
+
+ - data is the data specific to the driver.
+ This is the internal state of the storage.
+
+ - session is the session related to the storage.
+
+ - driver is the driver for the storage.
+
+ - shared_folders is the list of folders returned by the storage.
+*/
+
+struct mailstorage {
+ char * sto_id;
+ void * sto_data;
+ mailsession * sto_session;
+ mailstorage_driver * sto_driver;
+ clist * sto_shared_folders; /* list of (struct mailfolder *) */
+
+ void * sto_user_data;
+};
+
+
+
+/*
+ mailfolder is the data structure for a mailbox
+
+ - pathname is the path of the mailbox on the storage
+
+ - virtual_name is the folder identifier, it can be a path,
+ a name or NULL.
+
+ - storage is the storage to which the folder belongs to.
+
+ - session is the session related to the folder. It can be
+ different of the session of the storage.
+
+ - shared_session is != 0 if the session is the same as the
+ session of the storage.
+
+ - pos is the position of the folder in the "shared_folders" field
+ of the storage.
+
+ folders can be chained into a tree.
+
+ - parent is the parent of the folder.
+
+ - sibling_index is the index of the folder in the list of children
+ of the parent.
+
+ - children is the folder.
+*/
+
+struct mailfolder {
+ char * fld_pathname;
+ char * fld_virtual_name;
+
+ struct mailstorage * fld_storage;
+
+ mailsession * fld_session;
+ int fld_shared_session;
+ clistiter * fld_pos;
+
+ struct mailfolder * fld_parent;
+ unsigned int fld_sibling_index;
+ carray * fld_children; /* array of (struct mailfolder *) */
+
+ void * fld_user_data;
+};
+
+/*
+ this is the type of socket connection
+*/
+
+enum {
+ CONNECTION_TYPE_PLAIN, /* when the connection is plain text */
+ CONNECTION_TYPE_STARTTLS, /* when the connection is first plain,
+ then, we want to switch to
+ TLS (secure connection) */
+ CONNECTION_TYPE_TRY_STARTTLS, /* the connection is first plain,
+ then, we will try to switch to TLS */
+ CONNECTION_TYPE_TLS, /* the connection is over TLS */
+ CONNECTION_TYPE_COMMAND, /* the connection is over a shell command */
+ CONNECTION_TYPE_COMMAND_STARTTLS, /* the connection is over a shell
+ command and STARTTLS will be used */
+ CONNECTION_TYPE_COMMAND_TRY_STARTTLS, /* the connection is over
+ a shell command and STARTTLS will
+ be tried */
+ CONNECTION_TYPE_COMMAND_TLS, /* the connection is over a shell
+ command in TLS */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/tools/generic_cache.c b/libetpan/src/driver/tools/generic_cache.c
new file mode 100644
index 0000000..3ff6e43
--- a/dev/null
+++ b/libetpan/src/driver/tools/generic_cache.c
@@ -0,0 +1,729 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "generic_cache.h"
+
+#include "libetpan-config.h"
+
+#include <unistd.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "maildriver_types.h"
+#include "imfcache.h"
+#include "chash.h"
+#include "mailmessage.h"
+#include "mail_cache_db.h"
+
+int generic_cache_create_dir(char * dirname)
+{
+ struct stat buf;
+ int r;
+
+ r = stat(dirname, &buf);
+ if (r != 0) {
+ r = mkdir(dirname, 0700);
+
+ if (r < 0)
+ return MAIL_ERROR_FILE;
+ }
+ else {
+ if (!S_ISDIR(buf.st_mode))
+ return MAIL_ERROR_FILE;
+ }
+
+ return MAIL_NO_ERROR;
+}
+
+int generic_cache_store(char * filename, char * content, size_t length)
+{
+ int fd;
+ char * str;
+
+ fd = open(filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR);
+ if (fd == -1)
+ return MAIL_ERROR_FILE;
+
+ if (ftruncate(fd, length) < 0)
+ return MAIL_ERROR_FILE;
+
+ str = mmap(NULL, length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (str == MAP_FAILED)
+ return MAIL_ERROR_FILE;
+
+ memcpy(str, content, length);
+ msync(str, length, MS_SYNC);
+ munmap(str, length);
+
+ close(fd);
+
+ return MAIL_NO_ERROR;
+}
+
+int generic_cache_read(char * filename, char ** result, size_t * result_len)
+{
+ int fd;
+ char * str;
+ struct stat buf;
+ MMAPString * mmapstr;
+ char * content;
+ int res;
+
+ if (stat(filename, &buf) < 0) {
+ res = MAIL_ERROR_CACHE_MISS;
+ goto err;
+ }
+
+ fd = open(filename, O_RDONLY);
+ if (fd == -1) {
+ res = MAIL_ERROR_CACHE_MISS;
+ goto err;
+ }
+
+ str = mmap(NULL, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (str == MAP_FAILED) {
+ res = MAIL_ERROR_FILE;
+ goto close;
+ }
+
+ mmapstr = mmap_string_new_len(str, buf.st_size);
+ if (mmapstr == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto unmap;
+ }
+
+ if (mmap_string_ref(mmapstr) < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free;
+ }
+
+ content = mmapstr->str;
+
+ munmap(str, buf.st_size);
+ close(fd);
+
+ * result = content;
+ * result_len = buf.st_size;
+
+ return MAIL_NO_ERROR;
+
+ free:
+ mmap_string_free(mmapstr);
+ unmap:
+ munmap(str, buf.st_size);
+ close:
+ close(fd);
+ err:
+ return res;
+}
+
+static int flags_extension_read(MMAPString * mmapstr, size_t * index,
+ clist ** result)
+{
+ clist * list;
+ int r;
+ uint32_t count;
+ uint32_t i;
+ int res;
+
+ r = mailimf_cache_int_read(mmapstr, index, &count);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ list = clist_new();
+ if (list == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ for(i = 0 ; i < count ; i++) {
+ char * str;
+
+ r = mailimf_cache_string_read(mmapstr, index, &str);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free_list;
+ }
+
+ r = clist_append(list, str);
+ if (r < 0) {
+ free(str);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+ }
+
+ * result = list;
+
+ return MAIL_NO_ERROR;
+
+ free_list:
+ clist_foreach(list, (clist_func) free, NULL);
+ clist_free(list);
+ err:
+ return res;
+}
+
+static int generic_flags_read(MMAPString * mmapstr, size_t * index,
+ struct mail_flags ** result)
+{
+ clist * ext;
+ int r;
+ struct mail_flags * flags;
+ uint32_t value;
+ int res;
+
+ r = mailimf_cache_int_read(mmapstr, index, &value);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = flags_extension_read(mmapstr, index, &ext);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ flags = mail_flags_new(value, ext);
+ if (flags == NULL) {
+ res = r;
+ goto free;
+ }
+
+ * result = flags;
+
+ return MAIL_NO_ERROR;
+
+ free:
+ clist_foreach(ext, (clist_func) free, NULL);
+ clist_free(ext);
+ err:
+ return res;
+}
+
+static int flags_extension_write(MMAPString * mmapstr, size_t * index,
+ clist * ext)
+{
+ int r;
+ clistiter * cur;
+
+ r = mailimf_cache_int_write(mmapstr, index, clist_count(ext));
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ for(cur = clist_begin(ext) ; cur != NULL ; cur = clist_next(cur)) {
+ r = mailimf_cache_string_write(mmapstr, index,
+ clist_content(cur), strlen(clist_content(cur)));
+ if (r != MAIL_NO_ERROR)
+ return r;
+ }
+
+ return MAIL_NO_ERROR;
+}
+
+static int generic_flags_write(MMAPString * mmapstr, size_t * index,
+ struct mail_flags * flags)
+{
+ int r;
+
+ r = mailimf_cache_int_write(mmapstr, index,
+ flags->fl_flags & ~MAIL_FLAG_NEW);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ r = flags_extension_write(mmapstr, index,
+ flags->fl_extension);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ return MAIL_NO_ERROR;
+}
+
+
+
+
+static struct mail_flags * mail_flags_dup(struct mail_flags * flags)
+{
+ clist * list;
+ struct mail_flags * new_flags;
+ int r;
+ clistiter * cur;
+
+ list = clist_new();
+ if (list == NULL) {
+ goto err;
+ }
+
+ for(cur = clist_begin(flags->fl_extension) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ char * ext;
+
+ ext = strdup(clist_content(cur));
+ if (ext == NULL) {
+ goto free;
+ }
+
+ r = clist_append(list, ext);
+ if (r < 0) {
+ free(ext);
+ goto free;
+ }
+ }
+
+ new_flags = mail_flags_new(flags->fl_flags, list);
+ if (new_flags == NULL) {
+ goto free;
+ }
+
+ return new_flags;
+
+ free:
+ clist_foreach(list, (clist_func) free, NULL);
+ clist_free(list);
+ err:
+ return NULL;
+}
+
+static mailmessage * mailmessage_build(mailmessage * msg)
+{
+ mailmessage * new_msg;
+
+ new_msg = malloc(sizeof(* new_msg));
+ if (new_msg == NULL)
+ goto err;
+
+ new_msg->msg_session = msg->msg_session;
+ new_msg->msg_driver = msg->msg_driver;
+ new_msg->msg_index = msg->msg_index;
+ if (msg->msg_uid == NULL)
+ new_msg->msg_uid = NULL;
+ else {
+ new_msg->msg_uid = strdup(msg->msg_uid);
+ if (new_msg->msg_uid == NULL)
+ goto free;
+ }
+
+ new_msg->msg_cached = msg->msg_cached;
+ new_msg->msg_size = msg->msg_size;
+ new_msg->msg_fields = NULL;
+ new_msg->msg_flags = mail_flags_dup(msg->msg_flags);
+ if (new_msg->msg_flags == NULL) {
+ free(new_msg->msg_uid);
+ goto free;
+ }
+
+ new_msg->msg_mime = NULL;
+ new_msg->msg_data = NULL;
+
+ return new_msg;
+
+ free:
+ free(new_msg);
+ err:
+ return NULL;
+}
+
+struct mail_flags_store * mail_flags_store_new(void)
+{
+ struct mail_flags_store * flags_store;
+
+ flags_store = malloc(sizeof(struct mail_flags_store));
+ if (flags_store == NULL)
+ goto err;
+
+ flags_store->fls_tab = carray_new(128);
+ if (flags_store->fls_tab == NULL)
+ goto free;
+
+ flags_store->fls_hash = chash_new(128, CHASH_COPYALL);
+ if (flags_store->fls_hash == NULL)
+ goto free_tab;
+
+ return flags_store;
+
+ free_tab:
+ carray_free(flags_store->fls_tab);
+ free:
+ free(flags_store);
+ err:
+ return NULL;
+}
+
+void mail_flags_store_clear(struct mail_flags_store * flags_store)
+{
+ unsigned int i;
+
+ for(i = 0 ; i < carray_count(flags_store->fls_tab) ; i ++) {
+ chashdatum key;
+ mailmessage * msg;
+
+ msg = carray_get(flags_store->fls_tab, i);
+
+ key.data = &msg->msg_index;
+ key.len = sizeof(msg->msg_index);
+ chash_delete(flags_store->fls_hash, &key, NULL);
+
+ mailmessage_free(msg);
+ }
+ carray_set_size(flags_store->fls_tab, 0);
+}
+
+void mail_flags_store_free(struct mail_flags_store * flags_store)
+{
+ mail_flags_store_clear(flags_store);
+ chash_free(flags_store->fls_hash);
+ carray_free(flags_store->fls_tab);
+ free(flags_store);
+}
+
+int mail_flags_store_set(struct mail_flags_store * flags_store,
+ mailmessage * msg)
+{
+ chashdatum key;
+ chashdatum value;
+ unsigned int index;
+ int res;
+ int r;
+ mailmessage * new_msg;
+
+ if (msg->msg_flags == NULL) {
+ res = MAIL_NO_ERROR;
+ goto err;
+ }
+
+ /* duplicate needed message info */
+ new_msg = mailmessage_build(msg);
+ if (new_msg == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ key.data = &new_msg->msg_index;
+ key.len = sizeof(new_msg->msg_index);
+
+ r = chash_get(flags_store->fls_hash, &key, &value);
+ if (r == 0) {
+ mailmessage * old_msg;
+
+ index = * (unsigned int *) value.data;
+ old_msg = carray_get(flags_store->fls_tab, index);
+ mailmessage_free(old_msg);
+ }
+ else {
+ r = carray_set_size(flags_store->fls_tab,
+ carray_count(flags_store->fls_tab) + 1);
+ if (r != 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+ index = carray_count(flags_store->fls_tab) - 1;
+ }
+
+ carray_set(flags_store->fls_tab, index, new_msg);
+
+ value.data = &index;
+ value.len = sizeof(index);
+
+ r = chash_set(flags_store->fls_hash, &key, &value, NULL);
+ if (r < 0) {
+ carray_delete(flags_store->fls_tab, index);
+ res = MAIL_ERROR_MEMORY;
+ goto free;
+ }
+
+ return MAIL_NO_ERROR;
+
+ free:
+ mailmessage_free(new_msg);
+ err:
+ return res;
+}
+
+static int msg_index_compare(mailmessage ** msg1, mailmessage ** msg2)
+{
+ return (* msg1)->msg_index - (* msg2)->msg_index;
+}
+
+void mail_flags_store_sort(struct mail_flags_store * flags_store)
+{
+ qsort(carray_data(flags_store->fls_tab),
+ carray_count(flags_store->fls_tab), sizeof(mailmessage *),
+ (int (*)(const void *, const void *)) msg_index_compare);
+}
+
+struct mail_flags *
+mail_flags_store_get(struct mail_flags_store * flags_store, uint32_t index)
+{
+ struct mail_flags * flags;
+ chashdatum key;
+ chashdatum value;
+ int r;
+ unsigned int tab_index;
+ mailmessage * msg;
+
+ key.data = &index;
+ key.len = sizeof(index);
+
+ r = chash_get(flags_store->fls_hash, &key, &value);
+
+ if (r < 0)
+ return NULL;
+
+#if 0
+ flags = mail_flags_dup((struct mail_flags *) value.data);
+#endif
+ tab_index = * (unsigned int *) value.data;
+ msg = carray_get(flags_store->fls_tab, tab_index);
+ if (msg->msg_flags == NULL)
+ return NULL;
+
+ flags = mail_flags_dup(msg->msg_flags);
+
+ return flags;
+}
+
+int mail_flags_compare(struct mail_flags * flags1, struct mail_flags * flags2)
+{
+ clistiter * cur1;
+
+ if (clist_count(flags1->fl_extension) != clist_count(flags2->fl_extension))
+ return -1;
+
+ for(cur1 = clist_begin(flags1->fl_extension) ; cur1 != NULL ;
+ cur1 = clist_next(cur1)) {
+ char * flag1;
+ clistiter * cur2;
+ int found;
+
+ flag1 = clist_content(cur1);
+
+ found = 0;
+ for(cur2 = clist_begin(flags2->fl_extension) ; cur2 != NULL ;
+ cur2 = clist_next(cur2)) {
+ char * flag2;
+
+ flag2 = clist_content(cur2);
+
+ if (strcasecmp(flag1, flag2) == 0) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ return -1;
+ }
+
+ return flags1->fl_flags - flags2->fl_flags;
+}
+
+
+int generic_cache_fields_read(struct mail_cache_db * cache_db,
+ MMAPString * mmapstr,
+ char * keyname, struct mailimf_fields ** result)
+{
+ int r;
+ int res;
+ size_t cur_token;
+ struct mailimf_fields * fields;
+ void * data;
+ size_t data_len;
+
+ r = mail_cache_db_get(cache_db, keyname, strlen(keyname), &data, &data_len);
+ if (r != 0) {
+ res = MAIL_ERROR_CACHE_MISS;
+ goto err;
+ }
+
+ r = mail_serialize_clear(mmapstr, &cur_token);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ if (mmap_string_append_len(mmapstr, data, data_len) == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ r = mailimf_cache_fields_read(mmapstr, &cur_token, &fields);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ * result = fields;
+
+ return MAIL_NO_ERROR;
+
+ err:
+ return res;
+}
+
+int generic_cache_fields_write(struct mail_cache_db * cache_db,
+ MMAPString * mmapstr,
+ char * keyname, struct mailimf_fields * fields)
+{
+ int r;
+ int res;
+ size_t cur_token;
+
+ r = mail_serialize_clear(mmapstr, &cur_token);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_cache_fields_write(mmapstr, &cur_token, fields);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mail_cache_db_put(cache_db, keyname, strlen(keyname),
+ mmapstr->str, mmapstr->len);
+ if (r != 0) {
+ res = MAIL_ERROR_FILE;
+ goto err;
+ }
+
+ return MAIL_NO_ERROR;
+
+ err:
+ return res;
+}
+
+int generic_cache_flags_read(struct mail_cache_db * cache_db,
+ MMAPString * mmapstr,
+ char * keyname, struct mail_flags ** result)
+{
+ int r;
+ int res;
+ size_t cur_token;
+ struct mail_flags * flags;
+ void * data;
+ size_t data_len;
+
+ r = mail_cache_db_get(cache_db, keyname, strlen(keyname), &data, &data_len);
+ if (r != 0) {
+ res = MAIL_ERROR_CACHE_MISS;
+ goto err;
+ }
+
+ r = mail_serialize_clear(mmapstr, &cur_token);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ if (mmap_string_append_len(mmapstr, data, data_len) == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ r = generic_flags_read(mmapstr, &cur_token, &flags);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ * result = flags;
+
+ return MAIL_NO_ERROR;
+
+ err:
+ return res;
+}
+
+int generic_cache_flags_write(struct mail_cache_db * cache_db,
+ MMAPString * mmapstr,
+ char * keyname, struct mail_flags * flags)
+{
+ int r;
+ int res;
+ size_t cur_token;
+
+ r = mail_serialize_clear(mmapstr, &cur_token);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = generic_flags_write(mmapstr, &cur_token, flags);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mail_cache_db_put(cache_db, keyname, strlen(keyname),
+ mmapstr->str, mmapstr->len);
+ if (r != 0) {
+ res = MAIL_ERROR_FILE;
+ goto err;
+ }
+
+ return MAIL_NO_ERROR;
+
+ err:
+ return res;
+}
+
+
+int generic_cache_delete(struct mail_cache_db * cache_db,
+ char * keyname)
+{
+ int r;
+ int res;
+
+ r = mail_cache_db_del(cache_db, keyname, strlen(keyname));
+ if (r != 0) {
+ res = MAIL_ERROR_FILE;
+ goto err;
+ }
+
+ return MAIL_NO_ERROR;
+
+ err:
+ return res;
+}
diff --git a/libetpan/src/driver/tools/generic_cache.h b/libetpan/src/driver/tools/generic_cache.h
new file mode 100644
index 0000000..934a53d
--- a/dev/null
+++ b/libetpan/src/driver/tools/generic_cache.h
@@ -0,0 +1,109 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef GENERIC_CACHE_H
+
+#define GENERIC_CACHE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "generic_cache_types.h"
+#include "mailmessage_types.h"
+#include "chash.h"
+#include "carray.h"
+#include "mail_cache_db_types.h"
+
+int generic_cache_create_dir(char * dirname);
+
+int generic_cache_store(char * filename, char * content, size_t length);
+int generic_cache_read(char * filename, char ** result, size_t * result_len);
+
+int generic_cache_fields_read(struct mail_cache_db * cache_db,
+ MMAPString * mmapstr,
+ char * keyname, struct mailimf_fields ** result);
+
+int generic_cache_fields_write(struct mail_cache_db * cache_db,
+ MMAPString * mmapstr,
+ char * keyname, struct mailimf_fields * fields);
+
+int generic_cache_flags_read(struct mail_cache_db * cache_db,
+ MMAPString * mmapstr,
+ char * keyname, struct mail_flags ** result);
+
+int generic_cache_flags_write(struct mail_cache_db * cache_db,
+ MMAPString * mmapstr,
+ char * keyname, struct mail_flags * flags);
+
+int generic_cache_delete(struct mail_cache_db * cache_db, char * keyname);
+
+#if 0
+int generic_cache_fields_read(DB * dbp, MMAPString * mmapstr,
+ char * keyname, struct mailimf_fields ** result);
+
+int generic_cache_fields_write(DB * dbp, MMAPString * mmapstr,
+ char * keyname, struct mailimf_fields * fields);
+
+int generic_cache_flags_read(DB * dbp, MMAPString * mmapstr,
+ char * keyname, struct mail_flags ** result);
+
+int generic_cache_flags_write(DB * dbp, MMAPString * mmapstr,
+ char * keyname, struct mail_flags * flags);
+
+int generic_cache_delete(DB * dbp, char * keyname);
+#endif
+
+struct mail_flags_store * mail_flags_store_new(void);
+
+void mail_flags_store_clear(struct mail_flags_store * flags_store);
+
+void mail_flags_store_free(struct mail_flags_store * flags_store);
+
+int mail_flags_store_set(struct mail_flags_store * flags_store,
+ mailmessage * msg);
+
+void mail_flags_store_sort(struct mail_flags_store * flags_store);
+
+struct mail_flags *
+mail_flags_store_get(struct mail_flags_store * flags_store, uint32_t index);
+
+int mail_flags_compare(struct mail_flags * flags1, struct mail_flags * flags2);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/tools/generic_cache_types.h b/libetpan/src/driver/tools/generic_cache_types.h
new file mode 100644
index 0000000..bc69b3c
--- a/dev/null
+++ b/libetpan/src/driver/tools/generic_cache_types.h
@@ -0,0 +1,56 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef GENERIC_CACHE_TYPE_H
+
+#define GENERIC_CACHE_TYPE_H
+
+#include <libetpan/carray.h>
+#include <libetpan/chash.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct mail_flags_store {
+ carray * fls_tab;
+ chash * fls_hash;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/tools/imfcache.c b/libetpan/src/driver/tools/imfcache.c
new file mode 100644
index 0000000..7c6a5be
--- a/dev/null
+++ b/libetpan/src/driver/tools/imfcache.c
@@ -0,0 +1,1429 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "imfcache.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+static int mailimf_cache_field_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_field * field);
+static int mailimf_cache_orig_date_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_orig_date * date);
+static int mailimf_cache_date_time_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_date_time * date_time);
+static int mailimf_cache_from_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_from * from);
+static int mailimf_cache_sender_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_sender * sender);
+static int mailimf_cache_reply_to_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_reply_to * reply_to);
+static int mailimf_cache_to_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_to * to);
+static int mailimf_cache_cc_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_cc * to);
+static int mailimf_cache_bcc_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_bcc * to);
+static int mailimf_cache_message_id_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_message_id * message_id);
+static int mailimf_cache_msg_id_list_write(MMAPString * mmapstr, size_t * index,
+ clist * list);
+static int mailimf_cache_in_reply_to_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_in_reply_to *
+ in_reply_to);
+static int mailimf_cache_references_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_references * references);
+static int mailimf_cache_subject_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_subject * subject);
+static int mailimf_cache_address_list_write(MMAPString * mmapstr,
+ size_t * index,
+ struct mailimf_address_list *
+ addr_list);
+static int mailimf_cache_address_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_address * addr);
+static int mailimf_cache_group_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_group * group);
+static int mailimf_cache_mailbox_list_write(MMAPString * mmapstr,
+ size_t * index,
+ struct mailimf_mailbox_list * mb_list);
+static int mailimf_cache_mailbox_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_mailbox * mb);
+
+
+static int mailimf_cache_field_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_field ** result);
+static int mailimf_cache_orig_date_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_orig_date ** result);
+static int mailimf_cache_date_time_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_date_time ** result);
+static int mailimf_cache_from_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_from ** result);
+static int mailimf_cache_sender_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_sender ** result);
+static int mailimf_cache_reply_to_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_reply_to ** result);
+static int mailimf_cache_to_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_to ** result);
+static int mailimf_cache_cc_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_cc ** result);
+static int mailimf_cache_bcc_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_bcc ** result);
+static int mailimf_cache_message_id_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_message_id ** result);
+static int mailimf_cache_msg_id_list_read(MMAPString * mmapstr, size_t * index,
+ clist ** result);
+static int
+mailimf_cache_in_reply_to_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_in_reply_to ** result);
+
+static int mailimf_cache_references_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_references ** result);
+static int mailimf_cache_subject_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_subject ** result);
+static int mailimf_cache_address_list_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_address_list ** result);
+static int mailimf_cache_address_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_address ** result);
+static int mailimf_cache_group_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_group ** result);
+static int
+mailimf_cache_mailbox_list_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_mailbox_list ** result);
+static int mailimf_cache_mailbox_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_mailbox ** result);
+
+enum {
+ CACHE_NULL_POINTER = 0,
+ CACHE_NOT_NULL = 1,
+};
+
+int mail_serialize_clear(MMAPString * mmapstr, size_t * index)
+{
+ if (mmap_string_set_size(mmapstr, 0) == NULL)
+ return MAIL_ERROR_MEMORY;
+
+ * index = 0;
+
+ return MAIL_NO_ERROR;
+}
+
+int mail_serialize_write(MMAPString * mmapstr, size_t * index,
+ char * buf, size_t size)
+{
+ if (mmap_string_append_len(mmapstr, buf, size) == NULL)
+ return MAIL_ERROR_MEMORY;
+
+ * index = * index + size;
+
+ return MAIL_NO_ERROR;
+}
+
+int mail_serialize_read(MMAPString * mmapstr, size_t * index,
+ char * buf, size_t size)
+{
+ size_t cur_token;
+
+ cur_token = * index;
+
+ if (cur_token + size > mmapstr->len)
+ return MAIL_ERROR_STREAM;
+
+ memcpy(buf, mmapstr->str + cur_token, size);
+ * index = cur_token + size;
+
+ return MAIL_NO_ERROR;
+}
+
+int mailimf_cache_int_write(MMAPString * mmapstr, size_t * index,
+ uint32_t value)
+{
+ unsigned char ch;
+ int r;
+ int i;
+
+ for(i = 0 ; i < 4 ; i ++) {
+ ch = value % 256;
+
+ r = mail_serialize_write(mmapstr, index, &ch, 1);
+ if (r != MAIL_NO_ERROR)
+ return r;
+ value /= 256;
+ }
+
+ return MAIL_NO_ERROR;
+}
+
+int mailimf_cache_int_read(MMAPString * mmapstr, size_t * index,
+ uint32_t * result)
+{
+ unsigned char ch;
+ uint32_t value;
+ int i;
+ int r;
+
+ value = 0;
+ for(i = 0 ; i < 4 ; i ++) {
+ r = mail_serialize_read(mmapstr, index, &ch, 1);
+ if (r != MAIL_NO_ERROR)
+ return r;
+ value = value | ch << (i << 3);
+ }
+
+ * result = value;
+
+ return MAIL_NO_ERROR;
+}
+
+
+int mailimf_cache_string_write(MMAPString * mmapstr, size_t * index,
+ char * str, size_t length)
+{
+ int r;
+
+ if (str == NULL) {
+ r = mailimf_cache_int_write(mmapstr, index, CACHE_NULL_POINTER);
+ if (r != MAIL_NO_ERROR)
+ return r;
+ }
+ else {
+ r = mailimf_cache_int_write(mmapstr, index, CACHE_NOT_NULL);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ r = mailimf_cache_int_write(mmapstr, index, length);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ if (length != 0) {
+ r = mail_serialize_write(mmapstr, index, str, length);
+ if (r != MAIL_NO_ERROR)
+ return MAIL_ERROR_FILE;
+ }
+ }
+
+ return MAIL_NO_ERROR;
+}
+
+int mailimf_cache_string_read(MMAPString * mmapstr, size_t * index,
+ char ** result)
+{
+ int r;
+ uint32_t length;
+ char * str;
+ uint32_t type;
+
+ r = mailimf_cache_int_read(mmapstr, index, &type);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ if (type == CACHE_NULL_POINTER) {
+ str = NULL;
+ }
+ else {
+ r = mailimf_cache_int_read(mmapstr, index, &length);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ str = malloc(length + 1);
+ if (str == NULL)
+ return MAIL_ERROR_MEMORY;
+
+ r = mail_serialize_read(mmapstr, index, str, length);
+ if (r != MAIL_NO_ERROR)
+ return MAIL_ERROR_FILE;
+
+ str[length] = 0;
+ }
+
+ * result = str;
+
+ return MAIL_NO_ERROR;
+}
+
+int mailimf_cache_fields_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_fields * fields)
+{
+ clistiter * cur;
+ int r;
+
+ r = mailimf_cache_int_write(mmapstr, index,
+ clist_count(fields->fld_list));
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ for(cur = clist_begin(fields->fld_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ r = mailimf_cache_field_write(mmapstr, index, clist_content(cur));
+ if (r != MAIL_NO_ERROR)
+ return r;
+ }
+
+ return MAIL_NO_ERROR;
+}
+
+int mailimf_cache_fields_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_fields ** result)
+{
+ clist * list;
+ int r;
+ uint32_t count;
+ uint32_t i;
+ struct mailimf_fields * fields;
+ int res;
+
+ r = mailimf_cache_int_read(mmapstr, index, &count);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ list = clist_new();
+ if (list == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ for(i = 0 ; i < count ; i++) {
+ struct mailimf_field * field;
+
+ r = mailimf_cache_field_read(mmapstr, index, &field);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free_list;
+ }
+
+ r = clist_append(list, field);
+ if (r < 0) {
+ mailimf_field_free(field);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+ }
+
+ fields = mailimf_fields_new(list);
+ if (fields == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ * result = fields;
+
+ return MAIL_NO_ERROR;
+
+ free_list:
+ clist_foreach(list, (clist_func) mailimf_field_free, NULL);
+ clist_free(list);
+ err:
+ return res;
+}
+
+
+static int mailimf_cache_field_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_field * field)
+{
+ int r;
+
+ r = mailimf_cache_int_write(mmapstr, index, field->fld_type);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ switch (field->fld_type) {
+ case MAILIMF_FIELD_ORIG_DATE:
+ r = mailimf_cache_orig_date_write(mmapstr, index,
+ field->fld_data.fld_orig_date);
+ break;
+ case MAILIMF_FIELD_FROM:
+ r = mailimf_cache_from_write(mmapstr, index,
+ field->fld_data.fld_from);
+ break;
+ case MAILIMF_FIELD_SENDER:
+ r = mailimf_cache_sender_write(mmapstr, index,
+ field->fld_data.fld_sender);
+ break;
+ case MAILIMF_FIELD_REPLY_TO:
+ r = mailimf_cache_reply_to_write(mmapstr, index,
+ field->fld_data.fld_reply_to);
+ break;
+ case MAILIMF_FIELD_TO:
+ r = mailimf_cache_to_write(mmapstr, index,
+ field->fld_data.fld_to);
+ break;
+ case MAILIMF_FIELD_CC:
+ r = mailimf_cache_cc_write(mmapstr, index,
+ field->fld_data.fld_cc);
+ break;
+ case MAILIMF_FIELD_BCC:
+ r = mailimf_cache_bcc_write(mmapstr, index,
+ field->fld_data.fld_bcc);
+ break;
+ case MAILIMF_FIELD_MESSAGE_ID:
+ r = mailimf_cache_message_id_write(mmapstr, index,
+ field->fld_data.fld_message_id);
+ break;
+ case MAILIMF_FIELD_IN_REPLY_TO:
+ r = mailimf_cache_in_reply_to_write(mmapstr, index,
+ field->fld_data.fld_in_reply_to);
+ break;
+ case MAILIMF_FIELD_REFERENCES:
+ r = mailimf_cache_references_write(mmapstr, index,
+ field->fld_data.fld_references);
+ break;
+ case MAILIMF_FIELD_SUBJECT:
+ r = mailimf_cache_subject_write(mmapstr, index,
+ field->fld_data.fld_subject);
+ break;
+ default:
+ r = 0;
+ break;
+ }
+
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ return MAIL_NO_ERROR;
+}
+
+
+static int mailimf_cache_field_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_field ** result)
+{
+ int r;
+ uint32_t type;
+ struct mailimf_orig_date * orig_date;
+ struct mailimf_from * from;
+ struct mailimf_sender * sender;
+ struct mailimf_to * to;
+ struct mailimf_reply_to * reply_to;
+ struct mailimf_cc * cc;
+ struct mailimf_bcc * bcc;
+ struct mailimf_message_id * message_id;
+ struct mailimf_in_reply_to * in_reply_to;
+ struct mailimf_references * references;
+ struct mailimf_subject * subject;
+ struct mailimf_field * field;
+ int res;
+
+ orig_date = NULL;
+ from = NULL;
+ sender = NULL;
+ to = NULL;
+ reply_to = NULL;
+ cc = NULL;
+ bcc = NULL;
+ message_id = NULL;
+ in_reply_to = NULL;
+ references = NULL;
+ subject = NULL;
+ field = NULL;
+
+ r = mailimf_cache_int_read(mmapstr, index, &type);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ switch (type) {
+ case MAILIMF_FIELD_ORIG_DATE:
+ r = mailimf_cache_orig_date_read(mmapstr, index, &orig_date);
+ break;
+ case MAILIMF_FIELD_FROM:
+ r = mailimf_cache_from_read(mmapstr, index, &from);
+ break;
+ case MAILIMF_FIELD_SENDER:
+ r = mailimf_cache_sender_read(mmapstr, index, &sender);
+ break;
+ case MAILIMF_FIELD_REPLY_TO:
+ r = mailimf_cache_reply_to_read(mmapstr, index, &reply_to);
+ break;
+ case MAILIMF_FIELD_TO:
+ r = mailimf_cache_to_read(mmapstr, index, &to);
+ break;
+ case MAILIMF_FIELD_CC:
+ r = mailimf_cache_cc_read(mmapstr, index, &cc);
+ break;
+ case MAILIMF_FIELD_BCC:
+ r = mailimf_cache_bcc_read(mmapstr, index, &bcc);
+ break;
+ case MAILIMF_FIELD_MESSAGE_ID:
+ r = mailimf_cache_message_id_read(mmapstr, index, &message_id);
+ break;
+ case MAILIMF_FIELD_IN_REPLY_TO:
+ r = mailimf_cache_in_reply_to_read(mmapstr, index, &in_reply_to);
+ break;
+ case MAILIMF_FIELD_REFERENCES:
+ r = mailimf_cache_references_read(mmapstr, index, &references);
+ break;
+ case MAILIMF_FIELD_SUBJECT:
+ r = mailimf_cache_subject_read(mmapstr, index, &subject);
+ break;
+ default:
+ r = MAIL_ERROR_INVAL;
+ break;
+ }
+
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+
+ field = mailimf_field_new(type, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, orig_date, from, sender, reply_to,
+ to, cc, bcc, message_id,
+ in_reply_to, references,
+ subject, NULL, NULL, NULL);
+ if (field == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free;
+ }
+
+ * result = field;
+
+ return MAIL_NO_ERROR;
+
+ free:
+ if (orig_date != NULL)
+ mailimf_orig_date_free(orig_date);
+ if (from != NULL)
+ mailimf_from_free(from);
+ if (sender != NULL)
+ mailimf_sender_free(sender);
+ if (reply_to != NULL)
+ mailimf_reply_to_free(reply_to);
+ if (to != NULL)
+ mailimf_to_free(to);
+ if (cc != NULL)
+ mailimf_cc_free(cc);
+ if (bcc != NULL)
+ mailimf_bcc_free(bcc);
+ if (message_id != NULL)
+ mailimf_message_id_free(message_id);
+ if (in_reply_to != NULL)
+ mailimf_in_reply_to_free(in_reply_to);
+ if (references != NULL)
+ mailimf_references_free(references);
+ if (subject != NULL)
+ mailimf_subject_free(subject);
+ err:
+ return res;
+}
+
+static int mailimf_cache_orig_date_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_orig_date * date)
+{
+ return mailimf_cache_date_time_write(mmapstr, index, date->dt_date_time);
+}
+
+static int mailimf_cache_orig_date_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_orig_date ** result)
+{
+ int r;
+ struct mailimf_date_time * date_time;
+ struct mailimf_orig_date * orig_date;
+
+ r = mailimf_cache_date_time_read(mmapstr, index, &date_time);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ orig_date = mailimf_orig_date_new(date_time);
+ if (orig_date == NULL) {
+ mailimf_date_time_free(date_time);
+ return MAIL_ERROR_MEMORY;
+ }
+
+ * result = orig_date;
+
+ return MAIL_NO_ERROR;
+}
+
+static int mailimf_cache_date_time_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_date_time * date_time)
+{
+ int r;
+
+ r = mailimf_cache_int_write(mmapstr, index, date_time->dt_day);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ r = mailimf_cache_int_write(mmapstr, index, date_time->dt_month);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ r = mailimf_cache_int_write(mmapstr, index, date_time->dt_year);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ r = mailimf_cache_int_write(mmapstr, index, date_time->dt_hour);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ r = mailimf_cache_int_write(mmapstr, index, date_time->dt_min);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ r = mailimf_cache_int_write(mmapstr, index, date_time->dt_sec);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ r = mailimf_cache_int_write(mmapstr, index, date_time->dt_zone);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ return MAIL_NO_ERROR;
+}
+
+static int mailimf_cache_date_time_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_date_time ** result)
+{
+ int r;
+ uint32_t day;
+ uint32_t month;
+ uint32_t year;
+ uint32_t hour;
+ uint32_t min;
+ uint32_t sec;
+ uint32_t zone;
+ struct mailimf_date_time * date_time;
+
+ r = mailimf_cache_int_read(mmapstr, index, &day);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ r = mailimf_cache_int_read(mmapstr, index, &month);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ r = mailimf_cache_int_read(mmapstr, index, &year);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ r = mailimf_cache_int_read(mmapstr, index, &hour);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ r = mailimf_cache_int_read(mmapstr, index, &min);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ r = mailimf_cache_int_read(mmapstr, index, &sec);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ r = mailimf_cache_int_read(mmapstr, index, &zone);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ date_time = mailimf_date_time_new(day, month, year, hour, min, sec, zone);
+ if (date_time == NULL)
+ return MAIL_ERROR_MEMORY;
+
+ * result = date_time;
+
+ return MAIL_NO_ERROR;
+
+}
+
+
+static int mailimf_cache_from_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_from * from)
+{
+ return mailimf_cache_mailbox_list_write(mmapstr, index, from->frm_mb_list);
+}
+
+static int mailimf_cache_from_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_from ** result)
+{
+ struct mailimf_mailbox_list * mb_list;
+ struct mailimf_from * from;
+ int r;
+
+ r = mailimf_cache_mailbox_list_read(mmapstr, index, &mb_list);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ from = mailimf_from_new(mb_list);
+ if (from == NULL) {
+ mailimf_mailbox_list_free(mb_list);
+ return MAIL_ERROR_MEMORY;
+ }
+
+ * result = from;
+
+ return MAIL_NO_ERROR;
+}
+
+static int mailimf_cache_sender_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_sender * sender)
+{
+ return mailimf_cache_mailbox_write(mmapstr, index, sender->snd_mb);
+}
+
+static int mailimf_cache_sender_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_sender ** result)
+{
+ int r;
+ struct mailimf_mailbox * mb;
+ struct mailimf_sender * sender;
+
+ r = mailimf_cache_mailbox_read(mmapstr, index, &mb);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ sender = mailimf_sender_new(mb);
+ if (sender == NULL) {
+ mailimf_mailbox_free(mb);
+ return MAIL_ERROR_MEMORY;
+ }
+
+ * result = sender;
+
+ return MAIL_NO_ERROR;
+}
+
+static int mailimf_cache_reply_to_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_reply_to * reply_to)
+{
+ return mailimf_cache_address_list_write(mmapstr, index,
+ reply_to->rt_addr_list);
+}
+
+static int mailimf_cache_reply_to_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_reply_to ** result)
+{
+ int r;
+ struct mailimf_address_list * addr_list;
+ struct mailimf_reply_to * reply_to;
+
+ r = mailimf_cache_address_list_read(mmapstr, index, &addr_list);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ reply_to = mailimf_reply_to_new(addr_list);
+ if (reply_to == NULL) {
+ mailimf_address_list_free(addr_list);
+ return MAIL_ERROR_MEMORY;
+ }
+
+ * result = reply_to;
+
+ return MAIL_NO_ERROR;
+}
+
+static int mailimf_cache_to_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_to * to)
+{
+ return mailimf_cache_address_list_write(mmapstr, index, to->to_addr_list);
+}
+
+static int mailimf_cache_to_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_to ** result)
+{
+ int r;
+ struct mailimf_address_list * addr_list;
+ struct mailimf_to * to;
+
+ r = mailimf_cache_address_list_read(mmapstr, index, &addr_list);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ to = mailimf_to_new(addr_list);
+ if (to == NULL) {
+ mailimf_address_list_free(addr_list);
+ return MAIL_ERROR_MEMORY;
+ }
+
+ * result = to;
+
+ return MAIL_NO_ERROR;
+}
+
+static int mailimf_cache_cc_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_cc * cc)
+{
+ return mailimf_cache_address_list_write(mmapstr, index, cc->cc_addr_list);
+}
+
+static int mailimf_cache_cc_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_cc ** result)
+{
+ int r;
+ struct mailimf_address_list * addr_list;
+ struct mailimf_cc * cc;
+
+ r = mailimf_cache_address_list_read(mmapstr, index, &addr_list);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ cc = mailimf_cc_new(addr_list);
+ if (cc == NULL) {
+ mailimf_address_list_free(addr_list);
+ return MAIL_ERROR_MEMORY;
+ }
+
+ * result = cc;
+
+ return MAIL_NO_ERROR;
+}
+
+static int mailimf_cache_bcc_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_bcc * bcc)
+{
+ return mailimf_cache_address_list_write(mmapstr, index, bcc->bcc_addr_list);
+}
+
+static int mailimf_cache_bcc_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_bcc ** result)
+{
+ int r;
+ struct mailimf_address_list * addr_list;
+ struct mailimf_bcc * bcc;
+
+ r = mailimf_cache_address_list_read(mmapstr, index, &addr_list);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ bcc = mailimf_bcc_new(addr_list);
+ if (bcc == NULL) {
+ mailimf_address_list_free(addr_list);
+ return MAIL_ERROR_MEMORY;
+ }
+
+ * result = bcc;
+
+ return MAIL_NO_ERROR;
+}
+
+static int
+mailimf_cache_message_id_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_message_id * message_id)
+{
+ return mailimf_cache_string_write(mmapstr, index,
+ message_id->mid_value, strlen(message_id->mid_value));
+}
+
+static int mailimf_cache_message_id_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_message_id ** result)
+{
+ struct mailimf_message_id * message_id;
+ char * str;
+ int r;
+
+ r = mailimf_cache_string_read(mmapstr, index, &str);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ message_id = mailimf_message_id_new(str);
+ if (message_id == NULL) {
+ free(str);
+ return MAIL_ERROR_MEMORY;
+ }
+
+ * result = message_id;
+
+ return MAIL_NO_ERROR;
+}
+
+static int
+mailimf_cache_msg_id_list_write(MMAPString * mmapstr, size_t * index,
+ clist * list)
+{
+ clistiter * cur;
+ int r;
+
+ r = mailimf_cache_int_write(mmapstr, index, clist_count(list));
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ for(cur = clist_begin(list) ; cur != NULL ; cur = clist_next(cur)) {
+ char * msgid;
+
+ msgid = clist_content(cur);
+
+ r = mailimf_cache_string_write(mmapstr, index, msgid, strlen(msgid));
+ if (r != MAIL_NO_ERROR)
+ return r;
+ }
+
+ return MAIL_NO_ERROR;
+}
+
+static int mailimf_cache_msg_id_list_read(MMAPString * mmapstr, size_t * index,
+ clist ** result)
+{
+ clist * list;
+ int r;
+ uint32_t count;
+ uint32_t i;
+ int res;
+
+ r = mailimf_cache_int_read(mmapstr, index, &count);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ list = clist_new();
+ if (list == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ for(i = 0 ; i < count ; i++) {
+ char * msgid;
+
+ r = mailimf_cache_string_read(mmapstr, index, &msgid);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = clist_append(list, msgid);
+ if (r < 0) {
+ free(msgid);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+ }
+
+ * result = list;
+
+ return MAIL_NO_ERROR;
+
+ free_list:
+ clist_foreach(list, (clist_func) free, NULL);
+ clist_free(list);
+ err:
+ return res;
+}
+
+static int
+mailimf_cache_in_reply_to_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_in_reply_to * in_reply_to)
+{
+ return mailimf_cache_msg_id_list_write(mmapstr, index,
+ in_reply_to->mid_list);
+}
+
+static int mailimf_cache_in_reply_to_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_in_reply_to ** result)
+{
+ int r;
+ clist * msg_id_list;
+ struct mailimf_in_reply_to * in_reply_to;
+
+ r = mailimf_cache_msg_id_list_read(mmapstr, index, &msg_id_list);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ in_reply_to = mailimf_in_reply_to_new(msg_id_list);
+ if (in_reply_to == NULL) {
+ clist_foreach(msg_id_list, (clist_func) free, NULL);
+ clist_free(msg_id_list);
+ return MAIL_ERROR_MEMORY;
+ }
+
+ * result = in_reply_to;
+
+ return MAIL_NO_ERROR;
+}
+
+static int mailimf_cache_references_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_references * references)
+{
+ return mailimf_cache_msg_id_list_write(mmapstr, index,
+ references->mid_list);
+}
+
+static int mailimf_cache_references_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_references ** result)
+{
+ int r;
+ clist * msg_id_list;
+ struct mailimf_references * references;
+
+ r = mailimf_cache_msg_id_list_read(mmapstr, index, &msg_id_list);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ references = mailimf_references_new(msg_id_list);
+ if (references == NULL) {
+ clist_foreach(msg_id_list, (clist_func) free, NULL);
+ clist_free(msg_id_list);
+ return MAIL_ERROR_MEMORY;
+ }
+
+ * result = references;
+
+ return MAIL_NO_ERROR;
+}
+
+
+static int mailimf_cache_subject_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_subject * subject)
+{
+ return mailimf_cache_string_write(mmapstr, index,
+ subject->sbj_value, strlen(subject->sbj_value));
+}
+
+static int mailimf_cache_subject_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_subject ** result)
+{
+ char * str;
+ struct mailimf_subject * subject;
+ int r;
+
+ r = mailimf_cache_string_read(mmapstr, index, &str);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ if (str == NULL) {
+ str = strdup("");
+ if (str == NULL)
+ return MAIL_ERROR_MEMORY;
+ }
+
+ subject = mailimf_subject_new(str);
+ if (subject == NULL) {
+ free(str);
+ return MAIL_ERROR_MEMORY;
+ }
+
+ * result = subject;
+
+ return MAIL_NO_ERROR;
+}
+
+
+static int
+mailimf_cache_address_list_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_address_list * addr_list)
+{
+ clistiter * cur;
+ int r;
+
+ if (addr_list == NULL) {
+ r = mailimf_cache_int_write(mmapstr, index, CACHE_NULL_POINTER);
+ if (r != MAIL_NO_ERROR)
+ return r;
+ }
+ else {
+ r = mailimf_cache_int_write(mmapstr, index, CACHE_NOT_NULL);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ r = mailimf_cache_int_write(mmapstr, index,
+ clist_count(addr_list->ad_list));
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ for(cur = clist_begin(addr_list->ad_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailimf_address * addr;
+
+ addr = clist_content(cur);
+
+ r = mailimf_cache_address_write(mmapstr, index, addr);
+ if (r != MAIL_NO_ERROR)
+ return r;
+ }
+ }
+
+ return MAIL_NO_ERROR;
+}
+
+static int
+mailimf_cache_address_list_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_address_list ** result)
+{
+ struct mailimf_address_list * addr_list;
+ uint32_t count;
+ uint32_t i;
+ int r;
+ clist * list;
+ int res;
+ uint32_t type;
+
+ r = mailimf_cache_int_read(mmapstr, index, &type);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ if (type == CACHE_NULL_POINTER) {
+ * result = NULL;
+ return MAIL_NO_ERROR;
+ }
+
+ r = mailimf_cache_int_read(mmapstr, index, &count);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ list = clist_new();
+ if (list == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ for(i = 0 ; i < count ; i++) {
+ struct mailimf_address * addr;
+
+ r = mailimf_cache_address_read(mmapstr, index, &addr);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free_list;
+ }
+
+ r = clist_append(list, addr);
+ if (r < 0) {
+ mailimf_address_free(addr);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+ }
+
+ addr_list = mailimf_address_list_new(list);
+ if (addr_list == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ * result = addr_list;
+
+ return MAIL_NO_ERROR;
+
+ free_list:
+ clist_foreach(list, (clist_func) mailimf_address_free, NULL);
+ clist_free(list);
+ err:
+ return res;
+}
+
+static int mailimf_cache_address_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_address * addr)
+{
+ int r;
+
+ r = mailimf_cache_int_write(mmapstr, index, addr->ad_type);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ switch(addr->ad_type) {
+ case MAILIMF_ADDRESS_MAILBOX:
+ r = mailimf_cache_mailbox_write(mmapstr, index, addr->ad_data.ad_mailbox);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ break;
+
+ case MAILIMF_ADDRESS_GROUP:
+ r = mailimf_cache_group_write(mmapstr, index, addr->ad_data.ad_group);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ break;
+ }
+
+ return MAIL_NO_ERROR;
+}
+
+static int mailimf_cache_address_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_address ** result)
+{
+ uint32_t type;
+ int r;
+ struct mailimf_mailbox * mailbox;
+ struct mailimf_group * group;
+ struct mailimf_address * addr;
+
+ r = mailimf_cache_int_read(mmapstr, index, &type);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ mailbox = NULL;
+ group = NULL;
+
+ switch (type) {
+ case MAILIMF_ADDRESS_MAILBOX:
+ r = mailimf_cache_mailbox_read(mmapstr, index, &mailbox);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ break;
+
+ case MAILIMF_ADDRESS_GROUP:
+ r = mailimf_cache_group_read(mmapstr, index, &group);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ break;
+ }
+
+ addr = mailimf_address_new(type, mailbox, group);
+ if (addr == NULL)
+ goto free;
+
+ * result = addr;
+
+ return MAIL_NO_ERROR;
+
+ free:
+ if (mailbox != NULL)
+ mailimf_mailbox_free(mailbox);
+ if (group != NULL)
+ mailimf_group_free(group);
+ return MAIL_ERROR_MEMORY;
+}
+
+static int mailimf_cache_group_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_group * group)
+{
+ int r;
+
+ r = mailimf_cache_string_write(mmapstr, index, group->grp_display_name,
+ strlen(group->grp_display_name));
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ r = mailimf_cache_mailbox_list_write(mmapstr, index, group->grp_mb_list);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ return MAIL_NO_ERROR;
+}
+
+static int mailimf_cache_group_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_group ** result)
+{
+ int r;
+ char * display_name;
+ struct mailimf_mailbox_list * mb_list;
+ struct mailimf_group * group;
+ int res;
+
+ r = mailimf_cache_string_read(mmapstr, index, &display_name);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ r = mailimf_cache_mailbox_list_read(mmapstr, index, &mb_list);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free_dsp_name;
+ }
+
+ group = mailimf_group_new(display_name, mb_list);
+ if (group == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_mb_list;
+ }
+
+ * result = group;
+
+ return MAIL_NO_ERROR;
+
+ free_mb_list:
+ mailimf_mailbox_list_free(mb_list);
+ free_dsp_name:
+ free(display_name);
+ err:
+ return res;
+}
+
+static int
+mailimf_cache_mailbox_list_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_mailbox_list * mb_list)
+{
+ clistiter * cur;
+ int r;
+
+ if (mb_list == NULL) {
+ r = mailimf_cache_int_write(mmapstr, index, CACHE_NULL_POINTER);
+ if (r != MAIL_NO_ERROR)
+ return r;
+ }
+ else {
+ r = mailimf_cache_int_write(mmapstr, index, CACHE_NOT_NULL);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ r = mailimf_cache_int_write(mmapstr, index,
+ clist_count(mb_list->mb_list));
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ for(cur = clist_begin(mb_list->mb_list) ; cur != NULL ;
+ cur = clist_next(cur)) {
+ struct mailimf_mailbox * mb;
+
+ mb = clist_content(cur);
+
+ r = mailimf_cache_mailbox_write(mmapstr, index, mb);
+ if (r != MAIL_NO_ERROR)
+ return r;
+ }
+ }
+
+ return MAIL_NO_ERROR;
+}
+
+static int
+mailimf_cache_mailbox_list_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_mailbox_list ** result)
+{
+ clist * list;
+ int r;
+ uint32_t count;
+ uint32_t i;
+ struct mailimf_mailbox_list * mb_list;
+ int res;
+ uint32_t type;
+
+ r = mailimf_cache_int_read(mmapstr, index, &type);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ if (type == CACHE_NULL_POINTER) {
+ * result = NULL;
+ return MAIL_NO_ERROR;
+ }
+
+ r = mailimf_cache_int_read(mmapstr, index, &count);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+
+ list = clist_new();
+ if (list == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ for(i = 0 ; i < count ; i++) {
+ struct mailimf_mailbox * mb;
+
+ r = mailimf_cache_mailbox_read(mmapstr, index, &mb);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free_list;
+ }
+
+ r = clist_append(list, mb);
+ if (r < 0) {
+ mailimf_mailbox_free(mb);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+ }
+
+ mb_list = mailimf_mailbox_list_new(list);
+ if (mb_list == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ * result = mb_list;
+
+ return MAIL_NO_ERROR;
+
+ free_list:
+ clist_foreach(list, (clist_func) mailimf_mailbox_free, NULL);
+ clist_free(list);
+ err:
+ return res;
+}
+
+static int mailimf_cache_mailbox_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_mailbox * mb)
+{
+ int r;
+
+ if (mb->mb_display_name) {
+ r = mailimf_cache_string_write(mmapstr, index,
+ mb->mb_display_name, strlen(mb->mb_display_name));
+ if (r != MAIL_NO_ERROR)
+ return r;
+ }
+ else {
+ r = mailimf_cache_string_write(mmapstr, index, NULL, 0);
+ if (r != MAIL_NO_ERROR)
+ return r;
+ }
+
+ r = mailimf_cache_string_write(mmapstr, index,
+ mb->mb_addr_spec, strlen(mb->mb_addr_spec));
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ return MAIL_NO_ERROR;
+}
+
+static int mailimf_cache_mailbox_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_mailbox ** result)
+{
+ int r;
+ char * dsp_name;
+ char * addr_spec;
+ struct mailimf_mailbox * mb;
+
+ dsp_name = NULL;
+
+ r = mailimf_cache_string_read(mmapstr, index, &dsp_name);
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ r = mailimf_cache_string_read(mmapstr, index, &addr_spec);
+ if (r != MAIL_NO_ERROR)
+ goto free_dsp_name;
+
+ mb = mailimf_mailbox_new(dsp_name, addr_spec);
+ if (mb == NULL)
+ goto free_addr;
+
+ * result = mb;
+
+ return MAIL_NO_ERROR;
+
+ free_addr:
+ free(addr_spec);
+ free_dsp_name:
+ if (dsp_name != NULL)
+ free(dsp_name);
+ return MAIL_ERROR_MEMORY;
+}
diff --git a/libetpan/src/driver/tools/imfcache.h b/libetpan/src/driver/tools/imfcache.h
new file mode 100644
index 0000000..f054a12
--- a/dev/null
+++ b/libetpan/src/driver/tools/imfcache.h
@@ -0,0 +1,75 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef IMFCACHE_H
+
+#define IMFCACHE_H
+
+#include <stdio.h>
+#include "mailimf.h"
+#include "maildriver_types.h"
+#include "mmapstring.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int mail_serialize_clear(MMAPString * mmapstr, size_t * index);
+
+int mail_serialize_write(MMAPString * mmapstr, size_t * index,
+ char * buf, size_t size);
+
+int mail_serialize_read(MMAPString * mmapstr, size_t * index,
+ char * buf, size_t size);
+
+int mailimf_cache_int_write(MMAPString * mmapstr, size_t * index,
+ uint32_t value);
+int mailimf_cache_string_write(MMAPString * mmapstr, size_t * index,
+ char * str, size_t length);
+int mailimf_cache_int_read(MMAPString * mmapstr, size_t * index,
+ uint32_t * result);
+int mailimf_cache_string_read(MMAPString * mmapstr, size_t * index,
+ char ** result);
+
+int mailimf_cache_fields_write(MMAPString * mmapstr, size_t * index,
+ struct mailimf_fields * fields);
+int mailimf_cache_fields_read(MMAPString * mmapstr, size_t * index,
+ struct mailimf_fields ** result);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/tools/mailthread.c b/libetpan/src/driver/tools/mailthread.c
new file mode 100644
index 0000000..32f73cd
--- a/dev/null
+++ b/libetpan/src/driver/tools/mailthread.c
@@ -0,0 +1,1742 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "mailthread.h"
+#include "mailthread_types.h"
+
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "mail.h"
+#include "chash.h"
+#include "carray.h"
+#include "clist.h"
+#include "mailmessage.h"
+
+static inline char * get_msg_id(mailmessage * msg)
+{
+ if (msg->msg_single_fields.fld_message_id != NULL)
+ return msg->msg_single_fields.fld_message_id->mid_value;
+ else
+ return NULL;
+}
+
+static inline clist * get_ref(mailmessage * msg)
+{
+ if (msg->msg_single_fields.fld_references != NULL)
+ return msg->msg_single_fields.fld_references->mid_list;
+ else
+ return NULL;
+}
+
+static inline clist * get_in_reply_to(mailmessage * msg)
+{
+ if (msg->msg_single_fields.fld_in_reply_to != NULL)
+ return msg->msg_single_fields.fld_in_reply_to->mid_list;
+ else
+ return NULL;
+}
+
+static inline int skip_subj_blob(char * subj, size_t * begin,
+ size_t length)
+{
+ /* subj-blob = "[" *BLOBCHAR "]" *WSP */
+ size_t cur_token;
+
+ cur_token = * begin;
+
+ if (subj[cur_token] != '[')
+ return FALSE;
+
+ cur_token ++;
+
+ while (1) {
+ if (cur_token >= length)
+ return FALSE;
+
+ if (subj[cur_token] == '[')
+ return FALSE;
+
+ if (subj[cur_token] == ']')
+ break;
+
+ cur_token ++;
+ }
+
+ cur_token ++;
+
+ while (1) {
+ if (cur_token >= length)
+ break;
+
+ if (subj[cur_token] != ' ')
+ break;
+
+ cur_token ++;
+ }
+
+ * begin = cur_token;
+
+ return TRUE;
+}
+
+static inline int skip_subj_refwd(char * subj, size_t * begin,
+ size_t length)
+{
+ /* subj-refwd = ("re" / ("fw" ["d"])) *WSP [subj-blob] ":" */
+ size_t cur_token;
+ int prefix;
+
+ cur_token = * begin;
+
+ prefix = FALSE;
+ if (length >= 3) {
+ if (strncasecmp(subj + cur_token, "fwd", 3) == 0) {
+ cur_token += 3;
+ prefix = TRUE;
+ }
+ }
+ if (!prefix) {
+ if (length >= 2) {
+ if (strncasecmp(subj + cur_token, "fw", 2) == 0) {
+ cur_token += 2;
+ prefix = TRUE;
+ }
+ else if (strncasecmp(subj + cur_token, "re", 2) == 0) {
+ cur_token += 2;
+ prefix = TRUE;
+ }
+ }
+ }
+
+ if (!prefix)
+ return FALSE;
+
+ while (1) {
+ if (cur_token >= length)
+ break;
+
+ if (subj[cur_token] != ' ')
+ break;
+
+ cur_token ++;
+ }
+
+ skip_subj_blob(subj, &cur_token, length);
+
+ if (subj[cur_token] != ':')
+ return FALSE;
+
+ cur_token ++;
+
+ * begin = cur_token;
+
+ return TRUE;
+}
+
+static inline int skip_subj_leader(struct mailmessage_tree * tree,
+ char * subj, size_t * begin,
+ size_t length)
+{
+ size_t cur_token;
+
+ cur_token = * begin;
+
+ /* subj-leader = (*subj-blob subj-refwd) / WSP */
+
+ if (subj[cur_token] == ' ') {
+ cur_token ++;
+ }
+ else {
+ while (cur_token < length) {
+ if (!skip_subj_blob(subj, &cur_token, length))
+ break;
+ }
+ if (!skip_subj_refwd(subj, &cur_token, length))
+ return FALSE;
+ tree->node_is_reply = TRUE;
+ }
+
+ * begin = cur_token;
+
+ return TRUE;
+}
+
+
+static char * extract_subject(char * default_from,
+ struct mailmessage_tree * tree,
+ char * str)
+{
+ char * subj;
+ char * cur;
+ char * write_pos;
+ size_t len;
+ size_t begin;
+
+ char * decoded;
+ size_t cur_token;
+
+ int do_repeat_5;
+ int do_repeat_6;
+ int r;
+
+ /*
+ (1) Convert any RFC 2047 encoded-words in the subject to
+ UTF-8.
+ */
+
+ decoded = NULL;
+
+ cur_token = 0;
+ r = mailmime_encoded_phrase_parse(default_from, str, strlen(str),
+ &cur_token, "utf-8",
+ &decoded);
+
+ if (r == MAILIMF_NO_ERROR) {
+ subj = decoded;
+ }
+ else
+ subj = strdup(str);
+
+ len = strlen(subj);
+
+ /*
+ Convert all tabs and continuations to space.
+ Convert all multiple spaces to a single space.
+ */
+
+ cur = subj;
+ write_pos = subj;
+ while (* cur != '\0') {
+ int cont;
+
+ switch (* cur) {
+ case '\t':
+ case '\r':
+ case '\n':
+ cont = TRUE;
+
+ cur ++;
+ while (* cur && cont) {
+ switch (* cur) {
+ case '\t':
+ case '\r':
+ case '\n':
+ cont = TRUE;
+ break;
+ default:
+ cont = FALSE;
+ break;
+ }
+ cur ++;
+ }
+
+ * write_pos = ' ';
+ write_pos ++;
+
+ break;
+
+ default:
+ * write_pos = * cur;
+ write_pos ++;
+
+ cur ++;
+
+ break;
+ }
+ }
+ * write_pos = '\0';
+
+ begin = 0;
+
+ do {
+ do_repeat_6 = FALSE;
+
+ /*
+ (2) Remove all trailing text of the subject that matches
+ the subj-trailer ABNF, repeat until no more matches are
+ possible.
+ */
+
+ while (len > 0) {
+ int chg;
+
+ chg = FALSE;
+
+ /* subj-trailer = "(fwd)" / WSP */
+ if (subj[len - 1] == ' ') {
+ subj[len - 1] = '\0';
+ len --;
+ }
+ else {
+ if (len < 5)
+ break;
+
+ if (strncasecmp(subj + len - 5, "(fwd)", 5) != 0)
+ break;
+
+ subj[len - 5] = '\0';
+ len -= 5;
+ tree->node_is_reply = TRUE;
+ }
+ }
+
+ do {
+ size_t saved_begin;
+
+ do_repeat_5 = FALSE;
+
+ /*
+ (3) Remove all prefix text of the subject that matches the
+ subj-leader ABNF.
+ */
+
+ if (skip_subj_leader(tree, subj, &begin, len))
+ do_repeat_5 = TRUE;
+
+ /*
+ (4) If there is prefix text of the subject that matches the
+ subj-blob ABNF, and removing that prefix leaves a non-empty
+ subj-base, then remove the prefix text.
+ */
+
+ saved_begin = begin;
+ if (skip_subj_blob(subj, &begin, len)) {
+ if (begin == len) {
+ /* this will leave a empty subject base */
+ begin = saved_begin;
+ }
+ else
+ do_repeat_5 = TRUE;
+ }
+
+ /*
+ (5) Repeat (3) and (4) until no matches remain.
+ Note: it is possible to defer step (2) until step (6),
+ but this requires checking for subj-trailer in step (4).
+ */
+
+ }
+ while (do_repeat_5);
+
+ /*
+ (6) If the resulting text begins with the subj-fwd-hdr ABNF
+ and ends with the subj-fwd-trl ABNF, remove the
+ subj-fwd-hdr and subj-fwd-trl and repeat from step (2).
+ */
+
+ if (len >= 5) {
+ size_t saved_begin;
+
+ saved_begin = begin;
+ if (strncasecmp(subj + begin, "[fwd:", 5) == 0) {
+ begin += 5;
+
+ if (subj[len - 1] != ']')
+ saved_begin = begin;
+ else {
+ tree->node_is_reply = TRUE;
+
+ subj[len - 1] = '\0';
+ len --;
+ do_repeat_6 = TRUE;
+ }
+ }
+ }
+
+ }
+ while (do_repeat_6);
+
+ /*
+ (7) The resulting text is the "base subject" used in
+ threading.
+ */
+
+ /* convert to upper case */
+
+ cur = subj + begin;
+ write_pos = subj;
+
+ while (* cur != '\0') {
+ * write_pos = (char) toupper((unsigned char) * cur);
+ cur ++;
+ write_pos ++;
+ }
+ * write_pos = '\0';
+
+ return subj;
+}
+
+static int get_extracted_subject(char * default_from,
+ struct mailmessage_tree * tree,
+ char ** result)
+{
+ if (tree->node_msg->msg_single_fields.fld_subject != NULL) {
+ char * subj;
+
+ subj = extract_subject(default_from,
+ tree, tree->node_msg->msg_single_fields.fld_subject->sbj_value);
+ if (subj == NULL)
+ return MAIL_ERROR_MEMORY;
+
+ * result = subj;
+
+ return MAIL_NO_ERROR;
+ }
+
+ return MAIL_ERROR_SUBJECT_NOT_FOUND;
+}
+
+static int get_thread_subject(char * default_from,
+ struct mailmessage_tree * tree,
+ char ** result)
+{
+ char * thread_subject;
+ int r;
+ unsigned int i;
+
+ if (tree->node_msg != NULL) {
+ if (tree->node_msg->msg_fields != NULL) {
+ r = get_extracted_subject(default_from, tree, &thread_subject);
+
+ if (r != MAIL_NO_ERROR)
+ return r;
+
+ * result = thread_subject;
+ return MAIL_NO_ERROR;
+ }
+ }
+
+ for(i = 0 ; i < carray_count(tree->node_children) ; i ++) {
+ struct mailmessage_tree * child;
+
+ child = carray_get(tree->node_children, i);
+
+ r = get_thread_subject(default_from, child, &thread_subject);
+
+ switch (r) {
+ case MAIL_NO_ERROR:
+ * result = thread_subject;
+ return MAIL_NO_ERROR;
+
+ case MAIL_ERROR_SUBJECT_NOT_FOUND:
+ /* do nothing */
+ break;
+
+ default:
+ return r;
+ }
+ }
+
+ return MAIL_ERROR_SUBJECT_NOT_FOUND;
+}
+
+
+
+#ifndef WRONG
+#define WRONG (-1)
+#endif /* !defined WRONG */
+
+static int tmcomp(struct tm * atmp, struct tm * btmp)
+{
+ register int result;
+
+ if ((result = (atmp->tm_year - btmp->tm_year)) == 0 &&
+ (result = (atmp->tm_mon - btmp->tm_mon)) == 0 &&
+ (result = (atmp->tm_mday - btmp->tm_mday)) == 0 &&
+ (result = (atmp->tm_hour - btmp->tm_hour)) == 0 &&
+ (result = (atmp->tm_min - btmp->tm_min)) == 0)
+ result = atmp->tm_sec - btmp->tm_sec;
+ return result;
+}
+
+static time_t mkgmtime(struct tm * tmp)
+{
+ register int dir;
+ register int bits;
+ register int saved_seconds;
+ time_t t;
+ struct tm yourtm, *mytm;
+
+ yourtm = *tmp;
+ saved_seconds = yourtm.tm_sec;
+ yourtm.tm_sec = 0;
+ /*
+ ** Calculate the number of magnitude bits in a time_t
+ ** (this works regardless of whether time_t is
+ ** signed or unsigned, though lint complains if unsigned).
+ */
+ for (bits = 0, t = 1; t > 0; ++bits, t <<= 1)
+ ;
+ /*
+ ** If time_t is signed, then 0 is the median value,
+ ** if time_t is unsigned, then 1 << bits is median.
+ */
+ t = (t < 0) ? 0 : ((time_t) 1 << bits);
+ for ( ; ; ) {
+ mytm = gmtime(&t);
+ dir = tmcomp(mytm, &yourtm);
+ if (dir != 0) {
+ if (bits-- < 0)
+ return WRONG;
+ if (bits < 0)
+ --t;
+ else if (dir > 0)
+ t -= (time_t) 1 << bits;
+ else t += (time_t) 1 << bits;
+ continue;
+ }
+ break;
+ }
+ t += saved_seconds;
+ return t;
+}
+
+static inline time_t get_date(mailmessage * msg)
+{
+ struct tm tmval;
+ time_t timeval;
+ struct mailimf_date_time * date_time;
+
+ if (msg->msg_single_fields.fld_orig_date == NULL)
+ return (time_t) -1;
+
+ date_time = msg->msg_single_fields.fld_orig_date->dt_date_time;
+
+ tmval.tm_sec = date_time->dt_sec;
+ tmval.tm_min = date_time->dt_min;
+ tmval.tm_hour = date_time->dt_hour;
+ tmval.tm_sec = date_time->dt_sec;
+ tmval.tm_mday = date_time->dt_day;
+ tmval.tm_mon = date_time->dt_month - 1;
+ tmval.tm_year = date_time->dt_year - 1900;
+
+ timeval = mkgmtime(&tmval);
+
+ timeval -= date_time->dt_zone * 36;
+
+ return timeval;
+}
+
+static inline int is_descendant(struct mailmessage_tree * node,
+ struct mailmessage_tree * maybe_child)
+{
+ unsigned int i;
+
+ for(i = 0 ; i < carray_count(node->node_children) ; i++) {
+ struct mailmessage_tree * tree;
+
+ tree = carray_get(node->node_children, i);
+ if (tree == maybe_child)
+ return TRUE;
+ if (carray_count(tree->node_children) != 0)
+ if (is_descendant(tree, maybe_child))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static int delete_dummy(carray * rootlist, carray * sibling_list,
+ unsigned int cur, unsigned int * pnext)
+{
+ struct mailmessage_tree * env_tree;
+ int res;
+ int r;
+ unsigned int cur_child;
+ unsigned int next;
+
+ env_tree = carray_get(sibling_list, cur);
+
+ cur_child = 0;
+ while (cur_child < carray_count(env_tree->node_children)) {
+ delete_dummy(rootlist, env_tree->node_children, cur_child, &cur_child);
+ }
+
+ if (env_tree->node_msg == NULL) {
+ if (carray_count(env_tree->node_children) == 0) {
+
+ /* If it is a dummy message with NO children, delete it. */
+ mailmessage_tree_free(env_tree);
+ carray_delete(sibling_list, cur);
+ next = cur;
+ }
+ else {
+ /* If it is a dummy message with children, delete it, but
+ promote its children to the current level. */
+
+ /*
+ Do not promote the children if doing so would make them
+ children of the root, unless there is only one child.
+ */
+
+ cur_child = 0;
+ if ((sibling_list != rootlist) ||
+ (carray_count(env_tree->node_children) == 1)) {
+ while (cur_child < carray_count(env_tree->node_children)) {
+ struct mailmessage_tree * child;
+
+ child = carray_get(env_tree->node_children, cur_child);
+ r = carray_add(sibling_list, child, NULL);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+ /* set new parent of the children */
+ child->node_parent = env_tree->node_parent;
+
+ carray_delete(env_tree->node_children, cur_child);
+ }
+ mailmessage_tree_free(env_tree);
+ carray_delete(sibling_list, cur);
+ next = cur;
+ }
+ else
+ next = cur + 1;
+ }
+ }
+ else
+ next = cur + 1;
+
+ * pnext = next;
+
+ return MAIL_NO_ERROR;
+
+ err:
+ return res;
+}
+
+static inline time_t tree_get_date(struct mailmessage_tree * tree)
+{
+ if (tree->node_msg != NULL) {
+ return tree->node_date;
+ }
+ else {
+ struct mailmessage_tree * subtree;
+
+ if (carray_count(tree->node_children) == 0)
+ return (time_t) -1;
+
+ subtree = carray_get(tree->node_children, 0);
+
+ return subtree->node_date;
+ }
+}
+
+static inline uint32_t tree_get_index(struct mailmessage_tree * tree)
+{
+ if (tree->node_msg == NULL)
+ return 0;
+
+ return tree->node_msg->msg_index;
+}
+
+int mailthread_tree_timecomp(struct mailmessage_tree ** ptree1,
+ struct mailmessage_tree ** ptree2)
+{
+ time_t date1;
+ time_t date2;
+
+ date1 = tree_get_date(* ptree1);
+ date2 = tree_get_date(* ptree2);
+
+ if ((date1 == (time_t) -1) || (date2 == (time_t) -1)) {
+ uint32_t index1;
+ uint32_t index2;
+
+ index1 = tree_get_index(* ptree1);
+ index2 = tree_get_index(* ptree2);
+ return (int) ((long) index1 - (long) index2);
+ }
+
+ return (int) ((long) date1 - (long) date2);
+}
+
+static int tree_subj_time_comp(struct mailmessage_tree ** ptree1,
+ struct mailmessage_tree ** ptree2)
+{
+ char * subj1;
+ char * subj2;
+ time_t date1;
+ time_t date2;
+ int r;
+
+ subj1 = (* ptree1)->node_base_subject;
+ subj2 = (* ptree2)->node_base_subject;
+
+ if ((subj1 != NULL) && (subj2 != NULL))
+ r = strcmp(subj1, subj2);
+ else {
+ if ((subj1 == NULL) && (subj2 == NULL))
+ r = 0;
+ else if (subj1 == NULL)
+ r = -1;
+ else /* subj2 == NULL */
+ r = 1;
+ }
+
+ if (r != 0)
+ return r;
+
+ date1 = (* ptree1)->node_date;
+ date2 = (* ptree2)->node_date;
+
+ if ((date1 == (time_t) -1) || (date2 == (time_t) -1))
+ return ((int32_t) (* ptree1)->node_msg->msg_index) -
+ ((int32_t) (* ptree2)->node_msg->msg_index);
+
+ return (int) ((long) date1 - (long) date2);
+}
+
+
+
+int mail_thread_sort(struct mailmessage_tree * tree,
+ int (* comp_func)(struct mailmessage_tree **,
+ struct mailmessage_tree **),
+ int sort_sub)
+{
+ unsigned int cur;
+ int r;
+ int res;
+
+ for(cur = 0 ; cur < carray_count(tree->node_children) ; cur ++) {
+ struct mailmessage_tree * subtree;
+
+ subtree = carray_get(tree->node_children, cur);
+
+ if (sort_sub) {
+ r = mail_thread_sort(subtree, comp_func, sort_sub);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto err;
+ }
+ }
+ }
+
+ qsort(carray_data(tree->node_children), carray_count(tree->node_children),
+ sizeof(struct mailmessage_tree *),
+ (int (*)(const void *, const void *)) comp_func);
+
+ return MAIL_NO_ERROR;
+
+ err:
+ return res;
+}
+
+
+static int
+mail_build_thread_references(char * default_from,
+ struct mailmessage_list * env_list,
+ struct mailmessage_tree ** result,
+ int use_subject,
+ int (* comp_func)(struct mailmessage_tree **,
+ struct mailmessage_tree **))
+{
+ int r;
+ int res;
+ chash * msg_id_hash;
+ unsigned int cur;
+ struct mailmessage_tree * root;
+ carray * rootlist;
+ carray * msg_list;
+ unsigned int i;
+ chash * subject_hash;
+
+ msg_id_hash = chash_new(128, CHASH_COPYNONE);
+ if (msg_id_hash == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+
+ root = mailmessage_tree_new(NULL, (time_t) -1, NULL);
+ if (root == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_hash;
+ }
+ rootlist = root->node_children;
+
+ msg_list = carray_new(128);
+ if (msg_list == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_root;
+ }
+
+ /* collect message-ID */
+ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
+ mailmessage * msg;
+ char * msgid;
+ struct mailmessage_tree * env_tree;
+ chashdatum hashkey;
+ chashdatum hashdata;
+ chashdatum hashold;
+ time_t date;
+
+ msg = carray_get(env_list->msg_tab, i);
+
+ if (msg == NULL)
+ continue;
+
+ if (msg->msg_fields != NULL) {
+ msgid = get_msg_id(msg);
+
+ if (msgid == NULL) {
+ msgid = mailimf_get_message_id();
+ }
+ else {
+ hashkey.data = msgid;
+ hashkey.len = strlen(msgid);
+
+ if (chash_get(msg_id_hash, &hashkey, &hashdata) == 0)
+ msgid = mailimf_get_message_id();
+ else
+ msgid = strdup(msgid);
+ }
+
+ if (msgid == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ date = get_date(msg);
+
+ env_tree = mailmessage_tree_new(msgid, date, msg);
+ if (env_tree == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ r = carray_add(msg_list, env_tree, NULL);
+ if (r < 0) {
+ mailmessage_tree_free(env_tree);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ hashkey.data = msgid;
+ hashkey.len = strlen(msgid);
+
+ hashdata.data = env_tree;
+ hashdata.len = 0;
+
+ r = chash_set(msg_id_hash, &hashkey, &hashdata, &hashold);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+ }
+ }
+
+ /* (1) for all messages */
+
+ for(cur = 0 ; cur < carray_count(msg_list) ; cur ++) {
+ struct mailmessage_tree * env_tree;
+ mailmessage * msg;
+ clist * ref;
+
+ env_tree = carray_get(msg_list, cur);
+
+ msg = env_tree->node_msg;
+
+ ref = NULL;
+ if (msg != NULL) {
+ ref = get_ref(msg);
+ if (ref == NULL)
+ ref = get_in_reply_to(msg);
+ }
+
+ /* (A) Using the Message IDs in the message's references, link
+ the corresponding messages (those whose Message-ID header
+ line contains the given reference Message ID) together as
+ parent/child.
+ */
+
+ if (ref != NULL) {
+ /* try to start a tree */
+
+ clistiter * cur_ref;
+ chashdatum hashkey;
+ chashdatum hashdata;
+ chashdatum hashold;
+ struct mailmessage_tree * env_cur_tree;
+ struct mailmessage_tree * last_env_cur_tree;
+
+ env_cur_tree = NULL;
+ for(cur_ref = clist_begin(ref) ; cur_ref != NULL ;
+ cur_ref = clist_next(cur_ref)) {
+ char * msgid;
+
+ last_env_cur_tree = env_cur_tree;
+
+ msgid = clist_content(cur_ref);
+
+ hashkey.data = msgid;
+ hashkey.len = strlen(msgid);
+
+ r = chash_get(msg_id_hash, &hashkey, &hashdata);
+ if (r < 0) {
+ /* not found, create a dummy message */
+ msgid = strdup(msgid);
+ if (msgid == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ env_cur_tree = mailmessage_tree_new(msgid, (time_t) -1, NULL);
+ if (env_cur_tree == NULL) {
+ free(msgid);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ r = carray_add(msg_list, env_cur_tree, NULL);
+ if (r < 0) {
+ mailmessage_tree_free(env_cur_tree);
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ hashkey.data = msgid;
+ hashkey.len = strlen(msgid);
+
+ hashdata.data = env_cur_tree;
+ hashdata.len = 0;
+
+ r = chash_set(msg_id_hash, &hashkey, &hashdata, &hashold);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+ }
+ else {
+ env_cur_tree = hashdata.data;
+ }
+
+ if (last_env_cur_tree != NULL) {
+ if (env_cur_tree->node_parent == NULL) {
+ /* make it one child */
+ if (env_cur_tree != last_env_cur_tree) {
+ if (!is_descendant(env_cur_tree, last_env_cur_tree)) {
+ /* set parent */
+ env_cur_tree->node_parent = last_env_cur_tree;
+ r = carray_add(last_env_cur_tree->node_children,
+ env_cur_tree, NULL);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* (B) Create a parent/child link between the last reference
+ (or NIL if there are no references) and the current message.
+ If the current message already has a parent, it is probably
+ the result of a truncated References header line, so break
+ the current parent/child link before creating the new
+ correct one.
+ */
+
+ last_env_cur_tree = env_cur_tree;
+
+ if (last_env_cur_tree != NULL) {
+ if (env_tree->node_parent == NULL) {
+ if (last_env_cur_tree != env_tree) {
+ if (!is_descendant(env_tree, last_env_cur_tree)) {
+ /* set parent */
+ env_tree->node_parent = last_env_cur_tree;
+ r = carray_add(last_env_cur_tree->node_children, env_tree, NULL);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ chash_free(msg_id_hash);
+ msg_id_hash = NULL;
+
+ /* (2) Gather together all of the messages that have no parents
+ and make them all children (siblings of one another) of a dummy
+ parent (the "root").
+ */
+
+ for(cur = 0 ; cur < carray_count(msg_list) ; cur ++) {
+ struct mailmessage_tree * env_tree;
+
+ env_tree = carray_get(msg_list, cur);
+ if (env_tree->node_parent == NULL) {
+ r = carray_add(rootlist, env_tree, NULL);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+ /* set parent */
+ env_tree->node_parent = root;
+ }
+ }
+
+ carray_free(msg_list);
+ msg_list = NULL;
+
+ /* (3) Prune dummy messages from the thread tree.
+ */
+
+ cur = 0;
+ while (cur < carray_count(rootlist)) {
+ r = delete_dummy(rootlist, rootlist, cur, &cur);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free_list;
+ }
+ }
+
+ /* (4) Sort the messages under the root (top-level siblings only)
+ by sent date.
+ */
+
+ r = mail_thread_sort(root, mailthread_tree_timecomp, FALSE);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free_list;
+ }
+
+ if (use_subject) {
+
+ /* (5) Gather together messages under the root that have the same
+ extracted subject text.
+
+ (A) Create a table for associating extracted subjects with
+ messages.
+ */
+
+ subject_hash = chash_new(128, CHASH_COPYVALUE);
+ if (subject_hash == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_list;
+ }
+
+ /*
+ (B) Populate the subject table with one message per
+ extracted subject. For each child of the root:
+ */
+
+ for(cur = 0 ; cur < carray_count(rootlist) ; cur ++) {
+ struct mailmessage_tree * env_tree;
+ chashdatum key;
+ chashdatum data;
+ char * base_subject;
+ int r;
+
+ env_tree = carray_get(rootlist, cur);
+
+ /*
+ (i) Find the subject of this thread by extracting the
+ base subject from the current message, or its first child
+ if the current message is a dummy.
+ */
+
+ r = get_thread_subject(default_from, env_tree, &base_subject);
+
+ /*
+ (ii) If the extracted subject is empty, skip this
+ message.
+ */
+
+ if (r == MAIL_ERROR_SUBJECT_NOT_FOUND) {
+ /* no subject found */
+ continue;
+ }
+ else if (r == MAIL_NO_ERROR) {
+ if (* base_subject == '\0') {
+ /* subject empty */
+ free(base_subject);
+ continue;
+ }
+ else {
+ /* do nothing */
+ }
+ }
+ else {
+ res = r;
+ goto free_subject_hash;
+ }
+
+ env_tree->node_base_subject = base_subject;
+
+ /*
+ (iii) Lookup the message associated with this extracted
+ subject in the table.
+ */
+
+ key.data = base_subject;
+ key.len = strlen(base_subject);
+
+ r = chash_get(subject_hash, &key, &data);
+
+ if (r < 0) {
+ /*
+ (iv) If there is no message in the table with this
+ subject, add the current message and the extracted
+ subject to the subject table.
+ */
+
+ data.data = &cur;
+ data.len = sizeof(cur);
+
+ r = chash_set(subject_hash, &key, &data, NULL);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_subject_hash;
+ }
+ }
+ else {
+ /*
+ Otherwise, replace the message in the table with the
+ current message if the message in the table is not a
+ dummy AND either of the following criteria are true:
+ The current message is a dummy, OR
+ The message in the table is a reply or forward (its
+ original subject contains a subj-refwd part and/or a
+ "(fwd)" subj-trailer) and the current message is not.
+ */
+ struct mailmessage_tree * msg_in_table;
+ unsigned int * iter_in_table;
+ int replace;
+
+ iter_in_table = data.data;
+ msg_in_table = carray_get(rootlist, cur);
+
+ replace = FALSE;
+ /* message is dummy if info is NULL */
+ if (msg_in_table->node_msg != NULL) {
+
+ if (env_tree->node_msg == NULL)
+ replace = TRUE;
+ else {
+ if (env_tree->node_is_reply && !env_tree->node_is_reply)
+ replace = TRUE;
+ }
+ }
+
+ if (replace) {
+ data.data = &cur;
+ data.len = sizeof(cur);
+
+ r = chash_set(subject_hash, &key, &data, NULL);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_subject_hash;
+ }
+ }
+ }
+ }
+
+ /*
+ (C) Merge threads with the same subject. For each child of
+ the root:
+ */
+
+ cur = 0;
+ while (cur < carray_count(rootlist)) {
+ struct mailmessage_tree * env_tree;
+ chashdatum key;
+ chashdatum data;
+ int r;
+ struct mailmessage_tree * main_tree;
+ unsigned int * main_cur;
+
+ env_tree = carray_get(rootlist, cur);
+
+ if (env_tree == NULL)
+ goto next_msg;
+
+ /*
+ (i) Find the subject of this thread as in step 4.B.i
+ above.
+ */
+
+ /* already done in tree->node_base_subject */
+
+ /*
+ (ii) If the extracted subject is empty, skip this
+ message.
+ */
+
+ if (env_tree->node_base_subject == NULL)
+ goto next_msg;
+
+ if (* env_tree->node_base_subject == '\0')
+ goto next_msg;
+
+ /*
+ (iii) Lookup the message associated with this extracted
+ subject in the table.
+ */
+
+ key.data = env_tree->node_base_subject;
+ key.len = strlen(env_tree->node_base_subject);
+
+ r = chash_get(subject_hash, &key, &data);
+ if (r < 0)
+ goto next_msg;
+
+ /*
+ (iv) If the message in the table is the current message,
+ skip this message.
+ */
+
+ main_cur = data.data;
+ if (* main_cur == cur)
+ goto next_msg;
+
+ /*
+ Otherwise, merge the current message with the one in the
+ table using the following rules:
+ */
+
+ main_tree = carray_get(rootlist, * main_cur);
+
+ /*
+ If both messages are dummies, append the current
+ message's children to the children of the message in
+ the table (the children of both messages become
+ siblings), and then delete the current message.
+ */
+
+ if ((env_tree->node_msg == NULL) && (main_tree->node_msg == NULL)) {
+ unsigned int old_size;
+
+ old_size = carray_count(main_tree->node_children);
+
+ r = carray_set_size(main_tree->node_children, old_size +
+ carray_count(env_tree->node_children));
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_subject_hash;
+ }
+
+ for(i = 0 ; i < carray_count(env_tree->node_children) ; i ++) {
+ struct mailmessage_tree * child;
+
+ child = carray_get(env_tree->node_children, i);
+ carray_set(main_tree->node_children, old_size + i, child);
+ /* set parent */
+ child->node_parent = main_tree;
+ }
+ carray_set_size(env_tree->node_children, 0);
+ /* this is the only case where children can be NULL,
+ this is before freeing it */
+ mailmessage_tree_free(env_tree);
+ carray_delete_fast(rootlist, cur);
+ }
+
+ /*
+ If the message in the table is a dummy and the current
+ message is not, make the current message a child of
+ the message in the table (a sibling of it's children).
+ */
+
+ else if (main_tree->node_msg == NULL) {
+ r = carray_add(main_tree->node_children, env_tree, NULL);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_subject_hash;
+ }
+ /* set parent */
+ env_tree->node_parent = main_tree;
+
+ carray_delete_fast(rootlist, cur);
+ }
+
+ /*
+ If the current message is a reply or forward and the
+ message in the table is not, make the current message
+ a child of the message in the table (a sibling of it's
+ children).
+ */
+
+ else if (env_tree->node_is_reply && !main_tree->node_is_reply) {
+ r = carray_add(main_tree->node_children, env_tree, NULL);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_subject_hash;
+ }
+ /* set parent */
+ env_tree->node_parent = main_tree;
+
+ carray_delete_fast(rootlist, cur);
+ }
+
+ /*
+ Otherwise, create a new dummy message and make both
+ the current message and the message in the table
+ children of the dummy. Then replace the message in
+ the table with the dummy message.
+ Note: Subject comparisons are case-insensitive, as
+ described under "Internationalization
+ Considerations."
+ */
+
+ else {
+ struct mailmessage_tree * new_main_tree;
+ char * base_subject;
+ unsigned int last;
+
+ new_main_tree = mailmessage_tree_new(NULL, (time_t) -1, NULL);
+ if (new_main_tree == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_subject_hash;
+ }
+
+ /* main_tree->node_base_subject is never NULL */
+
+ base_subject = strdup(main_tree->node_base_subject);
+ if (base_subject == NULL) {
+ mailmessage_tree_free(new_main_tree);
+ res = MAIL_ERROR_MEMORY;
+ goto free_subject_hash;
+ }
+
+ new_main_tree->node_base_subject = base_subject;
+
+ r = carray_add(rootlist, new_main_tree, &last);
+ if (r < 0) {
+ mailmessage_tree_free(new_main_tree);
+ res = MAIL_ERROR_MEMORY;
+ goto free_subject_hash;
+ }
+
+ r = carray_add(new_main_tree->node_children, main_tree, NULL);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_subject_hash;
+ }
+ /* set parent */
+ main_tree->node_parent = new_main_tree;
+
+ carray_delete_fast(rootlist, * main_cur);
+
+ r = carray_add(new_main_tree->node_children, env_tree, NULL);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_subject_hash;
+ }
+ /* set parent */
+ env_tree->node_parent = new_main_tree;
+
+ carray_delete_fast(rootlist, cur);
+
+ data.data = &last;
+ data.len = sizeof(last);
+
+ r = chash_set(subject_hash, &key, &data, NULL);
+
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free_subject_hash;
+ }
+ }
+
+ continue;
+
+ next_msg:
+ cur ++;
+ continue;
+ }
+
+ i = 0;
+ for(cur = 0 ; cur < carray_count(rootlist) ; cur ++) {
+ struct mailmessage_tree * env_tree;
+
+ env_tree = carray_get(rootlist, cur);
+ if (env_tree == NULL)
+ continue;
+
+ carray_set(rootlist, i, env_tree);
+ i ++;
+ }
+ carray_set_size(rootlist, i);
+
+ chash_free(subject_hash);
+ }
+
+ /*
+ (6) Traverse the messages under the root and sort each set of
+ siblings by sent date. Traverse the messages in such a way
+ that the "youngest" set of siblings are sorted first, and the
+ "oldest" set of siblings are sorted last (grandchildren are
+ sorted before children, etc).
+
+ In the case of an exact match on
+ sent date or if either of the Date: headers used in a
+ comparison can not be parsed, use the order in which the
+ messages appear in the mailbox (that is, by sequence number) to
+ determine the order. In the case of a dummy message (which can
+ only occur with top-level siblings), use its first child for
+ sorting.
+ */
+
+#if 0
+ if (comp_func != NULL) {
+ r = mail_thread_sort(root, comp_func, TRUE);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free_list;
+ }
+ }
+#endif
+ if (comp_func == NULL)
+ comp_func = mailthread_tree_timecomp;
+
+ r = mail_thread_sort(root, comp_func, TRUE);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free_list;
+ }
+
+ * result = root;
+
+ return MAIL_NO_ERROR;
+
+ free_subject_hash:
+ chash_free(subject_hash);
+ free_list:
+ if (msg_list != NULL) {
+ for(i = 0 ; i < carray_count(msg_list) ; i ++)
+ mailmessage_tree_free(carray_get(msg_list, i));
+ carray_free(msg_list);
+ }
+ free_root:
+ mailmessage_tree_free_recursive(root);
+ free_hash:
+ if (msg_id_hash != NULL)
+ chash_free(msg_id_hash);
+ err:
+ return res;
+}
+
+
+
+static int
+mail_build_thread_orderedsubject(char * default_from,
+ struct mailmessage_list * env_list,
+ struct mailmessage_tree ** result,
+ int (* comp_func)(struct mailmessage_tree **,
+ struct mailmessage_tree **))
+{
+ unsigned int i;
+ carray * rootlist;
+ unsigned int cur;
+ struct mailmessage_tree * root;
+ int res;
+ int r;
+ struct mailmessage_tree * current_thread;
+
+ root = mailmessage_tree_new(NULL, (time_t) -1, NULL);
+ if (root == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+ rootlist = root->node_children;
+
+ /*
+ The ORDEREDSUBJECT threading algorithm is also referred to as
+ "poor man's threading."
+ */
+
+ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
+ mailmessage * msg;
+ struct mailmessage_tree * env_tree;
+ char * base_subject;
+ time_t date;
+
+ msg = carray_get(env_list->msg_tab, i);
+
+ if (msg == NULL)
+ continue;
+
+ if (msg->msg_fields != NULL) {
+
+ date = get_date(msg);
+
+ env_tree = mailmessage_tree_new(NULL, date, msg);
+ if (env_tree == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free;
+ }
+
+ /* set parent */
+ env_tree->node_parent = root;
+ r = carray_add(rootlist, env_tree, NULL);
+ if (r < 0) {
+ mailmessage_tree_free(env_tree);
+ res = MAIL_ERROR_MEMORY;
+ goto free;
+ }
+
+ r = get_extracted_subject(default_from, env_tree, &base_subject);
+ switch (r) {
+ case MAIL_NO_ERROR:
+ env_tree->node_base_subject = base_subject;
+ break;
+
+ case MAIL_ERROR_SUBJECT_NOT_FOUND:
+ break;
+
+ default:
+ res = r;
+ goto free;
+ }
+ }
+ }
+
+ /*
+ The searched messages are sorted by
+ subject and then by the sent date.
+ */
+
+ r = mail_thread_sort(root, tree_subj_time_comp, FALSE);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+
+ /*
+ The messages are then split
+ into separate threads, with each thread containing messages
+ with the same extracted subject text.
+ */
+
+ current_thread = NULL;
+
+ cur = 0;
+ while (cur < carray_count(rootlist)) {
+ struct mailmessage_tree * cur_env_tree;
+
+ cur_env_tree = carray_get(rootlist, cur);
+ if (current_thread == NULL) {
+ current_thread = cur_env_tree;
+ cur ++;
+ continue;
+ }
+
+ if ((cur_env_tree->node_base_subject == NULL) ||
+ (current_thread->node_base_subject == NULL)) {
+ current_thread = cur_env_tree;
+ cur ++;
+ continue;
+ }
+
+ if (strcmp(cur_env_tree->node_base_subject,
+ current_thread->node_base_subject) == 0) {
+
+ /* set parent */
+ cur_env_tree->node_parent = current_thread;
+ r = carray_add(current_thread->node_children, cur_env_tree, NULL);
+ if (r < 0) {
+ res = MAIL_ERROR_MEMORY;
+ goto free;
+ }
+
+ carray_delete(rootlist, cur);
+ }
+ else
+ cur ++;
+ current_thread = cur_env_tree;
+ }
+
+ /*
+ Finally, the threads are
+ sorted by the sent date of the first message in the thread.
+ Note that each message in a thread is a child (as opposed to a
+ sibling) of the previous message.
+ */
+
+#if 0
+ if (comp_func != NULL) {
+ r = mail_thread_sort(root, comp_func, FALSE);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+ }
+#endif
+
+ if (comp_func == NULL)
+ comp_func = mailthread_tree_timecomp;
+
+ r = mail_thread_sort(root, comp_func, FALSE);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+
+ * result = root;
+
+ return MAIL_NO_ERROR;
+
+ free:
+ mailmessage_tree_free_recursive(root);
+ err:
+ return res;
+}
+
+
+static int
+mail_build_thread_none(char * default_from,
+ struct mailmessage_list * env_list,
+ struct mailmessage_tree ** result,
+ int (* comp_func)(struct mailmessage_tree **,
+ struct mailmessage_tree **))
+{
+ unsigned int i;
+ carray * rootlist;
+ struct mailmessage_tree * root;
+ int res;
+ int r;
+
+ root = mailmessage_tree_new(NULL, (time_t) -1, NULL);
+ if (root == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto err;
+ }
+ rootlist = root->node_children;
+
+ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++) {
+ mailmessage * msg;
+ struct mailmessage_tree * env_tree;
+ char * base_subject;
+ time_t date;
+
+ msg = carray_get(env_list->msg_tab, i);
+
+ if (msg == NULL)
+ continue;
+
+ if (msg->msg_fields != NULL) {
+
+ date = get_date(msg);
+
+ env_tree = mailmessage_tree_new(NULL, date, msg);
+ if (env_tree == NULL) {
+ res = MAIL_ERROR_MEMORY;
+ goto free;
+ }
+
+ /* set parent */
+ env_tree->node_parent = root;
+ r = carray_add(rootlist, env_tree, NULL);
+ if (r < 0) {
+ mailmessage_tree_free(env_tree);
+ res = MAIL_ERROR_MEMORY;
+ goto free;
+ }
+
+ r = get_extracted_subject(default_from, env_tree, &base_subject);
+ switch (r) {
+ case MAIL_NO_ERROR:
+ env_tree->node_base_subject = base_subject;
+ break;
+
+ case MAIL_ERROR_SUBJECT_NOT_FOUND:
+ break;
+
+ default:
+ res = r;
+ goto free;
+ }
+ }
+ }
+
+ if (comp_func == NULL)
+ comp_func = mailthread_tree_timecomp;
+
+ r = mail_thread_sort(root, comp_func, FALSE);
+ if (r != MAIL_NO_ERROR) {
+ res = r;
+ goto free;
+ }
+
+ * result = root;
+
+ return MAIL_NO_ERROR;
+
+ free:
+ mailmessage_tree_free_recursive(root);
+ err:
+ return res;
+}
+
+
+int mail_build_thread(int type, char * default_from,
+ struct mailmessage_list * env_list,
+ struct mailmessage_tree ** result,
+ int (* comp_func)(struct mailmessage_tree **,
+ struct mailmessage_tree **))
+{
+ unsigned int i;
+
+ for(i = 0 ; i < carray_count(env_list->msg_tab) ; i ++)
+ mailmessage_resolve_single_fields(carray_get(env_list->msg_tab, i));
+
+ switch (type) {
+ case MAIL_THREAD_REFERENCES:
+ return mail_build_thread_references(default_from,
+ env_list, result, TRUE, comp_func);
+
+ case MAIL_THREAD_REFERENCES_NO_SUBJECT:
+ return mail_build_thread_references(default_from,
+ env_list, result, FALSE, comp_func);
+
+ case MAIL_THREAD_ORDEREDSUBJECT:
+ return mail_build_thread_orderedsubject(default_from,
+ env_list, result, comp_func);
+
+ case MAIL_THREAD_NONE:
+ return mail_build_thread_none(default_from,
+ env_list, result, comp_func);
+
+ default:
+ return MAIL_ERROR_NOT_IMPLEMENTED;
+ }
+}
diff --git a/libetpan/src/driver/tools/mailthread.h b/libetpan/src/driver/tools/mailthread.h
new file mode 100644
index 0000000..fa2f4bc
--- a/dev/null
+++ b/libetpan/src/driver/tools/mailthread.h
@@ -0,0 +1,108 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef MAILTHREAD_H
+
+#define MAILTHREAD_H
+
+#include <libetpan/mailthread_types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ mail_build_thread constructs a tree with the message using the
+ given style.
+
+ @param type is the type of threading to apply, the value can be
+ MAIL_THREAD_REFERENCES, MAIL_THREAD_REFERENCES_NO_SUBJECT,
+ MAIL_THREAD_ORDEREDSUBJECT or MAIL_THREAD_NONE,
+
+ @param default_from is the default charset to use whenever the
+ subject is not tagged with a charset. "US-ASCII" can be used
+ if you don't know what to use.
+
+ @param env_list is the message list (with header fields fetched)
+ to use to build the message tree.
+
+ @param result * result) will contain the resulting message tree.
+
+ @param if comp_func is NULL, no sorting algorithm is used.
+
+ @return MAIL_NO_ERROR is returned on success, MAIL_ERROR_XXX is returned
+ on error
+*/
+
+int mail_build_thread(int type, char * default_from,
+ struct mailmessage_list * env_list,
+ struct mailmessage_tree ** result,
+ int (* comp_func)(struct mailmessage_tree **,
+ struct mailmessage_tree **));
+
+/*
+ mail_thread_sort sort the messages in the message tree, using the
+ given sort function.
+
+ @param tree is the message tree to sort.
+
+ @param comp_func is the sort function to use (this is the same kind of
+ functions than those used for qsort()). mailthread_tree_timecomp can be
+ used for default sort.
+
+ @param sort_sub if this value is 0, only the children of the root message
+ are sorted.
+*/
+
+int mail_thread_sort(struct mailmessage_tree * tree,
+ int (* comp_func)(struct mailmessage_tree **,
+ struct mailmessage_tree **),
+ int sort_sub);
+
+/*
+ mailthread_tree_timecomp is the default sort function.
+
+ The message are compared by date, then by message numbers.
+ The tree are given in (* ptree1) and (* ptree2).
+*/
+
+int mailthread_tree_timecomp(struct mailmessage_tree ** ptree1,
+ struct mailmessage_tree ** ptree2);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libetpan/src/driver/tools/mailthread_types.c b/libetpan/src/driver/tools/mailthread_types.c
new file mode 100644
index 0000000..dc2a4ca
--- a/dev/null
+++ b/libetpan/src/driver/tools/mailthread_types.c
@@ -0,0 +1,90 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#include "mailthread_types.h"
+
+#include "mail.h"
+#include <stdlib.h>
+
+struct mailmessage_tree *
+mailmessage_tree_new(char * node_msgid, time_t node_date,
+ mailmessage * node_msg)
+{
+ struct mailmessage_tree * tree;
+ carray * array;
+
+ array = carray_new(16);
+ if (array == NULL)
+ return NULL;
+
+ tree = malloc(sizeof(* tree));
+ tree->node_parent = NULL;
+ tree->node_date = node_date;
+ tree->node_msgid = node_msgid;
+ tree->node_msg = node_msg;
+ tree->node_children = array;
+ tree->node_base_subject = NULL;
+ tree->node_is_reply = FALSE;
+
+ return tree;
+}
+
+void mailmessage_tree_free(struct mailmessage_tree * tree)
+{
+ if (tree->node_base_subject != NULL)
+ free(tree->node_base_subject);
+
+ if (tree->node_children != NULL)
+ carray_free(tree->node_children);
+ if (tree->node_msgid != NULL)
+ free(tree->node_msgid);
+
+ free(tree);
+}
+
+void mailmessage_tree_free_recursive(struct mailmessage_tree * tree)
+{
+ unsigned int i;
+
+ for(i = 0 ; i < carray_count(tree->node_children) ; i++) {
+ struct mailmessage_tree * child;
+
+ child = carray_get(tree->node_children, i);
+
+ mailmessage_tree_free_recursive(child);
+ }
+
+ mailmessage_tree_free(tree);
+}
diff --git a/libetpan/src/driver/tools/mailthread_types.h b/libetpan/src/driver/tools/mailthread_types.h
new file mode 100644
index 0000000..3325904
--- a/dev/null
+++ b/libetpan/src/driver/tools/mailthread_types.h
@@ -0,0 +1,64 @@
+/*
+ * libEtPan! -- a mail stuff library
+ *
+ * Copyright (C) 2001, 2005 - DINH Viet Hoa
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the libEtPan! project nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * $Id$
+ */
+
+#ifndef MAILTHREAD_TYPES_H
+
+#define MAILTHREAD_TYPES_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <libetpan/maildriver_types.h>
+#include <libetpan/mailmessage_types.h>
+
+/*
+ This is the type of tree construction to apply.
+*/
+
+enum {
+ MAIL_THREAD_REFERENCES, /* this is threading using
+ References fields only) */
+ MAIL_THREAD_REFERENCES_NO_SUBJECT, /* this is threading using References
+ fields, then subject */
+ MAIL_THREAD_ORDEREDSUBJECT, /* this is threading using only subject */
+ MAIL_THREAD_NONE, /* no thread */
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif