Pushing the on-disk summary changes from the madagascar branch
authorSankarasivasubramanian Pasupathilingam <psankar@src.gnome.org>
Wed, 16 Jul 2008 11:38:32 +0000 (11:38 +0000)
committerSankarasivasubramanian Pasupathilingam <psankar@src.gnome.org>
Wed, 16 Jul 2008 11:38:32 +0000 (11:38 +0000)
svn path=/trunk/; revision=9125

47 files changed:
ChangeLog
camel/ChangeLog
camel/Makefile.am
camel/camel-db.c [new file with mode: 0644]
camel/camel-db.h [new file with mode: 0644]
camel/camel-folder-search.c
camel/camel-folder-search.h
camel/camel-folder-summary.c
camel/camel-folder-summary.h
camel/camel-folder-thread.c
camel/camel-folder.c
camel/camel-folder.h
camel/camel-offline-journal.c
camel/camel-store.c
camel/camel-store.h
camel/camel-string-utils.c
camel/camel-vee-folder.c
camel/camel-vee-store.c
camel/camel-vee-summary.c
camel/camel-vee-summary.h
camel/camel-vtrash-folder.c
camel/db-scrap-tools/db.c [new file with mode: 0644]
camel/providers/groupwise/ChangeLog
camel/providers/groupwise/camel-groupwise-folder.c
camel/providers/groupwise/camel-groupwise-store.c
camel/providers/groupwise/camel-groupwise-summary.c
camel/providers/imap/ChangeLog
camel/providers/imap/camel-imap-folder.c
camel/providers/imap/camel-imap-message-cache.c
camel/providers/imap/camel-imap-store.c
camel/providers/imap/camel-imap-summary.c
camel/providers/imap/camel-imap-utils.c
camel/providers/local/ChangeLog
camel/providers/local/camel-local-folder.c
camel/providers/local/camel-local-store.c
camel/providers/local/camel-local-summary.c
camel/providers/local/camel-maildir-summary.c
camel/providers/local/camel-mbox-store.c
camel/providers/local/camel-mbox-summary.c
camel/providers/local/camel-mh-summary.c
camel/providers/nntp/ChangeLog
camel/providers/nntp/camel-nntp-folder.c
camel/providers/nntp/camel-nntp-summary.c
camel/providers/nntp/camel-nntp-utils.c
configure.in
libedataserver/e-sexp.c
libedataserver/e-sexp.h

index e2e1e0c..d7fe54a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2008-07-16  Sankar P  <psankar@novell.com>
+
+       Pushing disk summary changes from the madagascar branch
+
+       * configure.in:
+       * libedataserver/e-sexp.c (term_eval_and), (term_eval_or),
+       (e_sexp_parse_value):
+       * libedataserver/e-sexp.h:
+
 2008-07-14  Milan Crha  <mcrha@redhat.com>
 
        ** Fix for bug #253509
index 65450d4..8074b98 100644 (file)
@@ -1,3 +1,86 @@
+2008-07-16  Sankar P  <psankar@novell.com>
+
+       Pushing disk summary changes from the madagascar branch
+
+       * Makefile.am:
+       * camel-folder-search.c (camel_folder_search_class_init),
+       (camel_folder_search_finalize), (camel_folder_search_construct),
+       (camel_folder_search_set_folder),
+       (camel_folder_search_set_summary),
+       (camel_folder_search_execute_expression),
+       (camel_folder_search_search), (camel_folder_search_free_result),
+       (search_not), (search_match_all), (search_match_threads),
+       (check_header_deprecated), (check_header),
+       (search_header_contains), (db_search_header_contains),
+       (match_words_index), (match_words_messages),
+       (search_body_contains), (search_user_flag), (search_system_flag),
+       (search_user_tag), (search_uid), (read_uid_callback):
+       * camel-folder-search.h:
+       * camel-folder-summary.c (camel_folder_summary_init),
+       (camel_folder_summary_finalize), (camel_folder_summary_count),
+       (camel_folder_summary_index),
+       (camel_folder_summary_uid_from_index),
+       (camel_folder_summary_array), (message_info_from_uid),
+       (camel_folder_summary_uid), (perform_content_info_load_from_db),
+       (append_changed_uids), (camel_folder_summary_get_changed),
+       (remove_item), (remove_cache), (camel_folder_summary_cache_size),
+       (camel_folder_summary_reload_from_db),
+       (camel_folder_summary_load_from_db), (mir_from_cols),
+       (camel_read_mir_callback), (camel_folder_summary_load),
+       (perform_content_info_save_to_db), (save_to_db_cb),
+       (save_message_infos_to_db), (camel_folder_summary_save_to_db),
+       (camel_folder_summary_save),
+       (camel_folder_summary_header_load_from_db),
+       (camel_folder_summary_header_load), (summary_assign_uid),
+       (camel_folder_summary_add), (camel_folder_summary_insert),
+       (camel_folder_summary_add_from_header),
+       (camel_folder_summary_add_from_parser),
+       (camel_folder_summary_add_from_message),
+       (camel_folder_summary_clear), (camel_folder_summary_clear_db),
+       (summary_remove_uid), (camel_folder_summary_remove),
+       (camel_folder_summary_remove_uid),
+       (camel_folder_summary_remove_index_fast),
+       (camel_folder_summary_remove_index),
+       (camel_folder_summary_remove_range), (summary_meta_header_load),
+       (summary_header_from_db), (summary_header_to_db),
+       (camel_folder_summary_content_info_new), (message_info_from_db),
+       (message_info_to_db), (message_info_free), (content_info_from_db),
+       (content_info_to_db), (content_info_free), (camel_flag_set),
+       (camel_message_info_new), (info_set_flags), (info_set_user_flag),
+       (info_set_user_tag), (camel_folder_summary_class_init):
+       * camel-folder-summary.h:
+       * camel-folder-thread.c (camel_folder_thread_messages_new):
+       * camel-folder.c (camel_folder_finalize), (camel_folder_construct),
+       (camel_folder_refresh_info), (folder_getv), (folder_free),
+       (get_uids), (free_uids), (free_summary),
+       (camel_folder_free_summary), (search_free):
+       * camel-folder.h:
+       * camel-offline-journal.c:
+       * camel-store.c (camel_store_finalize), (construct):
+       * camel-store.h:
+       * camel-string-utils.c (camel_pstring_free):
+       * camel-vee-folder.c (camel_vee_folder_get_location),
+       (summary_header_to_db), (vee_sync), (vee_get_message),
+       (vee_search_by_expression), (vee_folder_add_uid),
+       (vee_folder_remove_folder), (folder_added_uid),
+       (vee_rebuild_folder), (folder_changed_remove_uid),
+       (subfolder_renamed_update), (vee_set_expression),
+       (camel_vee_folder_finalise):
+       * camel-vee-store.c (camel_vee_store_class_init),
+       (camel_vee_store_init), (construct), (vee_get_folder_info):
+       * camel-vee-summary.c (vee_message_info_free),
+       (vee_message_info_clone), (vee_info_ptr), (vee_info_uint32),
+       (vee_info_time), (vee_info_user_flag), (vee_info_user_tag),
+       (vee_info_set_user_flag), (vee_info_set_user_tag),
+       (vee_info_set_flags), (message_info_from_uid),
+       (camel_vee_summary_class_init), (camel_vee_summary_new),
+       (camel_vee_summary_get_ids), (camel_vee_summary_add):
+       * camel-vee-summary.h:
+       * camel-vtrash-folder.c (vtrash_transfer_messages_to),
+       (vtrash_search_by_expression), (vtrash_search_by_uids),
+       (vtrash_uid_added), (vtrash_folder_changed), (vtrash_add_folder),
+       (vtrash_remove_folder):
+
 2008-07-12  Srinivasa Ragavan  <sragavan@novell.com>
 
        ** Fix for bug #213072
index fc57ae9..5e0727c 100644 (file)
@@ -156,6 +156,7 @@ libcamel_1_2_la_SOURCES =                   \
        camel-charset-map.c                     \
        camel-data-cache.c                      \
        camel-data-wrapper.c                    \
+       camel-db.c                              \
        camel-debug.c                           \
        camel-exception.c                       \
        camel-file-utils.c                      \
@@ -226,6 +227,7 @@ libcamelinclude_HEADERS =                   \
        camel-charset-map.h                     \
        camel-data-cache.h                      \
        camel-data-wrapper.h                    \
+       camel-db.h                              \
        camel-debug.h                           \
        camel-exception-list.def                \
        camel-exception.h                       \
diff --git a/camel/camel-db.c b/camel/camel-db.c
new file mode 100644 (file)
index 0000000..48eeedd
--- /dev/null
@@ -0,0 +1,956 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* camel-imap-folder.c: class for an imap folder */
+
+/* 
+ * Authors:
+ *   Sankar P <psankar@novell.com>
+ *   Srinivasa Ragavan <sragavan@novell.com> 
+ *
+ * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
+ *
+ * This program is free software; you can redistribute it and/or 
+ * modify it under the terms of version 2 of the GNU Lesser General Public 
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ */
+
+
+#include "camel-db.h"
+#include "camel-string-utils.h"
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <glib.h>
+#include <glib/gi18n-lib.h>
+
+#define d(x) 
+
+#define CAMEL_DB_SLEEP_INTERVAL 1*10*10
+#define CAMEL_DB_RELEASE_SQLITE_MEMORY if(!g_getenv("CAMEL_SQLITE_PRESERVE_CACHE")) sqlite3_release_memory(CAMEL_DB_FREE_CACHE_SIZE);
+#define CAMEL_DB_USE_SHARED_CACHE if(!g_getenv("CAMEL_SQLITE_SHARED_CACHE_OFF")) sqlite3_enable_shared_cache(TRUE);
+
+static int 
+cdb_sql_exec (sqlite3 *db, const char* stmt, CamelException *ex) 
+{
+       char *errmsg;
+       int   ret = -1;
+
+       d(g_print("Camel SQL Exec:\n%s\n", stmt));
+
+       ret = sqlite3_exec(db, stmt, 0, 0, &errmsg);
+       while (ret == SQLITE_BUSY || ret == SQLITE_LOCKED || ret == -1) {
+               ret = sqlite3_exec(db, stmt, 0, 0, &errmsg);
+       }
+       
+       if (ret != SQLITE_OK) {
+               d(g_print ("Error in SQL EXEC statement: %s [%s].\n", stmt, errmsg));
+               if (ex) 
+                       camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _(errmsg));
+               sqlite3_free (errmsg);
+               return -1;
+       }
+       return 0;
+}
+
+CamelDB *
+camel_db_open (const char *path, CamelException *ex)
+{
+       CamelDB *cdb;
+       sqlite3 *db;
+       char *cache;
+       int ret;
+
+       CAMEL_DB_USE_SHARED_CACHE;
+       
+       sqlite3_enable_shared_cache(TRUE);
+
+       ret = sqlite3_open(path, &db);
+       if (ret) {
+
+               if (!db) {
+                       camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _("Insufficient memory"));
+               } else {
+                       const char *error;
+                       error = sqlite3_errmsg (db);
+                       d(g_print("Can't open database %s: %s\n", path, error));
+                       camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _(error));
+                       sqlite3_close(db);
+               }
+               return NULL;
+       }
+
+
+
+       cdb = g_new (CamelDB, 1);
+       cdb->db = db;
+       cdb->lock = g_mutex_new ();
+       d(g_print ("\nDatabase succesfully opened  \n"));
+
+       /* Which is big / costlier ? A Stack frame or a pointer */
+       if(!g_getenv("CAMEL_SQLITE_DEFAULT_CACHE_SIZE")) 
+               cache = g_strdup_printf ("PRAGMA cache_size=%s", g_getenv("CAMEL_SQLITE_DEFAULT_CACHE_SIZE"));
+       else 
+               cache = g_strdup ("PRAGMA cache_size=100");
+
+       camel_db_command (cdb, cache, NULL);
+
+       g_free (cache);
+
+       sqlite3_busy_timeout (cdb->db, CAMEL_DB_SLEEP_INTERVAL);
+
+       return cdb;
+}
+
+void
+camel_db_close (CamelDB *cdb)
+{
+       if (cdb) {
+               sqlite3_close (cdb->db);
+               g_mutex_free (cdb->lock);
+               g_free (cdb);
+               d(g_print ("\nDatabase succesfully closed \n"));
+       }
+}
+
+/* Should this be really exposed ? */
+int
+camel_db_command (CamelDB *cdb, const char *stmt, CamelException *ex)
+{
+       int ret;
+       
+       if (!cdb)
+               return TRUE;
+       g_mutex_lock (cdb->lock);
+       d(g_print("Executing: %s\n", stmt));
+       ret = cdb_sql_exec (cdb->db, stmt, ex);
+       g_mutex_unlock (cdb->lock);
+       return ret;
+}
+
+
+int 
+camel_db_begin_transaction (CamelDB *cdb, CamelException *ex)
+{
+       if (!cdb)
+               return -1;
+
+       d(g_print ("\n\aBEGIN TRANSACTION \n\a"));
+       g_mutex_lock (cdb->lock);
+       return (cdb_sql_exec (cdb->db, "BEGIN", ex));
+}
+
+int 
+camel_db_end_transaction (CamelDB *cdb, CamelException *ex)
+{
+       int ret;
+       if (!cdb)
+               return -1;
+
+       d(g_print ("\nCOMMIT TRANSACTION \n"));
+       ret = cdb_sql_exec (cdb->db, "COMMIT", ex);
+       g_mutex_unlock (cdb->lock);
+       CAMEL_DB_RELEASE_SQLITE_MEMORY;
+       
+       return ret;
+}
+
+int
+camel_db_abort_transaction (CamelDB *cdb, CamelException *ex)
+{
+       int ret;
+       
+       d(g_print ("\nABORT TRANSACTION \n"));
+       ret = cdb_sql_exec (cdb->db, "ROLLBACK", ex);
+       g_mutex_unlock (cdb->lock);
+       CAMEL_DB_RELEASE_SQLITE_MEMORY;
+       
+       return ret;
+}
+
+int
+camel_db_add_to_transaction (CamelDB *cdb, const char *stmt, CamelException *ex)
+{
+       if (!cdb)
+               return -1;
+
+       d(g_print("Adding the following query to transaction: %s\n", stmt));
+
+       return (cdb_sql_exec (cdb->db, stmt, ex));
+}
+
+int 
+camel_db_transaction_command (CamelDB *cdb, GSList *qry_list, CamelException *ex)
+{
+       int ret;
+       const char *query;
+
+       if (!cdb)
+               return -1;
+
+       g_mutex_lock (cdb->lock);
+
+       ret = cdb_sql_exec (cdb->db, "BEGIN", ex);
+       if (ret)
+               goto end;
+
+       d(g_print ("\nBEGIN Transaction\n"));
+
+       while (qry_list) {
+               query = qry_list->data;
+               d(g_print ("\nInside Transaction: [%s] \n", query));
+               ret = cdb_sql_exec (cdb->db, query, ex);
+               if (ret)
+                       goto end;
+               qry_list = g_slist_next (qry_list);
+       }
+
+       ret = cdb_sql_exec (cdb->db, "COMMIT", ex);
+
+end:
+       g_mutex_unlock (cdb->lock);
+       d(g_print ("\nTransaction Result: [%d] \n", ret));
+       return ret;
+}
+
+static int 
+count_cb (void *data, int argc, char **argv, char **azColName)
+{
+       int i;
+
+       for(i=0; i<argc; i++) {
+               if (strstr(azColName[i], "COUNT")) {
+                       *(guint32 *)data = argv [i] ? strtoul (argv [i], NULL, 10) : 0;
+               }
+       }
+
+       return 0;
+}
+
+static int
+camel_db_count_message_info (CamelDB *cdb, const char *query, guint32 *count, CamelException *ex)
+{
+       int ret = -1;
+       char *errmsg;
+
+       ret = sqlite3_exec(cdb->db, query, count_cb, count, &errmsg);
+       while (ret == SQLITE_BUSY || ret == SQLITE_LOCKED) {
+               ret = sqlite3_exec (cdb->db, query, count_cb, count, &errmsg);
+       }
+
+       CAMEL_DB_RELEASE_SQLITE_MEMORY;
+               
+       if (ret != SQLITE_OK) {
+                       g_print ("Error in SQL SELECT statement: %s [%s]\n", query, errmsg);
+                       camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, _(errmsg));
+                       sqlite3_free (errmsg);
+       }
+       return ret;
+}
+
+int
+camel_db_count_junk_message_info (CamelDB *cdb, const char *table_name, guint32 *count, CamelException *ex)
+{
+       int ret;
+
+       if (!cdb)
+               return -1;
+
+       char *query;
+       query = sqlite3_mprintf ("SELECT COUNT (*) FROM %Q WHERE junk = 1", table_name);
+
+       ret = camel_db_count_message_info (cdb, query, count, ex);
+       sqlite3_free (query);
+
+       return ret;
+}
+
+int
+camel_db_count_unread_message_info (CamelDB *cdb, const char *table_name, guint32 *count, CamelException *ex)
+{
+       int ret;
+
+       if (!cdb)
+               return -1;
+
+       char *query;
+       query = sqlite3_mprintf ("SELECT COUNT (*) FROM %Q WHERE read = 0", table_name);
+
+       ret = camel_db_count_message_info (cdb, query, count, ex);
+       sqlite3_free (query);
+
+       return ret;
+}
+
+int
+camel_db_count_visible_unread_message_info (CamelDB *cdb, const char *table_name, guint32 *count, CamelException *ex)
+{
+       int ret;
+
+       if (!cdb)
+               return -1;
+
+       char *query;
+       query = sqlite3_mprintf ("SELECT COUNT (*) FROM %Q WHERE read = 0 AND junk = 0 AND deleted = 0", table_name);
+
+       ret = camel_db_count_message_info (cdb, query, count, ex);
+       sqlite3_free (query);
+
+       return ret;
+}
+
+int
+camel_db_count_visible_message_info (CamelDB *cdb, const char *table_name, guint32 *count, CamelException *ex)
+{
+       int ret;
+
+       if (!cdb)
+               return -1;
+
+       char *query;
+       query = sqlite3_mprintf ("SELECT COUNT (*) FROM %Q WHERE junk = 0 AND deleted = 0", table_name);
+
+       ret = camel_db_count_message_info (cdb, query, count, ex);
+       sqlite3_free (query);
+
+       return ret;
+}
+
+int
+camel_db_count_junk_not_deleted_message_info (CamelDB *cdb, const char *table_name, guint32 *count, CamelException *ex)
+{
+       int ret;
+
+       if (!cdb)
+               return -1;
+
+       char *query ;
+       query = sqlite3_mprintf ("SELECT COUNT (*) FROM %Q WHERE junk = 1 AND deleted = 0", table_name);
+
+       ret = camel_db_count_message_info (cdb, query, count, ex);
+       sqlite3_free (query);
+
+       return ret;
+}
+
+int
+camel_db_count_deleted_message_info (CamelDB *cdb, const char *table_name, guint32 *count, CamelException *ex)
+{
+       int ret;
+
+       if (!cdb)
+               return -1;
+
+       char *query ;
+       query = sqlite3_mprintf ("SELECT COUNT (*) FROM %Q WHERE deleted = 1", table_name);
+
+       ret = camel_db_count_message_info (cdb, query, count, ex);
+       sqlite3_free (query);
+
+       return ret;
+}
+
+
+int
+camel_db_count_total_message_info (CamelDB *cdb, const char *table_name, guint32 *count, CamelException *ex)
+{
+
+       int ret;
+       char *query;
+
+       if (!cdb)
+               return -1;
+       
+       query = sqlite3_mprintf ("SELECT COUNT (*) FROM %Q", table_name);
+
+       ret = camel_db_count_message_info (cdb, query, count, ex);
+       sqlite3_free (query);
+
+       return ret;
+}
+
+int
+camel_db_select (CamelDB *cdb, const char* stmt, CamelDBSelectCB callback, gpointer data, CamelException *ex) 
+{
+       char *errmsg;
+       //int nrecs = 0;
+       int ret = -1;
+
+       if (!cdb)
+               return TRUE;
+       
+       d(g_print ("\n%s:\n%s \n", __FUNCTION__, stmt));
+
+       ret = sqlite3_exec(cdb->db, stmt, callback, data, &errmsg);
+       while (ret == SQLITE_BUSY || ret == SQLITE_LOCKED) {
+               ret = sqlite3_exec (cdb->db, stmt, callback, data, &errmsg);
+       }
+
+       CAMEL_DB_RELEASE_SQLITE_MEMORY;
+               
+       if (ret != SQLITE_OK) {
+               d(g_warning ("Error in select statement '%s' [%s].\n", stmt, errmsg));
+               camel_exception_set (ex, CAMEL_EXCEPTION_SYSTEM, errmsg);
+               sqlite3_free (errmsg);
+       }
+
+       return ret;
+}
+
+int
+camel_db_delete_folder (CamelDB *cdb, const char *folder, CamelException *ex)
+{
+       char *tab = sqlite3_mprintf ("DELETE FROM folders WHERE folder_name =%Q", folder);
+       int ret;
+
+       ret = camel_db_command (cdb, tab, ex);
+       sqlite3_free (tab);
+       CAMEL_DB_RELEASE_SQLITE_MEMORY;
+       return ret;
+}
+
+int
+camel_db_create_vfolder (CamelDB *db, const char *folder_name, CamelException *ex)
+{
+       int ret;
+       char *table_creation_query, *safe_index;
+       
+       table_creation_query = sqlite3_mprintf ("CREATE TABLE IF NOT EXISTS %Q (  vuid TEXT PRIMARY KEY)", folder_name);
+
+       ret = camel_db_command (db, table_creation_query, ex);  
+
+       sqlite3_free (table_creation_query);
+
+
+       safe_index = g_strdup_printf("VINDEX-%s", folder_name);
+       table_creation_query = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS %Q ON %Q (vuid)", safe_index, folder_name);
+       ret = camel_db_command (db, table_creation_query, ex);
+
+       sqlite3_free (table_creation_query);
+       g_free (safe_index);
+       CAMEL_DB_RELEASE_SQLITE_MEMORY;
+       
+       return ret;      
+}
+
+int
+camel_db_delete_uid_from_vfolder (CamelDB *db, char *folder_name, char *vuid, CamelException *ex)
+{
+        char *del_query;
+        int ret;
+        
+        del_query = sqlite3_mprintf ("DELETE FROM %Q WHERE vuid = %Q", folder_name, vuid);
+
+        ret = camel_db_command (db, del_query, ex);
+        
+        sqlite3_free (del_query);
+        CAMEL_DB_RELEASE_SQLITE_MEMORY;
+        return ret;
+}
+
+static int
+read_uids_callback (void *ref, int ncol, char ** cols, char ** name)
+{
+       GPtrArray *array = (GPtrArray *) ref;
+        
+       #if 0
+       int i;
+       for (i = 0; i < ncol; ++i) {
+               if (!strcmp (name [i], "uid"))
+                       g_ptr_array_add (array, (char *) (camel_pstring_strdup(cols [i])));
+       }
+       #else
+                       g_ptr_array_add (array, (char *) (camel_pstring_strdup(cols [0])));
+       #endif
+        
+        return 0;
+}
+
+int
+camel_db_get_folder_uids (CamelDB *db, char *folder_name, GPtrArray *array, CamelException *ex)
+{
+        char *sel_query;
+        int ret;
+        
+        sel_query = sqlite3_mprintf("SELECT uid FROM %Q", folder_name);
+
+        ret = camel_db_select (db, sel_query, read_uids_callback, array, ex);
+        sqlite3_free (sel_query);
+
+        return ret;
+}
+
+GPtrArray *
+camel_db_get_folder_junk_uids (CamelDB *db, char *folder_name, CamelException *ex)
+{
+        char *sel_query;
+        int ret;
+        GPtrArray *array = g_ptr_array_new();
+        
+        sel_query = sqlite3_mprintf("SELECT uid FROM %Q where junk=1", folder_name);
+
+        ret = camel_db_select (db, sel_query, read_uids_callback, array, ex);
+        sqlite3_free (sel_query);
+
+        if (!array->len) {
+                g_ptr_array_free (array, TRUE);
+                array = NULL;
+        } 
+        return array;
+}
+
+GPtrArray *
+camel_db_get_folder_deleted_uids (CamelDB *db, char *folder_name, CamelException *ex)
+{
+        char *sel_query;
+        int ret;
+        GPtrArray *array = g_ptr_array_new();
+        
+        sel_query = sqlite3_mprintf("SELECT uid FROM %Q where deleted=1", folder_name);
+
+        ret = camel_db_select (db, sel_query, read_uids_callback, array, ex);
+        sqlite3_free (sel_query);
+
+        if (!array->len) {
+                g_ptr_array_free (array, TRUE);
+                array = NULL;
+        }
+                
+        return array;
+}
+
+static int
+read_vuids_callback (void *ref, int ncol, char ** cols, char ** name)
+{
+        GPtrArray *array = (GPtrArray *)ref;
+        
+        #if 0
+        int i;
+        
+
+        for (i = 0; i < ncol; ++i) {
+                 if (!strcmp (name [i], "vuid"))
+                          g_ptr_array_add (array, (char *) (camel_pstring_strdup(cols [i]+8)));
+        }
+        #else
+                          g_ptr_array_add (array, (char *) (camel_pstring_strdup(cols [0]+8)));
+        #endif
+
+        return 0;
+}
+
+GPtrArray *
+camel_db_get_vuids_from_vfolder (CamelDB *db, char *folder_name, char *filter, CamelException *ex)
+{
+        char *sel_query;
+        char *cond = NULL;
+        GPtrArray *array;
+        char *tmp = g_strdup_printf("%s%%", filter ? filter:"");
+        if(filter) 
+                 cond = sqlite3_mprintf("WHERE vuid LIKE %Q", tmp);
+        g_free(tmp);
+        sel_query = sqlite3_mprintf("SELECT vuid FROM %Q%s", folder_name, filter ? cond : "");
+
+        if (cond)
+                 sqlite3_free (cond);
+        #warning "handle return values"
+        #warning "No The caller should parse the ex in case of NULL returns" 
+        array = g_ptr_array_new ();
+        camel_db_select (db, sel_query, read_vuids_callback, array, ex);
+        sqlite3_free (sel_query);
+        /* We make sure to return NULL if we don't get anything. Be good to your caller */ 
+        if (!array->len) {
+                 g_ptr_array_free (array, TRUE);
+                 array = NULL;
+        }
+
+        return array;
+}
+
+int
+camel_db_add_to_vfolder (CamelDB *db, char *folder_name, char *vuid, CamelException *ex)
+{
+        char *del_query, *ins_query;
+        int ret;
+        
+        ins_query = sqlite3_mprintf ("INSERT INTO %Q VALUES (%Q)", folder_name, vuid);
+        del_query = sqlite3_mprintf ("DELETE FROM %Q WHERE vuid = %Q", folder_name, vuid);
+
+        ret = camel_db_command (db, del_query, ex);
+        ret = camel_db_command (db, ins_query, ex);
+        
+        sqlite3_free (ins_query);
+        sqlite3_free (del_query);
+        CAMEL_DB_RELEASE_SQLITE_MEMORY;
+        return ret;
+}
+
+int
+camel_db_add_to_vfolder_transaction (CamelDB *db, char *folder_name, char *vuid, CamelException *ex)
+{
+        char *del_query, *ins_query;
+        int ret;
+        
+        ins_query = sqlite3_mprintf ("INSERT INTO %Q VALUES (%Q)", folder_name, vuid);
+        del_query = sqlite3_mprintf ("DELETE FROM %Q WHERE vuid = %Q", folder_name, vuid);
+
+        ret = camel_db_add_to_transaction (db, del_query, ex);
+        ret = camel_db_add_to_transaction (db, ins_query, ex);
+        
+        sqlite3_free (ins_query);
+        sqlite3_free (del_query);
+
+        return ret;
+}
+
+
+int
+camel_db_create_folders_table (CamelDB *cdb, CamelException *ex)
+{
+       char *query = "CREATE TABLE IF NOT EXISTS folders ( folder_name TEXT PRIMARY KEY, version REAL, flags INTEGER, nextuid INTEGER, time NUMERIC, saved_count INTEGER, unread_count INTEGER, deleted_count INTEGER, junk_count INTEGER, visible_count INTEGER, jnd_count INTEGER, bdata TEXT )";
+       CAMEL_DB_RELEASE_SQLITE_MEMORY;
+       return ((camel_db_command (cdb, query, ex)));
+}
+
+int 
+camel_db_prepare_message_info_table (CamelDB *cdb, const char *folder_name, CamelException *ex)
+{
+       int ret;
+       char *table_creation_query, *safe_index;
+
+       /* README: It is possible to compress all system flags into a single column and use just as userflags but that makes querying for other applications difficult an d bloats the parsing code. Instead, it is better to bloat the tables. Sqlite should have some optimizations for sparse columns etc. */
+
+       table_creation_query = sqlite3_mprintf ("CREATE TABLE IF NOT EXISTS %Q (  uid TEXT PRIMARY KEY , flags INTEGER , msg_type INTEGER , read INTEGER , deleted INTEGER , replied INTEGER , important INTEGER , junk INTEGER , attachment INTEGER , msg_security INTEGER , size INTEGER , dsent NUMERIC , dreceived NUMERIC , subject TEXT , mail_from TEXT , mail_to TEXT , mail_cc TEXT , mlist TEXT , followup_flag TEXT , followup_completed_on TEXT , followup_due_by TEXT , part TEXT , labels TEXT , usertags TEXT , cinfo TEXT , bdata TEXT )", folder_name);
+
+       ret = camel_db_add_to_transaction (cdb, table_creation_query, ex);
+
+       sqlite3_free (table_creation_query);
+
+       /* FIXME: sqlize folder_name before you create the index */
+       safe_index = g_strdup_printf("SINDEX-%s", folder_name);
+       table_creation_query = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS %Q ON %Q (uid, flags, size, dsent, dreceived, subject, mail_from, mail_to, mail_cc, mlist, part, labels, usertags, cinfo)", safe_index, folder_name);
+       ret = camel_db_add_to_transaction (cdb, table_creation_query, ex);
+       g_free (safe_index);
+       sqlite3_free (table_creation_query);
+       
+       return ret;
+}
+
+int
+camel_db_write_message_info_record (CamelDB *cdb, const char *folder_name, CamelMIRecord *record, CamelException *ex)
+{
+       int ret;
+       char *del_query;
+       char *ins_query;
+
+       ins_query = sqlite3_mprintf ("INSERT INTO %Q VALUES (%Q, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %ld, %ld, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q, %Q )", 
+                       folder_name, record->uid, record->flags,
+                       record->msg_type, record->read, record->deleted, record->replied,
+                       record->important, record->junk, record->attachment, record->msg_security,
+                       record->size, record->dsent, record->dreceived,
+                       record->subject, record->from, record->to,
+                       record->cc, record->mlist, record->followup_flag,
+                       record->followup_completed_on, record->followup_due_by, 
+                       record->part, record->labels, record->usertags,
+                       record->cinfo, record->bdata);
+
+       del_query = sqlite3_mprintf ("DELETE FROM %Q WHERE uid = %Q", folder_name, record->uid);
+
+#if 0
+       char *upd_query;
+
+       upd_query = g_strdup_printf ("IMPLEMENT AND THEN TRY");
+       camel_db_command (cdb, upd_query, ex);
+       g_free (upd_query);
+#else
+
+       ret = camel_db_add_to_transaction (cdb, del_query, ex);
+       ret = camel_db_add_to_transaction (cdb, ins_query, ex);
+
+#endif
+
+       sqlite3_free (del_query);
+       sqlite3_free (ins_query);
+
+       return ret;
+}
+
+int
+camel_db_write_folder_info_record (CamelDB *cdb, CamelFIRecord *record, CamelException *ex)
+{
+       int ret;
+
+       char *del_query;
+       char *ins_query;
+
+       ins_query = sqlite3_mprintf ("INSERT INTO folders VALUES ( %Q, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %Q ) ", 
+                       record->folder_name, record->version,
+                                                                record->flags, record->nextuid, record->time,
+                       record->saved_count, record->unread_count,
+                                                                record->deleted_count, record->junk_count, record->visible_count, record->jnd_count, record->bdata); 
+
+       del_query = sqlite3_mprintf ("DELETE FROM folders WHERE folder_name = %Q", record->folder_name);
+
+
+#if 0
+       char *upd_query;
+       
+       upd_query = g_strdup_printf ("UPDATE folders SET version = %d, flags = %d, nextuid = %d, time = 143, saved_count = %d, unread_count = %d, deleted_count = %d, junk_count = %d, bdata = %s, WHERE folder_name = %Q", record->version, record->flags, record->nextuid, record->saved_count, record->unread_count, record->deleted_count, record->junk_count, "PROVIDER SPECIFIC DATA", record->folder_name );
+       camel_db_command (cdb, upd_query, ex);
+       g_free (upd_query);
+#else
+
+       ret = camel_db_add_to_transaction (cdb, del_query, ex);
+       ret = camel_db_add_to_transaction (cdb, ins_query, ex);
+
+#endif
+
+       sqlite3_free (del_query);
+       sqlite3_free (ins_query);
+
+       return ret;
+}
+
+static int 
+read_fir_callback (void * ref, int ncol, char ** cols, char ** name)
+{
+       CamelFIRecord *record = *(CamelFIRecord **) ref;
+
+       d(g_print ("\nread_fir_callback called \n"));
+#if 0
+       record->folder_name = cols [0];
+       record->version = cols [1];
+       /* Just a sequential mapping of struct members to columns is enough I guess. 
+       Needs some checking */
+#else
+       int i;
+       
+       for (i = 0; i < ncol; ++i) {
+               if (!strcmp (name [i], "folder_name"))
+                       record->folder_name = g_strdup(cols [i]);
+
+               else if (!strcmp (name [i], "version"))
+                       record->version = cols [i] ? strtoul (cols [i], NULL, 10) : 0;
+
+               else if (!strcmp (name [i], "flags"))
+                       record->flags = cols [i] ? strtoul (cols [i], NULL, 10) : 0;
+
+               else if (!strcmp (name [i], "nextuid"))
+                       record->nextuid = cols [i] ? strtoul (cols [i], NULL, 10) : 0;
+
+               else if (!strcmp (name [i], "time"))
+                       record->time = cols [i] ? strtoul (cols [i], NULL, 10) : 0;
+
+               else if (!strcmp (name [i], "saved_count"))
+                       record->saved_count = cols [i] ? strtoul (cols [i], NULL, 10) : 0;
+
+               else if (!strcmp (name [i], "unread_count"))
+                       record->unread_count = cols [i] ? strtoul (cols [i], NULL, 10) : 0;
+
+               else if (!strcmp (name [i], "deleted_count"))
+                       record->deleted_count = cols [i] ? strtoul (cols [i], NULL, 10) : 0;
+
+               else if (!strcmp (name [i], "junk_count"))
+                       record->junk_count = cols [i] ? strtoul (cols [i], NULL, 10) : 0;
+               else if (!strcmp (name [i], "visible_count"))
+                       record->visible_count = cols [i] ? strtoul (cols [i], NULL, 10) : 0;
+               else if (!strcmp (name [i], "jnd_count"))
+                       record->jnd_count = cols [i] ? strtoul (cols [i], NULL, 10) : 0;
+               else if (!strcmp (name [i], "bdata"))
+                       record->bdata = g_strdup (cols [i]);
+       
+       }
+#endif 
+       return 0;
+}
+
+int
+camel_db_read_folder_info_record (CamelDB *cdb, const char *folder_name, CamelFIRecord **record, CamelException *ex)
+{
+       char *query;
+       int ret;
+
+       query = sqlite3_mprintf ("SELECT * FROM folders WHERE folder_name = %Q", folder_name);
+       ret = camel_db_select (cdb, query, read_fir_callback, record, ex);
+
+       sqlite3_free (query);
+       return (ret);
+}
+
+int
+camel_db_read_message_info_record_with_uid (CamelDB *cdb, const char *folder_name, const char *uid, gpointer p, CamelDBSelectCB read_mir_callback, CamelException *ex)
+{
+       char *query;
+       int ret;
+
+       query = sqlite3_mprintf ("SELECT uid, flags, size, dsent, dreceived, subject, mail_from, mail_to, mail_cc, mlist, part, labels, usertags, cinfo, bdata FROM %Q WHERE uid = %Q", folder_name, uid);
+       ret = camel_db_select (cdb, query, read_mir_callback, p, ex);
+       sqlite3_free (query);
+
+       return (ret);
+}
+
+int
+camel_db_read_message_info_records (CamelDB *cdb, const char *folder_name, gpointer p, CamelDBSelectCB read_mir_callback, CamelException *ex)
+{
+       char *query;
+       int ret;
+
+       query = sqlite3_mprintf ("SELECT uid, flags, size, dsent, dreceived, subject, mail_from, mail_to, mail_cc, mlist, part, labels, usertags, cinfo, bdata FROM %Q ", folder_name);
+       ret = camel_db_select (cdb, query, read_mir_callback, p, ex);
+       sqlite3_free (query);
+
+       return (ret);
+}
+
+int
+camel_db_delete_uid (CamelDB *cdb, const char *folder, const char *uid, CamelException *ex)
+{
+       char *tab = sqlite3_mprintf ("DELETE FROM %Q WHERE uid = %Q", folder, uid);
+       int ret;
+
+       ret = camel_db_command (cdb, tab, ex);
+       sqlite3_free (tab);
+       CAMEL_DB_RELEASE_SQLITE_MEMORY;
+       return ret;
+}
+
+int
+camel_db_delete_uids (CamelDB *cdb, const char * folder_name, GSList *uids, CamelException *ex)
+{
+       char *tmp;
+       int ret;
+       gboolean first = TRUE;
+       GString *str = g_string_new ("DELETE FROM ");
+       GSList *iterator;
+
+       tmp = sqlite3_mprintf ("%Q WHERE uid IN (", folder_name); 
+       g_string_append_printf (str, "%s ", tmp);
+       sqlite3_free (tmp);
+
+       iterator = uids;
+
+       while (iterator) {
+               tmp = sqlite3_mprintf ("%Q", (char *) iterator->data);
+               iterator = iterator->next;
+
+               if (first == TRUE) {
+                       g_string_append_printf (str, " %s ", tmp);
+                       first = FALSE;
+               } else
+                       g_string_append_printf (str, ", %s ", tmp);
+
+               sqlite3_free (tmp);
+       }
+
+       g_string_append (str, ")");
+
+       ret = camel_db_command (cdb, str->str, ex);
+       CAMEL_DB_RELEASE_SQLITE_MEMORY;
+       g_string_free (str, TRUE);
+
+       return ret;
+}
+
+int
+camel_db_clear_folder_summary (CamelDB *cdb, char *folder, CamelException *ex)
+{
+       int ret;
+
+       char *folders_del;
+       char *msginfo_del;
+
+       folders_del = sqlite3_mprintf ("DELETE FROM folders WHERE folder_name = %Q", folder);
+       msginfo_del = sqlite3_mprintf ("DELETE FROM %Q ", folder);
+
+       camel_db_begin_transaction (cdb, ex);
+       camel_db_add_to_transaction (cdb, msginfo_del, ex);
+       camel_db_add_to_transaction (cdb, folders_del, ex);
+       ret = camel_db_end_transaction (cdb, ex);
+
+       sqlite3_free (folders_del);
+       sqlite3_free (msginfo_del);
+
+       return ret;
+}
+
+
+
+void
+camel_db_camel_mir_free (CamelMIRecord *record)
+{
+       if (record) {
+               camel_pstring_free (record->uid);
+               camel_pstring_free (record->subject);
+               camel_pstring_free (record->from);
+               camel_pstring_free (record->to);
+               camel_pstring_free (record->cc);
+               camel_pstring_free (record->mlist);
+               camel_pstring_free (record->followup_flag);
+               camel_pstring_free (record->followup_completed_on);
+               camel_pstring_free (record->followup_due_by);
+               g_free (record->part);
+               g_free (record->labels);
+               g_free (record->usertags);
+               g_free (record->cinfo);
+               g_free (record->bdata);
+
+               g_free (record);
+       }
+}
+
+char * 
+camel_db_sqlize_string (const char *string)
+{
+       return sqlite3_mprintf ("%Q", string);
+}
+
+void 
+camel_db_free_sqlized_string (char *string)
+{
+       sqlite3_free (string);
+       string = NULL;
+}
+
+char * camel_db_get_column_name (const char *raw_name)
+{
+       d(g_print ("\n\aRAW name is : [%s] \n\a", raw_name));
+       if (!g_ascii_strcasecmp (raw_name, "Subject"))
+               return g_strdup ("subject");
+       else if (!g_ascii_strcasecmp (raw_name, "from"))
+               return g_strdup ("mail_from");
+       else if (!g_ascii_strcasecmp (raw_name, "Cc"))
+               return g_strdup ("mail_cc");
+       else if (!g_ascii_strcasecmp (raw_name, "To"))
+               return g_strdup ("mail_to");
+       else if (!g_ascii_strcasecmp (raw_name, "Flagged"))
+               return g_strdup ("important");
+       else if (!g_ascii_strcasecmp (raw_name, "deleted"))
+               return g_strdup ("deleted");
+       else if (!g_ascii_strcasecmp (raw_name, "junk"))
+               return g_strdup ("junk");
+       else if (!g_ascii_strcasecmp (raw_name, "Seen"))
+               return g_strdup ("read");
+       else if (!g_ascii_strcasecmp (raw_name, "Attachments"))
+               return g_strdup ("attachment");
+       else {
+               /* Let it crash for all unknown columns for now. 
+               We need to load the messages into memory and search etc. 
+               We should extend this for camel-folder-search system flags search as well 
+               otherwise, search-for-signed-messages will not work etc.*/
+
+               return g_strdup ("");
+       }
+
+}
diff --git a/camel/camel-db.h b/camel/camel-db.h
new file mode 100644 (file)
index 0000000..7c0becc
--- /dev/null
@@ -0,0 +1,155 @@
+/* Srinivasa Ragavan - <sragavan@novell.com> - GPL v2 or later */
+
+#ifndef __CAMEL_DB_H
+#define __CAMEL_DB_H
+#include <sqlite3.h>
+#include <glib.h>
+#define CAMEL_DB_FILE "folders.db"
+
+#include "camel-exception.h"
+
+struct _CamelDB {
+       sqlite3 *db;
+       GMutex *lock;
+};
+
+#define CAMEL_DB_FREE_CACHE_SIZE 2 * 1024 * 1024
+
+/* The extensive DB format, supporting basic searching and sorting
+  uid, - Message UID
+  flags, - Camel Message info flags
+  unread/read, - boolean read/unread status
+  deleted, - boolean deleted status
+  replied, - boolean replied status
+  imp, - boolean important status
+  junk, - boolean junk status
+  size, - size of the mail
+  attachment, boolean attachment status
+  dsent, - sent date
+  dreceived, - received date
+  subject, - subject of the mail
+  from, - sender
+  to, - recipient
+  cc, - CC members
+  mlist, - message list headers
+  follow-up-flag, - followup flag / also can be queried to see for followup or not
+  completed-on-set, - completed date, can be used to see if completed
+  due-by,  - to see the due by date
+  Location - This can be derived from the database location/name. No need to store.
+  label, - labels of mails also called as userflags
+  usertags, composite string of user tags
+  cinfo, content info string - composite string
+  bdata, provider specific data
+  part, part/references/thread id
+*/
+
+typedef struct _CamelMIRecord {
+       char *uid;
+       guint32 flags;
+       guint32 msg_type;
+       guint32 msg_security;
+       gboolean read;
+       gboolean deleted;
+       gboolean replied;
+       gboolean important;
+       gboolean junk;
+       gboolean attachment;
+       guint32 size;
+       time_t dsent;
+       time_t dreceived;
+       char *subject;
+       char *from;
+       char *to;
+       char *cc;
+       char *mlist;
+       char *followup_flag;
+       char *followup_completed_on;
+       char *followup_due_by;
+       char *part;
+       char *labels;
+       char *usertags;
+       char *cinfo;
+       char *bdata;
+} CamelMIRecord;
+
+typedef struct _CamelFIRecord {
+       char *folder_name;
+       guint32 version;
+       guint32 flags;
+       guint32 nextuid;
+       time_t time;
+       guint32 saved_count;
+       guint32 unread_count;
+       guint32 deleted_count;
+       guint32 junk_count;
+       guint32 visible_count;
+       guint32 jnd_count;  /* Junked not deleted */
+       char *bdata;
+} CamelFIRecord;
+
+
+
+
+typedef struct _CamelDB CamelDB;
+typedef int (*CamelDBSelectCB) (gpointer data, int ncol, char **colvalues, char **colnames);
+
+
+CamelDB * camel_db_open (const char *path, CamelException *ex);
+void camel_db_close (CamelDB *cdb);
+int camel_db_command (CamelDB *cdb, const char *stmt, CamelException *ex);
+
+int camel_db_transaction_command (CamelDB *cdb, GSList *qry_list, CamelException *ex);
+
+int camel_db_begin_transaction (CamelDB *cdb, CamelException *ex);
+int camel_db_add_to_transaction (CamelDB *cdb, const char *query, CamelException *ex);
+int camel_db_end_transaction (CamelDB *cdb, CamelException *ex);
+int camel_db_abort_transaction (CamelDB *cdb, CamelException *ex);
+int camel_db_clear_folder_summary (CamelDB *cdb, char *folder, CamelException *ex);
+
+int camel_db_delete_folder (CamelDB *cdb, const char *folder, CamelException *ex);
+int camel_db_delete_uid (CamelDB *cdb, const char *folder, const char *uid, CamelException *ex);
+/*int camel_db_delete_uids (CamelDB *cdb, CamelException *ex, int nargs, ... );*/
+int camel_db_delete_uids (CamelDB *cdb, const char* folder_name, GSList *uids, CamelException *ex);
+
+int camel_db_create_folders_table (CamelDB *cdb, CamelException *ex);
+int camel_db_select (CamelDB *cdb, const char* stmt, CamelDBSelectCB callback, gpointer data, CamelException *ex);
+
+int camel_db_write_folder_info_record (CamelDB *cdb, CamelFIRecord *record, CamelException *ex);
+int camel_db_read_folder_info_record (CamelDB *cdb, const char *folder_name, CamelFIRecord **record, CamelException *ex);
+
+int camel_db_prepare_message_info_table (CamelDB *cdb, const char *folder_name, CamelException *ex);
+
+int camel_db_write_message_info_record (CamelDB *cdb, const char *folder_name, CamelMIRecord *record, CamelException *ex);
+int camel_db_read_message_info_records (CamelDB *cdb, const char *folder_name, gpointer p, CamelDBSelectCB read_mir_callback, CamelException *ex);
+int camel_db_read_message_info_record_with_uid (CamelDB *cdb, const char *folder_name, const char *uid, gpointer p, CamelDBSelectCB read_mir_callback, CamelException *ex);
+
+int camel_db_count_junk_message_info (CamelDB *cdb, const char *table_name, guint32 *count, CamelException *ex);
+int camel_db_count_unread_message_info (CamelDB *cdb, const char *table_name, guint32 *count, CamelException *ex);
+int camel_db_count_deleted_message_info (CamelDB *cdb, const char *table_name, guint32 *count, CamelException *ex);
+int camel_db_count_total_message_info (CamelDB *cdb, const char *table_name, guint32 *count, CamelException *ex);
+
+int camel_db_count_visible_message_info (CamelDB *cdb, const char *table_name, guint32 *count, CamelException *ex);
+int camel_db_count_visible_unread_message_info (CamelDB *cdb, const char *table_name, guint32 *count, CamelException *ex);
+
+int camel_db_count_junk_not_deleted_message_info (CamelDB *cdb, const char *table_name, guint32 *count, CamelException *ex);
+
+void camel_db_camel_mir_free (CamelMIRecord *record);
+
+int camel_db_create_vfolder (CamelDB *db, const char *folder_name, CamelException *ex);
+int camel_db_delete_uid_from_vfolder (CamelDB *db, char *folder_name, char *vuid, CamelException *ex);
+GPtrArray * camel_db_get_vuids_from_vfolder (CamelDB *db, char *folder_name, char *filter, CamelException *ex);
+int camel_db_add_to_vfolder (CamelDB *db, char *folder_name, char *vuid, CamelException *ex);
+int camel_db_add_to_vfolder_transaction (CamelDB *db, char *folder_name, char *vuid, CamelException *ex);
+
+int camel_db_get_folder_uids (CamelDB *db, char *folder_name, GPtrArray *array, CamelException *ex);
+
+GPtrArray * camel_db_get_folder_junk_uids (CamelDB *db, char *folder_name, CamelException *ex);
+GPtrArray * camel_db_get_folder_deleted_uids (CamelDB *db, char *folder_name, CamelException *ex);
+
+char * camel_db_sqlize_string (const char *string);
+void camel_db_free_sqlized_string (char *string);
+
+char * camel_db_get_column_name (const char *raw_name);
+
+#endif
+
index 88d2900..9a02b47 100644 (file)
 #include "camel-multipart.h"
 #include "camel-search-private.h"
 #include "camel-stream-mem.h"
+#include "camel-db.h"
+#include "camel-store.h"
+#include "camel-vee-folder.h"
+#include "camel-string-utils.h"
 
 #define d(x) 
 #define r(x) 
@@ -65,6 +69,7 @@ struct _CamelFolderSearchPrivate {
 static ESExpResult *search_not(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search);
 
 static ESExpResult *search_header_contains(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search);
+static ESExpResult *db_search_header_contains(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search);
 static ESExpResult *search_header_matches(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search);
 static ESExpResult *search_header_starts_with(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search);
 static ESExpResult *search_header_ends_with(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search);
@@ -87,6 +92,8 @@ static void camel_folder_search_class_init (CamelFolderSearchClass *klass);
 static void camel_folder_search_init       (CamelFolderSearch *obj);
 static void camel_folder_search_finalize   (CamelObject *obj);
 
+static int read_uid_callback (void * ref, int ncol, char ** cols, char **name);
+
 static CamelObjectClass *camel_folder_search_parent;
 
 static void
@@ -99,7 +106,7 @@ camel_folder_search_class_init (CamelFolderSearchClass *klass)
        klass->match_all = search_match_all;
        klass->match_threads = search_match_threads;
        klass->body_contains = search_body_contains;
-       klass->header_contains = search_header_contains;
+       klass->header_contains = db_search_header_contains;
        klass->header_matches = search_header_matches;
        klass->header_starts_with = search_header_starts_with;
        klass->header_ends_with = search_header_ends_with;
@@ -150,13 +157,16 @@ camel_folder_search_finalize (CamelObject *obj)
 
        if (search->sexp)
                e_sexp_unref(search->sexp);
-       if (search->summary_hash)
-               g_hash_table_destroy(search->summary_hash);
 
        g_free(search->last_search);
        g_hash_table_foreach(p->mempool_hash, free_mempool, obj);
        g_hash_table_destroy(p->mempool_hash);
        g_free(p);
+
+       if (search->query) {
+               g_print ("\nFinalizing search query and the query is : \n%s\n", search->query->str);
+               g_string_free (search->query, TRUE);
+       }
 }
 
 CamelType
@@ -239,6 +249,8 @@ camel_folder_search_construct (CamelFolderSearch *search)
                        }
                }
        }
+
+       search->query = NULL;
 }
 
 /**
@@ -274,7 +286,16 @@ camel_folder_search_new (void)
 void
 camel_folder_search_set_folder(CamelFolderSearch *search, CamelFolder *folder)
 {
+       char *tmp = camel_db_sqlize_string(folder->full_name);
        search->folder = folder;
+
+       if (search->query)
+               g_string_free (search->query, TRUE);
+
+       /* FIXME: Get this string done from camel-db by parsing with sqlite_mprintf etc. */
+       search->query = g_string_new ("SELECT uid FROM ");
+       g_string_append_printf (search->query, "%s ", tmp);
+       camel_db_free_sqlized_string (tmp);
 }
 
 /**
@@ -290,14 +311,7 @@ camel_folder_search_set_folder(CamelFolderSearch *search, CamelFolder *folder)
 void
 camel_folder_search_set_summary(CamelFolderSearch *search, GPtrArray *summary)
 {
-       int i;
-
        search->summary = summary;
-       if (search->summary_hash)
-               g_hash_table_destroy(search->summary_hash);
-       search->summary_hash = g_hash_table_new(g_str_hash, g_str_equal);
-       for (i=0;i<summary->len;i++)
-               g_hash_table_insert(search->summary_hash, (char *)camel_message_info_uid(summary->pdata[i]), summary->pdata[i]);
 }
 
 /**
@@ -387,17 +401,18 @@ camel_folder_search_execute_expression(CamelFolderSearch *search, const char *ex
                                g_hash_table_insert(results, g_ptr_array_index(r->value.ptrarray, i), GINT_TO_POINTER (1));
                        }
                        for (i=0;i<search->summary->len;i++) {
-                               CamelMessageInfo *info = g_ptr_array_index(search->summary, i);
-                               char *uid = (char *)camel_message_info_uid(info);
+                               char *uid = g_ptr_array_index(search->summary, i);
                                if (g_hash_table_lookup(results, uid)) {
-                                       g_ptr_array_add(matches, e_mempool_strdup(pool, uid));
+//                                     g_ptr_array_add(matches, e_mempool_strdup(pool, uid));
+                                       g_ptr_array_add(matches, (char *) camel_pstring_strdup(uid));
                                }
                        }
                        g_hash_table_destroy(results);
                } else {
                        for (i=0;i<r->value.ptrarray->len;i++) {
                                d(printf("adding match: %s\n", (char *)g_ptr_array_index(r->value.ptrarray, i)));
-                               g_ptr_array_add(matches, e_mempool_strdup(pool, g_ptr_array_index(r->value.ptrarray, i)));
+//                             g_ptr_array_add(matches, e_mempool_strdup(pool, g_ptr_array_index(r->value.ptrarray, i)));
+                               g_ptr_array_add(matches, (char *) camel_pstring_strdup(g_ptr_array_index(r->value.ptrarray, i)));
                        }
                }
                /* instead of putting the mempool_hash in the structure, we keep the api clean by
@@ -443,8 +458,7 @@ camel_folder_search_search(CamelFolderSearch *search, const char *expr, GPtrArra
        ESExpResult *r;
        GPtrArray *matches = NULL, *summary_set;
        int i;
-       GHashTable *results;
-       EMemPool *pool;
+       CamelDB *cdb;
        struct _CamelFolderSearchPrivate *p = _PRIVATE(search);
 
        g_assert(search->folder);
@@ -453,7 +467,6 @@ camel_folder_search_search(CamelFolderSearch *search, const char *expr, GPtrArra
 
        /* setup our search list, summary_hash only contains those we're interested in */
        search->summary = camel_folder_get_summary(search->folder);
-       search->summary_hash = g_hash_table_new(g_str_hash, g_str_equal);
 
        if (uids) {
                GHashTable *uids_hash = g_hash_table_new(g_str_hash, g_str_equal);
@@ -462,16 +475,13 @@ camel_folder_search_search(CamelFolderSearch *search, const char *expr, GPtrArra
                for (i=0;i<uids->len;i++)
                        g_hash_table_insert(uids_hash, uids->pdata[i], uids->pdata[i]);
                for (i=0;i<search->summary->len;i++)
-                       if (g_hash_table_lookup(uids_hash, camel_message_info_uid(search->summary->pdata[i])))
+                       if (g_hash_table_lookup(uids_hash, search->summary->pdata[i]))
                                g_ptr_array_add(search->summary_set, search->summary->pdata[i]);
                g_hash_table_destroy(uids_hash);
        } else {
                summary_set = search->summary;
        }
 
-       for (i=0;i<summary_set->len;i++)
-               g_hash_table_insert(search->summary_hash, (char *)camel_message_info_uid(summary_set->pdata[i]), summary_set->pdata[i]);
-
        /* only re-parse if the search has changed */
        if (search->last_search == NULL
            || strcmp(search->last_search, expr)) {
@@ -491,41 +501,14 @@ camel_folder_search_search(CamelFolderSearch *search, const char *expr, GPtrArra
                goto fail;
        }
 
-       matches = g_ptr_array_new();
-
-       /* now create a folder summary to return?? */
-       if (r->type == ESEXP_RES_ARRAY_PTR) {
-               d(printf("got result ...\n"));
-
-               /* we use a mempool to store the strings, packed in tight as possible, and freed together */
-               /* because the strings are often short (like <8 bytes long), we would be wasting appx 50%
-                  of memory just storing the size tag that malloc assigns us and alignment padding, so this
-                  gets around that (and is faster to allocate and free as a bonus) */
-               pool = e_mempool_new(512, 256, E_MEMPOOL_ALIGN_BYTE);
-               /* reorder result in summary order */
-               results = g_hash_table_new(g_str_hash, g_str_equal);
-               for (i=0;i<r->value.ptrarray->len;i++) {
-                       d(printf("adding match: %s\n", (char *)g_ptr_array_index(r->value.ptrarray, i)));
-                       g_hash_table_insert(results, g_ptr_array_index(r->value.ptrarray, i), GINT_TO_POINTER (1));
-               }
-
-               for (i=0;i<summary_set->len;i++) {
-                       CamelMessageInfo *info = g_ptr_array_index(summary_set, i);
-                       char *uid = (char *)camel_message_info_uid(info);
-                       if (g_hash_table_lookup(results, uid))
-                               g_ptr_array_add(matches, e_mempool_strdup(pool, uid));
-               }
-               g_hash_table_destroy(results);
-
-               /* instead of putting the mempool_hash in the structure, we keep the api clean by
-                  putting a reference to it in a hashtable.  Lets us do some debugging and catch
-                  unfree'd results as well. */
-               g_hash_table_insert(p->mempool_hash, matches, pool);
-       } else {
-               g_warning("Search returned an invalid result type");
-       }
+       printf ("\nsexp is : [%s]\n", expr);
+       printf ("Something is returned in the top-level caller : [%s]\n", search->query->str);
 
+       matches = g_ptr_array_new();
+       cdb = (CamelDB *) (search->folder->cdb);
+       camel_db_select (cdb, search->query->str, (CamelDBSelectCB) read_uid_callback, matches, ex);
        e_sexp_result_free(search->sexp, r);
+
 fail:
        /* these might be allocated by match-threads */
        if (p->threads)
@@ -534,14 +517,12 @@ fail:
                g_hash_table_destroy(p->threads_hash);
        if (search->summary_set)
                g_ptr_array_free(search->summary_set, TRUE);
-       g_hash_table_destroy(search->summary_hash);
        camel_folder_free_summary(search->folder, search->summary);
 
        p->threads = NULL;
        p->threads_hash = NULL;
        search->folder = NULL;
        search->summary = NULL;
-       search->summary_hash = NULL;
        search->summary_set = NULL;
        search->current = NULL;
        search->body_index = NULL;
@@ -551,10 +532,10 @@ fail:
 
 void camel_folder_search_free_result(CamelFolderSearch *search, GPtrArray *result)
 {
+#if 0
        int i;
        struct _CamelFolderSearchPrivate *p = _PRIVATE(search);
        EMemPool *pool;
-
        pool = g_hash_table_lookup(p->mempool_hash, result);
        if (pool) {
                e_mempool_destroy(pool);
@@ -563,6 +544,8 @@ void camel_folder_search_free_result(CamelFolderSearch *search, GPtrArray *resul
                for (i=0;i<result->len;i++)
                        g_free(g_ptr_array_index(result, i));
        }
+#endif
+       g_ptr_array_foreach (result, (GFunc) camel_pstring_free, NULL);
        g_ptr_array_free(result, TRUE);
 }
 
@@ -616,16 +599,16 @@ search_not(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSe
                                /* 'not' against the whole summary */
                                GHashTable *have = g_hash_table_new(g_str_hash, g_str_equal);
                                char **s;
-                               CamelMessageInfo **m;
+                               char **m;
 
                                s = (char **)v->pdata;
                                for (i=0;i<v->len;i++)
                                        g_hash_table_insert(have, s[i], s[i]);
 
                                v = search->summary_set?search->summary_set:search->summary;
-                               m = (CamelMessageInfo **)v->pdata;
+                               m = (char **)v->pdata;
                                for (i=0;i<v->len;i++) {
-                                       char *uid = (char *)camel_message_info_uid(m[i]);
+                                       char *uid = m[i];
 
                                        if (g_hash_table_lookup(have, uid) == NULL)
                                                g_ptr_array_add(r->value.ptrarray, uid);
@@ -652,9 +635,7 @@ search_not(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSe
 static ESExpResult *
 search_match_all(struct _ESExp *f, int argc, struct _ESExpTerm **argv, CamelFolderSearch *search)
 {
-       int i;
        ESExpResult *r, *r1;
-       GPtrArray *v;
        gchar *error_msg;
 
        if (argc>1) {
@@ -664,7 +645,7 @@ search_match_all(struct _ESExp *f, int argc, struct _ESExpTerm **argv, CamelFold
        /* we are only matching a single message?  or already inside a match-all? */
        if (search->current) {
                d(printf("matching against 1 message: %s\n", camel_message_info_subject(search->current)));
-
+               
                r = e_sexp_result_new(f, ESEXP_RES_BOOL);
                r->value.bool = FALSE;
 
@@ -694,12 +675,22 @@ search_match_all(struct _ESExp *f, int argc, struct _ESExpTerm **argv, CamelFold
                g_assert(0);
                return r;
        }
-
+#if 0
        v = search->summary_set?search->summary_set:search->summary;
+       
+       if (v->len - g_hash_table_size (search->folder->summary->loaded_infos) > 50 && !CAMEL_IS_VEE_FOLDER (search->folder)) {
+               /* Load the DB contents. FIXME this 100 needs to be a better threshold to reload from DB. */
+               #warning "handle exception"
+               camel_folder_summary_reload_from_db (search->folder->summary, NULL);
+       } 
+
+#endif 
+       e_sexp_term_eval (f, argv [0]);
+#if 0
        for (i=0;i<v->len;i++) {
                const char *uid;
 
-               search->current = g_ptr_array_index(v, i);
+               search->current = camel_folder_summary_uid (search->folder->summary, v->pdata[i]);
                uid = camel_message_info_uid(search->current);
 
                if (argc>0) {
@@ -717,12 +708,14 @@ search_match_all(struct _ESExp *f, int argc, struct _ESExpTerm **argv, CamelFold
                } else {
                        g_ptr_array_add(r->value.ptrarray, (char *)uid);
                }
+               camel_message_info_free (search->current);
        }
+#endif 
        search->current = NULL;
-
        return r;
 }
 
+//FIXME Check threads mis
 static void
 fill_thread_table(struct _CamelFolderThreadNode *root, GHashTable *id_hash)
 {
@@ -817,6 +810,7 @@ search_match_threads(struct _ESExp *f, int argc, struct _ESExpTerm **argv, Camel
        }
 
        /* cache this, so we only have to re-calculate once per search at most */
+       #warning "make search threads work well. Not sure if that works"
        if (p->threads == NULL) {
                p->threads = camel_folder_thread_messages_new(search->folder, NULL, TRUE);
                p->threads_hash = g_hash_table_new(g_str_hash, g_str_equal);
@@ -867,7 +861,7 @@ search_match_threads(struct _ESExp *f, int argc, struct _ESExpTerm **argv, Camel
 }
 
 static ESExpResult *
-check_header(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search, camel_search_match_t how)
+check_header_deprecated (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search, camel_search_match_t how)
 {
        ESExpResult *r;
        int truth = FALSE;
@@ -940,12 +934,71 @@ check_header(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolder
 }
 
 static ESExpResult *
-search_header_contains(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search)
+check_header (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search, camel_search_match_t how)
+{
+       /* FIXME: What to do for headers that are not stored in db */
+
+       ESExpResult *r;
+
+       if (strlen (argv [1]->value.string) > 1) {
+
+               char *value;
+               char *temp=NULL;
+               char *column;
+
+               column = camel_db_get_column_name (argv [0]->value.string);
+
+               switch (how) {
+                       case CAMEL_SEARCH_MATCH_EXACT:
+                               temp = g_strdup_printf ("%s", argv [1]->value.string);
+                               break;
+                       case CAMEL_SEARCH_MATCH_CONTAINS:
+                       case CAMEL_SEARCH_MATCH_SOUNDEX:
+                               temp = g_strdup_printf ("%%%s%%", argv [1]->value.string);
+                               break;
+                       case CAMEL_SEARCH_MATCH_STARTS:
+                               temp = g_strdup_printf ("%s%%", argv [1]->value.string);
+                               break;
+                       case CAMEL_SEARCH_MATCH_ENDS:
+                               temp = g_strdup_printf ("%%%s", argv [1]->value.string);
+                               break;
+               }
+
+               value = camel_db_sqlize_string (temp);
+               g_free (temp);
+
+               if (g_str_has_suffix (search->query->str, " "))
+                       g_string_append_printf (search->query, "WHERE %s LIKE %s", column, value);
+               else {
+                       if (f->operators)
+                               g_string_append_printf (search->query, " %s %s LIKE %s", (char *) (g_slist_nth_data (f->operators, 0)), column, value);
+                       else
+                               g_string_append_printf (search->query, " OR %s LIKE %s", column, value);
+               }
+
+               g_free (column);
+               camel_db_free_sqlized_string (value);
+       }
+
+       r = e_sexp_result_new(f, ESEXP_RES_BOOL);
+       r->value.bool = FALSE;
+
+       return r;
+}
+
+static ESExpResult *
+search_header_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search)
 {
        return check_header(f, argc, argv, search, CAMEL_SEARCH_MATCH_CONTAINS);
 }
 
 static ESExpResult *
+db_search_header_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search)
+{
+       return check_header (f, argc, argv, search, CAMEL_SEARCH_MATCH_CONTAINS);
+}
+
+static ESExpResult *
 search_header_matches(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search)
 {
        return check_header(f, argc, argv, search, CAMEL_SEARCH_MATCH_EXACT);
@@ -1049,7 +1102,6 @@ match_words_index(CamelFolderSearch *search, struct _camel_search_words *words,
        struct _glib_sux_donkeys lambdafoo;
        CamelIndexCursor *wc, *nc;
        const char *word, *name;
-       CamelMessageInfo *mi;
        int i;
 
        /* we can have a maximum of 32 words, as we use it as the AND mask */
@@ -1063,14 +1115,11 @@ match_words_index(CamelFolderSearch *search, struct _camel_search_words *words,
                                        nc = camel_index_find(search->body_index, word);
                                        if (nc) {
                                                while ((name = camel_index_cursor_next(nc))) {
-                                                       mi = g_hash_table_lookup(search->summary_hash, name);
-                                                       if (mi) {
-                                                               int mask;
-                                                               const char *uid = camel_message_info_uid(mi);
-
-                                                               mask = (GPOINTER_TO_INT(g_hash_table_lookup(ht, uid))) | (1<<i);
-                                                               g_hash_table_insert(ht, (char *)uid, GINT_TO_POINTER(mask));
-                                                       }
+                                                       int mask;
+
+                                                       mask = (GPOINTER_TO_INT(g_hash_table_lookup(ht, name))) | (1<<i);
+                                                       g_hash_table_insert(ht, (char *)name, GINT_TO_POINTER(mask));
+                                                       
                                                }
                                                camel_object_unref((CamelObject *)nc);
                                        }
@@ -1181,8 +1230,7 @@ match_words_messages(CamelFolderSearch *search, struct _camel_search_words *word
                GPtrArray *v = search->summary_set?search->summary_set:search->summary;
 
                for (i=0;i<v->len;i++) {
-                       CamelMessageInfo *info = g_ptr_array_index(v, i);
-                       const char *uid = camel_message_info_uid(info);
+                       char *uid  = g_ptr_array_index(v, i);
                        
                        if (match_words_message(search->folder, uid, words, ex))
                                g_ptr_array_add(matches, (char *)uid);
@@ -1232,9 +1280,9 @@ search_body_contains(struct _ESExp *f, int argc, struct _ESExpResult **argv, Cam
                        GPtrArray *v = search->summary_set?search->summary_set:search->summary;
 
                        for (i=0;i<v->len;i++) {
-                               CamelMessageInfo *info = g_ptr_array_index(v, i);
+                               char *uid = g_ptr_array_index(v, i);
 
-                               g_ptr_array_add(r->value.ptrarray, (char *)camel_message_info_uid(info));
+                               g_ptr_array_add(r->value.ptrarray, uid);
                        }
                } else {
                        GHashTable *ht = g_hash_table_new(g_str_hash, g_str_equal);
@@ -1266,30 +1314,43 @@ search_body_contains(struct _ESExp *f, int argc, struct _ESExpResult **argv, Cam
 static ESExpResult *
 search_user_flag(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search)
 {
-       ESExpResult *r;
-       int i;
+               char *value = NULL;
+               ESExpResult *r;
+               char * tmp;
 
-       r(printf("executing user-flag\n"));
+               r(printf("\nexecuting user-flag with init str: [%s]\n", search->query->str));
+
+               if (argc == 1) {
+
+                               if (search->current) {
+                                               /* FIXME: I am not sure if this will ever be executed */
+                                               abort ();
+                               } else {
+                                               tmp = g_strdup_printf ("%%%s%%", argv[0]->value.string);
+                                               value = camel_db_sqlize_string (tmp);
+                                               g_free (tmp);
+
+                                               if (g_str_has_suffix (search->query->str, " ")) {
+                                                               g_string_append_printf (search->query, "WHERE labels LIKE %s", value);
+                                               } else {
+                                                               if (f->operators) {
+                                                                               g_string_append_printf (search->query, " %s labels LIKE %s", (char *) (g_slist_nth_data (f->operators, 0)), value);
+                                                                               f->operators = g_slist_remove_link (f->operators, g_slist_nth (f->operators, 0));
+                                                               } else {
+                                                                               g_string_append_printf (search->query, " OR labels LIKE %s", value);
+                                                               }
+                                               }
+
+                                               r(printf ("user-flag search value is : [%s] Appended str is : [%s]\n\n", value, search->query->str));
+                                               camel_db_free_sqlized_string (value);
+                               }
+               } else
+                               g_warning ("Makes no sense to search for multiple things in user flag. A flag is either set or not that's all: [%d]", argc);
 
-       /* are we inside a match-all? */
-       if (search->current) {
-               int truth = FALSE;
-               /* performs an OR of all words */
-               for (i=0;i<argc && !truth;i++) {
-                       if (argv[i]->type == ESEXP_RES_STRING
-                           && camel_message_info_user_flag(search->current, argv[i]->value.string)) {
-                               truth = TRUE;
-                               break;
-                       }
-               }
                r = e_sexp_result_new(f, ESEXP_RES_BOOL);
-               r->value.bool = truth;
-       } else {
-               r = e_sexp_result_new(f, ESEXP_RES_ARRAY_PTR);
-               r->value.ptrarray = g_ptr_array_new();
-       }
+               r->value.bool = FALSE;
 
-       return r;
+               return r;
 }
 
 static ESExpResult *
@@ -1302,14 +1363,35 @@ search_system_flag (struct _ESExp *f, int argc, struct _ESExpResult **argv, Came
        if (search->current) {
                gboolean truth = FALSE;
                
-               if (argc == 1)
+               if (argc == 1) 
                        truth = camel_system_flag_get (camel_message_info_flags(search->current), argv[0]->value.string);
                
                r = e_sexp_result_new(f, ESEXP_RES_BOOL);
                r->value.bool = truth;
        } else {
-               r = e_sexp_result_new(f, ESEXP_RES_ARRAY_PTR);
-               r->value.ptrarray = g_ptr_array_new ();
+                       /* FIXME: You need to complete the camel-db.c:camel_db_get_column_name function and use those return values */
+                       char * value = camel_db_get_column_name (argv[0]->value.string);
+                       char *connector = "=";
+
+                       if (argc > 1) {
+                               if (! strcmp(argv[1]->value.string, "set") )
+                                       connector = "!=";
+                       }
+
+                       if (g_str_has_suffix (search->query->str, " "))
+                                       g_string_append_printf (search->query, "WHERE (%s %s 0)", value, connector);
+                       else {
+                                       search->query->len -= 1;
+                                       if (f->operators)
+                                                       g_string_append_printf (search->query, " %s %s %s 0)", (char *) (g_slist_nth_data (f->operators, 0)), value, connector);
+                                       else
+                                                       g_string_append_printf (search->query, " OR %s %s 0", value, connector);
+                       }
+
+                       g_free (value);
+
+                       r = e_sexp_result_new(f, ESEXP_RES_BOOL);
+                       r->value.bool = FALSE; 
        }
        
        return r;
@@ -1318,18 +1400,42 @@ search_system_flag (struct _ESExp *f, int argc, struct _ESExpResult **argv, Came
 static ESExpResult *
 search_user_tag(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search)
 {
-       const char *value = NULL;
-       ESExpResult *r;
-       
-       r(printf("executing user-tag\n"));
-       
-       if (argc == 1)
-               value = camel_message_info_user_tag(search->current, argv[0]->value.string);
-       
-       r = e_sexp_result_new(f, ESEXP_RES_STRING);
-       r->value.string = g_strdup (value ? value : "");
-       
-       return r;
+               char *value = NULL;
+               ESExpResult *r;
+               char * tmp;
+
+               r(printf("executing user-tag\n"));
+
+               if (argc == 2) {
+
+                               if (search->current) {
+                                               /* FIXME: I am not sure if this will ever be executed */
+                                               abort ();
+                               } else {
+
+                                               tmp = g_strdup_printf ("%s%s", argv[0]->value.string, argv[1]->value.string);
+                                               value = camel_db_sqlize_string (tmp);
+                                               g_free (tmp);
+
+                                               if (g_str_has_suffix (search->query->str, " "))
+                                                               g_string_append_printf (search->query, "WHERE usertags = %s", value);
+                                               else {
+                                                               if (f->operators)
+                                                                               g_string_append_printf (search->query, " %s usertags = %s", (char *) (g_slist_nth_data (f->operators, 0)), value);
+                                                               else
+                                                                               g_string_append_printf (search->query, " OR usertags = %s", value);
+                                               }
+
+                                               camel_db_free_sqlized_string (value);
+
+                               }
+               } else
+                               g_warning ("Makes no sense to search for multiple things in user tag as it can hold only one string data : [%d] ", argc);
+
+               r = e_sexp_result_new(f, ESEXP_RES_BOOL);
+               r->value.bool = TRUE;
+
+               return r;
 }
 
 static ESExpResult *
@@ -1437,3 +1543,23 @@ search_uid(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSe
 
        return r;
 }
+
+static int 
+read_uid_callback (void * ref, int ncol, char ** cols, char **name)
+{
+       GPtrArray *matches;
+
+       matches = (GPtrArray *) ref;
+
+#if 0
+
+       int i;
+       for (i = 0; i < ncol; ++i) {
+               if ( !strcmp (name [i], "uid") ) 
+                       g_ptr_array_add (matches, g_strdup (cols [i]));
+       }
+#else
+       g_ptr_array_add (matches, (GFunc) camel_pstring_strdup (cols [0]));
+#endif
+       return 0;
+}
index 1ead29c..fd8d188 100644 (file)
@@ -48,7 +48,11 @@ struct _CamelFolderSearch {
        CamelFolder *folder;    /* folder for current search */
        GPtrArray *summary;     /* summary array for current search */
        GPtrArray *summary_set; /* subset of summary to actually include in search */
-       GHashTable *summary_hash; /* hashtable of summary items */
+
+       GString *query; /* shall contain the SQL quer that should be executed */
+
+// DEPRECATED  
+//     GHashTable *summary_hash; /* hashtable of summary items */
        CamelMessageInfo *current; /* current message info, when searching one by one */
        CamelMimeMessage *current_message; /* cache of current message, if required */
        CamelIndex *body_index;
index 15406e0..8bd3114 100644 (file)
@@ -34,6 +34,8 @@
 #include <errno.h>
 
 #include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n-lib.h>
 #include <glib/gstdio.h>
 
 #include <libedataserver/e-memory.h>
 #include "camel-stream-mem.h"
 #include "camel-stream-null.h"
 #include "camel-string-utils.h"
+#include "camel-store.h"
+#include "camel-vee-folder.h"
 
+/* To switch between e-memchunk and g-alloc */
+#define ALWAYS_ALLOC 1
+#define USE_GSLICE 1
+#define SUMMARY_CACHE_DROP 120
 static pthread_mutex_t info_lock = PTHREAD_MUTEX_INITIALIZER;
 
 /* this lock is ONLY for the standalone messageinfo stuff */
@@ -73,12 +81,17 @@ static pthread_mutex_t info_lock = PTHREAD_MUTEX_INITIALIZER;
 extern int strdup_count, malloc_count, free_count;
 #endif
 
-#define CAMEL_FOLDER_SUMMARY_VERSION (13)
+#define CAMEL_FOLDER_SUMMARY_VERSION (14)
 
 #define _PRIVATE(o) (((CamelFolderSummary *)(o))->priv)
 
 #define META_SUMMARY_SUFFIX_LEN 5 /* strlen("-meta") */
 
+#define EXTRACT_FIRST_STRING(val) len=strtoul (part, &part, 10); part++; val=g_strndup (part, len);
+#define EXTRACT_STRING(val) part++; len=strtoul (part, &part, 10); part++; val=g_strndup (part, len);
+#define EXTRACT_FIRST_DIGIT(val) val=strtoul (part, &part, 10);
+#define EXTRACT_DIGIT(val) part++; val=strtoul (part, &part, 10);
+
 /* trivial lists, just because ... */
 struct _node {
        struct _node *next;
@@ -92,6 +105,8 @@ static int summary_header_save(CamelFolderSummary *, FILE *);
 static int summary_meta_header_load(CamelFolderSummary *, FILE *);
 static int summary_meta_header_save(CamelFolderSummary *, FILE *);
 
+
+
 static CamelMessageInfo * message_info_new_from_header(CamelFolderSummary *, struct _camel_header_raw *);
 static CamelMessageInfo * message_info_new_from_parser(CamelFolderSummary *, CamelMimeParser *);
 static CamelMessageInfo * message_info_new_from_message(CamelFolderSummary *s, CamelMimeMessage *msg);
@@ -107,6 +122,9 @@ static CamelMessageContentInfo * content_info_load(CamelFolderSummary *, FILE *)
 static int                      content_info_save(CamelFolderSummary *, FILE *, CamelMessageContentInfo *);
 static void                     content_info_free(CamelFolderSummary *, CamelMessageContentInfo *);
 
+static int save_message_infos_to_db (CamelFolderSummary *s, CamelException *ex);
+static int camel_read_mir_callback (void * ref, int ncol, char ** cols, char ** name);
+
 static char *next_uid_string(CamelFolderSummary *s);
 
 static CamelMessageContentInfo * summary_build_content_info(CamelFolderSummary *s, CamelMessageInfo *msginfo, CamelMimeParser *mp);
@@ -117,6 +135,7 @@ static void camel_folder_summary_init       (CamelFolderSummary *obj);
 static void camel_folder_summary_finalize   (CamelObject *obj);
 
 static CamelObjectClass *camel_folder_summary_parent;
+static CamelMessageInfo * message_info_from_uid (CamelFolderSummary *s, const char *uid);
 
 static void
 camel_folder_summary_init (CamelFolderSummary *s)
@@ -142,8 +161,8 @@ camel_folder_summary_init (CamelFolderSummary *s)
        s->time = 0;
        s->nextuid = 1;
 
-       s->messages = g_ptr_array_new();
-       s->messages_uid = g_hash_table_new(g_str_hash, g_str_equal);
+       s->uids = g_ptr_array_new ();
+       s->loaded_infos = g_hash_table_new (g_str_hash, g_str_equal);
        
        p->summary_lock = g_mutex_new();
        p->io_lock = g_mutex_new();
@@ -157,6 +176,8 @@ camel_folder_summary_init (CamelFolderSummary *s)
           exceeding 20, has to override this value 
        */
        s->meta_summary->uid_len = 20;
+       s->cache_load_time = 0;
+       s->timeout_handle = 0;
 }
 
 static void free_o_name(void *key, void *value, void *data)
@@ -173,20 +194,25 @@ camel_folder_summary_finalize (CamelObject *obj)
 
        p = _PRIVATE(obj);
 
-       camel_folder_summary_clear(s);
-       g_ptr_array_free(s->messages, TRUE);
-       g_hash_table_destroy(s->messages_uid);
+       if (s->timeout_handle)
+               g_source_remove (s->timeout_handle);
+       //camel_folder_summary_clear(s);
+       g_ptr_array_foreach (s->uids, (GFunc) camel_pstring_free, NULL);
+       g_ptr_array_free (s->uids, TRUE);
+       g_hash_table_destroy (s->loaded_infos);
 
        g_hash_table_foreach(p->filter_charset, free_o_name, NULL);
        g_hash_table_destroy(p->filter_charset);
 
        g_free(s->summary_path);
 
+#ifndef ALWAYS_ALLOC   
        if (s->message_info_chunks)
                e_memchunk_destroy(s->message_info_chunks);
        if (s->content_info_chunks)
                e_memchunk_destroy(s->content_info_chunks);
-
+#endif
+       
        if (p->filter_index)
                camel_object_unref((CamelObject *)p->filter_index);
        if (p->filter_64)
@@ -329,7 +355,7 @@ camel_folder_summary_set_build_content(CamelFolderSummary *s, gboolean state)
 int
 camel_folder_summary_count(CamelFolderSummary *s)
 {
-       return s->messages->len;
+       return s->uids->len;
 }
 
 
@@ -346,18 +372,25 @@ camel_folder_summary_count(CamelFolderSummary *s)
  * Returns the summary item, or %NULL if @index is out of range
  **/
 CamelMessageInfo *
-camel_folder_summary_index(CamelFolderSummary *s, int i)
+camel_folder_summary_index (CamelFolderSummary *s, int i)
 {
        CamelMessageInfo *info = NULL;
 
        CAMEL_SUMMARY_LOCK(s, summary_lock);
        CAMEL_SUMMARY_LOCK(s, ref_lock);
 
-       if (i<s->messages->len)
-               info = g_ptr_array_index(s->messages, i);
+       if (i < s->uids->len) {
+               char *uid;
+               uid = g_ptr_array_index (s->uids, i);
 
-       if (info)
-               info->refcount++;
+               /* FIXME: Get exception from caller
+               and pass it on below */
+               
+               CAMEL_SUMMARY_UNLOCK(s, ref_lock);
+               CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+
+               return camel_folder_summary_uid (s, uid);
+       }
 
        CAMEL_SUMMARY_UNLOCK(s, ref_lock);
        CAMEL_SUMMARY_UNLOCK(s, summary_lock);
@@ -365,6 +398,35 @@ camel_folder_summary_index(CamelFolderSummary *s, int i)
        return info;
 }
 
+#warning "Implement - camel_folder_summary_uid_exist - directly through db than manual strcmp"
+
+/**
+ * camel_folder_summary_uid_from_index:
+ * @summary: a #CamelFolderSummary object
+ * @index: item index
+ * 
+ * Retrieve a summary item's uid  by index number.
+ *
+ * A newly allocated uid is returned, which must be
+ * free'd as appropriate.
+ * 
+ * Returns the summary item's uid , or %NULL if @index is out of range   
+ **/
+char *
+camel_folder_summary_uid_from_index (CamelFolderSummary *s, int i)
+{
+       char *uid=NULL;
+       CAMEL_SUMMARY_LOCK(s, summary_lock);
+
+       if (i<s->uids->len)
+               uid = g_strdup (g_ptr_array_index(s->uids, i));
+
+       CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+       
+       return uid;
+
+}
+
 
 /**
  * camel_folder_summary_array:
@@ -373,50 +435,94 @@ camel_folder_summary_index(CamelFolderSummary *s, int i)
  * Obtain a copy of the summary array.  This is done atomically,
  * so cannot contain empty entries.
  *
- * It must be freed using #camel_folder_summary_array_free.
+ * It must be freed using g_ptr_array_free
  *
- * Returns a #GPtrArray of #CamelMessageInfo items
+ * Returns a #GPtrArray of uids
  **/
 GPtrArray *
 camel_folder_summary_array(CamelFolderSummary *s)
 {
-       CamelMessageInfo *info;
        GPtrArray *res = g_ptr_array_new();
        int i;
        
        CAMEL_SUMMARY_LOCK(s, summary_lock);
-       CAMEL_SUMMARY_LOCK(s, ref_lock);
 
-       g_ptr_array_set_size(res, s->messages->len);
-       for (i=0;i<s->messages->len;i++) {
-               info = res->pdata[i] = g_ptr_array_index(s->messages, i);
-               info->refcount++;
-       }
+       g_ptr_array_set_size(res, s->uids->len);
+       for (i=0;i<s->uids->len;i++)
+               res->pdata[i] = (gpointer) camel_pstring_strdup ((char *)g_ptr_array_index(s->uids, i));
+       
 
-       CAMEL_SUMMARY_UNLOCK(s, ref_lock);
        CAMEL_SUMMARY_UNLOCK(s, summary_lock);
 
        return res;
 }
 
+struct _db_pass_data {
+       CamelFolderSummary *summary;
+       gboolean double_ref;
+       gboolean add; /* or just insert to hashtable */
+};
 
-/**
- * camel_folder_summary_array_free:
- * @summary: a #CamelFolderSummary object
- * @array: array of #CamelMessageInfo items as returned from #camel_folder_summary_array
- * 
- * Free the folder summary array.
- **/
-void
-camel_folder_summary_array_free(CamelFolderSummary *s, GPtrArray *array)
+static CamelMessageInfo *
+message_info_from_uid (CamelFolderSummary *s, const char *uid)
 {
-       int i;
+       CamelMessageInfo *info;
+       int ret;
+
+       CAMEL_SUMMARY_LOCK(s, summary_lock);
+       CAMEL_SUMMARY_LOCK(s, ref_lock);
+
+       info = g_hash_table_lookup (s->loaded_infos, uid);
+
+       if (!info) {
+               CamelDB *cdb;
+               CamelException ex;// May be this should come from the caller 
+               char *folder_name;
+               struct _db_pass_data data;
+               
+               d(printf ("\ncamel_folder_summary_uid called \n"));
+               camel_exception_init (&ex);
+               s->flags &= ~CAMEL_SUMMARY_DIRTY;
+
+               folder_name = s->folder->full_name;
+               cdb = s->folder->cdb;
+               
+               CAMEL_SUMMARY_UNLOCK(s, ref_lock);
+               CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+
+               data.summary = s;
+               data.double_ref = TRUE;
+               data.add = FALSE;
 
-       /* FIXME: do the locking around the whole lot to make it faster */
-       for (i=0;i<array->len;i++)
-               camel_message_info_free(array->pdata[i]);
+       
+               ret = camel_db_read_message_info_record_with_uid (cdb, folder_name, uid, &data, camel_read_mir_callback, &ex);
+               if (ret != 0) {
+                       // if (strcmp (folder_name, "UNMATCHED"))
+                       g_warning ("Unable to read uid %s from folder %s: %s", uid, folder_name, camel_exception_get_description(&ex));
+                       
+                       return NULL;
+               }
+               CAMEL_SUMMARY_LOCK(s, summary_lock);
+               CAMEL_SUMMARY_LOCK(s, ref_lock);
 
-       g_ptr_array_free(array, TRUE);
+               /* We would have double reffed at camel_read_mir_callback */
+               info = g_hash_table_lookup (s->loaded_infos, uid);
+               
+               if (!info) {
+                       /* Makes no sense now as the exception is local as of now. FIXME: Pass exception from caller */
+                       camel_exception_set (&ex, CAMEL_EXCEPTION_SYSTEM, _(g_strdup_printf ("no uid [%s] exists", uid)));
+                       // if (strcmp (folder_name, "UNMATCHED"))                       
+                       g_warning ("No uid[%s] exists in %s\n", uid, folder_name);
+                       camel_exception_clear (&ex);
+               }
+       } else
+               info->refcount++;
+
+       
+       CAMEL_SUMMARY_UNLOCK(s, ref_lock);
+       CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+
+       return info;
 }
 
 
@@ -433,25 +539,11 @@ camel_folder_summary_array_free(CamelFolderSummary *s, GPtrArray *array)
  * Returns the summary item, or %NULL if the uid @uid is not available
  **/
 CamelMessageInfo *
-camel_folder_summary_uid(CamelFolderSummary *s, const char *uid)
+camel_folder_summary_uid (CamelFolderSummary *s, const char *uid)
 {
-       CamelMessageInfo *info;
-
-       CAMEL_SUMMARY_LOCK(s, summary_lock);
-       CAMEL_SUMMARY_LOCK(s, ref_lock);
-
-       info = g_hash_table_lookup(s->messages_uid, uid);
-
-       if (info)
-               info->refcount++;
-
-       CAMEL_SUMMARY_UNLOCK(s, ref_lock);
-       CAMEL_SUMMARY_UNLOCK(s, summary_lock);
-
-       return info;
+       return ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->message_info_from_uid(s, uid);
 }
 
-
 /**
  * camel_folder_summary_next_uid:
  * @summary: a #CamelFolderSummary object
@@ -515,6 +607,38 @@ camel_folder_summary_next_uid_string(CamelFolderSummary *s)
        return ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->next_uid_string(s);
 }
 
+static CamelMessageContentInfo *
+perform_content_info_load_from_db (CamelFolderSummary *s, CamelMIRecord *mir)
+{
+       int i;
+       guint32 count;
+       CamelMessageContentInfo *ci, *pci;
+       char *part;
+       ci = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->content_info_from_db (s, mir);
+       if (ci == NULL)
+               return NULL;
+       part = mir->cinfo;
+       if (!part)
+               return ci;
+       if (*part == ' ') part++;
+       EXTRACT_DIGIT (count);
+
+       mir->cinfo = part;
+       for (i=0;i<count;i++) {
+               pci = perform_content_info_load_from_db (s, mir);
+               if (pci ) {
+                       my_list_append((struct _node **)&ci->childs, (struct _node *)pci);
+                       pci->parent = ci;
+               } else {
+                       d(fprintf (stderr, "Summary file format messed up?"));
+                       camel_folder_summary_content_info_free (s, ci);
+                       return NULL;
+               }
+       }
+       return ci;
+}
+
+
 /* loads the content descriptions, recursively */
 static CamelMessageContentInfo *
 perform_content_info_load(CamelFolderSummary *s, FILE *in)
@@ -546,6 +670,251 @@ perform_content_info_load(CamelFolderSummary *s, FILE *in)
        return ci;
 }
 
+static void
+append_changed_uids (char *key, CamelMessageInfoBase *info, GPtrArray *array)
+{
+       if (info->dirty || info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED)
+               g_ptr_array_add (array, (gpointer)camel_pstring_strdup((camel_message_info_uid(info))));
+}
+
+GPtrArray *
+camel_folder_summary_get_changed (CamelFolderSummary *s)
+{
+       GPtrArray *res = g_ptr_array_new();
+       
+       CAMEL_SUMMARY_LOCK (s, summary_lock);
+       g_hash_table_foreach (s->loaded_infos, (GHFunc) append_changed_uids, res);
+       CAMEL_SUMMARY_UNLOCK (s, summary_lock);
+
+       return res;
+}
+
+#warning "FIXME: I should have a better LRU algorithm "
+static gboolean
+remove_item (char *key, CamelMessageInfoBase *info, CamelFolderSummary *s)
+{
+       d(printf("%d(%d)\t", info->refcount, info->dirty)); //camel_message_info_dump (info);
+       CAMEL_SUMMARY_LOCK(info->summary, ref_lock);
+       if (info->refcount == 1 && !info->dirty && !(info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED)) {
+               CAMEL_SUMMARY_UNLOCK(info->summary, ref_lock);
+               /* Hackit so that hashtable isn;t corrupted. */
+               camel_pstring_free (info->uid);
+               info->uid = NULL;
+               /* Noone seems to need it. Why not free it then. */
+               camel_message_info_free (info);
+               return TRUE;
+       }
+       CAMEL_SUMMARY_UNLOCK(info->summary, ref_lock);  
+       return FALSE;
+}
+
+static gboolean      
+remove_cache (CamelFolderSummary *s)
+{
+       /* Attempt to release 2MB*/
+        sqlite3_release_memory(CAMEL_DB_FREE_CACHE_SIZE); 
+       
+       if (time(NULL) - s->cache_load_time < SUMMARY_CACHE_DROP)
+               return TRUE;
+       
+       printf("removing cache for  %s %d\n", s->folder->full_name, g_hash_table_size (s->loaded_infos));
+       #warning "hack. fix it"
+       CAMEL_SUMMARY_LOCK (s, summary_lock);
+       g_hash_table_foreach_remove  (s->loaded_infos, (GHRFunc) remove_item, s);
+       CAMEL_SUMMARY_UNLOCK (s, summary_lock);
+       printf("done .. now %d\n",g_hash_table_size (s->loaded_infos));
+
+       s->cache_load_time = time(NULL);
+       
+       return TRUE;
+}
+
+int
+camel_folder_summary_cache_size (CamelFolderSummary *s)
+{
+       #warning "this is a timely hack. fix it well"
+       if (!CAMEL_IS_VEE_FOLDER(s->folder))
+               return g_hash_table_size (s->loaded_infos);
+       else
+               return s->uids->len;
+}
+
+int
+camel_folder_summary_reload_from_db (CamelFolderSummary *s, CamelException *ex)
+{
+       CamelDB *cdb;
+       char *folder_name;
+       int ret = 0;
+       struct _db_pass_data data;
+       
+       #warning "baseclass this, and vfolders we may have to load better."
+       d(printf ("\ncamel_folder_summary_reload_from_db called \n"));
+
+       folder_name = s->folder->full_name;
+       cdb = s->folder->cdb;
+
+       /* FIXME FOR SANKAR: No need to pass the address of summary here. */
+       data.summary = s;
+       data.double_ref = FALSE;
+       data.add = FALSE;
+       ret = camel_db_read_message_info_records (cdb, folder_name, (gpointer)&data, camel_read_mir_callback, NULL);
+
+       s->cache_load_time = time (NULL);
+       return ret == 0 ? 0 : -1;
+}
+
+int
+camel_folder_summary_load_from_db (CamelFolderSummary *s, CamelException *ex)
+{
+       CamelDB *cdb;
+       char *folder_name;
+       int ret = 0;
+//     struct _db_pass_data data;
+       
+       d(printf ("\ncamel_folder_summary_load_from_db called \n"));
+       s->flags &= ~CAMEL_SUMMARY_DIRTY;
+
+       ret = camel_folder_summary_header_load_from_db (s, s->folder->parent_store, s->folder->full_name, ex);
+
+       if (ret)
+               return ret;
+
+       folder_name = s->folder->full_name;
+       cdb = s->folder->cdb;
+
+       ret = camel_db_get_folder_uids (cdb, folder_name, s->uids, ex);
+#if 0
+       /* FIXME FOR SANKAR: No need to pass the address of summary here. */
+       data.summary = s;
+       data.add = TRUE;
+       data.double_ref = FALSE;
+       ret = camel_db_read_message_info_records (cdb, folder_name, (gpointer) &data, camel_read_mir_callback, ex);
+#endif 
+       s->cache_load_time = time (NULL);
+       #warning "LRU please and not timeouts"
+       s->timeout_handle = g_timeout_add_seconds (SUMMARY_CACHE_DROP, (GSourceFunc) remove_cache, s);
+
+       return ret == 0 ? 0 : -1;
+}
+
+static void
+mir_from_cols (CamelMIRecord *mir, CamelFolderSummary *s, int ncol, char ** cols, char ** name)
+{
+       int i;
+       
+       for (i = 0; i < ncol; ++i) {
+
+               if ( !strcmp (name [i], "uid") ) 
+                       mir->uid = (char *) camel_pstring_strdup (cols [i]);
+               else if ( !strcmp (name [i], "flags") ) 
+                       mir->flags = cols [i] ? strtoul (cols [i], NULL, 10) : 0;
+               else if ( !strcmp (name [i], "read") ) 
+                       mir->read =  (cols [i]) ? ( ((strtoul (cols [i], NULL, 10)) ? TRUE : FALSE)) : FALSE;
+               else if ( !strcmp (name [i], "deleted") ) 
+                       mir->deleted = (cols [i]) ? ( ((strtoul (cols [i], NULL, 10)) ? TRUE : FALSE)) : FALSE;
+               else if ( !strcmp (name [i], "replied") ) 
+                       mir->replied = (cols [i]) ? ( ((strtoul (cols [i], NULL, 10)) ? TRUE : FALSE)) : FALSE;
+               else if ( !strcmp (name [i], "important") ) 
+                       mir->important = (cols [i]) ? ( ((strtoul (cols [i], NULL, 10)) ? TRUE : FALSE)) : FALSE;
+               else if ( !strcmp (name [i], "junk") ) 
+                       mir->junk = (cols [i]) ? ( ((strtoul (cols [i], NULL, 10)) ? TRUE : FALSE)) : FALSE;
+               else if ( !strcmp (name [i], "attachment") ) 
+                       mir->attachment = (cols [i]) ? ( ((strtoul (cols [i], NULL, 10)) ? TRUE : FALSE)) : FALSE;
+               else if ( !strcmp (name [i], "size") ) 
+                       mir->size =  cols [i] ? strtoul (cols [i], NULL, 10) : 0;
+               else if ( !strcmp (name [i], "dsent") ) 
+                       mir->dsent = cols [i] ? strtol (cols [i], NULL, 10) : 0;
+               else if ( !strcmp (name [i], "dreceived") ) 
+                       mir->dreceived = cols [i] ? strtol (cols [i], NULL, 10) : 0;
+               else if ( !strcmp (name [i], "subject") ) 
+                       mir->subject = (char *) camel_pstring_strdup (cols [i]);
+               else if ( !strcmp (name [i], "mail_from") ) 
+                       mir->from = (char *) camel_pstring_strdup (cols [i]);
+               else if ( !strcmp (name [i], "mail_to") ) 
+                       mir->to = (char *) camel_pstring_strdup (cols [i]);
+               else if ( !strcmp (name [i], "mail_cc") ) 
+                       mir->cc = (char *) camel_pstring_strdup(cols [i]);
+               else if ( !strcmp (name [i], "mlist") ) 
+                       mir->mlist = (char *) camel_pstring_strdup (cols [i]);
+               else if ( !strcmp (name [i], "followup_flag") ) 
+                       mir->followup_flag = (char *) camel_pstring_strdup(cols [i]);
+               else if ( !strcmp (name [i], "followup_completed_on") ) 
+                       mir->followup_completed_on = (char *) camel_pstring_strdup(cols [i]);
+               else if ( !strcmp (name [i], "followup_due_by") ) 
+                       mir->followup_due_by = (char *) camel_pstring_strdup(cols [i]);
+               else if ( !strcmp (name [i], "part") ) 
+                       mir->part = g_strdup (cols [i]);
+               else if ( !strcmp (name [i], "labels") ) 
+                       mir->labels = g_strdup (cols [i]);
+               else if ( !strcmp (name [i], "usertags") ) 
+                       mir->usertags = g_strdup (cols [i]);
+               else if ( !strcmp (name [i], "cinfo") ) 
+                       mir->cinfo = g_strdup(cols [i]);
+               else if ( !strcmp (name [i], "bdata") ) 
+                       mir->bdata = g_strdup(cols [i]);
+
+       }       
+}
+
+static int 
+camel_read_mir_callback (void * ref, int ncol, char ** cols, char ** name)
+{
+       struct _db_pass_data *data = (struct _db_pass_data *) ref;
+       CamelFolderSummary *s = data->summary;
+       CamelMIRecord *mir;
+       CamelMessageInfo *info;
+       int ret = 0;
+
+       mir = g_new0 (CamelMIRecord , 1);
+       mir_from_cols (mir, s, ncol, cols, name);
+       
+       CAMEL_SUMMARY_LOCK (s, summary_lock);
+       if (g_hash_table_lookup (s->loaded_infos, mir->uid)) {
+               /* Unlock and better return*/
+               CAMEL_SUMMARY_UNLOCK (s, summary_lock);
+               camel_db_camel_mir_free (mir);
+               return ret;
+       }
+       CAMEL_SUMMARY_UNLOCK (s, summary_lock);
+
+
+       info = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->message_info_from_db (s, mir);
+
+       if (info) {
+
+               if (s->build_content) {
+                       char *tmp;
+                       tmp = mir->cinfo;
+                       /* FIXME: this should be done differently, how i don't know */
+                       ((CamelMessageInfoBase *)info)->content = perform_content_info_load_from_db (s, mir);
+                       if (((CamelMessageInfoBase *)info)->content == NULL) {
+                               camel_message_info_free(info);
+                               info = NULL;
+                       } 
+                       mir->cinfo = tmp;
+               }
+
+               if (data->double_ref)
+                       /* double reffing, because, at times frees before, I could read it. so we dont ref and give it again, just use it */            
+                       camel_message_info_ref(info);
+               
+               /* Just now we are reading from the DB, it can't be dirty. */
+               ((CamelMessageInfoBase *)info)->dirty = FALSE;
+               //((CamelMessageInfoBase *)info)->flags &= ~CAMEL_MESSAGE_DB_DIRTY;             
+               if (data->add)
+                       camel_folder_summary_add (s, info);
+               else
+                       camel_folder_summary_insert (s, info, TRUE);
+
+       } else {
+               g_warning ("Loading messageinfo from db failed");
+               ret = -1;
+       }
+
+       camel_db_camel_mir_free (mir);
+
+       return ret;
+}
 
 /**
  * camel_folder_summary_load:
@@ -558,10 +927,13 @@ perform_content_info_load(CamelFolderSummary *s, FILE *in)
 int
 camel_folder_summary_load(CamelFolderSummary *s)
 {
+#if 0
        FILE *in;
        int i;
        CamelMessageInfo *mi;
 
+       d(g_print ("\ncamel_folder_summary_load from FLAT FILE called \n"));
+
        if (s->summary_path == NULL ||
            s->meta_summary->path == NULL)
                return 0;
@@ -590,7 +962,7 @@ camel_folder_summary_load(CamelFolderSummary *s)
                        }
                }
 
-               camel_folder_summary_add(s, mi);
+               camel_folder_summary_add (s, mi);
        }
 
        CAMEL_SUMMARY_UNLOCK(s, io_lock);
@@ -609,8 +981,32 @@ error:
        CAMEL_SUMMARY_UNLOCK(s, io_lock);
        fclose (in);
        s->flags |= ~CAMEL_SUMMARY_DIRTY;
-
+#endif 
        return -1;
+
+}
+
+/* saves the content descriptions, recursively */
+static int
+perform_content_info_save_to_db (CamelFolderSummary *s, CamelMessageContentInfo *ci, CamelMIRecord *record)
+{
+       CamelMessageContentInfo *part;
+       char *oldr;
+       if (((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS (s)))->content_info_to_db (s, ci, record) == -1)
+               return -1;
+       
+       oldr = record->cinfo;
+       record->cinfo = g_strdup_printf ("%s %d", oldr, my_list_size ((struct _node **)&ci->childs));
+       g_free (oldr);
+
+       part = ci->childs;
+       while (part) {
+               if (perform_content_info_save_to_db (s, part, record) == -1)
+                       return -1;
+               part = part->next;
+       }
+
+       return 0;
 }
 
 /* saves the content descriptions, recursively */
@@ -635,6 +1031,97 @@ perform_content_info_save(CamelFolderSummary *s, FILE *out, CamelMessageContentI
        return 0;
 }
 
+static void
+save_to_db_cb (gpointer key, gpointer value, gpointer data)
+{
+       CamelException *ex = (CamelException *)data;
+       CamelMessageInfoBase *mi = (CamelMessageInfoBase *)value;       
+       CamelFolderSummary *s = (CamelFolderSummary *)mi->summary;
+       char *folder_name = s->folder->full_name;
+       CamelDB *cdb = s->folder->cdb;
+       CamelMIRecord *mir;
+
+       if (!mi->dirty)
+               return;
+
+       mir = ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->message_info_to_db (s, (CamelMessageInfo *)mi);
+       
+       if (mir && s->build_content) {
+               if (perform_content_info_save_to_db (s, ((CamelMessageInfoBase *)mi)->content, mir) == -1) {
+                       g_warning ("unable to save mir+cinfo for uid: %s\n", mir->uid);
+                       camel_db_camel_mir_free (mir);
+                       /* FIXME: Add exception here */
+                       return;
+               }
+       }
+
+       if (camel_db_write_message_info_record (cdb, folder_name, mir, ex) != 0) {
+               camel_db_camel_mir_free (mir);
+               return;
+       }
+
+       /* Reset the flags */
+       mi->dirty = FALSE;
+       
+       camel_db_camel_mir_free (mir);  
+}
+
+static int
+save_message_infos_to_db (CamelFolderSummary *s, CamelException *ex)
+{
+       CamelDB *cdb = s->folder->cdb;
+       char *folder_name;
+
+       folder_name = s->folder->full_name;
+       if (camel_db_prepare_message_info_table (cdb, folder_name, ex) != 0) {
+               return -1;
+       }
+       CAMEL_SUMMARY_LOCK(s, summary_lock);
+       /* Push MessageInfo-es */
+       g_hash_table_foreach (s->loaded_infos, save_to_db_cb, ex);
+       CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+#warning "make sure we free the message infos that are loaded are freed if not used anymore or should we leave that to the timer? "
+       
+       return 0;
+}
+
+int
+camel_folder_summary_save_to_db (CamelFolderSummary *s, CamelException *ex)
+{
+       CamelDB *cdb = s->folder->cdb;
+       CamelFIRecord *record;
+       int ret;
+
+       d(printf ("\ncamel_folder_summary_save_to_db called \n"));
+
+       camel_db_begin_transaction (cdb, ex);
+
+       ret = save_message_infos_to_db (s, ex);
+
+       if (ret != 0) {
+               camel_db_abort_transaction (cdb, ex);
+               return -1;
+       }
+
+
+       record = (((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->summary_header_to_db (s, ex));
+       if (!record) {
+               camel_db_abort_transaction (cdb, ex);
+               return -1;
+       }
+
+       ret = camel_db_write_folder_info_record (cdb, record, ex);
+       g_free (record);
+
+       if (ret != 0) {
+               camel_db_abort_transaction (cdb, ex);
+               return -1;
+       }
+
+       camel_db_end_transaction (cdb, ex);
+
+       return ret;
+}
 
 /**
  * camel_folder_summary_save:
@@ -648,6 +1135,7 @@ perform_content_info_save(CamelFolderSummary *s, FILE *out, CamelMessageContentI
 int
 camel_folder_summary_save(CamelFolderSummary *s)
 {
+#if 0
        FILE *out;
        FILE *out_meta;
        int fd, i, fd_meta;
@@ -773,10 +1261,39 @@ exception:
        g_unlink (path);
        g_unlink (path_meta);
        errno = i;
-
+#endif
        return -1;
 }
 
+int
+camel_folder_summary_header_load_from_db (CamelFolderSummary *s, CamelStore *store, const char *folder_name, CamelException *ex)
+{
+       CamelDB *cdb;
+       CamelFIRecord *record;
+       int ret = 0;
+
+       d(printf ("\ncamel_folder_summary_load_from_db called \n"));
+       s->flags &= ~CAMEL_SUMMARY_DIRTY;
+
+       cdb = store->cdb;
+
+       record = g_new0 (CamelFIRecord, 1);
+       camel_db_read_folder_info_record (cdb, folder_name, &record, ex);
+
+       if (record) {
+               if ( ((CamelFolderSummaryClass *)(CAMEL_OBJECT_GET_CLASS(s)))->summary_header_from_db (s, record) == -1)
+                       ret = -1;
+       } else {
+               ret = -1;
+       }
+
+       g_free (record->folder_name);
+       #warning "Crashes, take care"
+       //g_free (record->bdata); 
+       g_free (record);
+
+       return ret;
+}
 
 /**
  * camel_folder_summary_header_load:
@@ -791,9 +1308,11 @@ exception:
 int
 camel_folder_summary_header_load(CamelFolderSummary *s)
 {
+       int ret=-1;     
+#if 0  
        FILE *in;
        FILE *in_meta;
-       int ret;
+
 
        if (s->summary_path == NULL ||
            s->meta_summary->path == NULL)
@@ -817,6 +1336,7 @@ camel_folder_summary_header_load(CamelFolderSummary *s)
        fclose(in);
        fclose(in_meta);
        s->flags &= ~CAMEL_SUMMARY_DIRTY;
+#endif 
        return ret;
 }
 
@@ -829,21 +1349,21 @@ summary_assign_uid(CamelFolderSummary *s, CamelMessageInfo *info)
        uid = camel_message_info_uid (info);
 
        if (uid == NULL || uid[0] == 0) {
-               g_free (info->uid);
-               uid = info->uid = camel_folder_summary_next_uid_string(s);
+               camel_pstring_free (info->uid);
+               uid = info->uid = (char *)camel_pstring_add (camel_folder_summary_next_uid_string(s), TRUE);
        }
 
        CAMEL_SUMMARY_LOCK(s, summary_lock);
 
-       while ((mi = g_hash_table_lookup(s->messages_uid, uid))) {
+       while ((mi = g_hash_table_lookup(s->loaded_infos, uid))) {
                CAMEL_SUMMARY_UNLOCK(s, summary_lock);
 
                if (mi == info)
                        return 0;
 
-               d(printf ("Trying to insert message with clashing uid (%s).  new uid re-assigned", camel_message_info_uid(info)));
+               d(printf ("Trying to insert message with clashing uid (%s).  new uid re-assigned", camel_message_info_uid (info)));
 
-               g_free(info->uid);
+               camel_pstring_free (info->uid);
                uid = info->uid = camel_folder_summary_next_uid_string(s);
 
                camel_message_info_set_flags(info, CAMEL_MESSAGE_FOLDER_FLAGGED, CAMEL_MESSAGE_FOLDER_FLAGGED);
@@ -857,28 +1377,57 @@ summary_assign_uid(CamelFolderSummary *s, CamelMessageInfo *info)
 }
 
 
-/**
- * camel_folder_summary_add:
- * @summary: a #CamelFolderSummary object
- * @info: a #CamelMessageInfo
- * 
- * Adds a new @info record to the summary.  If @info->uid is %NULL,
- * then a new uid is automatically re-assigned by calling
- * #camel_folder_summary_next_uid_string.
- *
- * The @info record should have been generated by calling one of the
- * info_new_*() functions, as it will be free'd based on the summary
- * class.  And MUST NOT be allocated directly using malloc.
- **/
+/**
+ * camel_folder_summary_add:
+ * @summary: a #CamelFolderSummary object
+ * @info: a #CamelMessageInfo
+ * 
+ * Adds a new @info record to the summary.  If @info->uid is %NULL,
+ * then a new uid is automatically re-assigned by calling
+ * #camel_folder_summary_next_uid_string.
+ *
+ * The @info record should have been generated by calling one of the
+ * info_new_*() functions, as it will be free'd based on the summary
+ * class.  And MUST NOT be allocated directly using malloc.
+ **/
+void
+camel_folder_summary_add (CamelFolderSummary *s, CamelMessageInfo *info)
+{
+       if (info == NULL)
+               return;
+
+       
+       if (summary_assign_uid(s, info) == 0)
+               return;
+       
+       CAMEL_SUMMARY_LOCK(s, summary_lock);
+
+/* unnecessary for pooled vectors */
+#ifdef DOESTRV
+       /* this is vitally important, and also if this is ever modified, then
+          the hash table needs to be resynced */
+       info->strings = e_strv_pack(info->strings);
+#endif
+
+       /* Summary always holds a ref for the loaded infos */
+       //camel_message_info_ref(info); //FIXME: Check how things are loaded.
+       #warning "FIXME: SHould we ref it or redesign it later on"
+       /* The uid array should have its own memory. We will unload the infos when not reqd.*/
+       g_ptr_array_add (s->uids, (gpointer) camel_pstring_strdup((camel_message_info_uid(info))));
+       
+       g_hash_table_insert (s->loaded_infos, (gpointer) camel_message_info_uid (info), info);
+       s->flags |= CAMEL_SUMMARY_DIRTY;
+
+       CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+}
+
+
 void
-camel_folder_summary_add(CamelFolderSummary *s, CamelMessageInfo *info)
+camel_folder_summary_insert (CamelFolderSummary *s, CamelMessageInfo *info, gboolean load)
 {
        if (info == NULL)
                return;
 
-       if (summary_assign_uid(s, info) == 0)
-               return;
-
        CAMEL_SUMMARY_LOCK(s, summary_lock);
 
 /* unnecessary for pooled vectors */
@@ -888,11 +1437,18 @@ camel_folder_summary_add(CamelFolderSummary *s, CamelMessageInfo *info)
        info->strings = e_strv_pack(info->strings);
 #endif
 
-       g_ptr_array_add(s->messages, info);
-       g_hash_table_insert(s->messages_uid, (char *)camel_message_info_uid(info), info);
-       s->flags |= CAMEL_SUMMARY_DIRTY;
+       /* Summary always holds a ref for the loaded infos */
+       //camel_message_info_ref(info); //FIXME: Check how things are loaded.
+       #warning "FIXME: SHould we ref it or redesign it later on"
+       /* The uid array should have its own memory. We will unload the infos when not reqd.*/
+       if (!load)
+               g_ptr_array_add (s->uids, (char *) camel_pstring_strdup(camel_message_info_uid(info)));
+       
+       g_hash_table_insert (s->loaded_infos, (char *) camel_message_info_uid (info), info);
+       if (!load)
+               s->flags |= CAMEL_SUMMARY_DIRTY;
 
-       CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+       CAMEL_SUMMARY_UNLOCK(s, summary_lock);  
 }
 
 
@@ -914,7 +1470,7 @@ camel_folder_summary_add_from_header(CamelFolderSummary *s, struct _camel_header
 {
        CamelMessageInfo *info = camel_folder_summary_info_new_from_header(s, h);
 
-       camel_folder_summary_add(s, info);
+       camel_folder_summary_add (s, info);
 
        return info;
 }
@@ -943,7 +1499,7 @@ camel_folder_summary_add_from_parser(CamelFolderSummary *s, CamelMimeParser *mp)
 
        info = camel_folder_summary_info_new_from_parser(s, mp);
 
-       camel_folder_summary_add(s, info);
+       camel_folder_summary_add (s, info);
 
        return info;
 }
@@ -959,11 +1515,11 @@ camel_folder_summary_add_from_parser(CamelFolderSummary *s, CamelMimeParser *mp)
  * Returns the newly added record
  **/
 CamelMessageInfo *
-camel_folder_summary_add_from_message(CamelFolderSummary *s, CamelMimeMessage *msg)
+camel_folder_summary_add_from_message (CamelFolderSummary *s, CamelMimeMessage *msg)
 {
        CamelMessageInfo *info = camel_folder_summary_info_new_from_message(s, msg);
 
-       camel_folder_summary_add(s, info);
+       camel_folder_summary_add (s, info);
 
        return info;
 }
@@ -1149,7 +1705,6 @@ camel_folder_summary_touch(CamelFolderSummary *s)
        CAMEL_SUMMARY_UNLOCK(s, summary_lock);
 }
 
-
 /**
  * camel_folder_summary_clear:
  * @summary: a #CamelFolderSummary object
@@ -1159,6 +1714,7 @@ camel_folder_summary_touch(CamelFolderSummary *s)
 void
 camel_folder_summary_clear(CamelFolderSummary *s)
 {
+#if 0
        int i;
 
        CAMEL_SUMMARY_LOCK(s, summary_lock);
@@ -1176,8 +1732,74 @@ camel_folder_summary_clear(CamelFolderSummary *s)
        s->flags |= CAMEL_SUMMARY_DIRTY;
        s->meta_summary->msg_expunged = TRUE;
        CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+#endif 
+}
+
+/* FIXME: This is non-sense. Neither an exception is passed,
+nor a value returned. How is the caller supposed to know, 
+whether the operation is succesful */
+
+void
+camel_folder_summary_clear_db (CamelFolderSummary *s)
+{
+       CamelDB *cdb;
+       char *folder_name;
+
+       d(printf ("\ncamel_folder_summary_load_from_db called \n"));
+       s->flags &= ~CAMEL_SUMMARY_DIRTY;
+
+       folder_name = s->folder->full_name;
+       cdb = s->folder->cdb;
+
+       CAMEL_SUMMARY_LOCK(s, summary_lock);
+       if (camel_folder_summary_count(s) == 0) {
+               CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+               return;
+       }
+
+
+       camel_db_clear_folder_summary (cdb, folder_name, NULL);
+       g_ptr_array_foreach (s->uids, (GFunc) camel_pstring_free, NULL);
+       g_ptr_array_free (s->uids, TRUE);
+       s->uids = g_ptr_array_new ();
+
+       g_hash_table_destroy(s->loaded_infos);
+       s->loaded_infos = g_hash_table_new(g_str_hash, g_str_equal);
+
+       s->flags |= CAMEL_SUMMARY_DIRTY;
+       CAMEL_SUMMARY_UNLOCK(s, summary_lock);
 }
 
+static void
+summary_remove_uid (CamelFolderSummary *s, const char *uid)
+{
+       int i;
+       CamelDB *cdb;
+       CamelException ex;// May be this should come from the caller 
+       char *folder_name;
+
+       d(printf ("\nsummary_remove_uid called \n"));
+       camel_exception_init (&ex);
+
+       folder_name = s->folder->full_name;
+       cdb = s->folder->cdb;
+
+       if (camel_db_delete_uid (cdb, folder_name, uid, &ex) != 0)
+               return ;
+
+       /* This could be slower, but no otherway really. FIXME: Callers have to effective and shouldn't call it recursively. */
+       for (i=0; i<s->uids->len; i++) {
+               if (strcmp(s->uids->pdata[i], uid) == 0) {
+                       /* FIXME: Does using fast remove affect anything ? */
+                       g_ptr_array_remove_index(s->uids, i);
+                       camel_pstring_free (uid);
+                       break;
+               }
+
+       }
+
+       return ;
+}
 
 /**
  * camel_folder_summary_remove:
@@ -1187,11 +1809,14 @@ camel_folder_summary_clear(CamelFolderSummary *s)
  * Remove a specific @info record from the summary.
  **/
 void
-camel_folder_summary_remove(CamelFolderSummary *s, CamelMessageInfo *info)
+camel_folder_summary_remove (CamelFolderSummary *s, CamelMessageInfo *info)
 {
        CAMEL_SUMMARY_LOCK(s, summary_lock);
-       g_hash_table_remove(s->messages_uid, camel_message_info_uid(info));
-       g_ptr_array_remove(s->messages, info);
+
+       g_hash_table_remove (s->loaded_infos, camel_message_info_uid(info));    
+       summary_remove_uid (s, camel_message_info_uid(info));
+
+       
        s->flags |= CAMEL_SUMMARY_DIRTY;
        s->meta_summary->msg_expunged = TRUE;
        CAMEL_SUMMARY_UNLOCK(s, summary_lock);
@@ -1215,7 +1840,7 @@ camel_folder_summary_remove_uid(CamelFolderSummary *s, const char *uid)
 
        CAMEL_SUMMARY_LOCK(s, summary_lock);
        CAMEL_SUMMARY_LOCK(s, ref_lock);
-        if (g_hash_table_lookup_extended(s->messages_uid, uid, (void *)&olduid, (void *)&oldinfo)) {
+        if (g_hash_table_lookup_extended(s->loaded_infos, uid, (void *)&olduid, (void *)&oldinfo)) {
                /* make sure it doesn't vanish while we're removing it */
                oldinfo->refcount++;
                CAMEL_SUMMARY_UNLOCK(s, ref_lock);
@@ -1223,11 +1848,42 @@ camel_folder_summary_remove_uid(CamelFolderSummary *s, const char *uid)
                camel_folder_summary_remove(s, oldinfo);
                camel_message_info_free(oldinfo);
        } else {
+               /* Info isn't loaded into the memory. We must just remove the UID*/
+               summary_remove_uid (s, uid);
                CAMEL_SUMMARY_UNLOCK(s, ref_lock);
                CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+
+               
        }
 }
 
+void
+camel_folder_summary_remove_index_fast (CamelFolderSummary *s, int index)
+{
+       const char *uid = s->uids->pdata[index];
+        CamelMessageInfo *oldinfo;
+        char *olduid;
+       
+       CAMEL_SUMMARY_LOCK(s, summary_lock);
+       CAMEL_SUMMARY_LOCK(s, ref_lock);
+
+       if (g_hash_table_lookup_extended(s->loaded_infos, uid, (void *)&olduid, (void *)&oldinfo)) {
+               /* make sure it doesn't vanish while we're removing it */
+               g_hash_table_remove (s->loaded_infos, uid);
+               camel_pstring_free (uid);
+               g_ptr_array_remove_index(s->uids, index);
+               CAMEL_SUMMARY_UNLOCK(s, ref_lock);
+               CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+               camel_message_info_free(oldinfo);
+       } else {
+               /* Info isn't loaded into the memory. We must just remove the UID*/
+               g_ptr_array_remove_index(s->uids, index);
+               CAMEL_SUMMARY_UNLOCK(s, ref_lock);
+               CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+
+               
+       }       
+}
 
 /**
  * camel_folder_summary_remove_index:
@@ -1239,19 +1895,9 @@ camel_folder_summary_remove_uid(CamelFolderSummary *s, const char *uid)
 void
 camel_folder_summary_remove_index(CamelFolderSummary *s, int index)
 {
-       CAMEL_SUMMARY_LOCK(s, summary_lock);
-       if (index < s->messages->len) {
-               CamelMessageInfo *info = s->messages->pdata[index];
-
-               g_hash_table_remove(s->messages_uid, camel_message_info_uid(info));
-               g_ptr_array_remove_index(s->messages, index);
-               s->flags |= CAMEL_SUMMARY_DIRTY;
+       const char *uid = s->uids->pdata[index];
 
-               CAMEL_SUMMARY_UNLOCK(s, summary_lock);
-               camel_message_info_free(info);
-       } else {
-               CAMEL_SUMMARY_UNLOCK(s, summary_lock);
-       }
+       camel_folder_summary_remove_uid (s, uid);
 }
 
 
@@ -1264,35 +1910,49 @@ camel_folder_summary_remove_index(CamelFolderSummary *s, int index)
  * Removes an indexed range of info records.
  **/
 void
-camel_folder_summary_remove_range(CamelFolderSummary *s, int start, int end)
+camel_folder_summary_remove_range (CamelFolderSummary *s, int start, int end)
 {
+       d(g_print ("\ncamel_folder_summary_remove_range called \n"));
        if (end < start)
                return;
 
        CAMEL_SUMMARY_LOCK(s, summary_lock);
-       if (start < s->messages->len) {
-               CamelMessageInfo **infos;
+
+       if (start < s->uids->len) {
+
                int i;
+               CamelDB *cdb;
+               CamelException ex;// May be this should come from the caller 
+               char *folder_name;
+               GSList *uids = NULL;
+
+               end = MIN(end+1, s->uids->len);
 
-               end = MIN(end+1, s->messages->len);
-               infos = g_malloc((end-start)*sizeof(infos[0]));
+               for (i = start; i < end; i++) {
+                       const char *uid = s->uids->pdata[i];
 
-               for (i=start;i<end;i++) {
-                       CamelMessageInfo *info = s->messages->pdata[i];
+                       uids = g_slist_prepend (uids, (gpointer) uid);
 
-                       infos[i-start] = info;
-                       g_hash_table_remove(s->messages_uid, camel_message_info_uid(info));
+                       g_hash_table_remove(s->loaded_infos, uid);
                }
+               camel_exception_init (&ex);
+
+               folder_name = s->folder->full_name;
+               cdb = s->folder->cdb;
+
+               #warning "lifecycle of infos should be checked. Add should add to db and del should del to db. Sync only the changes at interval and remove those full sync on folder switch"
+               camel_db_delete_uids (cdb, folder_name, uids, &ex);
+
+               g_slist_foreach (uids, (GFunc) camel_pstring_free, NULL);
+               g_slist_free (uids);
+
+               memmove(s->uids->pdata+start, s->uids->pdata+end, (s->uids->len-end)*sizeof(s->uids->pdata[0]));
+               g_ptr_array_set_size(s->uids, s->uids->len - (end - start));
 
-               memmove(s->messages->pdata+start, s->messages->pdata+end, (s->messages->len-end)*sizeof(s->messages->pdata[0]));
-               g_ptr_array_set_size(s->messages, s->messages->len - (end - start));
                s->flags |= CAMEL_SUMMARY_DIRTY;
 
                CAMEL_SUMMARY_UNLOCK(s, summary_lock);
 
-               for (i=start;i<end;i++)
-                       camel_message_info_free(infos[i-start]);
-               g_free(infos);
        } else {
                CAMEL_SUMMARY_UNLOCK(s, summary_lock);
        }
@@ -1490,14 +2150,49 @@ summary_meta_header_load(CamelFolderSummary *s, FILE *in)
        io(printf("Loading meta-header\n"));
 
        if (camel_file_util_decode_uint32(in, &s->meta_summary->major) == -1
-           || camel_file_util_decode_uint32(in, &s->meta_summary->minor) == -1
-           || camel_file_util_decode_uint32(in, &s->meta_summary->uid_len) == -1) {
+           || camel_file_util_decode_uint32(in, &s->meta_summary->minor) == -1     || camel_file_util_decode_uint32(in, &s->meta_summary->uid_len) == -1) {
                return -1;
        }
        
        return 0;
 }
 
+static int
+summary_header_from_db (CamelFolderSummary *s, CamelFIRecord *record)
+{
+       io(printf("Loading header from db \n"));
+       
+       s->version = record->version;
+
+       /* We may not worry, as we are setting a new standard here */
+#if 0  
+       /* Legacy version check, before version 12 we have no upgrade knowledge */
+       if ((s->version > 0xff) && (s->version & 0xff) < 12) {
+               io(printf ("Summary header version mismatch"));
+               errno = EINVAL;
+               return -1;
+       }
+
+       if (!(s->version < 0x100 && s->version >= 13))
+               io(printf("Loading legacy summary\n"));
+       else
+               io(printf("loading new-format summary\n"));
+#endif
+       
+       s->flags = record->flags;
+       s->nextuid = record->nextuid;
+       s->time = record->time;
+       s->saved_count = record->saved_count;
+
+       s->unread_count = record->unread_count;
+       s->deleted_count = record->deleted_count;
+       s->junk_count = record->junk_count;
+       s->visible_count = record->visible_count;
+       s->junk_not_deleted_count = record->jnd_count;
+       
+       return 0;       
+}
+
 static int
 summary_header_load(CamelFolderSummary *s, FILE *in)
 {
@@ -1542,6 +2237,43 @@ summary_header_load(CamelFolderSummary *s, FILE *in)
        return 0;
 }
 
+static CamelFIRecord *
+summary_header_to_db (CamelFolderSummary *s, CamelException *ex)
+{
+       CamelFIRecord * record = g_new0 (CamelFIRecord, 1);
+       CamelDB *db;
+
+       db = s->folder->cdb;
+       //char *table_name = safe_table (camel_file_util_safe_filename (s->folder->full_name));
+       char *table_name = s->folder->full_name;
+
+       io(printf("Savining header to db\n"));
+
+       record->folder_name = table_name;
+
+       /* we always write out the current version */
+       record->version = CAMEL_FOLDER_SUMMARY_VERSION;
+       record->flags  = s->flags;
+       record->nextuid = s->nextuid;
+       record->time = s->time;
+
+       /* FIXME: Ever heard of Constructors and initializing ? */
+       if (camel_db_count_total_message_info (db, table_name, &(record->saved_count), NULL))
+               record->saved_count = 0;
+       if (camel_db_count_junk_message_info (db, table_name, &(record->junk_count), NULL))
+               record->junk_count = 0;
+       if (camel_db_count_deleted_message_info (db, table_name, &(record->deleted_count), NULL))
+               record->deleted_count = 0;
+       if (camel_db_count_unread_message_info (db, table_name, &(record->unread_count), NULL))
+               record->unread_count = 0;
+       if (camel_db_count_visible_message_info (db, table_name, &(record->visible_count), NULL))
+               record->visible_count = 0;
+       if (camel_db_count_junk_not_deleted_message_info (db, table_name, &(record->jnd_count), NULL))
+               record->jnd_count = 0;
+       
+       return record;  
+}
+
 static int
 summary_header_save(CamelFolderSummary *s, FILE *out)
 {
@@ -1724,9 +2456,17 @@ camel_folder_summary_content_info_new(CamelFolderSummary *s)
        CamelMessageContentInfo *ci;
 
        CAMEL_SUMMARY_LOCK(s, alloc_lock);
+#ifndef ALWAYS_ALLOC   
        if (s->content_info_chunks == NULL)
                s->content_info_chunks = e_memchunk_new(32, s->content_info_size);
        ci = e_memchunk_alloc(s->content_info_chunks);
+#else  
+#ifndef USE_GSLICE
+       ci = g_malloc (s->content_info_size);
+#else  
+       ci = g_slice_alloc (s->content_info_size);
+#endif 
+#endif 
        CAMEL_SUMMARY_UNLOCK(s, alloc_lock);
 
        memset(ci, 0, s->content_info_size);
@@ -1842,6 +2582,81 @@ message_info_new_from_header(CamelFolderSummary *s, struct _camel_header_raw *h)
 }
 
 static CamelMessageInfo *
+message_info_from_db (CamelFolderSummary *s, CamelMIRecord *record)
+{
+       CamelMessageInfoBase *mi;
+       int i;
+       int count;
+       char *part, *label;
+       
+       mi = (CamelMessageInfoBase *)camel_message_info_new(s);
+
+       io(printf("Loading message info from db\n"));
+
+       mi->flags = record->flags;
+       mi->size = record->size;
+       mi->date_sent = record->dsent;
+       mi->date_received = record->dreceived;
+
+       mi->uid = (char *) camel_pstring_strdup (record->uid);
+       mi->subject = (char *) camel_pstring_add (record->subject, FALSE);
+       mi->from = (char *) camel_pstring_add (record->from, FALSE);
+       mi->to = (char *) camel_pstring_add (record->to, FALSE);
+       mi->cc = (char *) camel_pstring_add (record->cc, FALSE);
+       mi->mlist = (char *) camel_pstring_add (record->mlist, FALSE);
+
+       /* Extract Message id & References */
+       mi->content = NULL;
+       part = record->part;
+       if (part) {
+               EXTRACT_FIRST_DIGIT (mi->message_id.id.part.hi)
+               EXTRACT_DIGIT (mi->message_id.id.part.lo)
+               EXTRACT_DIGIT (count)
+       
+               if (count > 0) {
+                       mi->references = g_malloc(sizeof(*mi->references) + ((count-1) * sizeof(mi->references->references[0])));
+                       mi->references->size = count;
+                       for (i=0;i<count;i++) {
+                               EXTRACT_DIGIT (mi->references->references[i].id.part.hi)
+                               EXTRACT_DIGIT (mi->references->references[i].id.part.lo)
+                       }
+               } else
+                       mi->references = NULL;
+               
+       }
+
+       /* Extract User flags/labels */
+       part = record->labels;
+       if (part) {
+               label = part;
+               for (i=0;part[i];i++) {
+
+                       if (part[i] == ' ') {
+                               part[i] = 0;
+                               camel_flag_set(&mi->user_flags, label, TRUE);
+                               label = &(part[i+1]);
+                       }
+               }
+               camel_flag_set(&mi->user_flags, label, TRUE);
+       }
+
+       /* Extract User tags */
+       part = record->usertags;
+       EXTRACT_FIRST_DIGIT (count)
+       for (i=0;i<count;i++) {
+               int len;
+               char *name, *value;
+               EXTRACT_STRING (name)
+               EXTRACT_STRING (value)
+               camel_tag_set(&mi->user_tags, name, value);
+               g_free(name);
+               g_free(value);
+       }       
+
+       return (CamelMessageInfo *) mi;
+}
+
+static CamelMessageInfo *
 message_info_load(CamelFolderSummary *s, FILE *in)
 {
        CamelMessageInfoBase *mi;
@@ -1940,6 +2755,84 @@ meta_message_info_save(CamelFolderSummary *s, FILE *out_meta, FILE *out, CamelMe
        return ferror(out);
 }
 
+
+static CamelMIRecord *
+message_info_to_db (CamelFolderSummary *s, CamelMessageInfo *info)
+{
+       CamelMIRecord *record = g_new0(CamelMIRecord, 1);
+       CamelMessageInfoBase *mi = (CamelMessageInfoBase *) info;
+       GString *tmp;
+       CamelFlag *flag;
+       CamelTag *tag;
+       int count, i;
+
+       /* Assume that we dont have to take care of DB Safeness. It will be done while doing the DB transaction */
+       record->uid = (char *) camel_pstring_strdup(camel_message_info_uid(mi));
+       record->flags = mi->flags;
+       
+       record->read =  ((mi->flags & (CAMEL_MESSAGE_SEEN|CAMEL_MESSAGE_DELETED|CAMEL_MESSAGE_JUNK)));
+       record->deleted = mi->flags & CAMEL_MESSAGE_DELETED;
+       record->replied = mi->flags & CAMEL_MESSAGE_ANSWERED;   
+       record->important = mi->flags & CAMEL_MESSAGE_FLAGGED;          
+       record->junk = mi->flags & CAMEL_MESSAGE_JUNK;
+       record->attachment = mi->flags & CAMEL_MESSAGE_ATTACHMENTS;
+       
+       record->size = mi->size;
+       record->dsent = mi->date_sent;
+       record->dreceived = mi->date_received;
+
+       record->subject = (char *) camel_pstring_strdup(camel_message_info_subject (mi));
+       record->from = (char *) camel_pstring_strdup(camel_message_info_from (mi));
+       record->to = (char *) camel_pstring_strdup(camel_message_info_to (mi));
+       record->cc = (char *) camel_pstring_strdup(camel_message_info_cc (mi));
+       record->mlist = (char *) camel_pstring_strdup(camel_message_info_mlist (mi));
+       
+       record->followup_flag = (char *) camel_pstring_strdup(camel_message_info_user_tag(info, "follow-up"));
+       record->followup_completed_on = (char *) camel_pstring_strdup(camel_message_info_user_tag(info, "completed-on"));
+       record->followup_due_by = (char *) camel_pstring_strdup(camel_message_info_user_tag(info, "due-by"));
+
+       tmp = g_string_new (NULL);
+       if (mi->references) {
+               g_string_append_printf (tmp, "%lu %lu %lu", (long unsigned)mi->message_id.id.part.hi, (long unsigned)mi->message_id.id.part.lo, (long unsigned)mi->references->size);
+               for (i=0;i<mi->references->size;i++) 
+                       g_string_append_printf (tmp, " %lu %lu", (long unsigned)mi->references->references[i].id.part.hi, (long unsigned)mi->references->references[i].id.part.lo);
+       } else {
+               g_string_append_printf (tmp, "%lu %lu %lu", (long unsigned)mi->message_id.id.part.hi, (long unsigned)mi->message_id.id.part.lo, (unsigned long) 0);
+       }
+       record->part = tmp->str;
+       g_string_free (tmp, FALSE);
+
+       tmp = g_string_new (NULL);
+       flag = mi->user_flags;
+       while (flag) {
+               g_string_append_printf (tmp, "%s ", flag->name);
+               flag = flag->next;
+       }
+
+       /* Strip off the last space */ 
+       if (tmp->len)
+               tmp->len--;
+       
+       record->labels = tmp->str;
+       g_string_free (tmp, FALSE);
+
+       tmp = g_string_new (NULL);      
+       count = camel_tag_list_size(&mi->user_tags);
+       g_string_append_printf (tmp, "%lu", (long unsigned)count);      
+       tag = mi->user_tags;
+       while (tag) {
+               /* FIXME: Should we handle empty tags? Can it be empty? If it potential crasher ahead*/
+               g_string_append_printf (tmp, " %lu-%s %lu-%s", (long unsigned)strlen(tag->name), tag->name, (long unsigned)strlen(tag->value), tag->value);             
+               tag = tag->next;
+       }
+       record->usertags = tmp->str;
+       g_string_free (tmp, FALSE);
+               
+
+       return record;
+}
+
+
 static int
 message_info_save(CamelFolderSummary *s, FILE *out, CamelMessageInfo *info)
 {
@@ -1999,8 +2892,11 @@ static void
 message_info_free(CamelFolderSummary *s, CamelMessageInfo *info)
 {
        CamelMessageInfoBase *mi = (CamelMessageInfoBase *)info;
-
-       g_free(mi->uid);
+       
+       if (mi->uid) {
+               g_hash_table_remove (s->loaded_infos, mi->uid);
+               camel_pstring_free(mi->uid);
+       } 
        camel_pstring_free(mi->subject);
        camel_pstring_free(mi->from);
        camel_pstring_free(mi->to);
@@ -2014,9 +2910,21 @@ message_info_free(CamelFolderSummary *s, CamelMessageInfo *info)
        
 
        if (s)
-               e_memchunk_free(s->message_info_chunks, mi);
+#ifndef ALWAYS_ALLOC
+               e_memchunk_free(s->message_info_chunks, mi);            
+#else
+#ifndef USE_GSLICE     
+               g_free(mi);
+#else          
+               g_slice_free1 (s->message_info_size, mi);
+#endif         
+#endif
        else
+#ifndef USE_GSLICE
                g_free(mi);
+#else          
+               g_slice_free (CamelMessageInfoBase, mi);
+#endif         
 }
 
 static CamelMessageContentInfo *
@@ -2037,6 +2945,56 @@ content_info_new_from_header(CamelFolderSummary *s, struct _camel_header_raw *h)
 }
 
 static CamelMessageContentInfo *
+content_info_from_db(CamelFolderSummary *s, CamelMIRecord *record)
+{
+       CamelMessageContentInfo *ci;
+       char *type, *subtype;
+       guint32 count, i;
+       CamelContentType *ct;
+       char *part = record->cinfo;
+       int len;
+
+       io(printf("Loading content info from db\n"));
+       
+       if (!part)
+               return NULL;
+       
+       ci = camel_folder_summary_content_info_new(s);
+       if (*part == ' ') part++; /* Move off the space in the record*/
+
+       EXTRACT_FIRST_STRING (type)
+       EXTRACT_STRING (subtype)
+       ct = camel_content_type_new(type, subtype);
+       g_free(type);           /* can this be removed? */
+       g_free(subtype);
+       EXTRACT_DIGIT (count)
+
+       for (i = 0; i < count; i++) {
+               char *name, *value;
+               EXTRACT_STRING (name)
+               EXTRACT_STRING (value)
+
+               camel_content_type_set_param(ct, name, value);
+               /* TODO: do this so we dont have to double alloc/free */
+               g_free(name);
+               g_free(value);
+       }
+       ci->type = ct;
+
+       #warning "move all these to camel pstring"
+       EXTRACT_STRING (ci->id);
+       EXTRACT_STRING (ci->description)
+       EXTRACT_STRING (ci->encoding)
+       EXTRACT_DIGIT (ci->size)
+
+       record->cinfo = part; /* Keep moving the cursor in the record */
+
+       ci->childs = NULL;
+
+       return ci;
+}
+
+static CamelMessageContentInfo *
 content_info_load(CamelFolderSummary *s, FILE *in)
 {
        CamelMessageContentInfo *ci;
@@ -2088,6 +3046,71 @@ content_info_load(CamelFolderSummary *s, FILE *in)
 }
 
 static int
+content_info_to_db(CamelFolderSummary *s, CamelMessageContentInfo *ci, CamelMIRecord *record)
+{
+       CamelContentType *ct;
+       struct _camel_header_param *hp;
+       GString *str = g_string_new (NULL);
+       char *oldr;
+       
+       io(printf("Saving content info to db\n"));
+
+       ct = ci->type;
+       if (ct) {
+               if (ct->type)
+                       g_string_append_printf (str, " %d-%s", strlen (ct->type), ct->type);
+               else 
+                       g_string_append_printf (str, " 0-");
+               if (ct->subtype)
+                       g_string_append_printf (str, " %d-%s", strlen (ct->subtype), ct->subtype);
+               else 
+                       g_string_append_printf (str, " 0-");
+               g_string_append_printf (str, " %d", my_list_size((struct _node **)&ct->params));
+               hp = ct->params;
+               while (hp) {
+                       if (hp->name)
+                               g_string_append_printf (str, " %d-%s", strlen(hp->name), hp->name);
+                       else 
+                               g_string_append_printf (str, " 0-");
+                       if (hp->value)
+                               g_string_append_printf (str, " %d-%s", strlen (hp->value), hp->value);
+                       else
+                               g_string_append_printf (str, " 0-");
+                       hp = hp->next;
+               }
+       } else {
+               g_string_append_printf (str, " %d-", 0);
+               g_string_append_printf (str, " %d-", 0);
+               g_string_append_printf (str, " %d", 0);
+       }
+
+       if (ci->id)
+               g_string_append_printf (str, " %d-%s", strlen (ci->id), ci->id);
+       else 
+               g_string_append_printf (str, " 0-");
+       if (ci->description)
+               g_string_append_printf (str, " %d-%s", strlen (ci->description), ci->description);
+       else
+               g_string_append_printf (str, " 0-");
+       if (ci->encoding)
+               g_string_append_printf (str, " %d-%s", strlen (ci->encoding), ci->encoding);
+       else
+               g_string_append_printf (str, " 0-");
+       g_string_append_printf (str, " %u", ci->size);
+
+       if (record->cinfo) {
+               oldr = record->cinfo;
+               record->cinfo = g_strconcat(oldr, str->str, NULL);
+               g_free (oldr); g_string_free (str, TRUE);
+       } else {
+               record->cinfo = str->str;
+               g_string_free (str, FALSE);
+       }
+
+       return 0;       
+}
+
+static int
 content_info_save(CamelFolderSummary *s, FILE *out, CamelMessageContentInfo *ci)
 {
        CamelContentType *ct;
@@ -2125,7 +3148,15 @@ content_info_free(CamelFolderSummary *s, CamelMessageContentInfo *ci)
        g_free(ci->id);
        g_free(ci->description);
        g_free(ci->encoding);
+#ifndef ALWAYS_ALLOC   
        e_memchunk_free(s->content_info_chunks, ci);
+#else
+#ifndef USE_GSLICE     
+       g_free(ci);
+#else  
+       g_slice_free1 (s->content_info_size, ci);
+#endif 
+#endif 
 }
 
 static char *
@@ -2416,6 +3447,9 @@ camel_flag_set(CamelFlag **list, const char *name, gboolean value)
 {
        CamelFlag *flag, *tmp;
 
+       if (!name)
+               return TRUE;
+
        /* this 'trick' works because flag->next is the first element */
        flag = (CamelFlag *)list;
        while (flag->next) {
@@ -2759,17 +3793,34 @@ camel_message_info_new (CamelFolderSummary *s)
 
        if (s) {
                CAMEL_SUMMARY_LOCK(s, alloc_lock);
+#ifndef ALWAYS_ALLOC           
                if (s->message_info_chunks == NULL)
                        s->message_info_chunks = e_memchunk_new(32, s->message_info_size);
                info = e_memchunk_alloc0(s->message_info_chunks);
+#else
+#ifndef USE_GSLICE             
+               info = g_malloc0(s->message_info_size);
+#else          
+               info = g_slice_alloc0 (s->message_info_size);
+#endif         
+#endif         
                CAMEL_SUMMARY_UNLOCK(s, alloc_lock);
        } else {
+#ifndef USE_GSLICE             
                info = g_malloc0(sizeof(CamelMessageInfoBase));
+#else          
+               info = g_slice_alloc0 (sizeof(CamelMessageInfoBase));
+#endif
+
+               
        }
 
        info->refcount = 1;
        info->summary = s;
 
+       /* We assume that mi is always dirty unless freshly read or just saved*/
+       ((CamelMessageInfoBase *)info)->dirty = TRUE;
+       
        return info;
 }
 
@@ -3101,13 +4152,23 @@ info_set_flags(CamelMessageInfo *info, guint32 flags, guint32 set)
 {
        guint32 old;
        CamelMessageInfoBase *mi = (CamelMessageInfoBase *)info;
-
+       int read=0, deleted=0, junk=0;
        /* TODO: locking? */
 
+       if (flags & CAMEL_MESSAGE_SEEN && ((set & CAMEL_MESSAGE_SEEN) != (mi->flags & CAMEL_MESSAGE_SEEN)))
+       { read = set & CAMEL_MESSAGE_SEEN ? 1 : -1; printf("Setting read as %d\n", set & CAMEL_MESSAGE_SEEN ? 1 : 0);}
+
+       if (flags & CAMEL_MESSAGE_DELETED && ((set & CAMEL_MESSAGE_DELETED) != (mi->flags & CAMEL_MESSAGE_DELETED)))
+       { deleted = set & CAMEL_MESSAGE_DELETED ? 1 : -1; ;printf("Setting deleted as %d\n", set & CAMEL_MESSAGE_DELETED ? 1 : 0);}
+
+       if (flags & CAMEL_MESSAGE_JUNK && ((set & CAMEL_MESSAGE_JUNK) != (mi->flags & CAMEL_MESSAGE_JUNK)))
+       { junk = set & CAMEL_MESSAGE_JUNK ? 1 : -1; ;printf("Setting junk as %d\n", set & CAMEL_MESSAGE_JUNK ? 1 : 0);}
+       
        old = mi->flags;
        mi->flags = (old & ~flags) | (set & flags);
        if (old != mi->flags) {
                mi->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
+               mi->dirty = TRUE;
                if (mi->summary)
                        camel_folder_summary_touch(mi->summary);
        }
@@ -3123,6 +4184,20 @@ info_set_flags(CamelMessageInfo *info, guint32 flags, guint32 set)
                camel_folder_change_info_free(changes);
        }
 
+       if (mi->summary) {
+               if (read)
+                       mi->summary->unread_count -= read;
+               if (deleted)
+                       mi->summary->deleted_count += deleted;
+               if (junk)
+                       mi->summary->junk_count += junk;
+               if (junk && !deleted)
+                       mi->summary->junk_not_deleted_count += junk;
+               if (junk ||  deleted) 
+                       mi->summary->visible_count -= junk ? junk : deleted;
+       }
+
+       d(printf("%d %d %d %d %d\n", mi->summary->unread_count, mi->summary->deleted_count, mi->summary->junk_count, mi->summary->junk_not_deleted_count, mi->summary->visible_count));
        return TRUE;
 }
 
@@ -3159,6 +4234,7 @@ info_set_user_flag(CamelMessageInfo *info, const char *name, gboolean value)
                CamelFolderChangeInfo *changes = camel_folder_change_info_new();
 
                mi->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
+               mi->dirty = TRUE;
                camel_folder_summary_touch(mi->summary);
                camel_folder_change_info_change_uid(changes, camel_message_info_uid(info));
                camel_object_trigger_event(mi->summary->folder, "folder_changed", changes);
@@ -3200,6 +4276,7 @@ info_set_user_tag(CamelMessageInfo *info, const char *name, const char *value)
                CamelFolderChangeInfo *changes = camel_folder_change_info_new();
 
                mi->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
+               mi->dirty = TRUE;               
                camel_folder_summary_touch(mi->summary);
                camel_folder_change_info_change_uid(changes, camel_message_info_uid(info));
                camel_object_trigger_event(mi->summary->folder, "folder_changed", changes);
@@ -3285,6 +4362,13 @@ camel_folder_summary_class_init (CamelFolderSummaryClass *klass)
        klass->summary_header_load = summary_header_load;
        klass->summary_header_save = summary_header_save;
 
+       klass->summary_header_from_db = summary_header_from_db;
+       klass->summary_header_to_db = summary_header_to_db;
+       klass->message_info_from_db = message_info_from_db;
+       klass->message_info_to_db = message_info_to_db;
+       klass->content_info_from_db = content_info_from_db;
+       klass->content_info_to_db = content_info_to_db;
+
        klass->message_info_new_from_header  = message_info_new_from_header;
        klass->message_info_new_from_parser = message_info_new_from_parser;
        klass->message_info_new_from_message = message_info_new_from_message;
@@ -3293,7 +4377,8 @@ camel_folder_summary_class_init (CamelFolderSummaryClass *klass)
        klass->meta_message_info_save = meta_message_info_save;
        klass->message_info_free = message_info_free;
        klass->message_info_clone = message_info_clone;
-
+       klass->message_info_from_uid = message_info_from_uid;
+       
        klass->content_info_new_from_header  = content_info_new_from_header;
        klass->content_info_new_from_parser = content_info_new_from_parser;
        klass->content_info_new_from_message = content_info_new_from_message;
index 77c54a7..2ef8896 100644 (file)
@@ -27,6 +27,7 @@
 #include <camel/camel-mime-parser.h>
 #include <camel/camel-object.h>
 #include <camel/camel-index.h>
+#include <camel/camel-db.h>
 
 #define CAMEL_FOLDER_SUMMARY_TYPE         camel_folder_summary_get_type ()
 #define CAMEL_FOLDER_SUMMARY(obj)         CAMEL_CHECK_CAST (obj, camel_folder_summary_get_type (), CamelFolderSummary)
@@ -80,7 +81,7 @@ typedef enum _CamelMessageFlags {
 
        /* following flags are for the folder, and are not really permanent flags */
        CAMEL_MESSAGE_FOLDER_FLAGGED = 1<<16, /* for use by the folder implementation */
-
+       CAMEL_MESSAGE_DB_DIRTY = 1<<17, /* To say whether the changes are syned to db.*/
        /* flags after 1<<16 are used by camel providers,
            if adding non permanent flags, add them to the end  */
 
@@ -152,6 +153,8 @@ struct _CamelMessageInfo {
 
        guint32 refcount;       /* ??? */
        char *uid;
+       /*FIXME: Make it work with the CAMEL_MESSADE_DB_DIRTY flag instead of another 4 bytes*/
+       int dirty:1;
 };
 
 /* For classes wishing to do the provided i/o, or for anonymous users,
@@ -162,7 +165,9 @@ struct _CamelMessageInfoBase {
 
        guint32 refcount;       /* ??? */
        char *uid;
-
+       /*FIXME: Make it work with the CAMEL_MESSADE_DB_DIRTY flag instead of another 4 bytes*/
+       int dirty:1;
+       
        const char *subject;
        const char *from;
        const char *to;
@@ -184,6 +189,8 @@ struct _CamelMessageInfoBase {
        /* tree of content description - NULL if it is not available */
        CamelMessageContentInfo *content;
        struct _camel_header_param *headers;
+
+
 };
 
 /* probably do this as well, removing CamelFolderChangeInfo and interfaces 
@@ -214,7 +221,9 @@ struct _CamelFolderSummary {
        guint32 unread_count;   /* handy totals */
        guint32 deleted_count;
        guint32 junk_count;
-
+       guint32 junk_not_deleted_count;
+       guint32 visible_count;
+       
        /* sizes of memory objects */
        guint32 message_info_size;
        guint32 content_info_size;
@@ -226,11 +235,18 @@ struct _CamelFolderSummary {
        char *summary_path;
        gboolean build_content; /* do we try and parse/index the content, or not? */
 
-       GPtrArray *messages;    /* CamelMessageInfo's */
-       GHashTable *messages_uid; /* CamelMessageInfo's by uid */
+       /* Deprecated */
+//     GPtrArray *messages;    /* CamelMessageInfo's */
+//     GHashTable *messages_uid; /* CamelMessageInfo's by uid */
+
+       /* New members to replace the above depreacted members */
+       GPtrArray *uids;
+       GHashTable *loaded_infos;
 
        struct _CamelFolder *folder; /* parent folder, for events */
        struct _CamelFolderMetaSummary *meta_summary; /* Meta summary */
+       time_t cache_load_time;
+       guint timeout_handle;
 };
 
 struct _CamelFolderSummaryClass {
@@ -240,6 +256,14 @@ struct _CamelFolderSummaryClass {
        int (*summary_header_load)(CamelFolderSummary *, FILE *);
        int (*summary_header_save)(CamelFolderSummary *, FILE *);
 
+       /* Load/Save folder summary from DB*/
+       int (*summary_header_from_db)(CamelFolderSummary *, CamelFIRecord *);
+       CamelFIRecord * (*summary_header_to_db)(CamelFolderSummary *, CamelException *ex);
+       CamelMessageInfo * (*message_info_from_db) (CamelFolderSummary *, struct _CamelMIRecord*);
+       CamelMIRecord * (*message_info_to_db) (CamelFolderSummary *, CamelMessageInfo *);
+       CamelMessageContentInfo * (*content_info_from_db) (CamelFolderSummary *, CamelMIRecord *);
+       int (*content_info_to_db) (CamelFolderSummary *, CamelMessageContentInfo *, CamelMIRecord *);
+       
        /* create/save/load an individual message info */
        CamelMessageInfo * (*message_info_new_from_header)(CamelFolderSummary *, struct _camel_header_raw *);
        CamelMessageInfo * (*message_info_new_from_parser)(CamelFolderSummary *, CamelMimeParser *);
@@ -258,7 +282,7 @@ struct _CamelFolderSummaryClass {
        CamelMessageContentInfo * (*content_info_load)(CamelFolderSummary *, FILE *);
        int                       (*content_info_save)(CamelFolderSummary *, FILE *, CamelMessageContentInfo *);
        void                      (*content_info_free)(CamelFolderSummary *, CamelMessageContentInfo *);
-
+       CamelMessageInfo * (*message_info_from_uid) (CamelFolderSummary *, const char *);
        /* get the next uid */
        char *(*next_uid_string)(CamelFolderSummary *);
 
@@ -294,7 +318,10 @@ struct _CamelFolderMetaSummary {
 CamelType                       camel_folder_summary_get_type  (void);
 CamelFolderSummary      *camel_folder_summary_new      (struct _CamelFolder *folder);
 
+/* Deprecated */
 void camel_folder_summary_set_filename(CamelFolderSummary *summary, const char *filename);
+
+
 void camel_folder_summary_set_index(CamelFolderSummary *summary, CamelIndex *index);
 void camel_folder_summary_set_build_content(CamelFolderSummary *summary, gboolean state);
 
@@ -306,14 +333,30 @@ void       camel_folder_summary_set_uid         (CamelFolderSummary *summary, guint32
 int camel_folder_summary_load(CamelFolderSummary *summary);
 int camel_folder_summary_save(CamelFolderSummary *summary);
 
+/* load/save the full summary from/to the db */
+int camel_folder_summary_save_to_db (CamelFolderSummary *s, CamelException *ex);
+int camel_folder_summary_load_from_db (CamelFolderSummary *s, CamelException *ex);
+
 /* only load the header */
 int camel_folder_summary_header_load(CamelFolderSummary *summary);
+int camel_folder_summary_header_load_from_db (CamelFolderSummary *s, CamelStore *store, const char *folder_name, CamelException *ex);
 
 /* set the dirty bit on the summary */
 void camel_folder_summary_touch(CamelFolderSummary *summary);
 
 /* add a new raw summary item */
-void camel_folder_summary_add(CamelFolderSummary *summary, CamelMessageInfo *info);
+void camel_folder_summary_add (CamelFolderSummary *summary, CamelMessageInfo *info);
+
+/* Get only the uids of dirty/changed things to sync to server/db */
+GPtrArray * camel_folder_summary_get_changed (CamelFolderSummary *s);
+/* Gets the size of loaded mi's */
+int camel_folder_summary_cache_size (CamelFolderSummary *s);
+/* reload the summary at any required point if required */
+int camel_folder_summary_reload_from_db (CamelFolderSummary *s, CamelException *ex);
+/* insert mi to summary */
+void camel_folder_summary_insert (CamelFolderSummary *s, CamelMessageInfo *info, gboolean load);
+
+void camel_folder_summary_remove_index_fast (CamelFolderSummary *s, int index);
 
 /* build/add raw summary items */
 CamelMessageInfo *camel_folder_summary_add_from_header(CamelFolderSummary *summary, struct _camel_header_raw *headers);
@@ -336,13 +379,18 @@ void camel_folder_summary_remove_range(CamelFolderSummary *summary, int start, i
 
 /* remove all items */
 void camel_folder_summary_clear(CamelFolderSummary *summary);
+void camel_folder_summary_clear_db (CamelFolderSummary *s);
+
+int camel_folder_summary_reload_from_db (CamelFolderSummary *s, CamelException *ex);
+int camel_folder_summary_cache_size (CamelFolderSummary *s);
 
 /* lookup functions */
 int camel_folder_summary_count(CamelFolderSummary *summary);
 CamelMessageInfo *camel_folder_summary_index(CamelFolderSummary *summary, int index);
 CamelMessageInfo *camel_folder_summary_uid(CamelFolderSummary *summary, const char *uid);
+char * camel_folder_summary_uid_from_index (CamelFolderSummary *s, int i);
+
 GPtrArray *camel_folder_summary_array(CamelFolderSummary *summary);
-void camel_folder_summary_array_free(CamelFolderSummary *summary, GPtrArray *array);
 
 /* basically like strings, but certain keywords can be compressed and de-cased */
 int camel_folder_summary_encode_token(FILE *out, const char *str);
index c8026e2..08f680a 100644 (file)
@@ -618,15 +618,20 @@ camel_folder_thread_messages_new (CamelFolder *folder, GPtrArray *uids, gboolean
                        g_hash_table_insert(wanted, uids->pdata[i], uids->pdata[i]);
        }
 
-       fsummary = camel_folder_get_summary(folder);
+       fsummary = camel_folder_summary_array (folder->summary);
        thread->summary = summary = g_ptr_array_new();
-
-       for (i=0;i<fsummary->len;i++) {
-               CamelMessageInfo *info = fsummary->pdata[i];
-
-               if (wanted == NULL || g_hash_table_lookup(wanted, camel_message_info_uid(info)) != NULL) {
-                       camel_folder_ref_message_info(folder, info);
-                       g_ptr_array_add(summary, info);
+       if (fsummary->len - camel_folder_summary_cache_size (folder->summary) > 50)
+               camel_folder_summary_reload_from_db (folder->summary, NULL);
+
+       for (i = 0 ; i < fsummary->len ; i++) {
+               CamelMessageInfo *info ;
+               char *uid = fsummary->pdata[i];
+
+               if (wanted == NULL || g_hash_table_lookup(wanted, uid) != NULL) {
+                       info = camel_folder_get_message_info (folder, uid);
+                       if (info)
+                               g_ptr_array_add(summary, info);
+                       /* FIXME: Check if the info is leaking */
                }
        }
 
index b52ddeb..4b37c5b 100644 (file)
@@ -43,6 +43,7 @@
 #include "camel-session.h"
 #include "camel-store.h"
 #include "camel-vtrash-folder.h"
+#include "camel-string-utils.h"
 
 #define d(x)
 #define w(x)
@@ -201,7 +202,12 @@ camel_folder_finalize (CamelObject *object)
                camel_object_unref (camel_folder->summary);
 
        camel_folder_change_info_free(p->changed_frozen);
-       
+
+       if (camel_folder->cdb) {
+               camel_db_close (camel_folder->cdb);
+               camel_folder->cdb = NULL;
+       }
+
        g_static_rec_mutex_free(&p->lock);
        g_static_mutex_free(&p->change_lock);
        
@@ -240,6 +246,10 @@ void
 camel_folder_construct (CamelFolder *folder, CamelStore *parent_store,
                        const char *full_name, const char *name)
 {
+       char *store_db_path;
+       CamelService *service = (CamelService *) parent_store;
+       CamelException ex;
+       
        g_return_if_fail (CAMEL_IS_FOLDER (folder));
        g_return_if_fail (CAMEL_IS_STORE (parent_store));
        g_return_if_fail (folder->parent_store == NULL);
@@ -251,6 +261,23 @@ camel_folder_construct (CamelFolder *folder, CamelStore *parent_store,
 
        folder->name = g_strdup (name);
        folder->full_name = g_strdup (full_name);
+
+       store_db_path = g_build_filename (service->url->path, CAMEL_DB_FILE, NULL);
+       camel_exception_init(&ex);
+       if (strlen (store_db_path) < 2) {
+               g_free (store_db_path);
+               store_db_path = g_build_filename ( camel_session_get_storage_path ((CamelSession *)camel_service_get_session (service), service, &ex), CAMEL_DB_FILE, NULL);            
+       }
+
+
+       folder->cdb = camel_db_open (store_db_path, &ex);
+       g_free (store_db_path);
+       
+       if (camel_exception_is_set (&ex)) {
+               g_print ("Exiting without success for stire_db_path : [%s]: %s\n", store_db_path, camel_exception_get_description(&ex));
+               camel_exception_clear(&ex);
+               return;
+       }       
 }
 
 
@@ -305,7 +332,9 @@ camel_folder_refresh_info (CamelFolder *folder, CamelException *ex)
        g_return_if_fail (CAMEL_IS_FOLDER (folder));
 
        CAMEL_FOLDER_REC_LOCK(folder, lock);
+
        CF_CLASS (folder)->refresh_info (folder, ex);
+       
        CAMEL_FOLDER_REC_UNLOCK(folder, lock);
 }
 
@@ -352,31 +381,58 @@ folder_getv(CamelObject *object, CamelException *ex, CamelArgGetV *args)
                case CAMEL_FOLDER_ARG_JUNKED_NOT_DELETED:
                case CAMEL_FOLDER_ARG_VISIBLE:
                        /* This is so we can get the values atomically, and also so we can calculate them only once */
+
+                       #warning "Add a better base class function to get counts specific to normal/vee folder."
                        if (unread == -1) {
                                int j;
                                CamelMessageInfo *info;
 
-                               /* TODO: Locking? */
-                               unread = 0;
-                               count = camel_folder_summary_count (folder->summary);
-                               for (j = 0; j < count; j++) {
-                                       if ((info = camel_folder_summary_index (folder->summary, j))) {
-                                               guint32 flags = camel_message_info_flags(info);
-
-                                               if ((flags & (CAMEL_MESSAGE_SEEN|CAMEL_MESSAGE_DELETED|CAMEL_MESSAGE_JUNK)) == 0)
-                                                       unread++;
-                                               if (flags & CAMEL_MESSAGE_DELETED)
-                                                       deleted++;
-                                               if (flags & CAMEL_MESSAGE_JUNK) {
-                                                       junked++;
-                                                       if (! (flags & CAMEL_MESSAGE_DELETED))
-                                                               junked_not_deleted++;
+                               if (!CAMEL_IS_VEE_FOLDER (folder)) {
+                                       /* TODO: Locking? */
+                                       unread = folder->summary->unread_count;
+                                       deleted = folder->summary->deleted_count;
+                                       junked = folder->summary->junk_count;
+                                       junked_not_deleted = folder->summary->junk_not_deleted_count;
+                                       visible = folder->summary->visible_count;
+                                        #warning "unread should be unread and not del/junk and take care of dirty infos also"
+                                       // camel_folder_summary_save_to_db (folder->summary, NULL);
+                                       //camel_db_count_visible_unread_message_info (folder->cdb, folder->full_name, &unread, ex);
+                                       //camel_db_count_junk_message_info (folder->cdb, folder->full_name, &junked, ex);
+                                       //camel_db_count_deleted_message_info (folder->cdb, folder->full_name, &deleted, ex);
+                                       //camel_db_count_junk_not_deleted_message_info (folder->cdb, folder->full_name, &junked_not_deleted, ex);
+                                       //camel_db_count_visible_message_info (folder->cdb, folder->full_name, &visible, ex);
+                               } else {
+                                       count = camel_folder_summary_count (folder->summary);
+                                       for (j = 0; j < count; j++) {
+                                               if ((info = camel_folder_summary_index (folder->summary, j))) {
+                                                       guint32 flags = camel_message_info_flags(info);
+
+                                                       if ((flags & (CAMEL_MESSAGE_SEEN|CAMEL_MESSAGE_DELETED|CAMEL_MESSAGE_JUNK)) == 0)
+                                                               unread++;
+                                                       if (flags & CAMEL_MESSAGE_DELETED)
+                                                               deleted++;
+                                                       if (flags & CAMEL_MESSAGE_JUNK) {
+                                                               junked++;
+                                                               if (! (flags & CAMEL_MESSAGE_DELETED))
+                                                                       junked_not_deleted++;
+                                                       }
+                                                       if ((flags & (CAMEL_MESSAGE_DELETED|CAMEL_MESSAGE_JUNK)) == 0)
+                                                               visible++;
+                                                       camel_message_info_free(info);
                                                }
-                                               if ((flags & (CAMEL_MESSAGE_DELETED|CAMEL_MESSAGE_JUNK)) == 0)
-                                                       visible++;
-                                               camel_message_info_free(info);
+
+                                       }
+                                        #warning "I added it for vfolders summary storage, does it harm ?"
+                                       if (unread == -1) {
+                                               unread = folder->summary->unread_count;
+                                               /*
+                                               folder->summary->junk_count = junked;
+                                               folder->summary->deleted_count = deleted;
+                                               printf("*************************** %s %d %d %d\n", folder->full_name, folder->summary->unread_count, unread, count);
+                                               folder->summary->unread_count = unread; */
                                        }
                                }
+
                        }
 
                        switch (tag & CAMEL_ARG_TAG) {
@@ -400,7 +456,7 @@ folder_getv(CamelObject *object, CamelException *ex, CamelArgGetV *args)
                        *arg->ca_int = count;
                        break;
                case CAMEL_FOLDER_ARG_UID_ARRAY: {
-                       int j;
+/*                     int j;
                        CamelMessageInfo *info;
                        GPtrArray *array;
 
@@ -413,7 +469,9 @@ folder_getv(CamelObject *object, CamelException *ex, CamelArgGetV *args)
                                        camel_message_info_free(info);
                                }
                        }
-                       *arg->ca_ptr = array;
+                       *arg->ca_ptr = array;*/
+                       // WTH this is reqd ?, let it crash to find out who uses this
+                       g_assert (0);
                        break; }
                case CAMEL_FOLDER_ARG_INFO_ARRAY:
                        *arg->ca_ptr = camel_folder_summary_array(folder->summary);
@@ -446,7 +504,7 @@ folder_free(CamelObject *o, guint32 tag, void *val)
                g_ptr_array_free(array, TRUE);
                break; }
        case CAMEL_FOLDER_ARG_INFO_ARRAY:
-               camel_folder_summary_array_free(folder->summary, val);
+               camel_folder_free_summary (folder, val);
                break;
        case CAMEL_FOLDER_ARG_PROPERTIES:
                g_slist_free(val);
@@ -1114,7 +1172,7 @@ get_uids(CamelFolder *folder)
                CamelMessageInfo *info = camel_folder_summary_index(folder->summary, i);
                
                if (info) {
-                       array->pdata[j++] = g_strdup (camel_message_info_uid (info));
+                       array->pdata[j++] = (char *)camel_pstring_strdup (camel_message_info_uid (info));
                        camel_message_info_free(info);
                }
        }
@@ -1155,7 +1213,7 @@ free_uids (CamelFolder *folder, GPtrArray *array)
        int i;
 
        for (i=0; i<array->len; i++)
-               g_free(array->pdata[i]);
+               camel_pstring_free(array->pdata[i]);
        g_ptr_array_free(array, TRUE);
 }
 
@@ -1249,9 +1307,8 @@ camel_folder_get_summary (CamelFolder *folder)
 static void
 free_summary(CamelFolder *folder, GPtrArray *summary)
 {
-       g_assert(folder->summary != NULL);
-
-       camel_folder_summary_array_free(folder->summary, summary);
+       g_ptr_array_foreach (summary, (GFunc) camel_pstring_free, NULL);
+       g_ptr_array_free (summary, TRUE);
 }
 
 
@@ -1265,8 +1322,6 @@ free_summary(CamelFolder *folder, GPtrArray *summary)
 void
 camel_folder_free_summary(CamelFolder *folder, GPtrArray *array)
 {
-       g_return_if_fail(CAMEL_IS_FOLDER(folder));
-
        CF_CLASS(folder)->free_summary(folder, array);
 }
 
@@ -1376,7 +1431,7 @@ search_free (CamelFolder *folder, GPtrArray *result)
        int i;
 
        for (i = 0; i < result->len; i++)
-               g_free (g_ptr_array_index (result, i));
+               camel_pstring_free (g_ptr_array_index (result, i));
        g_ptr_array_free (result, TRUE);
 }
 
@@ -1415,7 +1470,7 @@ transfer_message_to (CamelFolder *source, const char *uid, CamelFolder *dest,
 
        /* if its deleted we poke the flags, so we need to copy the messageinfo */
        if ((source->folder_flags & CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY)
-           && (minfo = camel_folder_get_message_info(source, uid))) {
+                       && (minfo = camel_folder_get_message_info(source, uid))) {
                info = camel_message_info_clone(minfo);
                camel_folder_free_message_info(source, minfo);
        } else
index 8ed3155..c00b48a 100644 (file)
@@ -109,6 +109,7 @@ struct _CamelFolder {
 
        guint32 folder_flags;
        guint32 permanent_flags;
+       CamelDB *cdb;
 };
 
 #define CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY (1<<0)
index 1d365ac..422c47c 100644 (file)
@@ -45,7 +45,7 @@
 #include "camel-offline-journal.h"
 #include "camel-private.h"
 
-#define d(x) x
+#define d(x) 
 
 static void camel_offline_journal_class_init (CamelOfflineJournalClass *klass);
 static void camel_offline_journal_init (CamelOfflineJournal *journal, CamelOfflineJournalClass *klass);
index 2cc6074..043ee03 100644 (file)
@@ -42,7 +42,7 @@
 #include "camel-store.h"
 #include "camel-vtrash-folder.h"
 
-#define d(x)
+#define d(x) 
 #define w(x)
 
 static CamelServiceClass *parent_class = NULL;
@@ -153,11 +153,17 @@ camel_store_finalize (CamelObject *object)
 {
        CamelStore *store = CAMEL_STORE (object);
 
+       d(printf ("\ncamel_store_finalize called \n"));
        if (store->folders)
                camel_object_bag_destroy(store->folders);
        
        g_static_rec_mutex_free (&store->priv->folder_lock);
-       
+
+       if (store->cdb) {
+               camel_db_close (store->cdb);
+               store->cdb = NULL;
+       }
+
        g_free (store->priv);
 }
 
@@ -200,11 +206,35 @@ construct (CamelService *service, CamelSession *session,
           CamelException *ex)
 {
        CamelStore *store = CAMEL_STORE(service);
+       char *store_db_path;
 
        parent_class->construct(service, session, provider, url, ex);
        if (camel_exception_is_set (ex))
                return;
 
+       store_db_path = g_build_filename (service->url->path, CAMEL_DB_FILE, NULL);
+
+       if (strlen (store_db_path) < 2) {
+               g_free (store_db_path);
+               store_db_path = g_build_filename ( camel_session_get_storage_path (session, service, ex), CAMEL_DB_FILE, NULL);         
+       }
+
+       store->cdb = camel_db_open (store_db_path, ex);
+       printf("store_db_path %s\n", store_db_path);
+       g_free (store_db_path);
+       if (camel_exception_is_set (ex)) {
+               g_print ("Exiting without success for stire_db_path : [%s]\n", store_db_path);
+               return;
+       }
+
+       if (camel_db_create_folders_table (store->cdb, ex))
+               printf ("something went wrong terribly\n");
+       else
+               printf ("folders table succesfully created \n");
+
+       if (camel_exception_is_set (ex))
+               return;
+
        if (camel_url_get_param(url, "filter"))
                store->flags |= CAMEL_STORE_FILTER_INBOX;
 }
index 764bc8a..b11bd26 100644 (file)
@@ -32,6 +32,7 @@
 
 #include <camel/camel-object.h>
 #include <camel/camel-service.h>
+#include <camel/camel-db.h>
 
 G_BEGIN_DECLS
 
@@ -121,6 +122,7 @@ struct _CamelStore {
        struct _CamelStorePrivate *priv;
        
        CamelObjectBag *folders;
+       CamelDB *cdb;
 
        guint32 flags;
        guint32 mode;
index a3cfac8..cc9fd2d 100644 (file)
@@ -240,11 +240,15 @@ camel_pstring_free(const char *s)
                if (count == 0) {
                        g_hash_table_remove(pstring_table, p);
                        g_free(p);
+                       if (p != s) /* Only for debugging purposes */
+                               g_assert(0);
                } else {
                        g_hash_table_insert(pstring_table, p, GINT_TO_POINTER(count));
                }
        } else {
                g_warning("Trying to free string not allocated from the pool '%s'", s);
+               /*Only for debugging purposes */
+               g_assert (0);
        }
        pthread_mutex_unlock(&pstring_lock);
 }
index 2d9b410..5fdaaf1 100644 (file)
@@ -43,6 +43,7 @@
 #include "camel-vee-folder.h"
 #include "camel-vee-store.h"   /* for open flags */
 #include "camel-vee-summary.h"
+#include "camel-string-utils.h"
 
 #define d(x) 
 #define dd(x) (camel_debug("vfolder")?(x):0)
@@ -421,7 +422,7 @@ camel_vee_folder_get_location(CamelVeeFolder *vf, const CamelVeeMessageInfo *vin
 {
        CamelFolder *folder;
 
-       folder = vinfo->real->summary->folder;
+       folder = vinfo->summary->folder;
 
        /* locking?  yes?  no?  although the vfolderinfo is valid when obtained
           the folder in it might not necessarily be so ...? */
@@ -465,13 +466,40 @@ static void vee_refresh_info(CamelFolder *folder, CamelException *ex)
        g_list_free(list);
 }
 
+static CamelFIRecord *
+summary_header_to_db (CamelFolderSummary *s, CamelException *ex)
+{
+       CamelFIRecord * record = g_new0 (CamelFIRecord, 1);
+       CamelDB *db;
+
+       db = s->folder->parent_store->cdb;
+       char *table_name = s->folder->full_name;
+
+
+       record->folder_name = table_name;
+
+       /* we always write out the current version */
+       record->version = 13;  //FIXME CAMEL_FOLDER_SUMMARY_VERSION;
+       record->flags  = s->flags;
+       record->nextuid = s->nextuid;
+       record->time = s->time;
+
+       record->saved_count = s->uids->len;
+       record->junk_count = s->junk_count;
+       record->deleted_count = s->deleted_count;
+       record->unread_count = s->unread_count;
+
+       return record;  
+}
+
 static void
 vee_sync(CamelFolder *folder, gboolean expunge, CamelException *ex)
 {
        CamelVeeFolder *vf = (CamelVeeFolder *)folder;
        struct _CamelVeeFolderPrivate *p = _PRIVATE(vf);
        GList *node;
-
+       CamelFIRecord * record;
+       
        CAMEL_VEE_FOLDER_LOCK(vf, subfolder_lock);
 
        node = p->folders;
@@ -486,15 +514,20 @@ vee_sync(CamelFolder *folder, gboolean expunge, CamelException *ex)
                        camel_exception_setv(ex, ex->id, _("Error storing '%s': %s"), desc, ex->desc);
                        break;
                }
-
+#warning "see if it is really required"
                /* auto update vfolders shouldn't need a rebuild */
-               if ((vf->flags & CAMEL_STORE_VEE_FOLDER_AUTO) == 0
-                   && camel_vee_folder_rebuild_folder(vf, f, ex) == -1)
-                       break;
+/*             if ((vf->flags & CAMEL_STORE_VEE_FOLDER_AUTO) == 0 */
+/*                 && camel_vee_folder_rebuild_folder(vf, f, ex) == -1) */
+/*                     break; */
 
                node = node->next;
        }
-
+       
+       record = summary_header_to_db (folder->summary, ex);
+       #warning handle exception and ret
+       camel_db_write_folder_info_record (folder->parent_store->cdb, record, ex);
+       g_free (record);
+       
        if (node == NULL) {
                CAMEL_VEE_FOLDER_LOCK(vf, changed_lock);
                g_list_free(p->folders_changed);
@@ -521,7 +554,7 @@ vee_get_message(CamelFolder *folder, const char *uid, CamelException *ex)
 
        mi = (CamelVeeMessageInfo *)camel_folder_summary_uid(folder->summary, uid);
        if (mi) {
-               msg =  camel_folder_get_message(mi->real->summary->folder, camel_message_info_uid(mi)+8, ex);
+               msg =  camel_folder_get_message(mi->summary->folder, camel_message_info_uid(mi)+8, ex);
                camel_message_info_free((CamelMessageInfo *)mi);
        } else {
                camel_exception_setv(ex, CAMEL_EXCEPTION_FOLDER_INVALID_UID,
@@ -543,8 +576,6 @@ vee_search_by_expression(CamelFolder *folder, const char *expression, CamelExcep
        GHashTable *searched = g_hash_table_new(NULL, NULL);
        CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
        
-       CAMEL_VEE_FOLDER_LOCK(vf, subfolder_lock);
-       
        if (vf != folder_unmatched)
                expr = g_strdup_printf ("(and %s %s)", vf->expression ? vf->expression : "", expression);
        else
@@ -560,7 +591,7 @@ vee_search_by_expression(CamelFolder *folder, const char *expression, CamelExcep
                if (g_hash_table_lookup(searched, f) == NULL) {
                        camel_vee_folder_hash_folder(f, hash);
                        /* FIXME: shouldn't ignore search exception */
-                       matches = camel_folder_search_by_expression(f, expression, NULL);
+                       matches = camel_folder_search_by_expression(f, expr, NULL);
                        if (matches) {
                                for (i = 0; i < matches->len; i++) {
                                        char *uid = matches->pdata[i], *vuid;
@@ -568,7 +599,8 @@ vee_search_by_expression(CamelFolder *folder, const char *expression, CamelExcep
                                        vuid = g_malloc(strlen(uid)+9);
                                        memcpy(vuid, hash, 8);
                                        strcpy(vuid+8, uid);
-                                       g_ptr_array_add(result, vuid);
+                                       g_ptr_array_add(result, (gpointer) camel_pstring_strdup(vuid));
+                                       g_free (vuid);
                                }
                                camel_folder_search_free(f, matches);
                        }
@@ -577,11 +609,69 @@ vee_search_by_expression(CamelFolder *folder, const char *expression, CamelExcep
                node = g_list_next(node);
        }
 
+       
        g_free(expr);
-       CAMEL_VEE_FOLDER_UNLOCK(vf, subfolder_lock);
 
-       g_hash_table_destroy(searched);
+       if (0)
+       {
+               GHashTable *hashes = g_hash_table_new (g_str_hash, g_str_equal);
+               GPtrArray *subids = g_ptr_array_new ();
+               GPtrArray *summary = camel_folder_summary_array (folder->summary);
+               char *last_id = NULL;
+               printf("Doing for folder %s\n", folder->full_name);
+               CAMEL_VEE_FOLDER_LOCK(vf, subfolder_lock);              
+               node = p->folders;
+               while (node) {
+                       CamelFolder *f = node->data;
+                       char hash[9];
+
+                       camel_vee_folder_hash_folder(f, hash);
+                       hash[8] = 0;
+                       g_hash_table_insert(hashes, hash, f);
+                       node = g_list_next(node);
+               }
+               CAMEL_VEE_FOLDER_UNLOCK(vf, subfolder_lock);
+               if (summary->len) {
+                       int i, j;
+                       
+                       last_id = summary->pdata[0];
+                       g_ptr_array_add (subids, last_id+8);
+                       for (i=1; i<=summary->len; i++) {
+                               if (i==summary->len || strncmp(last_id, summary->pdata[i], 8)) {
+                                       /* We got a new id */
+                                       char shash[9];
+                                       strncpy (shash, last_id, 8);
+                                       shash[8] = 0;
+                                       CamelFolder *cf = g_hash_table_lookup (hashes, shash);
+                                       d(printf("Searching %s for %d uids (%d<%d )...\t", cf->full_name, subids->len, i, summary->len));
+                                       matches = camel_folder_search_by_uids (cf, expression, subids, NULL);
+                                       d(printf("Got %d\n", matches->len));
+                                       if (matches) {
+                                               for (j = 0; j < matches->len; j++) {
+                                                       char *uid = matches->pdata[j], *vuid;
+
+                                                       vuid = g_malloc(strlen(uid)+9);
+                                                       memcpy(vuid, shash, 8);
+                                                       strcpy(vuid+8, uid);
+                                                       g_ptr_array_add(result, vuid);
+                                               }
+                                               camel_folder_search_free(cf, matches);
+                                       }                                       
+                                       g_ptr_array_set_size(subids, 0);
+                               }
+                               if (i <summary->len) {
+                                       last_id = summary->pdata[i];
+                                       g_ptr_array_add (subids, last_id+8);
+                               }
+                       }
+                       
+               }
+               camel_folder_free_summary (folder, summary);            
+       }
 
+
+       g_hash_table_destroy(searched);
+       printf("returning %d\n", result->len);
        return result;
 }
 
@@ -695,14 +785,9 @@ static void vee_delete(CamelFolder *folder)
 static CamelVeeMessageInfo *
 vee_folder_add_uid(CamelVeeFolder *vf, CamelFolder *f, const char *inuid, const char hash[8])
 {
-       CamelMessageInfo *info;
        CamelVeeMessageInfo *mi = NULL;
 
-       info = camel_folder_get_message_info(f, inuid);
-       if (info) {
-               mi = camel_vee_summary_add((CamelVeeSummary *)((CamelFolder *)vf)->summary, info, hash);
-               camel_folder_free_message_info(f, info);
-       }
+       mi = camel_vee_summary_add((CamelVeeSummary *)((CamelFolder *)vf)->summary, f->summary, (char *)inuid, hash);
        return mi;
 }
 
@@ -749,7 +834,7 @@ vee_folder_remove_folder(CamelVeeFolder *vf, CamelFolder *source)
                                CamelVeeMessageInfo *mi = (CamelVeeMessageInfo *)camel_folder_summary_index(((CamelFolder *)folder_unmatched)->summary, i);
                                
                                if (mi) {
-                                       if (mi->real->summary == ssummary) {
+                                       if (mi->summary == ssummary) {
                                                camel_folder_change_info_remove_uid(folder_unmatched->changes, camel_message_info_uid(mi));
                                                if (last == -1) {
                                                        last = start = i;
@@ -775,7 +860,7 @@ vee_folder_remove_folder(CamelVeeFolder *vf, CamelFolder *source)
        for (i=0;i<count;i++) {
                CamelVeeMessageInfo *mi = (CamelVeeMessageInfo *)camel_folder_summary_index(folder->summary, i);
                if (mi) {
-                       if (mi->real->summary == ssummary) {
+                       if (mi->summary == ssummary) {
                                const char *uid = camel_message_info_uid(mi);
 
                                camel_folder_change_info_remove_uid(vf->changes, uid);
@@ -794,9 +879,12 @@ vee_folder_remove_folder(CamelVeeFolder *vf, CamelFolder *source)
                                                if (g_hash_table_lookup_extended(unmatched_uids, uid, (void **)&oldkey, &oldval)) {
                                                        n = GPOINTER_TO_INT (oldval);
                                                        if (n == 1) {
+                                                               CamelMessageInfo *tinfo;
                                                                g_hash_table_remove(unmatched_uids, oldkey);
-                                                               if (vee_folder_add_uid(folder_unmatched, source, oldkey+8, hash))
+                                                               if (tinfo = (CamelMessageInfo *) vee_folder_add_uid(folder_unmatched, source, oldkey+8, hash)) {
+                                                                       camel_message_info_free (tinfo);
                                                                        camel_folder_change_info_add_uid(folder_unmatched->changes, oldkey);
+                                                               }
                                                                g_free(oldkey);
                                                        } else {
                                                                g_hash_table_insert(unmatched_uids, oldkey, GINT_TO_POINTER(n-1));
@@ -850,6 +938,7 @@ struct _update_data {
        char hash[8];
        CamelVeeFolder *folder_unmatched;
        GHashTable *unmatched_uids;
+       gboolean rebuilt;
 };
 
 static void
@@ -885,7 +974,10 @@ folder_added_uid(char *uidin, void *value, struct _update_data *u)
 
        if ( (mi = vee_folder_add_uid(u->vf, u->source, uidin, u->hash)) ) {
                camel_folder_change_info_add_uid(u->vf->changes, camel_message_info_uid(mi));
-
+               #warning "Handle exceptions"
+               #warning "Make all these as transactions, just testing atm"
+               if (u->rebuilt)
+                       camel_db_add_to_vfolder_transaction (((CamelFolder *) u->vf)->parent_store->cdb, ((CamelFolder *) u->vf)->full_name, (char *) camel_message_info_uid(mi), NULL);
                if (!CAMEL_IS_VEE_FOLDER(u->source) && u->unmatched_uids != NULL) {
                        if (g_hash_table_lookup_extended(u->unmatched_uids, camel_message_info_uid(mi), (void **)&oldkey, &oldval)) {
                                n = GPOINTER_TO_INT (oldval);
@@ -911,24 +1003,35 @@ vee_rebuild_folder(CamelVeeFolder *vf, CamelFolder *source, CamelException *ex)
        CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
        GHashTable *unmatched_uids = vf->parent_vee_store ? vf->parent_vee_store->unmatched_uids : NULL;
        CamelFolderSummary *ssummary = source->summary;
-
+       gboolean rebuilded = FALSE;
+       
        if (vf == folder_unmatched)
                return 0;
 
+       #warning "Reframe these lines later on"
+       camel_vee_folder_hash_folder(source, u.hash);
+       
        /* if we have no expression, or its been cleared, then act as if no matches */
        if (vf->expression == NULL) {
                match = g_ptr_array_new();
        } else {
-               match = camel_folder_search_by_expression(f, vf->expression, ex);
-               if (match == NULL)
-                       return -1;
+               /* Load the folder results from the DB. */
+               match = camel_vee_summary_get_ids ((CamelVeeSummary *)folder->summary, u.hash);
+               
+               if (!match) {
+                       match = camel_folder_search_by_expression(f, vf->expression, ex);
+                       if (match == NULL)
+                               return -1;
+                       rebuilded = TRUE;
+               }
+               printf("len = %d %d\n", match->len, rebuilded);
        }
 
        u.source = source;
        u.vf = vf;
        u.folder_unmatched = folder_unmatched;
        u.unmatched_uids = unmatched_uids;
-       camel_vee_folder_hash_folder(source, u.hash);
+       u.rebuilt = rebuilded;
 
        CAMEL_VEE_FOLDER_LOCK(vf, summary_lock);
 
@@ -955,7 +1058,7 @@ vee_rebuild_folder(CamelVeeFolder *vf, CamelFolder *source, CamelException *ex)
                CamelVeeMessageInfo *mi = (CamelVeeMessageInfo *)camel_folder_summary_index(folder->summary, i);
 
                if (mi) {
-                       if (mi->real->summary == ssummary) {
+                       if (mi->summary == ssummary) {
                                char *uid = (char *)camel_message_info_uid(mi), *oldkey;
                                void *oldval;
                                
@@ -992,28 +1095,33 @@ vee_rebuild_folder(CamelVeeFolder *vf, CamelFolder *source, CamelException *ex)
                camel_folder_summary_remove_range(folder->summary, start, last);
 
        /* now matchhash contains any new uid's, add them, etc */
+       if (rebuilded) {
+               camel_db_begin_transaction (folder->parent_store->cdb, NULL);
+
+       }
        g_hash_table_foreach(matchhash, (GHFunc)folder_added_uid, &u);
 
+       if (rebuilded)
+               camel_db_end_transaction (folder->parent_store->cdb, NULL);
+       
        if (folder_unmatched != NULL) {
                /* scan unmatched, remove any that have vanished, etc */
                count = camel_folder_summary_count(((CamelFolder *)folder_unmatched)->summary);
                for (i=0;i<count;i++) {
-                       CamelVeeMessageInfo *mi = (CamelVeeMessageInfo *)camel_folder_summary_index(((CamelFolder *)folder_unmatched)->summary, i);
-
-                       if (mi) {
-                               if (mi->real->summary == ssummary) {
-                                       char *uid = (char *)camel_message_info_uid(mi);
+                       char *uid = camel_folder_summary_uid_from_index (((CamelFolder *)folder_unmatched)->summary, i);
 
+                       if (uid) {
+                               if (strncmp (uid, u.hash, 8) == 0) {
                                        if (g_hash_table_lookup(allhash, uid+8) == NULL) {
                                                /* no longer exists at all, just remove it entirely */
-                                               camel_folder_summary_remove_index(((CamelFolder *)folder_unmatched)->summary, i);
-                                               camel_folder_change_info_remove_uid(folder_unmatched->changes, camel_message_info_uid(mi));
+                                               camel_folder_summary_remove_index_fast(((CamelFolder *)folder_unmatched)->summary, i);
+                                               camel_folder_change_info_remove_uid(folder_unmatched->changes, uid);
                                                i--;
                                        } else {
                                                g_hash_table_remove(allhash, uid+8);
                                        }
                                }
-                               camel_message_info_free((CamelMessageInfo *)mi);
+                               g_free (uid);
                        }
                }
 
@@ -1040,9 +1148,10 @@ vee_rebuild_folder(CamelVeeFolder *vf, CamelFolder *source, CamelException *ex)
        g_hash_table_destroy(matchhash);
        g_hash_table_destroy(allhash);
        /* if expression not set, we only had a null list */
-       if (vf->expression == NULL)
+       if (vf->expression == NULL || !rebuilded) {
+               g_ptr_array_foreach (match, (GFunc) camel_pstring_free, NULL);
                g_ptr_array_free(match, TRUE);
-       else
+       else
                camel_folder_search_free(f, match);
        camel_folder_free_uids(f, all);
 
@@ -1119,6 +1228,8 @@ folder_changed_remove_uid(CamelFolder *sub, const char *uid, const char hash[8],
        vinfo = (CamelVeeMessageInfo *)camel_folder_summary_uid(folder->summary, vuid);
        if (vinfo) {
                camel_folder_change_info_remove_uid(vf->changes, vuid);
+                #warning "Handle exception"
+               camel_db_delete_uid_from_vfolder (folder->parent_store->cdb, folder->full_name, vuid, NULL);
                camel_folder_summary_remove(folder->summary, (CamelMessageInfo *)vinfo);
                camel_message_info_free((CamelMessageInfo *)vinfo);
        }
@@ -1499,7 +1610,7 @@ subfolder_renamed_update(CamelVeeFolder *vf, CamelFolder *sub, char hash[8])
                if (mi == NULL)
                        continue;
 
-               if (mi->real->summary == ssummary) {
+               if (mi->summary == ssummary) {
                        char *uid = (char *)camel_message_info_uid(mi);
                        char *oldkey;
                        void *oldval;
@@ -1641,7 +1752,7 @@ vee_set_expression(CamelVeeFolder *vf, const char *query)
        g_free(vf->expression);
        if (query)
                vf->expression = g_strdup(query);
-
+       #warning "reset the DB, err drop the table, . as the expression changed"
        node = p->folders;
        while (node) {
                CamelFolder *f = node->data;
@@ -1735,10 +1846,13 @@ camel_vee_folder_finalise (CamelObject *obj)
                for (node = p->folders;node;node = g_list_next(node))
                        camel_object_unref(node->data);
        } else {
+               #warning "See if it is really reqd"
+               camel_folder_freeze ((CamelFolder *)vf);
                while (p->folders) {
                        CamelFolder *f = p->folders->data;
                        camel_vee_folder_remove_folder(vf, f);
                }
+               camel_folder_thaw ((CamelFolder *)vf);
        }
 
        g_free(vf->expression);
index bb0d869..ee20fa6 100644 (file)
@@ -48,6 +48,7 @@ static CamelFolderInfo *vee_get_folder_info(CamelStore *store, const char *top,
 static void camel_vee_store_class_init (CamelVeeStoreClass *klass);
 static void camel_vee_store_init       (CamelVeeStore *obj);
 static void camel_vee_store_finalise   (CamelObject *obj);
+static void construct (CamelService *service, CamelSession *session, CamelProvider *provider, CamelURL *url, CamelException *ex);
 
 static CamelStoreClass *camel_vee_store_parent;
 
@@ -82,7 +83,8 @@ camel_vee_store_class_init (CamelVeeStoreClass *klass)
        store_class->delete_folder = vee_delete_folder;
        store_class->get_folder_info = vee_get_folder_info;
        store_class->free_folder_info = camel_store_free_folder_info_full;
-
+       ((CamelServiceClass *)store_class)->construct = construct;
+       
        store_class->sync = vee_sync;
        store_class->get_trash = vee_get_trash;
        store_class->get_junk = vee_get_junk;
@@ -95,13 +97,25 @@ camel_vee_store_init (CamelVeeStore *obj)
 
        /* we dont want a vtrash/vjunk on this one */
        store->flags &= ~(CAMEL_STORE_VTRASH | CAMEL_STORE_VJUNK);      
+}
 
+static void
+construct (CamelService *service, CamelSession *session, CamelProvider *provider, CamelURL *url, CamelException *ex)
+{
+       /*  CamelStore *store = (CamelStore *)service;
+        CamelVeeStore *obj = (CamelVeeStore *)service; */
+        
+        ((CamelServiceClass *) camel_vee_store_parent)->construct(service, session, provider, url, ex);
+        
        /* Set up unmatched folder */
+#ifdef VEE_UNMATCHED_ENABLE
        obj->unmatched_uids = g_hash_table_new (g_str_hash, g_str_equal);
        obj->folder_unmatched = (CamelVeeFolder *)camel_object_new (camel_vee_folder_get_type ());
        camel_vee_folder_construct (obj->folder_unmatched, store, CAMEL_UNMATCHED_NAME, _("Unmatched"), CAMEL_STORE_FOLDER_PRIVATE);
+       camel_db_create_vfolder (store->cdb, _("Unmatched"), NULL);
+#endif
+        
 }
-
 static void
 cvs_free_unmatched(void *key, void *value, void *data)
 {
@@ -333,7 +347,8 @@ vee_get_folder_info(CamelStore *store, const char *top, guint32 flags, CamelExce
        g_hash_table_destroy(infos_hash);
 
        /* and always add UNMATCHED, if scanning from top/etc */
-       if (top == NULL || top[0] == 0 || strncmp(top, CAMEL_UNMATCHED_NAME, strlen(CAMEL_UNMATCHED_NAME)) == 0) {
+       #warning "comment it out well"
+       if (0 && (top == NULL || top[0] == 0 || strncmp(top, CAMEL_UNMATCHED_NAME, strlen(CAMEL_UNMATCHED_NAME)) == 0)) {
                info = camel_folder_info_new ();
                url = camel_url_new("vfolder:", NULL);
                camel_url_set_path(url, ((CamelService *)store)->url->path);
index ca674c6..e39097c 100644 (file)
 #include <sys/stat.h>
 
 #include "camel-folder.h"
+#include "camel-store.h"
 #include "camel-vee-summary.h"
+#include "camel-private.h"
+#include "camel-string-utils.h"
 
 #define d(x)
 
@@ -40,15 +43,9 @@ static void
 vee_message_info_free(CamelFolderSummary *s, CamelMessageInfo *info)
 {
        CamelVeeMessageInfo *mi = (CamelVeeMessageInfo *)info;
-       CamelFolderSummary *real_summary = mi->real->summary;
 
        g_free(info->uid);
-       camel_message_info_free(mi->real);
-
-       /* and unref the real summary too */
-       /* FIXME: You may not need this during CamelDBSummary */
-       if (real_summary)
-               camel_object_unref (real_summary);
+       camel_object_unref (mi->summary);
 }
 
 static CamelMessageInfo *
@@ -59,42 +56,68 @@ vee_message_info_clone(CamelFolderSummary *s, const CamelMessageInfo *mi)
 
        to = (CamelVeeMessageInfo *)camel_message_info_new(s);
 
-       to->real = camel_message_info_clone(from->real);
+       to->summary = from->summary;
        /* FIXME: We may not need this during CamelDBSummary */
-       camel_object_ref (to->real->summary);
+       camel_object_ref (to->summary);
        to->info.summary = s;
        
        return (CamelMessageInfo *)to;
 }
 
 static const void *
-vee_info_ptr(const CamelMessageInfo *mi, int id)
+vee_info_ptr (const CamelMessageInfo *mi, int id)
 {
-       return camel_message_info_ptr(((CamelVeeMessageInfo *)mi)->real, id);
+       CamelVeeMessageInfo *vmi = (CamelVeeMessageInfo *) mi;
+       CamelMessageInfo *info;
+       gpointer p;
+       
+       info = camel_folder_summary_uid (vmi->summary, mi->uid+8);
+       p = (gpointer) camel_message_info_ptr(info, id);
+       camel_message_info_free (info);
+
+       return p;
 }
 
 static guint32
 vee_info_uint32(const CamelMessageInfo *mi, int id)
 {
-       return camel_message_info_uint32(((CamelVeeMessageInfo *)mi)->real, id);
+       CamelMessageInfo *rmi = camel_folder_summary_uid (((CamelVeeMessageInfo *)mi)->summary, mi->uid+8);
+       guint32 ret = camel_message_info_uint32 (rmi, id);
+
+       camel_message_info_free (rmi);
+
+       return ret;
+
 }
 
 static time_t
 vee_info_time(const CamelMessageInfo *mi, int id)
 {
-       return camel_message_info_time(((CamelVeeMessageInfo *)mi)->real, id);
+       CamelMessageInfo *rmi = camel_folder_summary_uid (((CamelVeeMessageInfo *)mi)->summary, mi->uid+8);
+       time_t ret = camel_message_info_time (rmi, id);
+       camel_message_info_free (rmi);
+
+       return ret;
 }
 
 static gboolean
 vee_info_user_flag(const CamelMessageInfo *mi, const char *id)
 {
-       return camel_message_info_user_flag(((CamelVeeMessageInfo *)mi)->real, id);
+       CamelMessageInfo *rmi = camel_folder_summary_uid (((CamelVeeMessageInfo *)mi)->summary, mi->uid+8);
+       gboolean ret =  camel_message_info_user_flag (rmi, id);
+       camel_message_info_free (rmi);
+
+       return ret;
 }
 
 static const char *
 vee_info_user_tag(const CamelMessageInfo *mi, const char *id)
 {
-       return camel_message_info_user_tag(((CamelVeeMessageInfo *)mi)->real, id);
+       CamelMessageInfo *rmi = camel_folder_summary_uid (((CamelVeeMessageInfo *)mi)->summary, mi->uid+8);
+       const char *ret = camel_message_info_user_tag (rmi, id);
+       camel_message_info_free (rmi);
+
+       return ret;
 }
 
 static gboolean
@@ -102,9 +125,12 @@ vee_info_set_user_flag(CamelMessageInfo *mi, const char *name, gboolean value)
 {
        int res = FALSE;
 
-       if (mi->uid)
-               res = camel_message_info_set_user_flag(((CamelVeeMessageInfo *)mi)->real, name, value);
-
+       if (mi->uid) {
+               CamelMessageInfo *rmi = camel_folder_summary_uid (((CamelVeeMessageInfo *)mi)->summary, mi->uid+8);
+               res = camel_message_info_set_user_flag(rmi, name, value);
+               camel_message_info_free (rmi);          
+       }
        return res;
 }
 
@@ -113,9 +139,12 @@ vee_info_set_user_tag(CamelMessageInfo *mi, const char *name, const char *value)
 {
        int res = FALSE;
 
-       if (mi->uid)
-               res = camel_message_info_set_user_tag(((CamelVeeMessageInfo *)mi)->real, name, value);
-
+       if (mi->uid) {
+               CamelMessageInfo *rmi = camel_folder_summary_uid (((CamelVeeMessageInfo *)mi)->summary, mi->uid+8);
+               res = camel_message_info_set_user_tag(rmi, name, value);
+               camel_message_info_free (rmi);                  
+       }
        return res;
 }
 
@@ -124,12 +153,35 @@ vee_info_set_flags(CamelMessageInfo *mi, guint32 flags, guint32 set)
 {
        int res = FALSE;
 
-       if (mi->uid)
-               res = camel_message_info_set_flags(((CamelVeeMessageInfo *)mi)->real, flags, set);
-
+       if (mi->uid) {
+               CamelMessageInfo *rmi = camel_folder_summary_uid (((CamelVeeMessageInfo *)mi)->summary, mi->uid+8);             
+               res = camel_message_info_set_flags(rmi, flags, set);
+               camel_message_info_free (rmi);
+       }
        return res;
 }
 
+static CamelMessageInfo *
+message_info_from_uid (CamelFolderSummary *s, const char *uid)
+{
+       CamelMessageInfoBase *info;
+
+       #warning "too bad design. Need to peek it from cfs instead of hacking ugly like this"
+       CAMEL_SUMMARY_LOCK(s, summary_lock);
+       CAMEL_SUMMARY_LOCK(s, ref_lock);
+
+       info = g_hash_table_lookup (s->loaded_infos, uid);
+
+       if (info)
+               info->refcount++;
+
+       CAMEL_SUMMARY_UNLOCK(s, ref_lock);
+       CAMEL_SUMMARY_UNLOCK(s, summary_lock);
+
+       return (CamelMessageInfo *) info;       
+}
+
 static void
 camel_vee_summary_class_init (CamelVeeSummaryClass *klass)
 {
@@ -152,6 +204,7 @@ camel_vee_summary_class_init (CamelVeeSummaryClass *klass)
        ((CamelFolderSummaryClass *)klass)->info_set_user_tag = vee_info_set_user_tag;
 
        ((CamelFolderSummaryClass *)klass)->info_set_flags = vee_info_set_flags;
+       ((CamelFolderSummaryClass *)klass)->message_info_from_uid = message_info_from_uid;
 }
 
 static void
@@ -201,41 +254,63 @@ camel_vee_summary_new(CamelFolder *parent)
        s = (CamelVeeSummary *)camel_object_new(camel_vee_summary_get_type());
        s->summary.folder = parent;
 
+        #warning "fix exceptions and note return values"
+       #warning "if Evo's junk/trash vfolders make it VJunk VTrash instead of .#evolution/Junk-or-whatever"            
+       camel_db_create_vfolder (parent->cdb, parent->full_name, NULL);
+
+       #warning "handle excep and ret"
+       camel_folder_summary_header_load_from_db ((CamelFolderSummary *)s, parent->parent_store, parent->full_name, NULL);      
        return &s->summary;
 }
 
+GPtrArray *
+camel_vee_summary_get_ids (CamelVeeSummary *summary, char hash[8])
+{
+       char *shash = g_strdup_printf("%c%c%c%c%c%c%c%c", hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7]);
+       CamelFolderSummary *cfs = (CamelFolderSummary *)summary;
+       GPtrArray *array;
+
+       #warning "fix exception passing"
+       array = camel_db_get_vuids_from_vfolder(cfs->folder->cdb, cfs->folder->full_name, shash, NULL);
+       
+       g_free(shash);
+
+       return array;
+}
+
 CamelVeeMessageInfo *
-camel_vee_summary_add(CamelVeeSummary *s, CamelMessageInfo *info, const char hash[8])
+camel_vee_summary_add(CamelVeeSummary *s, CamelFolderSummary *summary, const char *uid, const char hash[8])
 {
        CamelVeeMessageInfo *mi;
        char *vuid;
-       const char *uid;
 
-       uid = camel_message_info_uid(info);
        vuid = g_malloc(strlen(uid)+9);
        memcpy(vuid, hash, 8);
        strcpy(vuid+8, uid);
-       mi = (CamelVeeMessageInfo *)camel_folder_summary_uid(&s->summary, vuid);
+       
+       #warning do we need it really ?
+/*     mi = (CamelVeeMessageInfo *)camel_folder_summary_uid(&s->summary, vuid); */
+/*     if (mi) { */
+/*             d(printf("w:clash, we already have '%s' in summary\n", vuid)); */
+/*             camel_message_info_free((CamelMessageInfo *)mi); */
+/*             g_free(vuid); */
+/*             return NULL; */
+/*     } */
+
+       mi = (CamelVeeMessageInfo *) message_info_from_uid(&s->summary, vuid); 
        if (mi) {
-               d(printf("w:clash, we already have '%s' in summary\n", vuid));
-               camel_message_info_free((CamelMessageInfo *)mi);
-               g_free(vuid);
-               return NULL;
+               g_warning ("%s - already there\n", vuid);
+               g_free (vuid);
+               return mi;
        }
 
        mi = (CamelVeeMessageInfo *)camel_message_info_new(&s->summary);
-       mi->real = info;
-       camel_message_info_ref(info);
-
-       /* Ensures the owner of the message info will not die before we free the mi->real;
-          It's obvious that the real->summary should not be changed after this call. */
-       /* FIXME: We may not need this during CamelDBSummary */
-       if (info->summary)
-               camel_object_ref (info->summary);
-
-       mi->info.uid = vuid;
-
-       camel_folder_summary_add(&s->summary, (CamelMessageInfo *)mi);
-
+       mi->summary = summary;
+       camel_object_ref (summary);
+       mi->info.uid = (char *) camel_pstring_strdup (vuid);
+       g_free (vuid);
+       camel_message_info_ref (mi);
+       camel_folder_summary_insert(&s->summary, (CamelMessageInfo *)mi, FALSE);
+       
        return mi;
 }
index 435506a..ec9d10f 100644 (file)
@@ -42,8 +42,7 @@ typedef struct _CamelVeeMessageInfo CamelVeeMessageInfo;
 
 struct _CamelVeeMessageInfo {
        CamelMessageInfo info;
-
-       CamelMessageInfo *real;
+       CamelFolderSummary *summary;
 };
 
 struct _CamelVeeSummary {
@@ -58,7 +57,8 @@ struct _CamelVeeSummaryClass {
 CamelType               camel_vee_summary_get_type     (void);
 CamelFolderSummary *camel_vee_summary_new(struct _CamelFolder *parent);
 
-CamelVeeMessageInfo * camel_vee_summary_add(CamelVeeSummary *s, CamelMessageInfo *info, const char hash[8]);
+CamelVeeMessageInfo * camel_vee_summary_add(CamelVeeSummary *s, CamelFolderSummary *summary, const char *uid, const char hash[8]);
+GPtrArray * camel_vee_summary_get_ids (CamelVeeSummary *summary, char hash[8]);
 
 G_END_DECLS
 
index f29195b..e1e9289 100644 (file)
@@ -36,7 +36,7 @@
 #include "camel-store.h"
 #include "camel-vee-store.h"
 #include "camel-vtrash-folder.h"
-
+#include "camel-string-utils.h"
 
 /* Returns the class for a CamelFolder */
 #define CF_CLASS(so) ((CamelFolderClass *)((CamelObject *)(so))->klass)
@@ -48,11 +48,12 @@ static struct {
        guint32 bit;
        guint32 flags;
        const char *error_copy;
+       const char *db_col;
 } vdata[] = {
        { CAMEL_VTRASH_NAME, N_("Trash"), "(match-all (system-flag \"Deleted\"))", CAMEL_MESSAGE_DELETED, CAMEL_FOLDER_IS_TRASH,
-         N_("Cannot copy messages to the Trash folder") },
+         N_("Cannot copy messages to the Trash folder"), "deleted" },
        { CAMEL_VJUNK_NAME, N_("Junk"), "(match-all (system-flag \"Junk\"))", CAMEL_MESSAGE_JUNK, CAMEL_FOLDER_IS_JUNK,
-         N_("Cannot copy messages to the Junk folder") },
+         N_("Cannot copy messages to the Junk folder"), "junk" },
 };
 
 static CamelVeeFolderClass *camel_vtrash_folder_parent;
@@ -262,20 +263,20 @@ vtrash_transfer_messages_to (CamelFolder *source, GPtrArray *uids,
                        continue;
                }
                
-               if (dest == mi->real->summary->folder) {
+               if (dest == mi->summary->folder) {
                        /* Just unset the flag on the original message */
                        camel_folder_set_message_flags (source, uids->pdata[i], sbit, 0);
                } else {
                        if (batch == NULL)
                                batch = g_hash_table_new(NULL, NULL);
-                       md = g_hash_table_lookup(batch, mi->real->summary->folder);
+                       md = g_hash_table_lookup(batch, mi->summary->folder);
                        if (md == NULL) {
                                md = g_malloc0(sizeof(*md));
-                               md->folder = mi->real->summary->folder;
+                               md->folder = mi->summary->folder;
                                camel_object_ref((CamelObject *)md->folder);
                                md->uids = g_ptr_array_new();
                                md->dest = dest;
-                               g_hash_table_insert(batch, mi->real->summary->folder, md);
+                               g_hash_table_insert(batch, mi->summary->folder, md);
                        }
 
                        tuid = uids->pdata[i];
@@ -292,12 +293,14 @@ vtrash_transfer_messages_to (CamelFolder *source, GPtrArray *uids,
        }
 }
 
+#warning rewrite the same way as camel-vee-summary.c
 static GPtrArray *
 vtrash_search_by_expression(CamelFolder *folder, const char *expression, CamelException *ex)
 {
        GList *node;
        GPtrArray *matches, *result = g_ptr_array_new(), *uids = g_ptr_array_new();
        struct _CamelVeeFolderPrivate *p = ((CamelVeeFolder *)folder)->priv;
+       GPtrArray *infos = camel_folder_get_summary(folder);
 
        /* we optimise the search by only searching for messages which we have anyway */
        CAMEL_VEE_FOLDER_LOCK(folder, subfolder_lock);
@@ -306,17 +309,20 @@ vtrash_search_by_expression(CamelFolder *folder, const char *expression, CamelEx
                CamelFolder *f = node->data;
                int i;
                char hash[8];
-               GPtrArray *infos = camel_folder_get_summary(f);
 
                camel_vee_folder_hash_folder(f, hash);
 
                for (i=0;i<infos->len;i++) {
-                       CamelMessageInfo *mi = infos->pdata[i];
-
-                       if (camel_message_info_flags(mi) & ((CamelVTrashFolder *)folder)->bit)
-                               g_ptr_array_add(uids, (void *)camel_message_info_uid(mi));
+                       CamelVeeMessageInfo  *vmi = (CamelVeeMessageInfo *) camel_folder_summary_uid (folder->summary, infos->pdata[i]);
+                       if (!vmi)
+                               continue;
+                       //if (camel_message_info_flags(mi) & ((CamelVTrashFolder *)folder)->bit)
+                       if (vmi->summary == f->summary) /* Belongs to this folder */
+                               g_ptr_array_add(uids, (void *)camel_pstring_strdup(infos->pdata[i]+8));
+                       camel_message_info_free (vmi);
                }
 
+                #warning search in the DB of the folder, for the expression, with the vtrash bit (junk/trash)
                if (uids->len > 0
                    && (matches = camel_folder_search_by_uids(f, expression, uids, NULL))) {
                        for (i = 0; i < matches->len; i++) {
@@ -325,17 +331,19 @@ vtrash_search_by_expression(CamelFolder *folder, const char *expression, CamelEx
                                vuid = g_malloc(strlen(uid)+9);
                                memcpy(vuid, hash, 8);
                                strcpy(vuid+8, uid);
-                               g_ptr_array_add(result, vuid);
+                               g_ptr_array_add(result, camel_pstring_strdup(vuid));
+                               g_free (vuid);
                        }
                        camel_folder_search_free(f, matches);
                }
                g_ptr_array_set_size(uids, 0);
-               camel_folder_free_summary(f, infos);
 
                node = g_list_next(node);
        }
+       camel_folder_free_summary (folder, infos);
        CAMEL_VEE_FOLDER_UNLOCK(folder, subfolder_lock);
 
+       g_ptr_array_foreach (uids, camel_pstring_free, NULL);
        g_ptr_array_free(uids, TRUE);
 
        return result;
@@ -359,19 +367,22 @@ vtrash_search_by_uids(CamelFolder *folder, const char *expression, GPtrArray *ui
                camel_vee_folder_hash_folder(f, hash);
 
                /* map the vfolder uid's to the source folder uid's first */
-               g_ptr_array_set_size(uids, 0);
+               #warning "check this. is it uids od folder_uids"
+               //g_ptr_array_set_size(uids, 0);
+               g_ptr_array_set_size (folder_uids, 0);
                for (i=0;i<uids->len;i++) {
                        char *uid = uids->pdata[i];
                        
-                       if (strlen(uid) >= 8 && strncmp(uid, hash, 8) == 0) {
-                               CamelMessageInfo *mi;
-
-                               mi = camel_folder_get_message_info(f, uid+8);
-                               if (mi) {
-                                       if(camel_message_info_flags(mi) & ((CamelVTrashFolder *)folder)->bit)
+                       //if (strlen(uid) >= 8 && strncmp(uid, hash, 8) == 0) {
+                       if (strncmp(uid, hash, 8) == 0) {                               
+                               //CamelMessageInfo *mi;
+                               #warning "is it really reqd, if so uncomment it"
+                               //mi = camel_folder_get_message_info(f, uid+8);
+                               //if (mi) {
+                               //      if(camel_message_info_flags(mi) & ((CamelVTrashFolder *)folder)->bit)
                                                g_ptr_array_add(folder_uids, uid+8);
-                                       camel_folder_free_message_info(f, mi);
-                               }
+                               //      camel_folder_free_message_info(f, mi);
+                               //}
                        }
                }
 
@@ -383,7 +394,8 @@ vtrash_search_by_uids(CamelFolder *folder, const char *expression, GPtrArray *ui
                                vuid = g_malloc(strlen(uid)+9);
                                memcpy(vuid, hash, 8);
                                strcpy(vuid+8, uid);
-                               g_ptr_array_add(result, vuid);
+                               g_ptr_array_add(result, camel_pstring_strdup(vuid));
+                               g_free (vuid);
                        }
                        camel_folder_search_free(f, matches);
                }
@@ -415,7 +427,7 @@ vtrash_uid_removed(CamelVTrashFolder *vf, const char *uid, char hash[8])
 }
 
 static void
-vtrash_uid_added(CamelVTrashFolder *vf, const char *uid, CamelMessageInfo *info, char hash[8])
+vtrash_uid_added(CamelVTrashFolder *vf, const char *uid, CamelFolderSummary *ssummary, char hash[8])
 {
        char *vuid;
        CamelVeeMessageInfo *vinfo;
@@ -425,8 +437,12 @@ vtrash_uid_added(CamelVTrashFolder *vf, const char *uid, CamelMessageInfo *info,
        strcpy(vuid+8, uid);
        vinfo = (CamelVeeMessageInfo *)camel_folder_summary_uid(((CamelFolder *)vf)->summary, vuid);
        if (vinfo == NULL) {
-               camel_vee_summary_add((CamelVeeSummary *)((CamelFolder *)vf)->summary, info, hash);
-               camel_folder_change_info_add_uid(((CamelVeeFolder *)vf)->changes, vuid);
+               CamelMessageInfo *tinfo;
+               tinfo = camel_vee_summary_add((CamelVeeSummary *)((CamelFolder *)vf)->summary, ssummary, uid, hash);
+               if (tinfo) {
+                       camel_folder_change_info_add_uid(((CamelVeeFolder *)vf)->changes, vuid);
+                       camel_message_info_free (tinfo);
+               }
        } else {
                camel_folder_change_info_change_uid(((CamelVeeFolder *)vf)->changes, vuid);
                camel_message_info_free(vinfo);
@@ -460,7 +476,7 @@ vtrash_folder_changed(CamelVeeFolder *vf, CamelFolder *sub, CamelFolderChangeInf
                if ((camel_message_info_flags(info) & ((CamelVTrashFolder *)vf)->bit) == 0)
                        vtrash_uid_removed((CamelVTrashFolder *)vf, uid, hash);
                else
-                       vtrash_uid_added((CamelVTrashFolder *)vf, uid, info, hash);
+                       vtrash_uid_added((CamelVTrashFolder *)vf, uid, sub->summary, hash);
 
                camel_message_info_free(info);
        }
@@ -474,7 +490,7 @@ vtrash_folder_changed(CamelVeeFolder *vf, CamelFolder *sub, CamelFolderChangeInf
                        continue;
 
                if ((camel_message_info_flags(info) & ((CamelVTrashFolder *)vf)->bit) != 0)
-                       vtrash_uid_added((CamelVTrashFolder *)vf, uid, info, hash);
+                       vtrash_uid_added((CamelVTrashFolder *)vf, uid, sub->summary, hash);
 
                camel_message_info_free(info);
        }
@@ -495,7 +511,7 @@ vtrash_folder_changed(CamelVeeFolder *vf, CamelFolder *sub, CamelFolderChangeInf
 static void
 vtrash_add_folder(CamelVeeFolder *vf, CamelFolder *sub)
 {
-       GPtrArray *infos;
+       GPtrArray *infos=NULL;
        int i;
        char hash[8];
        CamelFolderChangeInfo *vf_changes = NULL;
@@ -504,14 +520,25 @@ vtrash_add_folder(CamelVeeFolder *vf, CamelFolder *sub)
 
        CAMEL_VEE_FOLDER_LOCK(vf, summary_lock);
 
-       infos = camel_folder_get_summary(sub);
-       for (i=0;i<infos->len;i++) {
-               CamelMessageInfo *info = infos->pdata[i];
+       #warning "Search for deleted /junk uids in the db and add them directly"
+       if (((CamelVTrashFolder *)vf)->bit == CAMEL_MESSAGE_DELETED)
+               infos = camel_db_get_folder_deleted_uids (sub->cdb, sub->full_name, NULL);
+       else if (((CamelVTrashFolder *)vf)->bit == CAMEL_MESSAGE_JUNK)
+               infos = camel_db_get_folder_junk_uids (sub->cdb, sub->full_name, NULL);
 
-               if ((camel_message_info_flags(info) & ((CamelVTrashFolder *)vf)->bit))
-                       vtrash_uid_added((CamelVTrashFolder *)vf, camel_message_info_uid(info), info, hash);
+       if (!infos) {
+               CAMEL_VEE_FOLDER_UNLOCK(vf, summary_lock);
+               return;
        }
-       camel_folder_free_summary(sub, infos);
+       
+       for (i=0;i<infos->len;i++) {
+               CamelMessageInfo *info;
+               char *uid = infos->pdata[i];
+               vtrash_uid_added((CamelVTrashFolder *)vf, uid, sub->summary, hash);
+       }
+       
+       g_ptr_array_foreach (infos, camel_pstring_free, NULL);
+       g_ptr_array_free (infos, TRUE);
 
        if (camel_folder_change_info_changed(vf->changes)) {
                vf_changes = vf->changes;
@@ -542,14 +569,18 @@ vtrash_remove_folder(CamelVeeFolder *vf, CamelFolder *sub)
 
        start = -1;
        last = -1;
-       infos = camel_folder_get_summary(sub);
+       infos = camel_folder_get_summary ((CamelFolder *) vf);
        for (i=0;i<infos->len;i++) {
-               CamelVeeMessageInfo *mi = infos->pdata[i];
 
-               if (mi == NULL || mi->real == NULL)
+               CamelVeeMessageInfo *mi = (CamelVeeMessageInfo *) camel_folder_summary_uid (((CamelFolder *)vf)->summary, infos->pdata[i]);
+               if (mi == NULL)
                        continue;
+               if (mi->summary == NULL) {
+                       camel_message_info_free (mi);
+                       continue;
+               }
 
-               if (mi->real->summary == ssummary) {
+               if (mi->summary == ssummary) {
                        const char *uid = camel_message_info_uid(mi);
 
                        camel_folder_change_info_remove_uid(vf->changes, uid);
@@ -564,6 +595,7 @@ vtrash_remove_folder(CamelVeeFolder *vf, CamelFolder *sub)
                                start = last = i;
                        }
                }
+               camel_message_info_free (mi);
        }
        camel_folder_free_summary(sub, infos);
 
diff --git a/camel/db-scrap-tools/db.c b/camel/db-scrap-tools/db.c
new file mode 100644 (file)
index 0000000..11ce1b6
--- /dev/null
@@ -0,0 +1,116 @@
+/* GPL v2 or later - Srinivasa Ragavan - sragavan@novell.com */
+
+#include <stdio.h>
+#include <sqlite3.h>
+
+
+sqlite3 *db;
+
+static int 
+callback (void *data, int argc, char **argv, char **azColName)
+{
+       int i;
+       for(i=0; i<argc; i++) {
+               printf("%s = %s\n", azColName[i], argv[i] ? argv[i] : "NULL");
+       }
+       printf("--DONE \n");
+
+       return 0;
+}
+
+static int
+select_stmt (const char* stmt) {
+       char *errmsg;
+       int   ret;
+       int   nrecs = 0;
+
+       ret = sqlite3_exec(db, stmt, callback, &nrecs, &errmsg);
+
+       if(ret!=SQLITE_OK) {
+               printf("Error in select statement %s [%s].\n", stmt, errmsg);
+       } else {
+               printf("\n   %d records returned.\n", nrecs);
+       }
+
+       return ret;
+}
+
+static int
+sql_stmt(const char* stmt) {
+       char *errmsg;
+       int   ret;
+
+       ret = sqlite3_exec(db, stmt, 0, 0, &errmsg);
+
+       if(ret != SQLITE_OK) {
+               printf("Error in statement: %s [%s].\n", stmt, errmsg);
+               exit (1);
+       }
+
+       return ret;
+}
+
+#define CREATE_STMT "CREATE TABLE %s (uid TEXT PRIMARY KEY, gflags INTEGER, isize INTEGER, dsent INTEGER, dreceived INTEGER, jsubject TEXT, ffrom TEXT, tto TEXT, cc TEXT, mlist TEXT, part TEXT, userflags TEXT, usertags TEXT, bdata TEXT)"
+
+static int
+create_table (const char *tablename)
+{
+       char *cmd = malloc (sizeof(CREATE_STMT)+20);
+       sprintf(cmd, CREATE_STMT, tablename);
+       sql_stmt (cmd);
+}
+
+int sort_uid (void *foo, int len, void * data1, int len2, void *data2)
+{
+       printf("%s \n%s\n\n", data1, data2);
+       int a1 = atoi (data1);
+       int a2 = atoi (data2);
+       return a1 < a2;
+}
+
+int sort_cmp (void *foo, int len, void * data1, int len2, void *data2)
+{
+       printf("%s \n%s\n\n", data1, data2);
+       int a1 = atoi (data1);
+       int a2 = atoi (data2);
+       return a1 == a2 ? 0 : a1 < a2 ? -1 : 1;
+}
+
+int main(int argc, char **argv) {
+       char *zErrMsg = 0;
+       int rc;
+
+//     rc = sqlite3_open_v2("test.db", &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE , NULL);
+       rc = sqlite3_open("test.db", &db);
+
+       if( rc ) {
+               fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
+               sqlite3_close(db);
+               exit(1);
+       }
+
+       sqlite3_create_collation(db, "uidcmp", SQLITE_UTF8,  NULL, sort_cmp);
+       sqlite3_create_collation(db, "uidsort", SQLITE_UTF8,  NULL, sort_uid);
+
+       char *subject_san = "San?%*()-234@#$!@#$@#$%32424kar's Subject";
+       create_table ("table1");
+       sql_stmt (sqlite3_mprintf("INSERT INTO table1 (uid, gflags, isize, jsubject, mlist) VALUES ('5120', 100, 123, '%q', 'mlistbinary')", subject_san));
+       sql_stmt ("INSERT INTO table1 (uid, gflags, isize, jsubject, mlist) VALUES ('6103', 100, 123, 'nice subject', 'mlistbinary')");
+       sql_stmt ("INSERT INTO table1 (uid, gflags, isize, jsubject, mlist) VALUES ('3194', 100, 123, 'nice subject', 'mlistbinary')");
+       sql_stmt ("INSERT INTO table1 (uid, gflags, isize, jsubject, mlist) VALUES ('8130', 100, 123, 'nice subject', 'mlistbinary')");
+       sql_stmt ("INSERT INTO table1 (uid, gflags, isize, jsubject, mlist) VALUES ('9102', 100, 123, 'nice subject', 'mlistbinary')");
+       sql_stmt ("INSERT INTO table1 (uid, gflags, isize, jsubject, mlist) VALUES ('3112', 100, 123, 'nice subject', 'mlistbinary')");
+       sql_stmt ("INSERT INTO table1 (uid, gflags, isize, jsubject, mlist) VALUES ('1102', 100, 123, 'nice subject', 'mlistbinary')");
+       sql_stmt ("INSERT INTO table1 (uid, gflags, isize, jsubject, mlist) VALUES ('214', 100, 123, 'nice subject', 'mlistbinary')");
+       sql_stmt ("INSERT INTO table1 (uid, gflags, isize, jsubject, mlist) VALUES ('3161', 0, 1123, '12nice subject', '123mlistbinary')");
+       
+//     select_stmt ("select * from table1 where uid collate uidsort order by uid collate uidsort");
+       select_stmt ("select * from table1 where uid == 5120 collate uidcmp");
+       printf ("\n\aFrom teh C File: [%s] \n\a", subject_san);
+
+       printf("------\n");
+       select_stmt ("select count(isize) from table1");
+       sqlite3_close(db);
+
+       return 0;
+}
index ff78d22..8dd131d 100644 (file)
@@ -1,3 +1,19 @@
+2008-07-16  Sankar P  <psankar@novell.com>
+
+       Pushing disk summary changes from the madagascar branch
+
+       * camel-groupwise-folder.c (groupwise_sync_summary),
+       (groupwise_sync), (groupwise_refresh_info),
+       (groupwise_refresh_folder), (gw_update_all_items):
+       * camel-groupwise-store.c (groupwise_get_folder),
+       (gw_store_reload_folder):
+       * camel-groupwise-summary.c (camel_groupwise_summary_class_init),
+       (camel_groupwise_summary_new), (summary_header_from_db),
+       (gw_summary_header_load), (summary_header_to_db),
+       (gw_summary_header_save), (message_info_from_db),
+       (message_info_to_db), (content_info_from_db), (content_info_to_db),
+       (groupwise_summary_clear):
+
 2008-05-21  Johnny Jacob  <jjohnny@novell.com>
 
        * camel-groupwise-store.c (convert_to_folder_info): Marking this
index d688128..307a535 100644 (file)
@@ -590,7 +590,7 @@ move_to_junk (CamelFolder *folder, CamelMessageInfo *info, CamelException *ex)
 static void 
 groupwise_sync_summary (CamelFolder *folder, CamelException *ex)
 {
-       camel_folder_summary_save (folder->summary);
+       camel_folder_summary_save_to_db (folder->summary, ex);
        camel_store_summary_touch ((CamelStoreSummary *)((CamelGroupwiseStore *)folder->parent_store)->summary);
        camel_store_summary_save ((CamelStoreSummary *)((CamelGroupwiseStore *)folder->parent_store)->summary);
 }
@@ -673,6 +673,7 @@ groupwise_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
                                const char *uid;
 
                                gw_info->info.flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED;
+                               gw_info->info.dirty = 1;
                                gw_info->server_flags = gw_info->info.flags;
                                uid = camel_message_info_uid (info);
                                if (diff.bits & CAMEL_MESSAGE_DELETED) {
@@ -1004,7 +1005,7 @@ groupwise_refresh_info(CamelFolder *folder, CamelException *ex)
                        }
                        camel_store_summary_info_free ((CamelStoreSummary *)((CamelGroupwiseStore *)folder->parent_store)->summary, si);
                }
-               camel_folder_summary_save (folder->summary);
+               //camel_folder_summary_save_to_db (folder->summary, ex);
                camel_store_summary_save ((CamelStoreSummary *)((CamelGroupwiseStore *)folder->parent_store)->summary);
        } else {
                /* We probably could not get the messages the first time. (get_folder) failed???!
@@ -1036,7 +1037,7 @@ groupwise_refresh_folder(CamelFolder *folder, CamelException *ex)
 
        /* Sync-up the (un)read changes before getting updates,
        so that the getFolderList will reflect the most recent changes too */
-       groupwise_sync (folder, FALSE, ex);
+       //groupwise_sync (folder, FALSE, ex);
 
        if (((CamelOfflineStore *) gw_store)->state == CAMEL_OFFLINE_STORE_NETWORK_UNAVAIL) {
                g_warning ("In offline mode. Cannot refresh!!!\n");
@@ -1969,7 +1970,8 @@ gw_update_all_items (CamelFolder *folder, GList *item_list, CamelException *ex)
        int index = 0;
        GList *temp;
        CamelFolderChangeInfo *changes = NULL;
-       CamelMessageInfo *info; 
+       char *uid;
+
        changes = camel_folder_change_info_new ();
 
        item_list = g_list_reverse (item_list);
@@ -1977,18 +1979,18 @@ gw_update_all_items (CamelFolder *folder, GList *item_list, CamelException *ex)
        summary = camel_folder_get_summary (folder);
        /*item_ids : List of ids from the summary*/
        while (index < summary->len) {
-               info = g_ptr_array_index (summary, index);
+               uid = g_ptr_array_index (summary, index);
                temp = NULL; 
 
                if (item_list) {
-                       temp = g_list_find_custom (item_list, (const char *)info->uid, (GCompareFunc) strcmp);
+                       temp = g_list_find_custom (item_list, (const char *)uid, (GCompareFunc) strcmp);
                }
 
                if (!temp) {
                        CAMEL_GROUPWISE_FOLDER_REC_LOCK (folder, cache_lock);
-                       camel_folder_summary_remove_uid (folder->summary, info->uid);
-                       camel_data_cache_remove (gw_folder->cache, "cache", info->uid, NULL);
-                       camel_folder_change_info_remove_uid (changes, info->uid);
+                       camel_folder_summary_remove_uid (folder->summary, uid);
+                       camel_data_cache_remove (gw_folder->cache, "cache", uid, NULL);
+                       camel_folder_change_info_remove_uid (changes, uid);
                        CAMEL_GROUPWISE_FOLDER_REC_UNLOCK (folder, cache_lock);
                } else { 
                        item_list = g_list_delete_link (item_list, temp);
index ea87465..ddc7d48 100644 (file)
@@ -634,7 +634,7 @@ groupwise_get_folder (CamelStore *store, const char *folder_name, guint32 flags,
                                CAMEL_SERVICE_REC_UNLOCK (gw_store, connect_lock);
                                e_gw_connection_destroy_cursor (priv->cnc, container_id, cursor);
                                //camel_folder_summary_clear (folder->summary);
-                               camel_folder_summary_save (folder->summary);
+                               camel_folder_summary_save_to_db (folder->summary, ex);
                                camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_INVALID, _("Authentication failed"));
                                camel_operation_end (NULL);
                                camel_object_unref (folder);
@@ -666,7 +666,7 @@ groupwise_get_folder (CamelStore *store, const char *folder_name, guint32 flags,
                summary->time_string = g_strdup (e_gw_connection_get_server_time (priv->cnc));
        }
 
-       camel_folder_summary_save (folder->summary);
+       camel_folder_summary_save_to_db (folder->summary, ex);
 
        gw_store->current_folder = folder;
        camel_object_ref (folder);
@@ -717,7 +717,7 @@ gw_store_reload_folder (CamelGroupwiseStore *gw_store, CamelFolder *folder, guin
 
        summary = (CamelGroupwiseSummary *) folder->summary;
        camel_folder_summary_clear (folder->summary);
-       camel_folder_summary_save (folder->summary);
+       camel_folder_summary_save_to_db (folder->summary, ex);
 
        summary_count = camel_folder_summary_count (folder->summary);
        if(!summary_count || !summary->time_string) {
@@ -742,7 +742,7 @@ gw_store_reload_folder (CamelGroupwiseStore *gw_store, CamelFolder *folder, guin
                        if (status != E_GW_CONNECTION_STATUS_OK) {
                                CAMEL_SERVICE_REC_UNLOCK (gw_store, connect_lock);
                                e_gw_connection_destroy_cursor (priv->cnc, container_id, cursor);
-                               camel_folder_summary_save (folder->summary);
+                               camel_folder_summary_save_to_db (folder->summary, ex);
                                camel_exception_set (ex, CAMEL_EXCEPTION_SERVICE_INVALID, _("Authentication failed"));
                                camel_operation_end (NULL);
                                g_free (container_id);
@@ -774,7 +774,7 @@ gw_store_reload_folder (CamelGroupwiseStore *gw_store, CamelFolder *folder, guin
                summary->time_string = g_strdup (e_gw_connection_get_server_time (priv->cnc));
        }
 
-       camel_folder_summary_save (folder->summary);
+       camel_folder_summary_save_to_db (folder->summary, ex);
 
        gw_store->current_folder = folder;
        
index c897681..f5d90d7 100644 (file)
@@ -42,6 +42,9 @@
 
 #define CAMEL_GW_SUMMARY_VERSION (1)
 
+#define EXTRACT_FIRST_DIGIT(val) part ? val=strtoul (part, &part, 10) : 0;
+#define EXTRACT_DIGIT(val) part++; part ? val=strtoul (part, &part, 10) : 0;
+
 /*Prototypes*/
 static int gw_summary_header_load (CamelFolderSummary *, FILE *);
 static int gw_summary_header_save (CamelFolderSummary *, FILE *);
@@ -53,6 +56,13 @@ static CamelMessageContentInfo * gw_content_info_load (CamelFolderSummary *s, FI
 static int gw_content_info_save (CamelFolderSummary *s, FILE *out, CamelMessageContentInfo *info) ;
 static gboolean gw_info_set_flags(CamelMessageInfo *info, guint32 flags, guint32 set);         
 
+static int summary_header_from_db (CamelFolderSummary *s, CamelFIRecord *mir);
+static CamelFIRecord * summary_header_to_db (CamelFolderSummary *s, CamelException *ex);
+static CamelMIRecord * message_info_to_db (CamelFolderSummary *s, CamelMessageInfo *info);
+static CamelMessageInfo * message_info_from_db (CamelFolderSummary *s, CamelMIRecord *mir);
+static int content_info_to_db (CamelFolderSummary *s, CamelMessageContentInfo *info, CamelMIRecord *mir);
+static CamelMessageContentInfo * content_info_from_db (CamelFolderSummary *s, CamelMIRecord *mir);
+
 static void camel_groupwise_summary_class_init (CamelGroupwiseSummaryClass *klass);
 static void camel_groupwise_summary_init       (CamelGroupwiseSummary *obj);
 
@@ -112,6 +122,14 @@ camel_groupwise_summary_class_init (CamelGroupwiseSummaryClass *klass)
        cfs_class->content_info_load = gw_content_info_load;
        cfs_class->content_info_save = gw_content_info_save;
        cfs_class->info_set_flags = gw_info_set_flags;
+
+       cfs_class->summary_header_to_db = summary_header_to_db;
+       cfs_class->summary_header_from_db = summary_header_from_db;
+       cfs_class->message_info_to_db = message_info_to_db;
+       cfs_class->message_info_from_db = message_info_from_db;
+       cfs_class->content_info_to_db = content_info_to_db;
+       cfs_class->content_info_from_db = content_info_from_db;
+       
 }
 
 
@@ -141,53 +159,109 @@ camel_groupwise_summary_init (CamelGroupwiseSummary *obj)
 CamelFolderSummary *
 camel_groupwise_summary_new (struct _CamelFolder *folder, const char *filename)
 {
+       CamelException ex;
        CamelFolderSummary *summary = CAMEL_FOLDER_SUMMARY (
                        camel_object_new (camel_groupwise_summary_get_type ()));
        
        summary->folder = folder ;
        camel_folder_summary_set_build_content (summary, TRUE);
-       camel_folder_summary_set_filename (summary, filename);
 
-       if (camel_folder_summary_load (summary) == -1) {
+       camel_exception_init (&ex);
+       if (camel_folder_summary_load_from_db (summary, &ex) == -1) {
                camel_folder_summary_clear (summary);
-               camel_folder_summary_touch (summary);
        }
 
        return summary;
 }
 
 static int
+summary_header_from_db (CamelFolderSummary *s, CamelFIRecord *mir)
+{
+       CamelGroupwiseSummary *gms = CAMEL_GROUPWISE_SUMMARY (s);
+       char *part;
+
+       if (camel_groupwise_summary_parent->summary_header_from_db (s, mir) == -1)
+               return -1 ;
+
+       part = mir->bdata;
+
+       if (part)
+               EXTRACT_FIRST_DIGIT(gms->version);
+
+       if (part)
+               EXTRACT_DIGIT (gms->validity);
+
+       if (part && part++) {
+               gms->time_string = g_strdup (part);
+       }
+               
+       return 0;
+}
+
+static int
 gw_summary_header_load (CamelFolderSummary *s, FILE *in)
 {
-       CamelGroupwiseSummary *ims = CAMEL_GROUPWISE_SUMMARY (s);
+       CamelGroupwiseSummary *gms = CAMEL_GROUPWISE_SUMMARY (s);
 
        if (camel_groupwise_summary_parent->summary_header_load (s, in) == -1)
                return -1 ;
 
-       if (camel_file_util_decode_fixed_int32(in, &ims->version) == -1
-                       || camel_file_util_decode_fixed_int32(in, &ims->validity) == -1)
+       if (camel_file_util_decode_fixed_int32(in, &gms->version) == -1
+                       || camel_file_util_decode_fixed_int32(in, &gms->validity) == -1)
                return -1;
        
-       if (camel_file_util_decode_string (in, &ims->time_string) == -1)
+       if (camel_file_util_decode_string (in, &gms->time_string) == -1)
                return -1;
        return 0 ;
 }
 
 
+
+
+
+static CamelFIRecord *
+summary_header_to_db (CamelFolderSummary *s, CamelException *ex)
+{
+       CamelGroupwiseSummary *ims = CAMEL_GROUPWISE_SUMMARY(s);
+       struct _CamelFIRecord *fir;
+       
+       fir = camel_groupwise_summary_parent->summary_header_to_db (s, ex);
+       if (!fir)
+               return NULL;
+       
+       fir->bdata = g_strdup_printf ("%d %d %s", CAMEL_GW_SUMMARY_VERSION, ims->validity, ims->time_string);
+
+       return fir;
+       
+}
+
 static int
 gw_summary_header_save (CamelFolderSummary *s, FILE *out)
 {
-       CamelGroupwiseSummary *ims = CAMEL_GROUPWISE_SUMMARY(s);
+       CamelGroupwiseSummary *gms = CAMEL_GROUPWISE_SUMMARY(s);
 
        if (camel_groupwise_summary_parent->summary_header_save (s, out) == -1)
                return -1;
 
        camel_file_util_encode_fixed_int32(out, CAMEL_GW_SUMMARY_VERSION);
-       camel_file_util_encode_fixed_int32(out, ims->validity);
-       return camel_file_util_encode_string (out, ims->time_string);
+       camel_file_util_encode_fixed_int32(out, gms->validity);
+       return camel_file_util_encode_string (out, gms->time_string);
+}
 
+static CamelMessageInfo * 
+message_info_from_db (CamelFolderSummary *s, CamelMIRecord *mir)
+{
+       CamelMessageInfo *info;
+       CamelGroupwiseMessageInfo *iinfo;
 
-}
+       info = camel_groupwise_summary_parent->message_info_from_db (s, mir);
+       if (info) {
+               char *part = mir->bdata;
+               iinfo = (CamelGroupwiseMessageInfo *)info;
+               EXTRACT_FIRST_DIGIT (iinfo->server_flags)
+       }
+
+       return info;}
 
 static CamelMessageInfo *
 gw_message_info_load (CamelFolderSummary *s, FILE *in)
@@ -209,6 +283,18 @@ error:
        return NULL ;
 }
 
+static CamelMIRecord * 
+message_info_to_db (CamelFolderSummary *s, CamelMessageInfo *info)
+{
+       CamelGroupwiseMessageInfo *iinfo = (CamelGroupwiseMessageInfo *)info;
+       struct _CamelMIRecord *mir;
+
+       mir = camel_groupwise_summary_parent->message_info_to_db (s, info);
+       if (mir) 
+               mir->bdata = g_strdup_printf ("%u", iinfo->server_flags);
+
+       return mir;     
+}
 
 static int
 gw_message_info_save (CamelFolderSummary *s, FILE *out, CamelMessageInfo *info)
@@ -221,6 +307,21 @@ gw_message_info_save (CamelFolderSummary *s, FILE *out, CamelMessageInfo *info)
        return camel_file_util_encode_uint32 (out, gw_info->server_flags);
 }
 
+static CamelMessageContentInfo * 
+content_info_from_db (CamelFolderSummary *s, CamelMIRecord *mir)
+{
+       char *part = mir->cinfo;
+       guint32 type=0;
+       
+       if (part) {
+               EXTRACT_FIRST_DIGIT (type);
+       }
+       if (type)
+               return camel_groupwise_summary_parent->content_info_from_db (s, mir);
+       else
+               return camel_folder_summary_content_info_new (s);
+}
+
 
 static CamelMessageContentInfo *
 gw_content_info_load (CamelFolderSummary *s, FILE *in)
@@ -231,6 +332,18 @@ gw_content_info_load (CamelFolderSummary *s, FILE *in)
                return camel_folder_summary_content_info_new (s);
 }
 
+static int 
+content_info_to_db (CamelFolderSummary *s, CamelMessageContentInfo *info, CamelMIRecord *mir)
+{
+
+       if (info->type) {
+               mir->cinfo = g_strdup ("1");
+               return camel_groupwise_summary_parent->content_info_to_db (s, info, mir);
+       } else {
+               mir->cinfo = g_strdup ("0");
+               return 0;
+       }
+}
 
 static int
 gw_content_info_save (CamelFolderSummary *s, FILE *out,
@@ -355,7 +468,7 @@ groupwise_summary_clear (CamelFolderSummary *summary, gboolean uncache)
        }
 
        camel_folder_summary_clear (summary);
-       camel_folder_summary_save (summary);
+       //camel_folder_summary_save (summary);
 
        if (uncache)
                camel_data_cache_clear (((CamelGroupwiseFolder *) summary->folder)->cache, "cache", NULL);
index e24dd03..ecb3254 100644 (file)
@@ -1,3 +1,22 @@
+2008-07-16  Sankar P  <psankar@novell.com>
+
+       Pushing disk summary changes from the madagascar branch
+
+       * camel-imap-folder.c (camel_imap_folder_selected),
+       (imap_refresh_info), (fillup_custom_flags), (merge_custom_flags),
+       (imap_rescan), (get_matching), (imap_sync_offline),
+       (imap_sync_online), (imap_expunge_uids_offline),
+       (imap_update_summary), (camel_imap_folder_changed):
+       * camel-imap-message-cache.c (camel_imap_message_cache_new):
+       * camel-imap-store.c (fill_fi):
+       * camel-imap-summary.c (camel_imap_summary_class_init),
+       (camel_imap_summary_new), (summary_header_from_db),
+       (summary_header_to_db), (message_info_from_db),
+       (message_info_to_db), (content_info_from_db), (content_info_to_db),
+       (camel_imap_summary_add_offline),
+       (camel_imap_summary_add_offline_uncached), (uid_compare):
+       * camel-imap-utils.c (get_summary_uid_numeric):
+
 2008-06-30  Milan Crha  <mcrha@redhat.com>
 
        ** Fix for bug #330838
index 1f954a4..faca3e0 100644 (file)
@@ -306,11 +306,10 @@ camel_imap_folder_selected (CamelFolder *folder, CamelImapResponse *response,
        CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
        CamelImapSummary *imap_summary = CAMEL_IMAP_SUMMARY (folder->summary);
        unsigned long exists = 0, validity = 0, val, uid;
-       CamelMessageInfo *info;
        guint32 perm_flags = 0;
        GData *fetch_data;
        int i, count;
-       char *resp;
+       char *resp, *old_uid;
        
        count = camel_folder_summary_count (folder->summary);
        
@@ -408,11 +407,13 @@ camel_imap_folder_selected (CamelFolder *folder, CamelImapResponse *response,
                }
                camel_imap_response_free_without_processing (store, response);
                
-               info = camel_folder_summary_index (folder->summary, count - 1);
-               val = strtoul (camel_message_info_uid (info), NULL, 10);
-               camel_message_info_free(info);
-               if (uid == 0 || uid != val)
-                       imap_folder->need_rescan = TRUE;
+               old_uid = camel_folder_summary_uid_from_index (folder->summary, count - 1);
+               if (old_uid) { 
+                       val = strtoul (old_uid, NULL, 10);
+                       g_free (old_uid);
+                       if (uid == 0 || uid != val)
+                               imap_folder->need_rescan = TRUE;
+               }
        }
        
        /* Now rescan if we need to */
@@ -725,7 +726,7 @@ imap_refresh_info (CamelFolder *folder, CamelException *ex)
 done:
        CAMEL_SERVICE_REC_UNLOCK (imap_store, connect_lock);
 
-       camel_folder_summary_save(folder->summary);
+       camel_folder_summary_save_to_db (folder->summary, ex);
        camel_store_summary_save((CamelStoreSummary *)((CamelImapStore *)folder->parent_store)->summary);
 }
 
@@ -738,7 +739,7 @@ fillup_custom_flags (CamelMessageInfo *mi, char *custom_flags)
        array_str = g_strsplit (custom_flags, " ", -1);
 
        while (array_str[index] != NULL) {
-               camel_message_info_set_user_flag (mi, array_str[index], TRUE);
+               camel_flag_set(&((CamelMessageInfoBase *)mi)->user_flags, array_str[index], TRUE);
                ++ index;
        }
 
@@ -791,7 +792,8 @@ merge_custom_flags (CamelMessageInfo *mi, const char *custom_flags)
                        /* If this value came from the server, then add it to our local summary,
                           otherwise it was in local summary, but isn't on the server, thus remove it. */
                        changed = TRUE;
-                       camel_message_info_set_user_flag (mi, p->data, g_hash_table_lookup (server, p->data) != NULL);
+                       camel_flag_set (mi, p->data, g_hash_table_lookup (server, p->data) != NULL);
+                       ((CamelMessageInfoBase *) mi)->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
                }
        }
 
@@ -814,7 +816,7 @@ imap_rescan (CamelFolder *folder, int exists, CamelException *ex)
                guint32 flags;
                char *custom_flags;
        } *new;
-       char *resp;
+       char *resp, *uid;
        CamelImapResponseType type;
        int i, seq, summary_len, summary_got;
        CamelMessageInfo *info;
@@ -837,11 +839,17 @@ imap_rescan (CamelFolder *folder, int exists, CamelException *ex)
        
        /* Check UIDs and flags of all messages we already know of. */
        camel_operation_start (NULL, _("Scanning for changed messages in %s"), folder->name);
-       info = camel_folder_summary_index (folder->summary, summary_len - 1);
+       uid = camel_folder_summary_uid_from_index (folder->summary, summary_len - 1);
+
+       if (!uid) {
+               camel_operation_end (NULL);
+               return;
+       }
+
        ok = camel_imap_command_start (store, folder, ex,
                                       "UID FETCH 1:%s (FLAGS)",
-                                      camel_message_info_uid (info));
-       camel_message_info_free(info);
+                                      uid);
+       g_free (uid);
        if (!ok) {
                camel_operation_end (NULL);
                return;
@@ -875,6 +883,11 @@ imap_rescan (CamelFolder *folder, int exists, CamelException *ex)
                g_datalist_clear (&data);
        }
 
+       if (summary_got == 0) {
+               CAMEL_SERVICE_REC_UNLOCK (store, connect_lock);
+               g_free(new);
+               return;
+       }
        camel_operation_end (NULL);
        if (type == CAMEL_IMAP_RESPONSE_ERROR || camel_application_is_exiting) {
                for (i = 0; i < summary_len && new[i].uid; i++) {
@@ -900,21 +913,35 @@ imap_rescan (CamelFolder *folder, int exists, CamelException *ex)
         * from the summary.
         */
        removed = g_array_new (FALSE, FALSE, sizeof (int));
+       
+       if (summary_len - camel_folder_summary_cache_size (folder->summary) > 50)
+               camel_folder_summary_reload_from_db (folder->summary, ex);
+       
        for (i = 0; i < summary_len && new[i].uid; i++) {
                gboolean changed = FALSE;
 
-               info = camel_folder_summary_index (folder->summary, i);
-               iinfo = (CamelImapMessageInfo *)info;
+               uid = camel_folder_summary_uid_from_index (folder->summary, i);
                
-               if (strcmp (camel_message_info_uid (info), new[i].uid) != 0) {
-                       camel_message_info_free(info);
+               if (!uid) 
+                       continue; 
+
+               info = camel_folder_summary_uid (folder->summary, uid);
+
+               iinfo = (CamelImapMessageInfo *)info;
+
+               if (strcmp (uid, new[i].uid) != 0) {
+                       g_free (uid);
+
                        seq = i + 1;
                        g_array_append_val (removed, seq);
                        i--;
                        summary_len--;
+                       camel_message_info_free(info);
                        continue;
                }
                
+               g_free (uid);
+
                /* Update summary flags */
                if (new[i].flags != iinfo->server_flags) {
                        guint32 server_set, server_cleared;
@@ -984,7 +1011,7 @@ imap_rescan (CamelFolder *folder, int exists, CamelException *ex)
  * caller must free the infos, the array, and the set string.
  */
 static GPtrArray *
-get_matching (CamelFolder *folder, guint32 flags, guint32 mask, CamelMessageInfo *master_info, char **set)
+get_matching (CamelFolder *folder, guint32 flags, guint32 mask, CamelMessageInfo *master_info, char **set, GPtrArray *summary)
 {
        GPtrArray *matches;
        CamelImapMessageInfo *info;
@@ -992,6 +1019,7 @@ get_matching (CamelFolder *folder, guint32 flags, guint32 mask, CamelMessageInfo
        GString *gset;
        GSList *list1 = NULL;
        int count1 = 0;
+       char *uid;
 
        #define close_range()                                                                           \
                if (range != -1) {                                                                      \
@@ -1004,10 +1032,16 @@ get_matching (CamelFolder *folder, guint32 flags, guint32 mask, CamelMessageInfo
 
        matches = g_ptr_array_new ();
        gset = g_string_new ("");
-       max = camel_folder_summary_count (folder->summary);
+       max = summary->len;     
        range = -1;
        for (i = 0; i < max && !UID_SET_FULL (gset->len, UID_SET_LIMIT); i++) {
-               info = (CamelImapMessageInfo *)camel_folder_summary_index (folder->summary, i);
+               uid = summary->pdata[i];
+
+               if (uid) {
+                       info = (CamelImapMessageInfo *) camel_folder_summary_uid (folder->summary, uid);
+               } else
+                       continue;
+               
                if (!info)
                        continue;
                if ((info->info.flags & mask) != flags) {
@@ -1059,6 +1093,10 @@ get_matching (CamelFolder *folder, guint32 flags, guint32 mask, CamelMessageInfo
                }
                
                g_ptr_array_add (matches, info);
+               /* Remove the uid from the list, to optimize*/
+               camel_pstring_free(summary->pdata[i]);
+               summary->pdata[i] = NULL;
+               
                if (range != -1)
                        continue;
                range = i;
@@ -1116,7 +1154,7 @@ imap_sync_offline (CamelFolder *folder, CamelException *ex)
                }
        }
 
-       camel_folder_summary_save (folder->summary);
+       camel_folder_summary_save_to_db (folder->summary, ex);
        camel_store_summary_save((CamelStoreSummary *)((CamelImapStore *)folder->parent_store)->summary);
 }
 
@@ -1126,8 +1164,9 @@ imap_sync_online (CamelFolder *folder, CamelException *ex)
        CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
        CamelImapMessageInfo *info;
        CamelException local_ex;
-       GPtrArray *matches;
-       char *set, *flaglist;
+
+       GPtrArray *matches, *summary;
+       char *set, *flaglist, *uid;
        int i, j, max;
        
        if (folder->permanent_flags == 0) {
@@ -1142,14 +1181,22 @@ imap_sync_online (CamelFolder *folder, CamelException *ex)
         * messages like it, sync them as a group, mark them as
         * updated, and continue.
         */
-       max = camel_folder_summary_count (folder->summary);
+       summary = camel_folder_summary_get_changed (folder->summary); /* These should be in memory anyways*/
+       max = summary->len;
+               
        for (i = 0; i < max; i++) {
                gboolean unset = FALSE;
                CamelImapResponse *response = NULL;
 
-               if (!(info = (CamelImapMessageInfo *)camel_folder_summary_index (folder->summary, i)))
+               uid = summary->pdata[i];
+
+               if (!uid) /* Possibly it was sync by matching flags, which we NULLify */
                        continue;
-               
+
+               if (!(info = (CamelImapMessageInfo *) camel_folder_summary_uid (folder->summary, uid))) {
+                       continue;
+               }
+
                if (!(info->info.flags & CAMEL_MESSAGE_FOLDER_FLAGGED)) {
                        camel_message_info_free((CamelMessageInfo *)info);
                        continue;
@@ -1161,7 +1208,7 @@ imap_sync_online (CamelFolder *folder, CamelException *ex)
                   they will be scooped up later by our parent loop (I
                   think?). -- Jeff */
                matches = get_matching (folder, info->info.flags & (folder->permanent_flags | CAMEL_MESSAGE_FOLDER_FLAGGED),
-                                       folder->permanent_flags | CAMEL_MESSAGE_FOLDER_FLAGGED, (CamelMessageInfo *)info, &set);
+                                       folder->permanent_flags | CAMEL_MESSAGE_FOLDER_FLAGGED, (CamelMessageInfo *)info, &set, summary);
                camel_message_info_free(info);
                if (matches == NULL)
                        continue;
@@ -1231,6 +1278,9 @@ imap_sync_online (CamelFolder *folder, CamelException *ex)
                /* Re-lock the connect_lock */
                CAMEL_SERVICE_REC_LOCK (store, connect_lock);
        }
+
+       g_ptr_array_foreach (summary, camel_pstring_free, NULL);
+       g_ptr_array_free (summary, TRUE);
        
        /* Save the summary */
        imap_sync_offline (folder, ex);
@@ -1271,7 +1321,7 @@ imap_expunge_uids_offline (CamelFolder *folder, GPtrArray *uids, CamelException
                 * the cached data may be useful in replaying a COPY later.
                 */
        }
-       camel_folder_summary_save (folder->summary);
+       camel_folder_summary_save_to_db (folder->summary, ex);
 
        camel_disco_diary_log (CAMEL_DISCO_STORE (folder->parent_store)->diary,
                               CAMEL_DISCO_DIARY_FOLDER_EXPUNGE, folder, uids);
@@ -2834,7 +2884,7 @@ imap_update_summary (CamelFolder *folder, int exists,
        GString *header_spec = NULL;
        CamelImapMessageInfo *mi, *info;
        CamelStream *stream;
-       char *uid, *resp;
+       char *uid, *resp, *tempuid;
        GData *data;
        extern int camel_application_is_exiting;
 
@@ -2869,9 +2919,13 @@ imap_update_summary (CamelFolder *folder, int exists,
        seq = camel_folder_summary_count (folder->summary);
        first = seq + 1;
        if (seq > 0) {
-               mi = (CamelImapMessageInfo *)camel_folder_summary_index (folder->summary, seq - 1);
-               uidval = strtoul(camel_message_info_uid (mi), NULL, 10);
-               camel_message_info_free(&mi->info);
+               tempuid = camel_folder_summary_uid_from_index (folder->summary, seq -1 );
+
+               if (tempuid) {
+                       uidval = strtoul(tempuid, NULL, 10);
+                       g_free (tempuid);
+               } else
+                       uidval = 0;
        } else
                uidval = 0;
        
@@ -2891,10 +2945,13 @@ imap_update_summary (CamelFolder *folder, int exists,
         */
        fetch_data = g_ptr_array_new ();
        messages = g_ptr_array_new ();
+       int k = 0, ct;
+       ct = exists - seq;
        while ((type = camel_imap_command_response (store, &resp, ex)) ==
               CAMEL_IMAP_RESPONSE_UNTAGGED && !camel_application_is_exiting) {
                data = parse_fetch_response (imap_folder, resp);
                g_free (resp);
+               k++;
                if (!data)
                        continue;
                
@@ -2919,7 +2976,7 @@ imap_update_summary (CamelFolder *folder, int exists,
                        g_datalist_set_data (&data, "BODY_PART_STREAM", NULL);
                }
 
-               camel_operation_progress (NULL, got * 100 / size);
+               camel_operation_progress (NULL, k * 100 / ct);
                g_ptr_array_add (fetch_data, data);
        }
        camel_operation_end (NULL);
@@ -3047,7 +3104,7 @@ imap_update_summary (CamelFolder *folder, int exists,
                
                uid = g_datalist_get_data (&data, "UID");
                if (uid)
-                       mi->info.uid = g_strdup (uid);
+                       mi->info.uid = camel_pstring_strdup (uid);
                flags = GPOINTER_TO_INT (g_datalist_get_data (&data, "FLAGS"));
                if (flags) {
                        char *custom_flags = NULL;
@@ -3098,22 +3155,26 @@ imap_update_summary (CamelFolder *folder, int exists,
                                              i + first);
                        break;
                }
-               info = (CamelImapMessageInfo *)camel_folder_summary_uid(folder->summary, uid);
-               if (info) {
-                       for (seq = 0; seq < camel_folder_summary_count (folder->summary); seq++) {
-                               if (folder->summary->messages->pdata[seq] == info)
-                                       break;
-                       }
 
-                       g_warning("Message already present? %s", camel_message_info_uid(mi));
-                       camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-                                             _("Unexpected server response: Identical UIDs provided for messages %d and %d"),
-                                             seq + 1, i + first);
+               /* FIXME: If it enters if(info) it will always match the exception. So stupid */
+               #warning "Use a db query to see if the DB exists"
+/*             info = (CamelImapMessageInfo *)camel_folder_summary_uid(folder->summary, uid); */
+/*             if (info) { */
+/*                     for (seq = 0; seq < camel_folder_summary_count (folder->summary); seq++) { */
+/*                             if (folder->summary->messages->pdata[seq] == info) */
+/*                                     break; */
+/*                     } */
 
-                       camel_message_info_free(&info->info);
-                       break;
-               } 
+/*                     g_warning("Message already present? %s", camel_message_info_uid(mi)); */
+/*                     camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM, */
+/*                                           _("Unexpected server response: Identical UIDs provided for messages %d and %d"), */
+/*                                           seq + 1, i + first); */
+
+/*                     camel_message_info_free(&info->info); */
+/*                     break; */
+/*             }  */
 
+               ((CamelMessageInfoBase *)mi)->dirty = TRUE;
                camel_folder_summary_add (folder->summary, (CamelMessageInfo *)mi);
                camel_folder_change_info_add_uid (changes, camel_message_info_uid (mi));
 
@@ -3123,11 +3184,6 @@ imap_update_summary (CamelFolder *folder, int exists,
                        camel_folder_change_info_recent_uid (changes, camel_message_info_uid (mi));
        }
 
-       for ( ; i < messages->len; i++) {
-               if ((mi = messages->pdata[i]))
-                       camel_message_info_free(&mi->info);
-       }
-       
        g_ptr_array_free (messages, TRUE);
        
        return;
@@ -3159,26 +3215,27 @@ camel_imap_folder_changed (CamelFolder *folder, int exists,
        CamelFolderChangeInfo *changes;
        CamelMessageInfo *info;
        int len;
-       
+       char *uid;
+
        changes = camel_folder_change_info_new ();
        if (expunged) {
                int i, id;
                
                for (i = 0; i < expunged->len; i++) {
                        id = g_array_index (expunged, int, i);
-                       info = camel_folder_summary_index (folder->summary, id - 1);
-                       if (info == NULL) {
+                       uid = camel_folder_summary_uid_from_index (folder->summary, id - 1);
+                       if (uid == NULL) {
                                /* FIXME: danw: does this mean that the summary is corrupt? */
                                /* I guess a message that we never retrieved got expunged? */
                                continue;
                        }
                        
-                       camel_folder_change_info_remove_uid (changes, camel_message_info_uid (info));
+                       camel_folder_change_info_remove_uid (changes, uid);
                        CAMEL_IMAP_FOLDER_REC_LOCK (imap_folder, cache_lock);
-                       camel_imap_message_cache_remove (imap_folder->cache, camel_message_info_uid (info));
+                       camel_imap_message_cache_remove (imap_folder->cache, uid);
                        CAMEL_IMAP_FOLDER_REC_UNLOCK (imap_folder, cache_lock);
-                       camel_folder_summary_remove (folder->summary, info);
-                       camel_message_info_free(info);
+                       camel_folder_summary_remove_uid (folder->summary, uid);
+                       g_free (uid);
                }
        }
 
@@ -3190,7 +3247,7 @@ camel_imap_folder_changed (CamelFolder *folder, int exists,
                camel_object_trigger_event (CAMEL_OBJECT (folder), "folder_changed", changes);
 
        camel_folder_change_info_free (changes);
-       camel_folder_summary_save (folder->summary);
+       camel_folder_summary_save_to_db (folder->summary, ex);
 }
 
 static void
index 706f888..4dd0252 100644 (file)
@@ -179,12 +179,17 @@ camel_imap_message_cache_new (const char *path, CamelFolderSummary *summary,
                else
                        uid = g_strdup (dname);
 
+               #warning "this could be wrong"
+               if (summary->loaded_infos && g_hash_table_lookup (summary->loaded_infos, uid))
+                       cache_put (cache, uid, dname, NULL);
+
+               /*
                info = camel_folder_summary_uid (summary, uid);
                if (info) {
                        camel_message_info_free(info);
                        cache_put (cache, uid, dname, NULL);
                } else
-                       g_ptr_array_add (deletes, g_strdup_printf ("%s/%s", cache->path, dname));
+                       g_ptr_array_add (deletes, g_strdup_printf ("%s/%s", cache->path, dname)); */
                g_free (uid);
        }
        g_dir_close (dir);
index e08231a..1c08884 100644 (file)
@@ -2660,10 +2660,15 @@ fill_fi(CamelStore *store, CamelFolderInfo *fi, guint32 flags)
 
        folder = camel_object_bag_peek(store->folders, fi->full_name);
        if (folder) {
-               fi->unread = camel_folder_get_unread_message_count(folder);
-               fi->total = camel_folder_get_message_count(folder);
+               CamelImapSummary *ims;
+               ims = (CamelImapSummary *) camel_imap_summary_new (folder, NULL);
+
+               fi->unread = ((CamelFolderSummary *)ims)->unread_count;
+               fi->total = ((CamelFolderSummary *)ims)->saved_count;
+
+               camel_object_unref(ims);
                camel_object_unref(folder);
-       }
+       } 
 }
 
 struct _refresh_msg {
index 963d67b..d69463c 100644 (file)
@@ -38,6 +38,9 @@
 
 #define CAMEL_IMAP_SUMMARY_VERSION (3)
 
+#define EXTRACT_FIRST_DIGIT(val) val=strtoul (part, &part, 10);
+#define EXTRACT_DIGIT(val) part++; val=strtoul (part, &part, 10);
+
 static int summary_header_load (CamelFolderSummary *, FILE *);
 static int summary_header_save (CamelFolderSummary *, FILE *);
 
@@ -49,9 +52,19 @@ static CamelMessageContentInfo *content_info_load (CamelFolderSummary *s, FILE *
 static int content_info_save (CamelFolderSummary *s, FILE *out,
                              CamelMessageContentInfo *info);
 
+static int summary_header_from_db (CamelFolderSummary *s, CamelFIRecord *mir);
+static CamelFIRecord * summary_header_to_db (CamelFolderSummary *s, CamelException *ex);
+static CamelMIRecord * message_info_to_db (CamelFolderSummary *s, CamelMessageInfo *info);
+static CamelMessageInfo * message_info_from_db (CamelFolderSummary *s, CamelMIRecord *mir);
+static int content_info_to_db (CamelFolderSummary *s, CamelMessageContentInfo *info, CamelMIRecord *mir);
+static CamelMessageContentInfo * content_info_from_db (CamelFolderSummary *s, CamelMIRecord *mir);
+
+
 static void camel_imap_summary_class_init (CamelImapSummaryClass *klass);
 static void camel_imap_summary_init       (CamelImapSummary *obj);
 
+static int uid_compare (const void *va, const void *vb);
+
 static CamelFolderSummaryClass *camel_imap_summary_parent;
 
 CamelType
@@ -103,6 +116,13 @@ camel_imap_summary_class_init (CamelImapSummaryClass *klass)
        cfs_class->message_info_save = message_info_save;
        cfs_class->content_info_load = content_info_load;
        cfs_class->content_info_save = content_info_save;
+       
+       cfs_class->summary_header_to_db = summary_header_to_db;
+       cfs_class->summary_header_from_db = summary_header_from_db;
+       cfs_class->message_info_to_db = message_info_to_db;
+       cfs_class->message_info_from_db = message_info_from_db;
+       cfs_class->content_info_to_db = content_info_to_db;
+       cfs_class->content_info_from_db = content_info_from_db;
 
        cfs_class->info_set_user_flag = info_set_user_flag;
 }
@@ -131,21 +151,55 @@ CamelFolderSummary *
 camel_imap_summary_new (struct _CamelFolder *folder, const char *filename)
 {
        CamelFolderSummary *summary = CAMEL_FOLDER_SUMMARY (camel_object_new (camel_imap_summary_get_type ()));
+       CamelException ex;
+       camel_exception_init (&ex);
 
        summary->folder = folder;
 
        camel_folder_summary_set_build_content (summary, TRUE);
-       camel_folder_summary_set_filename (summary, filename);
 
-       if (camel_folder_summary_load (summary) == -1) {
-               camel_folder_summary_clear (summary);
-               camel_folder_summary_touch (summary);
+       if (camel_folder_summary_load_from_db (summary, &ex) == -1) {
+               /* FIXME: Isn't this dangerous ? We clear the summary
+               if it cannot be loaded, for some random reason.
+               We need to pass the ex and find out why it is not loaded etc. ? */
+               camel_folder_summary_clear_db (summary);
+               g_warning ("Unable to load summary %s\n", camel_exception_get_description (&ex));
+               camel_exception_clear (&ex);
        }
 
+       g_ptr_array_sort (summary->uids, (GCompareFunc) uid_compare); 
        return summary;
 }
 
 static int
+summary_header_from_db (CamelFolderSummary *s, CamelFIRecord *mir)
+{
+       CamelImapSummary *ims = CAMEL_IMAP_SUMMARY (s);
+       char *part;
+
+       if (camel_imap_summary_parent->summary_header_from_db (s, mir) == -1)
+               return -1;
+
+       part = mir->bdata;
+
+       if (part) {
+               EXTRACT_FIRST_DIGIT (ims->version)
+       }
+       
+       if (part) {
+               EXTRACT_DIGIT (ims->validity)
+       }
+       
+       if (ims->version > CAMEL_IMAP_SUMMARY_VERSION) {
+               g_warning("Unkown summary version\n");
+               errno = EINVAL;
+               return -1;
+       }
+
+       return 0;
+}
+
+static int
 summary_header_load (CamelFolderSummary *s, FILE *in)
 {
        CamelImapSummary *ims = CAMEL_IMAP_SUMMARY (s);
@@ -181,6 +235,20 @@ summary_header_load (CamelFolderSummary *s, FILE *in)
        return 0;
 }
 
+static CamelFIRecord *
+summary_header_to_db (CamelFolderSummary *s, CamelException *ex)
+{
+       CamelImapSummary *ims = CAMEL_IMAP_SUMMARY(s);
+       struct _CamelFIRecord *fir;
+       
+       fir = camel_imap_summary_parent->summary_header_to_db (s, ex);
+       if (!fir)
+               return NULL;
+       fir->bdata = g_strdup_printf ("%d %u", CAMEL_IMAP_SUMMARY_VERSION, ims->validity);
+
+       return fir;
+}
+
 static int
 summary_header_save (CamelFolderSummary *s, FILE *out)
 {
@@ -195,6 +263,22 @@ summary_header_save (CamelFolderSummary *s, FILE *out)
 }
 
 static CamelMessageInfo *
+message_info_from_db (CamelFolderSummary *s, CamelMIRecord *mir)
+{
+       CamelMessageInfo *info;
+       CamelImapMessageInfo *iinfo;
+
+       info = camel_imap_summary_parent->message_info_from_db (s, mir);
+       if (info) {
+               char *part = g_strdup (mir->bdata);
+               iinfo = (CamelImapMessageInfo *)info;
+               EXTRACT_FIRST_DIGIT (iinfo->server_flags)
+       }
+
+       return info;
+}
+
+static CamelMessageInfo *
 message_info_load (CamelFolderSummary *s, FILE *in)
 {
        CamelMessageInfo *info;
@@ -214,6 +298,19 @@ error:
        return NULL;
 }
 
+static CamelMIRecord *
+message_info_to_db (CamelFolderSummary *s, CamelMessageInfo *info)
+{
+       CamelImapMessageInfo *iinfo = (CamelImapMessageInfo *)info;
+       struct _CamelMIRecord *mir;
+
+       mir = camel_imap_summary_parent->message_info_to_db (s, info);
+       if (mir) 
+               mir->bdata = g_strdup_printf ("%u", iinfo->server_flags);
+
+       return mir;
+}
+
 static int
 message_info_save (CamelFolderSummary *s, FILE *out, CamelMessageInfo *info)
 {
@@ -240,6 +337,22 @@ info_set_user_flag (CamelMessageInfo *info, const char *id, gboolean state)
 }
 
 static CamelMessageContentInfo *
+content_info_from_db (CamelFolderSummary *s, CamelMIRecord *mir)
+{
+       char *part = mir->cinfo;
+       guint32 type=0;
+       
+       if (part) {
+               EXTRACT_FIRST_DIGIT (type);
+       }
+       mir->cinfo = part;
+       if (type)
+               return camel_imap_summary_parent->content_info_from_db (s, mir);
+       else
+               return camel_folder_summary_content_info_new (s);
+}
+
+static CamelMessageContentInfo *
 content_info_load (CamelFolderSummary *s, FILE *in)
 {
        if (fgetc (in))
@@ -249,6 +362,18 @@ content_info_load (CamelFolderSummary *s, FILE *in)
 }
 
 static int
+content_info_to_db (CamelFolderSummary *s, CamelMessageContentInfo *info, CamelMIRecord *mir)
+{
+       if (info->type) {
+               mir->cinfo = g_strdup ("1");
+               return camel_imap_summary_parent->content_info_to_db (s, info, mir);
+       } else {
+               mir->cinfo = g_strdup ("0");
+               return 0;
+       }
+}
+
+static int
 content_info_save (CamelFolderSummary *s, FILE *out,
                   CamelMessageContentInfo *info)
 {
@@ -286,7 +411,7 @@ camel_imap_summary_add_offline (CamelFolderSummary *summary, const char *uid,
        }
 
        mi->info.size = camel_message_info_size(info);
-       mi->info.uid = g_strdup (uid);
+       mi->info.uid = camel_pstring_strdup (uid);
 
        camel_folder_summary_add (summary, (CamelMessageInfo *)mi);
 }
@@ -298,7 +423,25 @@ camel_imap_summary_add_offline_uncached (CamelFolderSummary *summary, const char
        CamelImapMessageInfo *mi;
 
        mi = camel_message_info_clone(info);
-       mi->info.uid = g_strdup(uid);
+       mi->info.uid = camel_pstring_strdup(uid);
 
        camel_folder_summary_add (summary, (CamelMessageInfo *)mi);
 }
+
+
+static int
+uid_compare (const void *va, const void *vb)
+{
+       const char **sa = (const char **)va, **sb = (const char **)vb;
+       unsigned long a, b;
+
+       a = strtoul (*sa, NULL, 10);
+       b = strtoul (*sb, NULL, 10);
+       if (a < b)
+               return -1;
+       else if (a == b)
+               return 0;
+       else
+               return 1;
+}
+
index c0e0c60..c8b1a66 100644 (file)
@@ -1179,10 +1179,12 @@ get_summary_uid_numeric (CamelFolderSummary *summary, int index)
 {
        CamelMessageInfo *info;
        unsigned long uid;
-       
-       info = camel_folder_summary_index (summary, index);
-       uid = strtoul (camel_message_info_uid (info), NULL, 10);
-       camel_message_info_free(info);
+       char *suid;
+
+       suid = camel_folder_summary_uid_from_index (summary, index);
+       uid = strtoul (suid, NULL, 10);
+       g_free (suid);
+
        return uid;
 }
 
index 3d52fba..b839db8 100644 (file)
@@ -1,3 +1,23 @@
+2008-07-16  Sankar P  <psankar@novell.com>
+
+       Pushing disk summary changes from the madagascar branch
+
+       * camel-local-folder.c (camel_local_folder_construct):
+       * camel-local-store.c (camel_local_store_finalize):
+       * camel-local-summary.c (camel_local_summary_class_init),
+       (local_summary_load), (camel_local_summary_load),
+       (local_summary_sync), (local_summary_add),
+       (local_summary_decode_x_evolution), (summary_header_from_db),
+       (summary_header_to_db), (message_info_new_from_header):
+       * camel-maildir-summary.c (maildir_summary_check):
+       * camel-mbox-store.c (fill_fi):
+       * camel-mbox-summary.c (camel_mbox_summary_class_init),
+       (summary_header_from_db), (summary_header_to_db),
+       (message_info_new_from_header), (message_info_from_db),
+       (message_info_to_db), (mbox_summary_sync_quick),
+       (mbox_summary_sync):
+       * camel-mh-summary.c (mh_summary_check):
+
 2008-05-30  Milan Crha  <mcrha@redhat.com>
 
        ** Fix for bug #318803 (Patch by Ilkka Tuohela)
index 014fd3a..93eb478 100644 (file)
@@ -289,6 +289,14 @@ camel_local_folder_construct(CamelLocalFolder *lf, CamelStore *parent_store, con
        folder->summary = (CamelFolderSummary *)CLOCALF_CLASS(lf)->create_summary(lf, lf->summary_path, lf->folder_path, lf->index);
        if (camel_local_summary_load((CamelLocalSummary *)folder->summary, forceindex, NULL) == -1) {
                /* ? */
+               if (camel_local_summary_check((CamelLocalSummary *)folder->summary, lf->changes, ex) == 0) {
+                       /* we sync here so that any hard work setting up the folder isn't lost */
+                       if (camel_local_summary_sync((CamelLocalSummary *)folder->summary, FALSE, lf->changes, ex) == -1) {
+                               camel_object_unref (CAMEL_OBJECT (folder));
+                               g_free(name);
+                               return NULL;
+                       }               
+               }
        }
 
        /* We don't need to sync here ..., it can sync later on when it calls refresh info */
index 792ecf1..6d33cea 100644 (file)
@@ -100,6 +100,18 @@ camel_local_store_finalize (CamelLocalStore *local_store)
 {
        if (local_store->toplevel_dir)
                g_free (local_store->toplevel_dir);
+
+       CamelStore *store;
+
+       store = ((CamelStore *)local_store); 
+       d(printf ("\n\aLocal Store Finalize \n\a"));
+
+       if (store && store->cdb) {
+       d(printf ("\n\aClosing Store DB for hte local provider \n\a"));
+               camel_db_close (store->cdb);
+               store->cdb = NULL;
+       }
+
 }
 
 CamelType
index a895fb2..ff35c94 100644 (file)
 
 #define CAMEL_LOCAL_SUMMARY_VERSION (1)
 
+#define EXTRACT_FIRST_DIGIT(val) val=strtoul (part, &part, 10);
+
+static CamelFIRecord * summary_header_to_db (CamelFolderSummary *, CamelException *ex);
+static int summary_header_from_db (CamelFolderSummary *, CamelFIRecord *);
+
 static int summary_header_load (CamelFolderSummary *, FILE *);
 static int summary_header_save (CamelFolderSummary *, FILE *);
 
@@ -91,7 +96,10 @@ camel_local_summary_class_init(CamelLocalSummaryClass *klass)
 
        sklass->summary_header_load = summary_header_load;
        sklass->summary_header_save = summary_header_save;
-
+       
+       sklass->summary_header_from_db = summary_header_from_db;
+       sklass->summary_header_to_db = summary_header_to_db;
+       
        sklass->message_info_new_from_header  = message_info_new_from_header;
 
        klass->load = local_summary_load;
@@ -140,20 +148,17 @@ camel_local_summary_construct(CamelLocalSummary *new, const char *filename, cons
 static int
 local_summary_load(CamelLocalSummary *cls, int forceindex, CamelException *ex)
 {
-       return camel_folder_summary_load((CamelFolderSummary *)cls);
+       d(g_print ("\nlocal_summary_load called \n"));
+       return camel_folder_summary_load_from_db ((CamelFolderSummary *)cls, ex);
 }
 
 /* load/check the summary */
 int
 camel_local_summary_load(CamelLocalSummary *cls, int forceindex, CamelException *ex)
 {
-       struct stat st;
-       CamelFolderSummary *s = (CamelFolderSummary *)cls;
-
        d(printf("Loading summary ...\n"));
 
        if (forceindex
-           || g_stat(s->summary_path, &st) == -1
            || ((CamelLocalSummaryClass *)(CAMEL_OBJECT_GET_CLASS(cls)))->load(cls, forceindex, ex) == -1) {
                w(g_warning("Could not load summary: flags may be reset"));
                camel_folder_summary_clear((CamelFolderSummary *)cls);
@@ -403,13 +408,10 @@ local_summary_sync(CamelLocalSummary *cls, gboolean expunge, CamelFolderChangeIn
 {
        int ret = 0;
 
-       ret = camel_folder_summary_save((CamelFolderSummary *)cls);
+       ret = camel_folder_summary_save_to_db ((CamelFolderSummary *)cls, ex);
        if (ret == -1) {
-               camel_exception_setv (ex, CAMEL_EXCEPTION_SYSTEM,
-                                     _("Could not save summary: %s: %s"),
-                                     cls->folder_path, g_strerror (errno));
-               
-               g_warning ("Could not save summary for %s: %s", cls->folder_path, strerror (errno));
+               g_warning ("Could not save summary for local providers");
+               return -1;
        }
 
        if (cls->index && camel_index_sync(cls->index) == -1)
@@ -428,7 +430,7 @@ local_summary_add(CamelLocalSummary *cls, CamelMimeMessage *msg, const CamelMess
        
        mi = (CamelLocalMessageInfo *)camel_folder_summary_add_from_message((CamelFolderSummary *)cls, msg);
        if (mi) {
-               d(printf("Added, uid = %s\n", mi->uid));
+               //d(printf("Added, uid = %s\n", mi->uid));
                if (info) {
                        const CamelTag *tag = camel_message_info_user_tags(info);
                        const CamelFlag *flag = camel_message_info_user_flags(info);
@@ -583,12 +585,34 @@ local_summary_decode_x_evolution(CamelLocalSummary *cls, const char *xev, CamelL
                camel_header_param_list_free(params);
        }
 
-       mi->info.uid = g_strdup(uidstr);
+       mi->info.uid = camel_pstring_strdup(uidstr);
        mi->info.flags = flags;
 
        return 0;
 }
 
+
+static int 
+summary_header_from_db (CamelFolderSummary *s, CamelFIRecord *fir)
+{
+       CamelLocalSummary *cls = (CamelLocalSummary *)s;
+       char *part;
+
+       /* We dont actually add our own headers, but version that we don't anyway */
+
+       if (((CamelFolderSummaryClass *)camel_local_summary_parent)->summary_header_from_db(s, fir) == -1)
+               return -1;
+
+       part = fir->bdata;
+       if (part) {
+               EXTRACT_FIRST_DIGIT (cls->version)
+       }
+       fir->bdata = part;
+
+       return 0;
+}
+
+
 static int
 summary_header_load(CamelFolderSummary *s, FILE *in)
 {
@@ -607,6 +631,18 @@ summary_header_load(CamelFolderSummary *s, FILE *in)
        return camel_file_util_decode_fixed_int32(in, &cls->version);
 }
 
+static struct _CamelFIRecord * 
+summary_header_to_db (CamelFolderSummary *s, CamelException *ex)
+{
+       struct _CamelFIRecord *fir;
+       
+       fir = ((CamelFolderSummaryClass *)camel_local_summary_parent)->summary_header_to_db (s, ex);
+       if (fir)
+               fir->bdata = g_strdup_printf ("%d", CAMEL_LOCAL_SUMMARY_VERSION);
+       
+       return fir;
+}
 static int
 summary_header_save(CamelFolderSummary *s, FILE *out)
 {
@@ -633,8 +669,8 @@ message_info_new_from_header(CamelFolderSummary *s, struct _camel_header_raw *h)
                if (xev==NULL || camel_local_summary_decode_x_evolution(cls, xev, mi) == -1) {
                        /* to indicate it has no xev header */
                        mi->info.flags |= CAMEL_MESSAGE_FOLDER_FLAGGED | CAMEL_MESSAGE_FOLDER_NOXEV;
-                       g_free (mi->info.uid);
-                       mi->info.uid = camel_folder_summary_next_uid_string(s);
+                       camel_pstring_free (mi->info.uid);
+                       mi->info.uid = camel_pstring_add (camel_folder_summary_next_uid_string(s), TRUE);
 
                        /* shortcut, no need to look it up in the index library */
                        doindex = TRUE;
index 47fc569..d32dcf8 100644 (file)
@@ -726,7 +726,8 @@ maildir_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changes, Ca
 
        /* sort the summary based on receive time, since the directory order is not useful */
        CAMEL_SUMMARY_LOCK(s, summary_lock);
-       qsort(s->messages->pdata, s->messages->len, sizeof(CamelMessageInfo *), sort_receive_cmp);
+       #warning Add support for sorting via the DB.
+/*     qsort(s->messages->pdata, s->messages->len, sizeof(CamelMessageInfo *), sort_receive_cmp); */
        CAMEL_SUMMARY_UNLOCK(s, summary_lock);
 
        g_mutex_unlock (((CamelMaildirSummary *) cls)->priv->summary_lock);
index e0a1c3f..5ac95cd 100644 (file)
@@ -101,7 +101,7 @@ camel_mbox_store_get_type(void)
 }
 
 static char *extensions[] = {
-       ".msf", ".ev-summary", ".ev-summary-meta", ".ibex.index", ".ibex.index.data", ".cmeta", ".lock"
+       ".msf", ".ev-summary", ".ev-summary-meta", ".ibex.index", ".ibex.index.data", ".cmeta", ".lock", ".db"
 };
 
 static gboolean
@@ -638,7 +638,8 @@ fill_fi(CamelStore *store, CamelFolderInfo *fi, guint32 flags)
                folderpath = camel_local_store_get_full_path(store, fi->full_name);
                
                mbs = (CamelMboxSummary *)camel_mbox_summary_new(NULL, path, folderpath, NULL);
-               if (camel_folder_summary_header_load((CamelFolderSummary *)mbs) != -1) {
+               #warning "track exception"
+               if (camel_folder_summary_header_load_from_db ((CamelFolderSummary *)mbs, store, fi->full_name, NULL) != -1) {
                        fi->unread = ((CamelFolderSummary *)mbs)->unread_count;
                        fi->total = ((CamelFolderSummary *)mbs)->saved_count;
                }
index 30bed06..1aca496 100644 (file)
@@ -42,6 +42,9 @@
 #include "camel-private.h"
 
 #include "camel-mbox-summary.h"
+#include "camel-string-utils.h"
+#include "camel-store.h"
+#include "camel-folder.h"
 
 #define io(x)
 #define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/
 
 #define CAMEL_MBOX_SUMMARY_VERSION (1)
 
+#define EXTRACT_DIGIT(val) part++; val=strtoul (part, &part, 10);
+#define EXTRACT_FIRST_DIGIT(val) val=strtoul (part, &part, 10);
+static CamelFIRecord * summary_header_to_db (CamelFolderSummary *, CamelException *ex);
+static int summary_header_from_db (CamelFolderSummary *, CamelFIRecord *);
+static CamelMessageInfo * message_info_from_db(CamelFolderSummary *s, CamelMIRecord *record);
+static CamelMIRecord * message_info_to_db(CamelFolderSummary *s, CamelMessageInfo *info);
+
+
 static int summary_header_load (CamelFolderSummary *, FILE *);
 static int summary_header_save (CamelFolderSummary *, FILE *);
 
@@ -154,6 +166,11 @@ camel_mbox_summary_class_init(CamelMboxSummaryClass *klass)
        sklass->summary_header_load = summary_header_load;
        sklass->summary_header_save = summary_header_save;
 
+       sklass->summary_header_from_db = summary_header_from_db;
+       sklass->summary_header_to_db = summary_header_to_db;
+       sklass->message_info_from_db = message_info_from_db;
+       sklass->message_info_to_db = message_info_to_db;
+       
        sklass->message_info_new_from_header  = message_info_new_from_header;
        sklass->message_info_new_from_parser = message_info_new_from_parser;
        sklass->message_info_load = message_info_load;
@@ -238,6 +255,24 @@ mbox_summary_encode_x_evolution (CamelLocalSummary *cls, const CamelLocalMessage
        }
 }
 
+static int 
+summary_header_from_db (CamelFolderSummary *s, struct _CamelFIRecord *fir)
+{
+       CamelMboxSummary *mbs = CAMEL_MBOX_SUMMARY(s);
+       char *part;
+
+       ((CamelFolderSummaryClass *)camel_mbox_summary_parent)->summary_header_from_db(s, fir);
+
+       part = fir->bdata;
+       if (part) {
+               EXTRACT_DIGIT(mbs->version)
+               EXTRACT_DIGIT(mbs->folder_size)
+       }
+       
+       return 0;
+}
+
+
 static int
 summary_header_load(CamelFolderSummary *s, FILE *in)
 {
@@ -258,6 +293,23 @@ summary_header_load(CamelFolderSummary *s, FILE *in)
        return 0;
 }
 
+static CamelFIRecord * 
+summary_header_to_db (CamelFolderSummary *s, CamelException *ex)
+{
+       CamelMboxSummary *mbs = CAMEL_MBOX_SUMMARY(s);
+       struct _CamelFIRecord *fir;
+       char *tmp;
+
+       fir = ((CamelFolderSummaryClass *)camel_mbox_summary_parent)->summary_header_to_db (s, ex);
+       if (fir) {
+               tmp = fir->bdata;
+               fir->bdata = g_strdup_printf ("%s %d %d", tmp ? tmp : "", CAMEL_MBOX_SUMMARY_VERSION, mbs->folder_size);
+               g_free (tmp);
+       }
+       
+       return fir;
+}
+
 static int
 summary_header_save(CamelFolderSummary *s, FILE *out)
 {
@@ -324,8 +376,8 @@ message_info_new_from_header(CamelFolderSummary *s, struct _camel_header_raw *h)
 
                if (add&1) {
                        mi->info.info.flags |= CAMEL_MESSAGE_FOLDER_FLAGGED | CAMEL_MESSAGE_FOLDER_NOXEV;
-                       g_free (mi->info.info.uid);
-                       mi->info.info.uid = camel_folder_summary_next_uid_string(s);
+                       camel_pstring_free (mi->info.info.uid);
+                       mi->info.info.uid = camel_pstring_add(camel_folder_summary_next_uid_string(s), TRUE);
                } else {
                        camel_folder_summary_set_uid(s, strtoul(camel_message_info_uid(mi), NULL, 10));
                }
@@ -366,6 +418,25 @@ message_info_new_from_parser(CamelFolderSummary *s, CamelMimeParser *mp)
        return mi;
 }
 
+static CamelMessageInfo * 
+message_info_from_db(CamelFolderSummary *s, struct _CamelMIRecord *mir)
+{
+       CamelMessageInfo *mi;
+       char *part;
+
+       mi = ((CamelFolderSummaryClass *)camel_mbox_summary_parent)->message_info_from_db(s, mir);
+
+       if (mi) {
+               CamelMboxMessageInfo *mbi = (CamelMboxMessageInfo *)mi;
+               part = mir->bdata;
+               if (part) {
+                       EXTRACT_FIRST_DIGIT (mbi->frompos)
+               }
+       }
+
+       return mi;
+}
+
 static CamelMessageInfo *
 message_info_load(CamelFolderSummary *s, FILE *in)
 {
@@ -401,6 +472,19 @@ meta_message_info_save(CamelFolderSummary *s, FILE *out_meta, FILE *out, CamelMe
        return 0;
 }
 
+static struct _CamelMIRecord * 
+message_info_to_db(CamelFolderSummary *s, CamelMessageInfo *info)
+{
+       CamelMboxMessageInfo *mbi = (CamelMboxMessageInfo *)info;
+       struct _CamelMIRecord *mir;
+
+       mir = ((CamelFolderSummaryClass *)camel_mbox_summary_parent)->message_info_to_db(s, info);
+       mir->bdata = g_strdup_printf("%lu", mbi->frompos);
+
+       return mir;
+}
+
+
 static int
 message_info_save(CamelFolderSummary *s, FILE *out, CamelMessageInfo *mi)
 {
@@ -575,7 +659,7 @@ mbox_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changes, Camel
                                ret = summary_update(cls, mbs->folder_size, changes, ex);
                        } else {
                                d(printf("folder shrank!  rebuilding from start\n"));
-                               ret = summary_update(cls, 0, changes, ex);
+                                ret = summary_update(cls, 0, changes, ex);
                        }
                } else {
                        d(printf("Folder unchanged, do nothing\n"));
@@ -698,7 +782,7 @@ mbox_summary_sync_quick(CamelMboxSummary *mbs, gboolean expunge, CamelFolderChan
        const char *xev;
        int len;
        off_t lastpos;
-
+       GPtrArray *summary = NULL;
        int mbox_file_is_corrupt = 0;
 
        d(printf("Performing quick summary sync\n"));
@@ -730,16 +814,15 @@ mbox_summary_sync_quick(CamelMboxSummary *mbs, gboolean expunge, CamelFolderChan
        camel_mime_parser_scan_pre_from(mp, TRUE);
        camel_mime_parser_init_with_fd(mp, pfd);
 
-       count = camel_folder_summary_count(s);
-       for (i = 0; i < count; i++) {
+       /* Sync only the changes */
+       summary = camel_folder_summary_get_changed ((CamelFolderSummary *)mbs);
+       for (i = 0; i < summary->len; i++) {
                int xevoffset;
-               int pc = (i+1)*100/count;
+               int pc = (i+1)*100/summary->len;
 
                camel_operation_progress(NULL, pc);
 
-               info = (CamelMboxMessageInfo *)camel_folder_summary_index(s, i);
-
-               g_assert(info);
+               info = (CamelMboxMessageInfo *)camel_folder_summary_uid(s, summary->pdata[i]);
 
                d(printf("Checking message %s %08x\n", camel_message_info_uid(info), info->info.flags));
 
@@ -862,12 +945,16 @@ mbox_summary_sync_quick(CamelMboxSummary *mbs, gboolean expunge, CamelFolderChan
                goto error;
        }
 
+       g_ptr_array_foreach (summary, camel_pstring_free, NULL);
+       g_ptr_array_free (summary, TRUE);
        camel_object_unref((CamelObject *)mp);
 
        camel_operation_end(NULL);
        
        return 0;
  error:
+       g_ptr_array_foreach (summary, camel_pstring_free, NULL);
+       g_ptr_array_free (summary, TRUE);       
        if (fd != -1)
                close(fd);
        if (mp)
@@ -889,28 +976,41 @@ mbox_summary_sync(CamelLocalSummary *cls, gboolean expunge, CamelFolderChangeInf
        int i, count;
        int quick = TRUE, work=FALSE;
        int ret;
-
+       GPtrArray *summary = NULL;
+       
        /* first, sync ourselves up, just to make sure */
        if (camel_local_summary_check(cls, changeinfo, ex) == -1)
                return -1;
 
-       count = camel_folder_summary_count(s);
-       if (count == 0)
-               return 0;
+       /* Sync only the changes */
 
-       /* check what work we have to do, if any */
-       for (i=0;quick && i<count; i++) {
-               CamelMboxMessageInfo *info = (CamelMboxMessageInfo *)camel_folder_summary_index(s, i);
 
-               g_assert(info);
+       summary = camel_folder_summary_get_changed ((CamelFolderSummary *)mbs);
+       for (i=0; i<summary->len; i++) {
+               CamelMboxMessageInfo *info = (CamelMboxMessageInfo *)camel_folder_summary_uid(s, summary->pdata[i]);
+               
                if ((expunge && (info->info.info.flags & CAMEL_MESSAGE_DELETED)) ||
                    (info->info.info.flags & (CAMEL_MESSAGE_FOLDER_NOXEV|CAMEL_MESSAGE_FOLDER_XEVCHANGE)))
                        quick = FALSE;
                else
                        work |= (info->info.info.flags & CAMEL_MESSAGE_FOLDER_FLAGGED) != 0;
-               camel_message_info_free(info);
+               camel_message_info_free(info);          
        }
 
+       g_ptr_array_foreach (summary, camel_pstring_free, NULL);
+       g_ptr_array_free (summary, TRUE);
+       
+       if (quick && expunge) {
+               int dcount =0;
+
+       
+               if (camel_db_count_deleted_message_info (s->folder->cdb, s->folder->full_name, &dcount, ex) == -1)
+                       return -1;
+               if (dcount)
+                       quick = FALSE;
+       }
+       
+
        /* yuck i hate this logic, but its to simplify the 'all ok, update summary' and failover cases */
        ret = -1;
        if (quick) {
index 36316ff..39c5898 100644 (file)
@@ -294,7 +294,10 @@ mh_summary_check(CamelLocalSummary *cls, CamelFolderChangeInfo *changeinfo, Came
 
        /* sort the summary based on message number (uid), since the directory order is not useful */
        CAMEL_SUMMARY_LOCK(s, summary_lock);
-       qsort(s->messages->pdata, s->messages->len, sizeof(CamelMessageInfo *), sort_uid_cmp);
+/*     qsort(s->uids->pdata, s->uids->len, sizeof(CamelMessageInfo *), sort_uid_cmp); */
+       #warning "verify if strcmp works the same as the other one. Too busy to check this."
+    #warning "lets build a sort support for uid fetching from the db"
+       qsort(s->uids->pdata, s->uids->len, sizeof(CamelMessageInfo *), strcmp);        
        CAMEL_SUMMARY_UNLOCK(s, summary_lock);
 
        return 0;
index d7ea828..f5df2fd 100644 (file)
@@ -1,3 +1,15 @@
+2008-07-16  Sankar P  <psankar@novell.com>
+
+       Pushing disk summary changes from the madagascar branch
+
+       * camel-nntp-folder.c (nntp_folder_sync_online),
+       (nntp_folder_sync_offline), (nntp_folder_finalise),
+       (camel_nntp_folder_new):
+       * camel-nntp-summary.c (camel_nntp_summary_class_init),
+       (summary_header_from_db), (summary_header_to_db),
+       (camel_nntp_summary_check):
+       * camel-nntp-utils.c (uid_num):
+
 2008-03-27  Matthew Barnes  <mbarnes@redhat.com>
 
        ** Fixes part of bug #518710
index 6c6e3fd..763baef 100644 (file)
@@ -105,7 +105,7 @@ static void
 nntp_folder_sync_online (CamelFolder *folder, CamelException *ex)
 {
        CAMEL_SERVICE_REC_LOCK(folder->parent_store, connect_lock);
-       camel_folder_summary_save (folder->summary);
+       camel_folder_summary_save_to_db (folder->summary, ex);
        CAMEL_SERVICE_REC_UNLOCK(folder->parent_store, connect_lock);
 }
 
@@ -113,7 +113,7 @@ static void
 nntp_folder_sync_offline (CamelFolder *folder, CamelException *ex)
 {
        CAMEL_SERVICE_REC_LOCK(folder->parent_store, connect_lock);
-       camel_folder_summary_save (folder->summary);
+       camel_folder_summary_save_to_db (folder->summary, ex);
        CAMEL_SERVICE_REC_UNLOCK(folder->parent_store, connect_lock);
 }
 
@@ -419,8 +419,12 @@ static void
 nntp_folder_finalise (CamelNNTPFolder *nntp_folder)
 {
        struct _CamelNNTPFolderPrivate *p;
+
+       CamelException ex;
+
+       camel_exception_init (&ex);
        
-       camel_folder_summary_save (((CamelFolder*) nntp_folder)->summary);
+       camel_folder_summary_save_to_db (((CamelFolder*) nntp_folder)->summary, &ex);
        
        p = nntp_folder->priv;
        g_mutex_free (p->search_lock);
@@ -512,7 +516,8 @@ camel_nntp_folder_new (CamelStore *parent, const char *folder_name, CamelExcepti
        root = g_strdup_printf("%s.ev-summary", nntp_folder->storage_path);
        folder->summary = (CamelFolderSummary *) camel_nntp_summary_new (folder, root);
        g_free(root);
-       camel_folder_summary_load (folder->summary);
+
+       camel_folder_summary_load_from_db (folder->summary, ex);
        
        si = camel_store_summary_path ((CamelStoreSummary *) ((CamelNNTPStore*) parent)->summary, folder_name);
        if (si) {
index 0a405a9..cca3f15 100644 (file)
@@ -51,6 +51,9 @@
 
 #define CAMEL_NNTP_SUMMARY_VERSION (1)
 
+#define EXTRACT_FIRST_DIGIT(val) val=strtoul (part, &part, 10);
+#define EXTRACT_DIGIT(val) part++; val=strtoul (part, &part, 10);
+
 struct _CamelNNTPSummaryPrivate {
        char *uid;
 
@@ -63,6 +66,8 @@ struct _CamelNNTPSummaryPrivate {
 static CamelMessageInfo * message_info_new_from_header (CamelFolderSummary *, struct _camel_header_raw *);
 static int summary_header_load(CamelFolderSummary *, FILE *);
 static int summary_header_save(CamelFolderSummary *, FILE *);
+static int summary_header_from_db (CamelFolderSummary *s, CamelFIRecord *mir);
+static CamelFIRecord * summary_header_to_db (CamelFolderSummary *s, CamelException *ex);
 
 static void camel_nntp_summary_class_init (CamelNNTPSummaryClass *klass);
 static void camel_nntp_summary_init       (CamelNNTPSummary *obj);
@@ -97,6 +102,8 @@ camel_nntp_summary_class_init(CamelNNTPSummaryClass *klass)
        sklass->message_info_new_from_header  = message_info_new_from_header;
        sklass->summary_header_load = summary_header_load;
        sklass->summary_header_save = summary_header_save;
+       sklass->summary_header_from_db = summary_header_from_db;
+       sklass->summary_header_to_db = summary_header_to_db;
 }
 
 static void
@@ -160,6 +167,33 @@ message_info_new_from_header(CamelFolderSummary *s, struct _camel_header_raw *h)
 }
 
 static int
+summary_header_from_db (CamelFolderSummary *s, CamelFIRecord *mir)
+{
+       CamelNNTPSummary *cns = CAMEL_NNTP_SUMMARY(s);
+       char *part;
+
+       
+       if (camel_nntp_summary_parent->summary_header_from_db (s, mir) == -1)
+               return -1;
+
+       part = mir->bdata;
+
+       if (part) {
+               EXTRACT_FIRST_DIGIT (cns->version)
+       }
+       
+       if (part) {
+               EXTRACT_DIGIT (cns->high)
+       }
+
+       if (part) {
+               EXTRACT_DIGIT (cns->low)
+       }
+
+       return 0;
+}
+
+static int
 summary_header_load(CamelFolderSummary *s, FILE *in)
 {
        CamelNNTPSummary *cns = CAMEL_NNTP_SUMMARY(s);
@@ -189,6 +223,21 @@ summary_header_load(CamelFolderSummary *s, FILE *in)
        return 0;
 }
 
+
+static CamelFIRecord *
+summary_header_to_db (CamelFolderSummary *s, CamelException *ex)
+{
+       CamelNNTPSummary *cns = CAMEL_NNTP_SUMMARY(s);
+       struct _CamelFIRecord *fir;
+       
+       fir = camel_nntp_summary_parent->summary_header_to_db (s, ex);
+       if (!fir)
+               return NULL;
+       fir->bdata = g_strdup_printf ("%d %d %d", CAMEL_NNTP_SUMMARY_VERSION, cns->high, cns->low);
+
+       return fir;
+}
+
 static int
 summary_header_save(CamelFolderSummary *s, FILE *out)
 {
@@ -427,28 +476,24 @@ camel_nntp_summary_check(CamelNNTPSummary *cns, CamelNNTPStore *store, char *lin
        if (cns->low != f) {
                count = camel_folder_summary_count(s);
                for (i = 0; i < count; i++) {
-                       CamelMessageInfo *mi = camel_folder_summary_index(s, i);
-
-                       if (mi) {
-                               const char *uid = camel_message_info_uid(mi);
-                               const char *msgid;
-
-                               n = strtoul(uid, NULL, 10);
-                               if (n < f || n > l) {
-                                       dd(printf("nntp_summary: %u is lower/higher than lowest/highest article, removed\n", n));
-                                       /* Since we use a global cache this could prematurely remove
-                                          a cached message that might be in another folder - not that important as
-                                          it is a true cache */
-                                       msgid = strchr(uid, ',');
-                                       if (msgid)
-                                               camel_data_cache_remove(store->cache, "cache", msgid+1, NULL);
-                                       camel_folder_change_info_remove_uid(changes, uid);
-                                       camel_folder_summary_remove(s, mi);
-                                       count--;
-                                       i--;
-                               }
-                               
-                               camel_message_info_free(mi);
+                       const char *uid;
+                       const char *msgid;
+
+                       uid  = camel_folder_summary_uid_from_index(s, i);
+                       n = strtoul(uid, NULL, 10);
+
+                       if (n < f || n > l) {
+                               dd(printf("nntp_summary: %u is lower/higher than lowest/highest article, removed\n", n));
+                               /* Since we use a global cache this could prematurely remove
+                                  a cached message that might be in another folder - not that important as
+                                  it is a true cache */
+                               msgid = strchr(uid, ',');
+                               if (msgid)
+                                       camel_data_cache_remove(store->cache, "cache", msgid+1, NULL);
+                               camel_folder_change_info_remove_uid(changes, uid);
+                               camel_folder_summary_remove_uid (s, uid);
+                               count--;
+                               i--;
                        }
                }
                cns->low = f;
@@ -467,7 +512,7 @@ camel_nntp_summary_check(CamelNNTPSummary *cns, CamelNNTPStore *store, char *lin
 
        /* TODO: not from here */
        camel_folder_summary_touch(s);
-       camel_folder_summary_save(s);
+       camel_folder_summary_save_to_db (s, ex);
 update:
        /* update store summary if we have it */
        if (folder
index 2f266b4..a6613d6 100644 (file)
@@ -227,16 +227,10 @@ uid_num (CamelFolderSummary *summary, int index)
 {
        char *tmp;
        char *brk;
-       CamelMessageInfo *minfo;
        int ret;
        
-       minfo = camel_folder_summary_index(summary, index);
-       if(minfo == NULL)
-               return 0;
+       tmp = camel_folder_summary_uid_from_index(summary, index);
 
-       tmp = g_strdup(camel_message_info_uid(minfo));
-       camel_message_info_free(minfo);
-       
        if((brk = strchr(tmp, ',')) == NULL)
                ret = 0;
        else {
index aacc41b..fefa3c8 100644 (file)
@@ -31,6 +31,7 @@ m4_define([libgnome_minimum_version], [2.0.0])          # XXX Just a Guess
 m4_define([libxml_minimum_version], [2.0.0])            # XXX Just a Guess
 m4_define([libsoup_minimum_version], [2.3.0])
 m4_define([gnome_keyring_minimum_version], [2.20.1])
+m4_define([sqlite_minimum_version], [3.5])
 
 dnl *************************************************************************************************
 dnl Base Version
@@ -238,7 +239,8 @@ PKG_CHECK_MODULES(GNOME_PLATFORM,
          libglade-2.0 >= libglade_minimum_version
          libgnome-2.0 >= libgnome_minimum_version
          libxml-2.0 >= libxml_minimum_version
-         libsoup-2.4 >= libsoup_minimum_version])
+         libsoup-2.4 >= libsoup_minimum_version
+                sqlite3 >= sqlite_minimum_version])
 
 dnl **************************************************
 dnl * regex checking
@@ -1443,7 +1445,7 @@ dnl ****************************************
 
 dnl --- libedataserver, libedataserverui, libebackend flags
 
-E_DATA_SERVER_DEPS="libxml-2.0 libbonobo-2.0 libsoup-2.4 gconf-2.0 $mozilla_nspr"
+E_DATA_SERVER_DEPS="libxml-2.0 libbonobo-2.0 libsoup-2.4 gconf-2.0 $mozilla_nspr sqlite3"
 
 EVO_SET_COMPILE_FLAGS(E_DATA_SERVER, $E_DATA_SERVER_DEPS, $THREADS_CFLAGS $MANUAL_NSPR_CFLAGS, $THREADS_LIBS $MANUAL_NSPR_LIBS)
 AC_SUBST(E_DATA_SERVER_CFLAGS)
@@ -1495,6 +1497,8 @@ AC_SUBST(SOUP_CFLAGS)
 AC_SUBST(SOUP_LIBS)
 
 dnl --- Camel flags
+SQLITE_REQUIRED=sqlite_minimum_version
+AC_SUBST(SQLITE_REQUIRED)
 
 zlib_found=false
 dnl deflateInit is a #define, use deflateEnd instead
index 5914613..364cc65 100644 (file)
@@ -251,6 +251,9 @@ term_eval_and(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data)
 
        r = e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
 
+       char *oper = "AND";
+       f->operators = g_slist_prepend (f->operators, oper);
+
        for (i=0;bool && i<argc;i++) {
                r1 = e_sexp_term_eval(f, argv[i]);
                if (type == -1)
@@ -291,6 +294,7 @@ term_eval_and(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data)
        }
 
        g_hash_table_destroy(ht);
+       f->operators = g_slist_remove (f->operators, oper);
 
        return r;
 }
@@ -307,6 +311,9 @@ term_eval_or(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data)
 
        r(printf("(or \n"));
 
+       char *oper = "OR";
+       f->operators = g_slist_prepend (f->operators, oper);
+
        r = e_sexp_result_new(f, ESEXP_RES_UNDEFINED);
 
        for (i=0;!bool && i<argc;i++) {
@@ -345,6 +352,7 @@ term_eval_or(struct _ESExp *f, int argc, struct _ESExpTerm **argv, void *data)
        }
        g_hash_table_destroy(ht);
 
+       f->operators = g_slist_remove (f->operators, oper);
        return r;
 }
 
@@ -887,6 +895,12 @@ parse_values(ESExp *f, int *len)
        return terms;
 }
 
+ESExpTerm * e_sexp_parse_value (ESExp *f) 
+{
+       return parse_value (f);
+}
+
+
 static struct _ESExpTerm *
 parse_value(ESExp *f)
 {
index cdc22fa..3109b92 100644 (file)
@@ -117,6 +117,7 @@ struct _ESExp {
        /* private stuff */
        jmp_buf failenv;
        char *error;
+       GSList *operators;
 
        /* TODO: may also need a pool allocator for term strings, so we dont lose them
           in error conditions? */
@@ -173,6 +174,8 @@ void                e_sexp_fatal_error      (struct _ESExp *f, char *why, ...);
 /* return the error string */
 const char     *e_sexp_error           (struct _ESExp *f);
 
+ESExpTerm * e_sexp_parse_value(ESExp *f);
+
 G_END_DECLS
 
 #endif /* _E_SEXP_H */