File bnc-472719-eds-disk-summary-patches.patch of Package evolution-data-server
--- camel/camel-db.c 2009-02-04 09:13:36.000000000 +0530
+++ camel/camel-db.c 2009-02-04 10:19:57.000000000 +0530
@@ -36,9 +36,375 @@
#include "camel-debug.h"
+/* how long to wait before invoking sync on the file; in miliseconds */
+#define SYNC_TIMEOUT 5000
+
+static sqlite3_vfs *old_vfs = NULL;
+
+GStaticRecMutex only_once_lock = G_STATIC_REC_MUTEX_INIT;
+GStaticRecMutex sync_queue_lock = G_STATIC_REC_MUTEX_INIT;
+#define LockQueue() g_static_rec_mutex_lock (&sync_queue_lock)
+#define UnlockQueue() g_static_rec_mutex_unlock (&sync_queue_lock)
+
+/* 'sync_queue' is using keys sqlite3_file to sync_queue_data structures.
+ Access to this is guarded with LockQueue/UnlockQueue function. */
+static GHashTable *sync_queue = NULL;
+
+typedef struct _sync_queue_data {
+ guint timeout_source; /* id of the source */
+ GThread *running_thread;
+
+ int sync_flags;
+} sync_queue_data;
+
+struct CamelSqlite3File
+{
+ sqlite3_file parent;
+ sqlite3_file *old_vfs_file; /* pointer to old_vfs' file */
+};
+
+static int
+call_old_file_Sync (sqlite3_file *pFile, int flags)
+{
+ struct CamelSqlite3File *cFile;
+
+ g_return_val_if_fail (old_vfs != NULL, SQLITE_ERROR);
+ g_return_val_if_fail (pFile != NULL, SQLITE_ERROR);
+
+ cFile = (struct CamelSqlite3File *)pFile;
+ g_return_val_if_fail (cFile->old_vfs_file->pMethods != NULL, SQLITE_ERROR);
+ return cFile->old_vfs_file->pMethods->xSync (cFile->old_vfs_file, flags);
+}
+
+static gboolean prepare_to_run_sync_in_thread (gpointer pFile);
+
+static gpointer
+run_sync_in_thread (gpointer pFile)
+{
+ int sync_flags = 0;
+ sync_queue_data *data;
+
+ g_return_val_if_fail (pFile != NULL, NULL);
+ g_return_val_if_fail (sync_queue != NULL, NULL);
+
+ LockQueue ();
+ data = g_hash_table_lookup (sync_queue, pFile);
+ if (data) {
+ /* sync_flags can change while we are running */
+ sync_flags = data->sync_flags;
+ data->sync_flags = 0;
+ }
+ UnlockQueue ();
+
+ /* this should not happen, once we are in a thread, the datas are ours */
+ g_return_val_if_fail (data != NULL, NULL);
+
+ /* do the sync itself, but do not block the sync_queue;
+ any error here is silently ignored. */
+ call_old_file_Sync (/*sqlite3_file*/pFile, sync_flags);
+
+ LockQueue ();
+ if (data->timeout_source == -1) {
+ /* new sync request arrived meanwhile, indicate thread finished... */
+ data->running_thread = NULL;
+ /* ...and reschedule */
+ data->timeout_source = g_timeout_add (SYNC_TIMEOUT, prepare_to_run_sync_in_thread, pFile);
+ } else {
+ /* remove it from a sync_queue and free memory */
+ g_hash_table_remove (sync_queue, pFile);
+ g_free (data);
+ }
+ UnlockQueue ();
+
+ return NULL;
+}
+
+static gboolean
+prepare_to_run_sync_in_thread (gpointer pFile)
+{
+ sync_queue_data *data;
+
+ g_return_val_if_fail (pFile != NULL, FALSE);
+ g_return_val_if_fail (sync_queue != NULL, FALSE);
+
+ LockQueue ();
+
+ data = g_hash_table_lookup (sync_queue, pFile);
+ /* check if still tracking this file and if didn't get rescheduled */
+ if (data && data->timeout_source == g_source_get_id (g_main_current_source ())) {
+ /* run the thread */
+ data->running_thread = g_thread_create (run_sync_in_thread, pFile, TRUE, NULL);
+ data->timeout_source = 0;
+ }
+
+ UnlockQueue ();
+
+ return FALSE;
+}
+
+/*
+ Adds sync on this file to the queue. Flags are just bit-OR-ed,
+ which will not hopefully hurt. In case the file is waiting for
+ it's sync, we just postpone it once again.
+ In case file is syncing just in call of this, we schedule other
+ sync after that.
+ */
+static void
+queue_sync (sqlite3_file *pFile, int flags)
+{
+ sync_queue_data *data;
+
+ g_return_if_fail (pFile != NULL);
+ g_return_if_fail (flags != 0);
+
+ LockQueue ();
+
+ if (!sync_queue)
+ sync_queue = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+ data = g_hash_table_lookup (sync_queue, pFile);
+ if (data) {
+ /* There is a sync request for this file already. */
+ if (data->running_thread) {
+ /* -1 indicates to reschedule after the actual sync finishes */
+ data->timeout_source = -1;
+ /* start with new flags - thread set it to 0; next time just add others */
+ data->sync_flags = data->sync_flags | flags;
+ } else {
+ data->sync_flags = data->sync_flags | flags;
+
+ /* reschedule */
+ g_source_remove (data->timeout_source);
+ data->timeout_source = g_timeout_add (SYNC_TIMEOUT, prepare_to_run_sync_in_thread, pFile);
+ }
+ } else {
+ data = g_malloc0 (sizeof (sync_queue_data));
+ data->sync_flags = flags;
+ data->running_thread = NULL;
+ data->timeout_source = g_timeout_add (SYNC_TIMEOUT, prepare_to_run_sync_in_thread, pFile);
+
+ g_hash_table_insert (sync_queue, pFile, data);
+ }
+
+ UnlockQueue ();
+}
+
+/*
+ If file is not in a queue, it does nothing, otherwise it removes
+ it from a queue, and calls sync immediately.
+ If file is syncing at the moment, it waits until the previous sync finishes.
+ */
+static void
+dequeue_sync (sqlite3_file *pFile)
+{
+ sync_queue_data *data;
+
+ g_return_if_fail (pFile != NULL);
+
+ LockQueue ();
+
+ if (!sync_queue) {
+ /* closing file which wasn't requested to sync, and none
+ before it too. */
+ UnlockQueue ();
+ return;
+ }
+
+ data = g_hash_table_lookup (sync_queue, pFile);
+ if (data) {
+ int sync_flags = data->sync_flags;
+
+ if (data->timeout_source) {
+ if (data->timeout_source != -1)
+ g_source_remove (data->timeout_source);
+ data->timeout_source = 0;
+ }
+
+ if (data->running_thread) {
+ GThread *thread = data->running_thread;
+
+ /* do not do anything later */
+ data = NULL;
+
+ /* unlock here, thus the thread can hold the lock again */
+ UnlockQueue ();
+
+ /* it's running at the moment, wait for a finish.
+ it'll remove structure from a sync_queue too. */
+ g_thread_join (thread);
+ } else {
+ g_hash_table_remove (sync_queue, pFile);
+ }
+
+ if (data) {
+ static gboolean no_sync_on_close = FALSE, iKnow = FALSE;
+
+ if (!iKnow) {
+ iKnow = TRUE;
+ no_sync_on_close = getenv ("CAMEL_NO_SYNC_ON_CLOSE") != NULL;
+ }
+
+ /* do not block queue on while syncing */
+ UnlockQueue ();
+
+ if (!no_sync_on_close) {
+ /* sync on close */
+ call_old_file_Sync (pFile, sync_flags);
+ }
+
+ g_free (data);
+ }
+ } else {
+ UnlockQueue ();
+ }
+}
+
+#define def_subclassed(_nm, _params, _call) \
+static int \
+camel_sqlite3_file_ ## _nm _params \
+{ \
+ struct CamelSqlite3File *cFile; \
+ \
+ g_return_val_if_fail (old_vfs != NULL, SQLITE_ERROR); \
+ g_return_val_if_fail (pFile != NULL, SQLITE_ERROR); \
+ \
+ cFile = (struct CamelSqlite3File *) pFile; \
+ g_return_val_if_fail (cFile->old_vfs_file->pMethods != NULL, SQLITE_ERROR); \
+ return cFile->old_vfs_file->pMethods->_nm _call; \
+}
+
+def_subclassed (xRead, (sqlite3_file *pFile, void *pBuf, int iAmt, sqlite3_int64 iOfst), (cFile->old_vfs_file, pBuf, iAmt, iOfst))
+def_subclassed (xWrite, (sqlite3_file *pFile, const void *pBuf, int iAmt, sqlite3_int64 iOfst), (cFile->old_vfs_file, pBuf, iAmt, iOfst))
+def_subclassed (xTruncate, (sqlite3_file *pFile, sqlite3_int64 size), (cFile->old_vfs_file, size))
+def_subclassed (xFileSize, (sqlite3_file *pFile, sqlite3_int64 *pSize), (cFile->old_vfs_file, pSize))
+def_subclassed (xLock, (sqlite3_file *pFile, int lockType), (cFile->old_vfs_file, lockType))
+def_subclassed (xUnlock, (sqlite3_file *pFile, int lockType), (cFile->old_vfs_file, lockType))
+#if SQLITE_VERSION_NUMBER < 3006000
+def_subclassed (xCheckReservedLock, (sqlite3_file *pFile), (cFile->old_vfs_file))
+#else
+def_subclassed (xCheckReservedLock, (sqlite3_file *pFile, int *pResOut), (cFile->old_vfs_file, pResOut))
+#endif
+def_subclassed (xFileControl, (sqlite3_file *pFile, int op, void *pArg), (cFile->old_vfs_file, op, pArg))
+def_subclassed (xSectorSize, (sqlite3_file *pFile), (cFile->old_vfs_file))
+def_subclassed (xDeviceCharacteristics, (sqlite3_file *pFile), (cFile->old_vfs_file))
+
+#undef def_subclassed
+
+static int
+camel_sqlite3_file_xClose (sqlite3_file *pFile)
+{
+ struct CamelSqlite3File *cFile;
+ int res;
+
+ g_return_val_if_fail (old_vfs != NULL, SQLITE_ERROR);
+ g_return_val_if_fail (pFile != NULL, SQLITE_ERROR);
+
+ dequeue_sync (pFile);
+
+ cFile = (struct CamelSqlite3File *) pFile;
+ if (cFile->old_vfs_file->pMethods)
+ res = cFile->old_vfs_file->pMethods->xClose (cFile->old_vfs_file);
+ else
+ res = SQLITE_OK;
+
+ g_free (cFile->old_vfs_file);
+ cFile->old_vfs_file = NULL;
+
+ return res;
+}
+
+static int
+camel_sqlite3_file_xSync (sqlite3_file *pFile, int flags)
+{
+ g_return_val_if_fail (old_vfs != NULL, SQLITE_ERROR);
+ g_return_val_if_fail (pFile != NULL, SQLITE_ERROR);
+
+ queue_sync (pFile, flags);
+
+ return SQLITE_OK;
+}
+
+static int
+camel_sqlite3_vfs_xOpen (sqlite3_vfs *pVfs, const char *zPath, sqlite3_file *pFile, int flags, int *pOutFlags)
+{
+ static sqlite3_io_methods io_methods = {0};
+ struct CamelSqlite3File *cFile;
+ int res;
+
+ g_return_val_if_fail (old_vfs != NULL, -1);
+ g_return_val_if_fail (pFile != NULL, -1);
+
+ cFile = (struct CamelSqlite3File *)pFile;
+ cFile->old_vfs_file = g_malloc0 (old_vfs->szOsFile);
+
+ res = old_vfs->xOpen (old_vfs, zPath, cFile->old_vfs_file, flags, pOutFlags);
+
+ g_static_rec_mutex_lock (&only_once_lock);
+
+ /* cFile->old_vfs_file->pMethods is NULL when open failed for some reason,
+ thus do not initialize our structure when do not know the version */
+ if (io_methods.xClose == NULL && cFile->old_vfs_file->pMethods) {
+ /* initialize our subclass function only once */
+ io_methods.iVersion = cFile->old_vfs_file->pMethods->iVersion;
+
+ #define use_subclassed(x) io_methods.x = camel_sqlite3_file_ ## x
+ use_subclassed (xClose);
+ use_subclassed (xRead);
+ use_subclassed (xWrite);
+ use_subclassed (xTruncate);
+ use_subclassed (xSync);
+ use_subclassed (xFileSize);
+ use_subclassed (xLock);
+ use_subclassed (xUnlock);
+ use_subclassed (xCheckReservedLock);
+ use_subclassed (xFileControl);
+ use_subclassed (xSectorSize);
+ use_subclassed (xDeviceCharacteristics);
+ #undef use_subclassed
+ }
+
+ g_static_rec_mutex_unlock (&only_once_lock);
+
+ cFile->parent.pMethods = &io_methods;
+
+ return res;
+}
+
+static void
+init_sqlite_vfs (void)
+{
+ static sqlite3_vfs vfs = { 0 };
+
+ g_static_rec_mutex_lock (&only_once_lock);
+ if (old_vfs) {
+ g_static_rec_mutex_unlock (&only_once_lock);
+ return;
+ }
+
+ old_vfs = sqlite3_vfs_find (NULL);
+ if (!old_vfs) {
+ g_static_rec_mutex_unlock (&only_once_lock);
+ g_return_if_fail (old_vfs != NULL);
+ return;
+ }
+
+ memcpy (&vfs, old_vfs, sizeof (sqlite3_vfs));
+
+ vfs.szOsFile = sizeof (struct CamelSqlite3File);
+ vfs.zName = "camel_sqlite3_vfs";
+ vfs.xOpen = camel_sqlite3_vfs_xOpen;
+
+ sqlite3_vfs_register (&vfs, 1);
+
+ g_static_rec_mutex_unlock (&only_once_lock);
+}
+
#define d(x) if (camel_debug("sqlite")) x
#define START(stmt) if (camel_debug("dbtime")) { g_print ("\n===========\nDB SQL operation [%s] started\n", stmt); if (!cdb->priv->timer) { cdb->priv->timer = g_timer_new (); } else { g_timer_reset(cdb->priv->timer);} }
#define END if (camel_debug("dbtime")) { g_timer_stop (cdb->priv->timer); g_print ("DB Operation ended. Time Taken : %f\n###########\n", g_timer_elapsed (cdb->priv->timer, NULL)); }
+#define STARTTS(stmt) if (camel_debug("dbtimets")) { g_print ("\n===========\nDB SQL operation [%s] started\n", stmt); if (!cdb->priv->timer) { cdb->priv->timer = g_timer_new (); } else { g_timer_reset(cdb->priv->timer);} }
+#define ENDTS if (camel_debug("dbtimets")) { g_timer_stop (cdb->priv->timer); g_print ("DB Operation ended. Time Taken : %f\n###########\n", g_timer_elapsed (cdb->priv->timer, NULL)); }
+
struct _CamelDBPrivate {
GTimer *timer;
@@ -92,6 +458,8 @@ camel_db_open (const char *path, CamelEx
char *cache;
int ret;
+ init_sqlite_vfs ();
+
CAMEL_DB_USE_SHARED_CACHE;
ret = sqlite3_open(path, &db);
@@ -126,8 +494,13 @@ camel_db_open (const char *path, CamelEx
cache = g_strdup ("PRAGMA cache_size=100");
camel_db_command (cdb, cache, NULL);
-
g_free (cache);
+ if (g_getenv("CAMEL_SQLITE_IN_MEMORY") != NULL) {
+ /* Optionally turn off Journaling, this gets over fsync issues, but could be risky */
+ camel_db_command (cdb, "PRAGMA main.journal_mode = off", NULL);
+ camel_db_command (cdb, "PRAGMA temp_store = memory", NULL);
+ }
+
sqlite3_busy_timeout (cdb->db, CAMEL_DB_SLEEP_INTERVAL);
@@ -196,6 +569,8 @@ camel_db_begin_transaction (CamelDB *cdb
g_static_rec_mutex_lock (&trans_lock);
g_mutex_lock (cdb->lock);
+ STARTTS("BEGIN");
+
return (cdb_sql_exec (cdb->db, "BEGIN", ex));
}
@@ -206,9 +581,9 @@ camel_db_end_transaction (CamelDB *cdb,
if (!cdb)
return -1;
- START("COMMIT");
ret = cdb_sql_exec (cdb->db, "COMMIT", ex);
- END;
+ ENDTS;
+
g_mutex_unlock (cdb->lock);
if (g_getenv("SQLITE_TRANSLOCK"))
g_static_rec_mutex_unlock (&trans_lock);
@@ -251,7 +626,7 @@ camel_db_transaction_command (CamelDB *c
return -1;
g_mutex_lock (cdb->lock);
- START("BEGIN");
+ STARTTS("BEGIN");
ret = cdb_sql_exec (cdb->db, "BEGIN", ex);
if (ret)
goto end;
@@ -266,7 +641,7 @@ camel_db_transaction_command (CamelDB *c
}
ret = cdb_sql_exec (cdb->db, "COMMIT", ex);
- END;
+ ENDTS;
end:
g_mutex_unlock (cdb->lock);
return ret;
@@ -440,7 +815,7 @@ camel_db_count_total_message_info (Camel
if (!cdb)
return -1;
- query = sqlite3_mprintf ("SELECT COUNT (*) FROM %Q", table_name);
+ query = sqlite3_mprintf ("SELECT COUNT (*) FROM %Q where read=0 or read=1", table_name);
ret = camel_db_count_message_info (cdb, query, count, ex);
sqlite3_free (query);
@@ -563,6 +938,53 @@ camel_db_delete_uid_from_vfolder_transac
return ret;
}
+struct _db_data_uids_flags {
+ GPtrArray *uids;
+ GPtrArray *flags;
+};
+static int
+read_uids_flags_callback (void *ref, int ncol, char ** cols, char ** name)
+{
+ struct _db_data_uids_flags *data= (struct _db_data_uids_flags *) ref;
+
+ int i;
+ for (i = 0; i < ncol; ++i) {
+ if (!strcmp (name [i], "uid"))
+ g_ptr_array_add (data->uids, (char *) (camel_pstring_strdup(cols [i])));
+ else if (!strcmp (name [i], "flags"))
+ g_ptr_array_add (data->flags, GUINT_TO_POINTER(strtoul (cols [i], NULL, 10)));
+ }
+
+ return 0;
+}
+
+int
+camel_db_get_folder_uids_flags (CamelDB *db, char *folder_name, char *sort_by, char *collate, GPtrArray *summary, GHashTable *table, CamelException *ex)
+{
+ GPtrArray *uids = summary;
+ GPtrArray *flags = g_ptr_array_new ();
+ char *sel_query;
+ int ret;
+ struct _db_data_uids_flags data;
+ int i;
+
+ data.uids = uids;
+ data.flags = flags;
+
+
+ sel_query = sqlite3_mprintf("SELECT uid,flags FROM %Q%s%s%s%s", folder_name, sort_by ? " order by " : "", sort_by ? sort_by: "", (sort_by && collate) ? " collate " : "", (sort_by && collate) ? collate : "");
+
+ ret = camel_db_select (db, sel_query, read_uids_flags_callback, &data, ex);
+ sqlite3_free (sel_query);
+
+ for (i=0; i<uids->len; i++) {
+ g_hash_table_insert (table, uids->pdata[i], flags->pdata[i]);
+ }
+
+ g_ptr_array_free (flags, TRUE);
+ return ret;
+}
+
static int
read_uids_callback (void *ref, int ncol, char ** cols, char ** name)
{
@@ -792,7 +1214,7 @@ write_mir (CamelDB *cdb, const char *fol
/* NB: UGLIEST Hack. We can't modify the schema now. We are using msg_security (an unsed one to notify of FLAGGED/Dirty infos */
- 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 )",
+ ins_query = sqlite3_mprintf ("INSERT OR REPLACE 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->dirty,
@@ -803,8 +1225,8 @@ write_mir (CamelDB *cdb, const char *fol
record->part, record->labels, record->usertags,
record->cinfo, record->bdata);
- if (delete_old_record)
- del_query = sqlite3_mprintf ("DELETE FROM %Q WHERE uid = %Q", folder_name, record->uid);
+// if (delete_old_record)
+// del_query = sqlite3_mprintf ("DELETE FROM %Q WHERE uid = %Q", folder_name, record->uid);
#if 0
char *upd_query;
@@ -852,12 +1274,14 @@ camel_db_write_folder_info_record (Camel
g_free (upd_query);
#else
- ret = camel_db_add_to_transaction (cdb, del_query, ex);
+ //if (delete_old_record)
+ // 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);
+ //if (delete_old_record)
+ // sqlite3_free (del_query);
sqlite3_free (ins_query);
return ret;
@@ -1009,6 +1433,9 @@ cdb_delete_ids (CamelDB *cdb, const char
int
camel_db_delete_uids (CamelDB *cdb, const char * folder_name, GSList *uids, CamelException *ex)
{
+ if(!uids || !uids->data)
+ return 0;
+
return cdb_delete_ids (cdb, folder_name, uids, "", "uid", ex);
}
--- camel/camel-db.h 2009-02-04 09:13:36.000000000 +0530
+++ camel/camel-db.h 2009-02-04 10:11:32.000000000 +0530
@@ -163,6 +163,7 @@ int camel_db_add_to_vfolder (CamelDB *db
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, char *sort_by, char *collate, GPtrArray *array, CamelException *ex);
+int camel_db_get_folder_uids_flags (CamelDB *db, char *folder_name, char *sort_by, char *collate, GPtrArray *summary, GHashTable *table, 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);
--- camel/camel-folder.c 2009-02-04 09:13:36.000000000 +0530
+++ camel/camel-folder.c 2009-02-04 10:11:32.000000000 +0530
@@ -1171,24 +1171,9 @@ get_uids(CamelFolder *folder)
GPtrArray *array;
int i, j, count;
- array = g_ptr_array_new();
+ g_return_val_if_fail(folder->summary != NULL, g_ptr_array_new ());
- g_return_val_if_fail(folder->summary != NULL, array);
-
- count = camel_folder_summary_count(folder->summary);
- g_ptr_array_set_size(array, count);
- for (i = 0, j = 0; i < count; i++) {
- CamelMessageInfo *info = camel_folder_summary_index(folder->summary, i);
-
- if (info) {
- array->pdata[j++] = (char *)camel_pstring_strdup (camel_message_info_uid (info));
- camel_message_info_free(info);
- }
- }
-
- g_ptr_array_set_size (array, j);
-
- return array;
+ return camel_folder_summary_array (folder->summary);
}
--- camel/camel-folder-summary.c 2009-02-04 09:13:36.000000000 +0530
+++ camel/camel-folder-summary.c 2009-02-04 10:23:32.000000000 +0530
@@ -40,6 +40,7 @@
#include <libedataserver/e-memory.h>
+#include "camel-debug.h"
#include "camel-db.h"
#include "camel-file-utils.h"
#include "camel-folder-summary.h"
@@ -79,7 +80,6 @@ static pthread_mutex_t info_lock = PTHRE
/* this should probably be conditional on it existing */
#define USE_BSEARCH
-#define dd(x)
#define d(x)
#define io(x) /* io debug */
#define w(x)
@@ -155,6 +155,7 @@ camel_folder_summary_init (CamelFolderSu
s->message_info_size = sizeof(CamelMessageInfoBase);
s->content_info_size = sizeof(CamelMessageContentInfo);
+ p->flag_cache = g_hash_table_new (g_str_hash, g_str_equal);
s->message_info_chunks = NULL;
s->content_info_chunks = NULL;
@@ -200,7 +201,7 @@ camel_folder_summary_finalize (CamelObje
CamelFolderSummary *s = (CamelFolderSummary *)obj;
p = _PRIVATE(obj);
-
+ g_hash_table_destroy (p->flag_cache);
if (s->timeout_handle)
g_source_remove (s->timeout_handle);
//camel_folder_summary_clear(s);
@@ -834,7 +835,7 @@ remove_cache (CamelSession *session, Cam
CAMEL_SUMMARY_LOCK (s, summary_lock);
g_hash_table_foreach_remove (s->loaded_infos, (GHRFunc) remove_item, s);
CAMEL_SUMMARY_UNLOCK (s, summary_lock);
- d(printf("done .. now %d\n",g_hash_table_size (s->loaded_infos)));
+ dd(printf("done .. now %d\n",g_hash_table_size (s->loaded_infos)));
s->cache_load_time = time(NULL);
@@ -915,8 +916,6 @@ camel_folder_summary_reload_from_db (Cam
if (!g_getenv("CAMEL_FREE_INFOS") && !s->timeout_handle)
s->timeout_handle = g_timeout_add_seconds (SUMMARY_CACHE_DROP, (GSourceFunc) cfs_try_release_memory, s);
- d(printf("Triggering summary_reloaded on %s %p\n", s->folder->full_name, s));
- camel_object_trigger_event(s, "summary_reloaded", s);
return ret == 0 ? 0 : -1;
}
@@ -931,14 +930,23 @@ camel_folder_summary_dump (CamelFolderSu
printf("\n");
}
+GHashTable *
+camel_folder_summary_get_flag_cache (CamelFolderSummary *summary)
+{
+ struct _CamelFolderSummaryPrivate *p = _PRIVATE(summary);
+
+ return p->flag_cache;
+}
+
int
camel_folder_summary_load_from_db (CamelFolderSummary *s, CamelException *ex)
{
CamelDB *cdb;
char *folder_name;
int ret = 0;
+ struct _CamelFolderSummaryPrivate *p = _PRIVATE(s);
+
/* struct _db_pass_data data; */
-
d(printf ("\ncamel_folder_summary_load_from_db called \n"));
s->flags &= ~CAMEL_SUMMARY_DIRTY;
@@ -950,7 +958,7 @@ camel_folder_summary_load_from_db (Camel
folder_name = s->folder->full_name;
cdb = s->folder->parent_store->cdb_r;
- ret = camel_db_get_folder_uids (cdb, folder_name, (char *)s->sort_by, (char *)s->collate, s->uids, ex);
+ ret = camel_db_get_folder_uids_flags (cdb, folder_name, (char *)s->sort_by, (char *)s->collate, s->uids, p->flag_cache, ex);
/* camel_folder_summary_dump (s); */
#if 0
@@ -1761,7 +1769,8 @@ camel_folder_summary_add (CamelFolderSum
#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_replace (_PRIVATE(s)->flag_cache, (char *)info->uid, GUINT_TO_POINTER(camel_message_info_flags(info)));
+
g_hash_table_insert (s->loaded_infos, (gpointer) camel_message_info_uid (info), info);
s->flags |= CAMEL_SUMMARY_DIRTY;
@@ -1792,9 +1801,13 @@ camel_folder_summary_insert (CamelFolder
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) {
+ g_hash_table_replace (_PRIVATE(s)->flag_cache, (char *)info->uid, GUINT_TO_POINTER(camel_message_info_flags(info)));
+ }
+
if (!load)
s->flags |= CAMEL_SUMMARY_DIRTY;
-
+
CAMEL_SUMMARY_UNLOCK(s, summary_lock);
}
@@ -3102,7 +3115,7 @@ static CamelMessageInfo *
message_info_load(CamelFolderSummary *s, FILE *in)
{
CamelMessageInfoBase *mi;
- guint count;
+ guint32 count;
int i;
char *subject, *from, *to, *cc, *mlist, *uid;
@@ -4667,7 +4680,8 @@ info_set_flags(CamelMessageInfo *info, g
if (((junk && !(mi->flags & CAMEL_MESSAGE_DELETED)))|| (deleted && !(mi->flags & CAMEL_MESSAGE_JUNK)) )
mi->summary->visible_count -= junk ? junk : deleted;
}
-
+ if (mi->uid)
+ g_hash_table_replace (_PRIVATE(mi->summary)->flag_cache, (char *)mi->uid, GUINT_TO_POINTER(mi->flags));
if (mi->summary && mi->summary->folder && mi->uid) {
CamelFolderChangeInfo *changes = camel_folder_change_info_new();
@@ -4682,7 +4696,11 @@ info_set_flags(CamelMessageInfo *info, g
return TRUE;
}
-
+void
+camel_folder_summary_update_flag_cache (CamelFolderSummary *s, const char *uid, guint32 flag)
+{
+ g_hash_table_replace (_PRIVATE(s)->flag_cache, (char *) uid, GUINT_TO_POINTER(flag));
+}
/**
* camel_message_info_set_flags:
* @mi: a #CamelMessageInfo
@@ -4887,6 +4905,4 @@ camel_folder_summary_class_init (CamelFo
klass->info_set_flags = info_set_flags;
- camel_object_class_add_event(camel_object_class, "summary_reloaded", NULL);
-
}
--- camel/camel-folder-summary.h 2008-10-16 10:07:29.000000000 +0530
+++ camel/camel-folder-summary.h 2009-02-04 10:11:32.000000000 +0530
@@ -407,6 +407,8 @@ gboolean camel_folder_summary_check_uid
GPtrArray *camel_folder_summary_array(CamelFolderSummary *summary);
GHashTable *camel_folder_summary_get_hashtable(CamelFolderSummary *s);
void camel_folder_summary_free_hashtable (GHashTable *ht);
+GHashTable *camel_folder_summary_get_flag_cache (CamelFolderSummary *summary);
+void camel_folder_summary_update_flag_cache (CamelFolderSummary *s, const char *uid, guint32 flag);
/* basically like strings, but certain keywords can be compressed and de-cased */
int camel_folder_summary_encode_token(FILE *out, const char *str);
--- camel/camel-private.h 2008-10-13 13:37:53.000000000 +0530
+++ camel/camel-private.h 2009-02-04 10:11:32.000000000 +0530
@@ -128,6 +128,7 @@ struct _CamelFolderSummaryPrivate {
GMutex *filter_lock; /* for accessing any of the filtering/indexing stuff, since we share them */
GMutex *alloc_lock; /* for setting up and using allocators */
GMutex *ref_lock; /* for reffing/unreffing messageinfo's ALWAYS obtain before summary_lock */
+ GHashTable *flag_cache;
};
#define CAMEL_SUMMARY_LOCK(f, l) \
@@ -157,6 +158,7 @@ struct _CamelVeeFolderPrivate {
GMutex *summary_lock; /* for locking vfolder summary */
GMutex *subfolder_lock; /* for locking the subfolder list */
GMutex *changed_lock; /* for locking the folders-changed list */
+ int unread_vfolder;
};
#define CAMEL_VEE_FOLDER_LOCK(f, l) \
--- camel/camel-search-sql-sexp.c 2009-02-04 09:13:36.000000000 +0530
+++ camel/camel-search-sql-sexp.c 2009-02-04 10:34:08.000000000 +0530
@@ -297,11 +297,11 @@ match_all(struct _ESExp *f, int argc, st
ESExpResult *r;
d(printf("executing match-all: %d", argc));
- if (argv[0]->type != ESEXP_TERM_TIME)
+ if (argv[0]->type != ESEXP_TERM_BOOL)
r = e_sexp_term_eval(f, argv[0]);
else {
r = e_sexp_result_new(f, ESEXP_RES_STRING);
- r->value.string = g_strdup("");
+ r->value.string = g_strdup(argv[0]->value.bool ? "1" : "0");
}
return r;
@@ -371,7 +371,7 @@ check_header (struct _ESExp *f, int argc
value = get_db_safe_string (tstr);
g_free (tstr);
}
- str = g_strdup_printf("(%s LIKE %s)", headername, value);
+ str = g_strdup_printf("(%s IS NOT NULL AND %s LIKE %s)", headername, headername, value);
g_free(value);
}
}
@@ -562,7 +562,7 @@ sql_exp (struct _ESExp *f, int argc, str
static struct {
char *name;
ESExpFunc *func;
- int builtin :1;
+ int immediate :1;
} symbols[] = {
{ "and", (ESExpFunc *) func_and, 1 },
{ "or", (ESExpFunc *) func_or, 1},
@@ -571,8 +571,8 @@ static struct {
{ ">", (ESExpFunc *)eval_gt, 1},
{ "<", (ESExpFunc *)eval_lt, 1},
- { "match-all", (ESExpFunc *)match_all, 0 },
- { "match-threads", (ESExpFunc *)match_threads, 0 },
+ { "match-all", (ESExpFunc *)match_all, 1 },
+ { "match-threads", (ESExpFunc *)match_threads, 1 },
/* { "body-contains", body_contains}, */ /* We don't store body on the db. */
{ "header-contains", header_contains, 0},
{ "header-matches", header_matches, 0},
@@ -603,8 +603,12 @@ camel_sexp_to_sql_sexp (const char *sql)
sexp = e_sexp_new();
for(i=0;i<sizeof(symbols)/sizeof(symbols[0]);i++) {
- e_sexp_add_function(sexp, 0, symbols[i].name,
- symbols[i].func, NULL);
+ if (symbols[i].immediate)
+ e_sexp_add_ifunction(sexp, 0, symbols[i].name,
+ symbols[i].func, NULL);
+ else
+ e_sexp_add_function(sexp, 0, symbols[i].name,
+ symbols[i].func, NULL);
}
e_sexp_input_text (sexp, sql, strlen (sql));
--- camel/camel-vee-folder.c 2009-02-04 09:13:36.000000000 +0530
+++ camel/camel-vee-folder.c 2009-02-04 10:11:34.000000000 +0530
@@ -83,9 +83,6 @@ static void folder_changed(CamelFolder *
static void subfolder_deleted(CamelFolder *f, void *event_data, CamelVeeFolder *vf);
static void folder_renamed(CamelFolder *f, const char *old, CamelVeeFolder *vf);
-static void folder_changed_remove_uid(CamelFolder *sub, const char *uid, const char hash[8], int keep, CamelVeeFolder *vf);
-static void summary_reloaded(CamelObject *o, void *event_data, void *data);
-
static CamelFolderClass *camel_vee_folder_parent;
CamelType
@@ -150,7 +147,7 @@ camel_vee_folder_new(CamelStore *parent_
camel_vee_folder_construct(vf, parent_store, full, name, flags);
}
- d(printf("returning folder %s %p, count = %d\n", name, vf, camel_folder_get_message_count((CamelFolder *)vf)));
+ d(printf("returning folder %s %p, count = %d\n", full, vf, camel_folder_get_message_count((CamelFolder *)vf)));
if (vf) {
tmp = g_strdup_printf("%s/%s.cmeta", ((CamelService *)parent_store)->url->path, full);
@@ -221,19 +218,12 @@ camel_vee_folder_add_folder(CamelVeeFold
d(printf("camel_vee_folder_add_folder(%s, %s)\n", ((CamelFolder *)vf)->full_name, sub->full_name));
- cache = camel_folder_summary_cache_size(sub->summary);
- if (!cache) {
- camel_object_hook_event(sub->summary, "summary_reloaded", summary_reloaded, vf);
- g_hash_table_insert(vf->loaded, sub, GINT_TO_POINTER(1));
- }
camel_object_hook_event((CamelObject *)sub, "folder_changed", (CamelObjectEventHookFunc)folder_changed, vf);
camel_object_hook_event((CamelObject *)sub, "deleted", (CamelObjectEventHookFunc)subfolder_deleted, vf);
camel_object_hook_event((CamelObject *)sub, "renamed", (CamelObjectEventHookFunc)folder_renamed, vf);
((CamelVeeFolderClass *)((CamelObject *)vf)->klass)->add_folder(vf, sub);
- if (cache)
- summary_reloaded((CamelObject *) sub->summary, (void *)sub->summary, (void *)vf);
}
/**
@@ -266,10 +256,7 @@ camel_vee_folder_remove_folder(CamelVeeF
camel_object_unhook_event((CamelObject *)sub, "folder_changed", (CamelObjectEventHookFunc) folder_changed, vf);
camel_object_unhook_event((CamelObject *)sub, "deleted", (CamelObjectEventHookFunc) subfolder_deleted, vf);
camel_object_unhook_event((CamelObject *)sub, "renamed", (CamelObjectEventHookFunc) folder_renamed, vf);
- if (GPOINTER_TO_INT(g_hash_table_lookup (vf->loaded, sub))) {
- g_hash_table_remove (vf->loaded, sub);
- camel_object_unhook_event((CamelObject *)sub->summary, "summary_reloaded", (CamelObjectEventHookFunc) summary_reloaded, vf);
- }
+
p->folders = g_list_remove(p->folders, sub);
@@ -516,6 +503,7 @@ summary_header_to_db (CamelFolderSummary
CamelFIRecord * record = g_new0 (CamelFIRecord, 1);
CamelDB *db;
char *table_name;
+ guint32 visible, unread, deleted, junked, junked_not_deleted;
/* We do this during write, so lets use write handle, though we gonna read */
db = s->folder->parent_store->cdb_w;
@@ -530,7 +518,14 @@ summary_header_to_db (CamelFolderSummary
record->time = s->time;
record->saved_count = s->uids->len;
- if (!(((CamelVeeSummary *) s)->force_counts) && !g_getenv("FORCE_VFOLDER_COUNT")) {
+ camel_object_get(s->folder, NULL,
+ CAMEL_FOLDER_DELETED, &deleted,
+ CAMEL_FOLDER_VISIBLE, &visible,
+ CAMEL_FOLDER_JUNKED, &junked,
+ CAMEL_FOLDER_JUNKED_NOT_DELETED, &junked_not_deleted,
+ CAMEL_FOLDER_UNREAD, &unread, NULL);
+ if (1) { /* We always would do this. Just refactor the code again. */
+ //!(((CamelVeeSummary *) s)->force_counts) && !g_getenv("FORCE_VFOLDER_COUNT")) {
/* We should be in sync always. so use the count. Don't search.*/
record->junk_count = s->junk_count;
record->deleted_count = s->deleted_count;
@@ -597,6 +592,7 @@ vee_sync(CamelFolder *folder, gboolean e
node = node->next;
}
+
#if 0
/* Seems like we are doing something wrong with this, as folder_changed happens after this, the counts are misleading.
* Anyways we do a force sync on exit, it should be all fine.
@@ -605,13 +601,37 @@ vee_sync(CamelFolder *folder, gboolean e
camel_db_write_folder_info_record (folder->parent_store->cdb, record, ex);
g_free (record);
#endif
+ /* It makes no sense to clear the folders_changed list without
+ * actually rebuilding. */
+#if 0
if (node == NULL) {
CAMEL_VEE_FOLDER_LOCK(vf, changed_lock);
g_list_free(p->folders_changed);
p->folders_changed = NULL;
CAMEL_VEE_FOLDER_UNLOCK(vf, changed_lock);
}
-
+#endif
+ if (vf->priv->unread_vfolder == 1) {
+ /* Cleanup Junk/Trash uids */
+ int i, count;
+ count = folder->summary->uids->len;
+ GSList *del = NULL;
+
+ for (i=0; i < count; i++) {
+ CamelVeeMessageInfo *mi = camel_folder_summary_index (folder->summary, i);
+ if (mi->old_flags & CAMEL_MESSAGE_DELETED) {
+ del = g_slist_prepend (del, (gpointer) camel_pstring_strdup(((CamelMessageInfo *)mi)->uid));
+ camel_folder_summary_remove_index_fast (folder->summary, i);
+ count--;
+ i--;
+
+ }
+ camel_message_info_free (mi);
+ }
+ camel_db_delete_vuids (folder->parent_store->cdb_w, folder->full_name, "", del, ex);
+ g_slist_foreach (del, (GFunc) camel_pstring_free, NULL);
+ g_slist_free (del);
+ }
CAMEL_VEE_FOLDER_UNLOCK(vf, subfolder_lock);
camel_object_state_write(vf);
@@ -839,8 +859,21 @@ static void vee_delete(CamelFolder *fold
/* ********************************************************************** *
utility functions */
-#define COUNT_ADD_EXPR(lval, sexpr) expr = g_strdup_printf("and (%s %s)", vf->expression, sexpr); lval += count_folder(f, expr, ex); g_free(expr);
-#define COUNT_DEL_EXPR(lval, sexpr) expr = g_strdup_printf("and (%s %s)", vf->expression, sexpr); lval -= count_folder(ssummary->folder, expr, NULL); g_free(expr);
+/* A "correlating" expression has the property that whether a message matches
+ * depends on the other messages being searched. folder_changed_change on a
+ * vfolder with a correlating expression may not make all the necessary updates,
+ * so the query is redone on the entire changed source folder the next time
+ * the vfolder is opened.
+ *
+ * The only current example of a correlating expression is one that uses
+ * "match-threads". */
+static gboolean
+expression_is_correlating(const char *expr)
+{
+ /* XXX: Actually parse the expression to avoid triggering on
+ * "match-threads" in the text the user is searching for! */
+ return (strstr(expr, "match-threads") != NULL);
+}
/* must be called with summary_lock held */
static CamelVeeMessageInfo *
@@ -865,7 +898,6 @@ vee_folder_remove_folder(CamelVeeFolder
GHashTable *unmatched_uids = vf->parent_vee_store ? vf->parent_vee_store->unmatched_uids : NULL;
CamelFolderSummary *ssummary = source->summary;
int killun = FALSE;
- char *expr;
if (vf == folder_unmatched)
return;
@@ -966,12 +998,6 @@ vee_folder_remove_folder(CamelVeeFolder
if (last != -1)
camel_folder_summary_remove_range(folder->summary, start, last);
-
- COUNT_DEL_EXPR(folder->summary->junk_count, "(match-all (system-flag \"junk\"))");
- COUNT_DEL_EXPR(folder->summary->deleted_count, "(match-all (system-flag \"deleted\"))");
- COUNT_DEL_EXPR(folder->summary->unread_count, "(match-all (not (system-flag \"Seen\")))");
- COUNT_DEL_EXPR(folder->summary->visible_count, "(match-all (and (not (system-flag \"deleted\")) (not (system-flag \"junk\"))))");
- COUNT_DEL_EXPR(folder->summary->junk_not_deleted_count, "(match-all (and (not (system-flag \"deleted\")) (system-flag \"junk\")))");
if (folder_unmatched) {
if (camel_folder_change_info_changed(folder_unmatched->changes)) {
@@ -1006,7 +1032,7 @@ struct _update_data {
char hash[8];
CamelVeeFolder *folder_unmatched;
GHashTable *unmatched_uids;
- gboolean rebuilt;
+ gboolean rebuilt, correlating;
};
static void
@@ -1044,7 +1070,7 @@ folder_added_uid(char *uidin, void *valu
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)
+ if (u->rebuilt && !u->correlating)
camel_db_add_to_vfolder_transaction (((CamelFolder *) u->vf)->parent_store->cdb_w, ((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)) {
@@ -1075,6 +1101,11 @@ vee_rebuild_folder(CamelVeeFolder *vf, C
CamelFolderSummary *ssummary = source->summary;
gboolean rebuilded = FALSE;
char *shash;
+
+ /* Since the source of a correlating vfolder has to be requeried in
+ * full every time it changes, caching the results in the db is not
+ * worth the effort. Thus, DB use is conditioned on !correlating. */
+ gboolean correlating = expression_is_correlating(vf->expression);
if (vf == folder_unmatched)
return 0;
@@ -1088,30 +1119,30 @@ vee_rebuild_folder(CamelVeeFolder *vf, C
if (vf->expression == NULL) {
match = g_ptr_array_new();
} else {
- /* Load the folder results from the DB. */
- match = camel_vee_summary_get_ids ((CamelVeeSummary *)folder->summary, u.hash);
- d(printf("len = %d %d for %s %s\n", match ? match->len:0, rebuilded, source->full_name, shash));
- if (!match) {
- char *expr;
+ if (!correlating) {
+ /* Load the folder results from the DB. */
+ match = camel_vee_summary_get_ids ((CamelVeeSummary *)folder->summary, u.hash);
+ }
+ if (correlating ||
+ /* We take this to mean the results have not been cached.
+ * XXX: It will also trigger if the result set is empty. */
+ match == NULL) {
match = camel_folder_search_by_expression(f, vf->expression, ex);
- if (match == NULL)
+ if (match == NULL) /* Search failed */
return 0;
rebuilded = TRUE;
- /* Update the counts */
- COUNT_ADD_EXPR(folder->summary->junk_count, "(match-all (system-flag \"junk\"))");
- COUNT_ADD_EXPR(folder->summary->deleted_count, "(match-all (system-flag \"deleted\"))");
- COUNT_ADD_EXPR(folder->summary->unread_count, "(match-all (not (system-flag \"Seen\")))");
- COUNT_ADD_EXPR(folder->summary->visible_count, "(match-all (and (not (system-flag \"deleted\")) (not (system-flag \"junk\"))))");
- COUNT_ADD_EXPR(folder->summary->junk_not_deleted_count, "(match-all (and (not (system-flag \"deleted\")) (system-flag \"junk\")))");
}
}
+ dd(printf("vee_rebuild_folder(%s <- %s %s): match %d, correlating %d, rebuilded %d\n",
+ folder->full_name, source->full_name, shash, match->len, correlating, rebuilded));
u.source = source;
u.vf = vf;
u.folder_unmatched = folder_unmatched;
u.unmatched_uids = unmatched_uids;
u.rebuilt = rebuilded;
+ u.correlating = correlating;
CAMEL_VEE_FOLDER_LOCK(vf, summary_lock);
@@ -1190,13 +1221,13 @@ vee_rebuild_folder(CamelVeeFolder *vf, C
camel_folder_summary_remove_range(folder->summary, start, last);
/* now matchhash contains any new uid's, add them, etc */
- if (rebuilded) {
+ if (rebuilded && !correlating) {
camel_db_begin_transaction (folder->parent_store->cdb_w, NULL);
}
g_hash_table_foreach(matchhash, (GHFunc)folder_added_uid, &u);
- if (rebuilded)
+ if (rebuilded && !correlating)
camel_db_end_transaction (folder->parent_store->cdb_w, NULL);
if (folder_unmatched != NULL) {
@@ -1242,7 +1273,8 @@ vee_rebuild_folder(CamelVeeFolder *vf, C
/* Del the unwanted things from the summary, we don't hold any locks now. */
if (del_list) {
- camel_db_delete_vuids(folder->parent_store->cdb_w, folder->full_name, shash, del_list, NULL);
+ if (!correlating)
+ camel_db_delete_vuids(folder->parent_store->cdb_w, folder->full_name, shash, del_list, NULL);
((CamelVeeSummary *)folder->summary)->force_counts = TRUE;
g_slist_foreach (del_list, (GFunc) camel_pstring_free, NULL);
g_slist_free (del_list);
@@ -1274,95 +1306,10 @@ vee_rebuild_folder(CamelVeeFolder *vf, C
return 0;
}
-/*
-
- (match-folder "folder1" "folder2")
-
- */
-
-static void
-update_summary (CamelVeeMessageInfo *mi, guint32 flags, guint32 oldflags, gboolean add, gboolean use_old)
-{
- int unread=0, deleted=0, junk=0;
- CamelFolderSummary *summary = ((CamelMessageInfo *) mi)->summary;
-
- if (!(flags & CAMEL_MESSAGE_SEEN) && !(flags & CAMEL_MESSAGE_JUNK))
- unread = 1;
-
- if (flags & CAMEL_MESSAGE_DELETED)
- deleted = 1;
-
- if (flags & CAMEL_MESSAGE_JUNK)
- junk = 1;
-
- d(printf("folder: %s %d %d: %p:%s\n", summary->folder->full_name, oldflags, add, mi, ((CamelMessageInfo *)mi)->uid));
- d(printf("%d %d %d\n%d %d %d\n", !(flags & CAMEL_MESSAGE_SEEN), flags & CAMEL_MESSAGE_DELETED, flags & CAMEL_MESSAGE_JUNK, !(oldflags & CAMEL_MESSAGE_SEEN), oldflags & CAMEL_MESSAGE_DELETED, oldflags & CAMEL_MESSAGE_JUNK));
-
- if (!use_old) {
- if (add) {
- if (unread)
- summary->unread_count += unread;
- if (deleted)
- summary->deleted_count += deleted;
- if (junk)
- summary->junk_count += junk;
- if (junk && !deleted)
- summary->junk_not_deleted_count += junk;
- summary->visible_count++;
- if (junk || deleted)
- summary->visible_count -= junk ? junk : deleted;
-
- summary->saved_count++;
- } else {
- oldflags = use_old ? oldflags : flags;
- unread = deleted = junk = 0;
- if (!(oldflags & CAMEL_MESSAGE_SEEN) && !(oldflags & CAMEL_MESSAGE_JUNK))
- unread -= 1;
-
- if (oldflags & CAMEL_MESSAGE_DELETED)
- deleted -= 1;
-
- if (oldflags & CAMEL_MESSAGE_JUNK)
- junk -= 1;
-
- if (unread)
- summary->unread_count += unread;
- if (deleted)
- summary->deleted_count += deleted;
- if (junk)
- summary->junk_count += junk;
- if (junk && !deleted)
- summary->junk_not_deleted_count += junk;
- if (!junk && !deleted)
- summary->visible_count--;
-
- summary->saved_count--;
- }
- } else {
- if (!(oldflags & CAMEL_MESSAGE_SEEN) && !(oldflags & CAMEL_MESSAGE_JUNK))
- unread -= 1;
-
- if (oldflags & CAMEL_MESSAGE_DELETED)
- deleted -= 1;
-
- if (oldflags & CAMEL_MESSAGE_JUNK)
- junk -= 1;
- if (unread)
- summary->unread_count += unread;
- if (deleted)
- summary->deleted_count += deleted;
- if (junk)
- summary->junk_count += junk;
- if (junk && !deleted)
- summary->junk_not_deleted_count += junk;
- if (junk || deleted)
- summary->visible_count -= junk ? junk : deleted;
- }
-}
/* Hold all these with summary lock and unmatched summary lock held */
static void
-folder_changed_add_uid(CamelFolder *sub, const char *uid, const char hash[8], CamelVeeFolder *vf)
+folder_changed_add_uid(CamelFolder *sub, const char *uid, const char hash[8], CamelVeeFolder *vf, gboolean use_db)
{
CamelFolder *folder = (CamelFolder *)vf;
CamelVeeMessageInfo *vinfo;
@@ -1378,10 +1325,9 @@ folder_changed_add_uid(CamelFolder *sub,
return;
vuid = camel_message_info_uid(vinfo);
- camel_db_add_to_vfolder_transaction (folder->parent_store->cdb_w, folder->full_name, (char *)vuid, NULL);
+ if (use_db)
+ camel_db_add_to_vfolder_transaction (folder->parent_store->cdb_w, folder->full_name, (char *)vuid, NULL);
camel_folder_change_info_add_uid(vf->changes, vuid);
- /* old flags and new flags should be same, since we sync all times */
- update_summary (vinfo, camel_message_info_flags(vinfo), 0, TRUE, FALSE);
if ((vf->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0 && !CAMEL_IS_VEE_FOLDER(sub) && folder_unmatched != NULL) {
if (g_hash_table_lookup_extended(unmatched_uids, vuid, (void **)&oldkey, &oldval)) {
n = GPOINTER_TO_INT (oldval);
@@ -1399,7 +1345,7 @@ folder_changed_add_uid(CamelFolder *sub,
}
static void
-folder_changed_remove_uid(CamelFolder *sub, const char *uid, const char hash[8], int keep, CamelVeeFolder *vf)
+folder_changed_remove_uid(CamelFolder *sub, const char *uid, const char hash[8], int keep, CamelVeeFolder *vf, gboolean use_db)
{
CamelFolder *folder = (CamelFolder *)vf;
char *vuid, *oldkey;
@@ -1413,14 +1359,10 @@ folder_changed_remove_uid(CamelFolder *s
memcpy(vuid, hash, 8);
strcpy(vuid+8, uid);
- vinfo = (CamelVeeMessageInfo *) camel_folder_summary_uid (((CamelFolder *) vf)->summary, vuid);
- if (vinfo) {
- update_summary (vinfo, vinfo->old_flags, 0, FALSE, FALSE);
- camel_message_info_free((CamelMessageInfo *)vinfo);
- }
camel_folder_change_info_remove_uid(vf->changes, vuid);
- /* FIXME[disk-summary] Handle exception */
- camel_db_delete_uid_from_vfolder_transaction (folder->parent_store->cdb_w, folder->full_name, vuid, NULL);
+ if (use_db)
+ /* FIXME[disk-summary] Handle exception */
+ camel_db_delete_uid_from_vfolder_transaction (folder->parent_store->cdb_w, folder->full_name, vuid, NULL);
camel_folder_summary_remove_uid_fast(folder->summary, vuid);
if ((vf->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0 && !CAMEL_IS_VEE_FOLDER(sub) && folder_unmatched != NULL) {
@@ -1456,7 +1398,7 @@ folder_changed_remove_uid(CamelFolder *s
}
static void
-folder_changed_change_uid(CamelFolder *sub, const char *uid, const char hash[8], CamelVeeFolder *vf)
+folder_changed_change_uid(CamelFolder *sub, const char *uid, const char hash[8], CamelVeeFolder *vf, gboolean use_db)
{
char *vuid;
CamelVeeMessageInfo *vinfo, *uinfo = NULL;
@@ -1475,22 +1417,19 @@ folder_changed_change_uid(CamelFolder *s
info = camel_folder_get_message_info(sub, uid);
if (info) {
if (vinfo) {
- guint32 of = vinfo->old_flags;
camel_folder_change_info_change_uid(vf->changes, vuid);
- update_summary (vinfo, camel_message_info_flags(info), of, FALSE /* Doesn't matter */, TRUE);
camel_message_info_free((CamelMessageInfo *)vinfo);
}
if (uinfo) {
camel_folder_change_info_change_uid(folder_unmatched->changes, vuid);
- update_summary (uinfo, camel_message_info_flags(info), uinfo->old_flags, FALSE /* Doesn't matter */, TRUE);
camel_message_info_free((CamelMessageInfo *)uinfo);
}
camel_folder_free_message_info(sub, info);
} else {
if (vinfo) {
- folder_changed_remove_uid(sub, uid, hash, FALSE, vf);
+ folder_changed_remove_uid(sub, uid, hash, FALSE, vf, use_db);
camel_message_info_free((CamelMessageInfo *)vinfo);
}
if (uinfo)
@@ -1529,6 +1468,9 @@ folder_changed_change(CamelSession *sess
GHashTable *unmatched_uids = vf->parent_vee_store ? vf->parent_vee_store->unmatched_uids : NULL;
GPtrArray *present = NULL;
+ /* See vee_rebuild_folder. */
+ gboolean correlating = expression_is_correlating(vf->expression);
+
/* Check the folder hasn't beem removed while we weren't watching */
CAMEL_VEE_FOLDER_LOCK(vf, subfolder_lock);
if (g_list_find(_PRIVATE(vf)->folders, sub) == NULL) {
@@ -1598,7 +1540,7 @@ folder_changed_change(CamelSession *sess
/* Always remove removed uid's, in any case */
for (i=0;i<changes->uid_removed->len;i++) {
dd(printf(" removing uid '%s'\n", (char *)changes->uid_removed->pdata[i]));
- folder_changed_remove_uid(sub, changes->uid_removed->pdata[i], hash, FALSE, vf);
+ folder_changed_remove_uid(sub, changes->uid_removed->pdata[i], hash, FALSE, vf, !correlating);
}
/* Add any newly matched or to unmatched folder if they dont */
@@ -1612,7 +1554,7 @@ folder_changed_change(CamelSession *sess
uid = changes->uid_added->pdata[i];
if (g_hash_table_lookup(matches_hash, uid)) {
dd(printf(" adding uid '%s' [newly matched]\n", (char *)uid));
- folder_changed_add_uid(sub, uid, hash, vf);
+ folder_changed_add_uid(sub, uid, hash, vf, !correlating);
} else if ((vf->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0) {
if (strlen(uid)+9 > vuidlen) {
vuidlen = strlen(uid)+64;
@@ -1638,20 +1580,31 @@ folder_changed_change(CamelSession *sess
/* Change any newly changed */
if (always_changed) {
- GHashTable *ht_present = g_hash_table_new (g_str_hash, g_str_equal);
-
- for (i=0;present && i<present->len;i++) {
- folder_changed_change_uid(sub, present->pdata[i], hash, vf);
- g_hash_table_insert (ht_present, present->pdata[i], present->pdata[i]);
- }
-
- for (i=0; i<always_changed->len; i++) {
- if (!present || !g_hash_table_lookup(ht_present, always_changed->pdata[i])) {
- folder_changed_remove_uid(sub, always_changed->pdata[i], hash, FALSE, vf);
+ if (correlating) {
+ /* Messages may be pulled in by the correlation even if
+ * they do not match the expression individually, so it
+ * would be wrong to preemptively remove anything here.
+ * vee_rebuild_folder will make any necessary removals
+ * when it re-queries the entire source folder. */
+ for (i=0;i<always_changed->len;i++)
+ folder_changed_change_uid(sub, always_changed->pdata[i], hash, vf, !correlating);
+ } else {
+ GHashTable *ht_present = g_hash_table_new (g_str_hash, g_str_equal);
+
+ for (i=0;present && i<present->len;i++) {
+ folder_changed_change_uid(sub, present->pdata[i], hash, vf, !correlating);
+ g_hash_table_insert (ht_present, present->pdata[i], present->pdata[i]);
+ }
+
+ for (i=0; i<always_changed->len; i++) {
+ if (!present || !g_hash_table_lookup(ht_present, always_changed->pdata[i]))
+ /* XXX: IIUC, these messages haven't been deleted from the
+ * source folder, so shouldn't "keep" be set to TRUE? */
+ folder_changed_remove_uid(sub, always_changed->pdata[i], hash, TRUE, vf, !correlating);
}
+
+ g_hash_table_destroy (ht_present);
}
-
- g_hash_table_destroy (ht_present);
g_ptr_array_free(always_changed, TRUE);
}
@@ -1679,21 +1632,21 @@ folder_changed_change(CamelSession *sess
if (g_hash_table_lookup(matches_hash, uid)) {
/* A uid we dont have, but now it matches, add it */
dd(printf(" adding uid '%s' [newly matched]\n", uid));
- folder_changed_add_uid(sub, uid, hash, vf);
+ folder_changed_add_uid(sub, uid, hash, vf, !correlating);
} else {
/* A uid we still don't have, just change it (for unmatched) */
- folder_changed_change_uid(sub, uid, hash, vf);
+ folder_changed_change_uid(sub, uid, hash, vf, !correlating);
}
} else {
if ((vf->flags & CAMEL_STORE_VEE_FOLDER_AUTO) == 0
|| g_hash_table_lookup(matches_hash, uid)) {
/* still match, or we're not auto-updating, change event, (if it changed) */
dd(printf(" changing uid '%s' [still matches]\n", uid));
- folder_changed_change_uid(sub, uid, hash, vf);
+ folder_changed_change_uid(sub, uid, hash, vf, !correlating);
} else {
/* No longer matches, remove it, but keep it in unmatched (potentially) */
dd(printf(" removing uid '%s' [did match]\n", uid));
- folder_changed_remove_uid(sub, uid, hash, TRUE, vf);
+ folder_changed_remove_uid(sub, uid, hash, TRUE, vf, !correlating);
}
camel_message_info_free((CamelMessageInfo *)vinfo);
}
@@ -1702,7 +1655,7 @@ folder_changed_change(CamelSession *sess
} else {
/* stuff didn't match but it changed - check unmatched folder for changes */
for (i=0;i<changed->len;i++)
- folder_changed_change_uid(sub, changed->pdata[i], hash, vf);
+ folder_changed_change_uid(sub, changed->pdata[i], hash, vf, !correlating);
}
if (folder_unmatched != NULL) {
@@ -1745,15 +1698,25 @@ folder_changed_change(CamelSession *sess
camel_folder_change_info_free(unmatched_changes);
}
- if (vf_changes) {
- /* If not auto-updating, keep track of changed folders for later re-sync */
- if ((vf->flags & CAMEL_STORE_VEE_FOLDER_AUTO) == 0) {
- CAMEL_VEE_FOLDER_LOCK(vf, changed_lock);
- if (g_list_find(vf->priv->folders_changed, sub) != NULL)
- vf->priv->folders_changed = g_list_prepend(vf->priv->folders_changed, sub);
- CAMEL_VEE_FOLDER_UNLOCK(vf, changed_lock);
- }
+ /* Add to folders_changed if we need to call vee_rebuild_folder, which
+ * could be the case for two reasons:
+ * - We changed the vfolder and it is not auto-updating. Need to re-sync.
+ * - Vfolder is correlating. Changes to non-matching source messages
+ * won't be processed here and won't show up in vf_changes but may
+ * still affect the vfolder contents (e.g., non-matching messages
+ * added to a matching thread), so we re-run the query on the whole
+ * source folder. (For match-threads, it may be enough to do this if
+ * changes->uid_added->len > 0, but I'm not completely sure and I'd
+ * rather be safe than sorry.)
+ */
+ if ((vf_changes && (vf->flags & CAMEL_STORE_VEE_FOLDER_AUTO) == 0) || correlating) {
+ CAMEL_VEE_FOLDER_LOCK(vf, changed_lock);
+ if (g_list_find(vf->priv->folders_changed, sub) == NULL)
+ vf->priv->folders_changed = g_list_prepend(vf->priv->folders_changed, sub);
+ CAMEL_VEE_FOLDER_UNLOCK(vf, changed_lock);
+ }
+ if (vf_changes) {
camel_object_trigger_event((CamelObject *)vf, "folder_changed", vf_changes);
camel_folder_change_info_free(vf_changes);
}
@@ -1937,95 +1900,6 @@ vee_thaw(CamelFolder *folder)
CAMEL_FOLDER_CLASS (camel_vee_folder_parent)->thaw(folder);
}
-
-struct _folder_flags_msg {
- CamelSessionThreadMsg msg;
- CamelFolder *sub;
- CamelVeeFolder *vf;
-};
-
-static void
-folder_load_flags(CamelSession *session, CamelSessionThreadMsg *msg)
-{
- struct _folder_flags_msg *m = (struct _folder_flags_msg *)msg;
- CamelFolder *sub = m->sub;
- CamelFolder *folder = (CamelFolder *)m->vf;
- GPtrArray *array;
- char *shash, hash[8];
- int i;
-
- camel_vee_folder_hash_folder(sub, hash);
- 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]);
- dd(printf("Loading summary of %s to vfolder %s\n", sub->full_name, folder->full_name));
-
- /* Get the summary of vfolder */
- array = camel_folder_summary_array (folder->summary);
- for (i=0; i<array->len; i++) {
- if (strncmp(array->pdata[i], shash, 8) == 0) {
- /* We have got a vuid for this sub folder.*/
- CamelVeeMessageInfo *vinfo;
- CamelMessageInfo *info;
- char *uid;
- vinfo = (CamelVeeMessageInfo *) camel_folder_summary_uid (folder->summary, (char *)array->pdata[i]);
- if (!vinfo) /* What else we can do ?*/
- continue;
- uid = ((char *)array->pdata[i])+8;
- info = camel_folder_summary_uid (sub->summary, uid);
- if (!info) {
- camel_message_info_free((CamelMessageInfo *)vinfo);
- continue;
- }
-
- vinfo->old_flags = camel_message_info_flags (info);
- camel_message_info_free((CamelMessageInfo *)info);
- camel_message_info_free((CamelMessageInfo *)vinfo);
- }
- }
- camel_folder_free_summary (folder, array);
- g_free(shash);
-}
-
-static void
-folder_load_flags_free(CamelSession *session, CamelSessionThreadMsg *msg)
-{
- struct _folder_flags_msg *m = (struct _folder_flags_msg *)msg;
-
- camel_object_unref((CamelObject *)m->vf);
- camel_object_unref((CamelObject *)m->sub);
-}
-
-static CamelSessionThreadOps folder_flags_ops = {
- folder_load_flags,
- folder_load_flags_free,
-};
-
-static void
-summary_reloaded(CamelObject *o, void *event_data, void *data)
-{
- CamelFolderSummary *summary = event_data;
- CamelVeeFolder *vf = (CamelVeeFolder *)data;
- struct _CamelVeeFolderPrivate *p = _PRIVATE(vf);
- struct _folder_flags_msg *m;
- CamelSession *session = ((CamelService *)((CamelFolder *)vf)->parent_store)->session;
-
- if (p->destroyed)
- return;
-
- /* Kick off a thread to reload flags from the summary */
- if (GPOINTER_TO_INT(g_hash_table_lookup (vf->loaded, summary->folder))) {
- g_hash_table_remove (vf->loaded, summary->folder);
- camel_object_unhook_event((CamelObject *)o, "summary_reloaded", (CamelObjectEventHookFunc) summary_reloaded, data);
- }
-
- m = camel_session_thread_msg_new(session, &folder_flags_ops, sizeof(*m));
- m->sub = summary->folder;
- camel_object_ref((CamelObject *)summary->folder);
- m->vf = vf;
- camel_object_ref((CamelObject *)vf);
- camel_session_thread_queue(session, &m->msg, 0);
-
-}
-
/* vfolder base implementaitons */
static void
vee_add_folder(CamelVeeFolder *vf, CamelFolder *sub)
@@ -2098,6 +1972,106 @@ vee_set_expression(CamelVeeFolder *vf, c
CAMEL_VEE_FOLDER_UNLOCK(vf, subfolder_lock);
}
+/* This entire code will be useless, since we sync the counts always. */
+static int
+vf_getv(CamelObject *object, CamelException *ex, CamelArgGetV *args)
+{
+ CamelFolder *folder = (CamelFolder *)object;
+ CamelVeeFolder *vf = (CamelVeeFolder *)folder;
+ int i;
+ guint32 tag;
+ int unread = -1, deleted = 0, junked = 0, visible = 0, count = -1, junked_not_deleted = -1;
+
+
+ for (i=0;i<args->argc;i++) {
+ CamelArgGet *arg = &args->argv[i];
+
+ tag = arg->tag;
+
+ /* NB: this is a copy of camel-folder.c with the unread count logic altered.
+ makes sure its still atomically calculated */
+ switch (tag & CAMEL_ARG_TAG) {
+ case CAMEL_FOLDER_ARG_UNREAD:
+ case CAMEL_FOLDER_ARG_DELETED:
+ case CAMEL_FOLDER_ARG_JUNKED:
+ case CAMEL_FOLDER_ARG_JUNKED_NOT_DELETED:
+ case CAMEL_FOLDER_ARG_VISIBLE:
+
+ if (vf->expression && vf->priv->unread_vfolder == -1)
+ camel_vee_summary_load_check_unread_vfolder ((CamelVeeSummary *)folder->summary);
+
+ /* This is so we can get the values atomically, and also so we can calculate them only once */
+ if (unread == -1) {
+ int j;
+ CamelMessageInfoBase *info;
+ CamelVeeMessageInfo *vinfo;
+
+ unread = deleted = visible = junked = junked_not_deleted = 0;
+ count = camel_folder_summary_count(folder->summary);
+ for (j=0; j<count; j++) {
+ if ((info = (CamelMessageInfoBase *) camel_folder_summary_index(folder->summary, j))) {
+ guint32 flags;
+
+ vinfo = (CamelVeeMessageInfo *) info;
+ flags = vinfo->old_flags;// ? vinfo->old_flags : camel_message_info_flags(info);
+
+ if ((flags & (CAMEL_MESSAGE_SEEN)) == 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);
+ }
+ }
+ }
+
+ switch (tag & CAMEL_ARG_TAG) {
+ case CAMEL_FOLDER_ARG_UNREAD:
+ if (vf->priv->unread_vfolder == 1)
+ count = unread == -1 ? 0 : unread - junked_not_deleted;
+ else
+ count = unread == -1 ? 0 : unread;
+ break;
+ case CAMEL_FOLDER_ARG_DELETED:
+ count = deleted == -1 ? 0 : deleted;
+ break;
+ case CAMEL_FOLDER_ARG_JUNKED:
+ count = junked == -1 ? 0 : junked;
+ break;
+ case CAMEL_FOLDER_ARG_JUNKED_NOT_DELETED:
+ count = junked_not_deleted == -1 ? 0 : junked_not_deleted;
+ break;
+ case CAMEL_FOLDER_ARG_VISIBLE:
+ if (vf->priv->unread_vfolder == 1)
+ count = unread == -1 ? 0 : unread - junked_not_deleted;
+ else
+ count = visible == -1 ? 0 : visible;
+
+ break;
+ }
+ folder->summary->unread_count = unread == -1 ? 0 : unread;
+ folder->summary->deleted_count = deleted == -1 ? 0 : deleted;
+ junked = folder->summary->junk_count = junked == -1 ? 0 : junked;
+ folder->summary->junk_not_deleted_count = junked_not_deleted == -1 ? 0 : junked_not_deleted;
+ folder->summary->visible_count = visible == -1 ? 0 : visible;
+ *arg->ca_int = count;
+ break;
+ default:
+ continue;
+ }
+
+ arg->tag = (tag & CAMEL_ARG_TYPE) | CAMEL_ARG_IGNORE;
+ }
+
+ return ((CamelObjectClass *)camel_vee_folder_parent)->getv(object, ex, args);
+}
+
static void
camel_vee_folder_class_init (CamelVeeFolderClass *klass)
{
@@ -2105,6 +2079,8 @@ camel_vee_folder_class_init (CamelVeeFol
camel_vee_folder_parent = CAMEL_FOLDER_CLASS(camel_type_get_global_classfuncs (camel_folder_get_type ()));
+ ((CamelObjectClass *)klass)->getv = vf_getv;
+
folder_class->refresh_info = vee_refresh_info;
folder_class->sync = vee_sync;
folder_class->expunge = vee_expunge;
@@ -2152,11 +2128,13 @@ camel_vee_folder_init (CamelVeeFolder *o
obj->changes = camel_folder_change_info_new();
obj->search = camel_folder_search_new();
obj->hashes = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
- obj->loaded = g_hash_table_new (g_direct_hash, g_direct_equal);
+ /* Loaded is no longer used.*/
+ obj->loaded = NULL;
obj->deleted = FALSE;
p->summary_lock = g_mutex_new();
p->subfolder_lock = g_mutex_new();
p->changed_lock = g_mutex_new();
+ p->unread_vfolder = -1;
}
void
@@ -2195,10 +2173,6 @@ vee_folder_stop_folder(CamelVeeFolder *v
camel_object_unhook_event((CamelObject *)sub, "folder_changed", (CamelObjectEventHookFunc) folder_changed, vf);
camel_object_unhook_event((CamelObject *)sub, "deleted", (CamelObjectEventHookFunc) subfolder_deleted, vf);
camel_object_unhook_event((CamelObject *)sub, "renamed", (CamelObjectEventHookFunc) folder_renamed, vf);
- if (GPOINTER_TO_INT(g_hash_table_lookup (vf->loaded, sub))) {
- g_hash_table_remove (vf->loaded, sub);
- camel_object_unhook_event((CamelObject *)sub->summary, "summary_reloaded", (CamelObjectEventHookFunc) summary_reloaded, vf);
- }
p->folders = g_list_remove(p->folders, sub);
@@ -2307,6 +2281,5 @@ camel_vee_folder_finalise (CamelObject *
g_mutex_free(p->subfolder_lock);
g_mutex_free(p->changed_lock);
g_hash_table_destroy (vf->hashes);
- g_hash_table_destroy (vf->loaded);
g_free(p);
}
--- camel/camel-vee-summary.c 2009-02-04 09:13:36.000000000 +0530
+++ camel/camel-vee-summary.c 2009-02-04 10:42:04.000000000 +0530
@@ -171,24 +171,61 @@ vee_info_set_user_tag(CamelMessageInfo *
return res;
}
-static gboolean
-vee_info_set_flags(CamelMessageInfo *mi, guint32 flags, guint32 set)
+void
+camel_vee_summary_load_check_unread_vfolder (CamelVeeSummary *vs)
{
- int res = FALSE;
- CamelVeeFolder *vf = (CamelVeeFolder *)mi->summary->folder;
- const char *exp = g_getenv("CAMEL_VFOLDER_UNREAD_EXP");
+ static int only_once = FALSE;
+ static char *exp = NULL;
+ char *meta;
gboolean hacked_unread_folder = FALSE;
+ CamelVeeFolder *vf = (CamelVeeFolder *) ((CamelFolderSummary *)vs)->folder;
/* HACK: Ugliest of all hacks. Its virtually not possible now
* to maintain counts and the non matching uids of unread vfolder here.
* So, I hardcode unread vfolder expression and hack it. */
+ if (!only_once) {
+ exp = g_getenv("CAMEL_VFOLDER_UNREAD_EXP") ? g_strcompress(g_getenv("CAMEL_VFOLDER_UNREAD_EXP")) : NULL;
+ only_once = TRUE;
+ }
+
if (!exp || !*exp)
- exp = unread_str;
+ exp = g_strcompress(unread_str);
+
+ if (vf->expression && strstr(exp, vf->expression) && (vf->flags & CAMEL_STORE_VEE_FOLDER_SPECIAL) == 0)
+ hacked_unread_folder = TRUE;
+
+ meta = camel_object_meta_get (vf, "vfolder:unread");
+ if (!hacked_unread_folder && meta && strcmp (meta, "true") == 0)
+ hacked_unread_folder = TRUE;
+ g_free(meta);
+
+ if (hacked_unread_folder)
+ vf->priv->unread_vfolder = 1;
+ else
+ vf->priv->unread_vfolder = 0;
+}
+
+static gboolean
+vee_info_set_flags(CamelMessageInfo *mi, guint32 flags, guint32 set)
+{
+ int res = FALSE;
+ CamelVeeFolder *vf = (CamelVeeFolder *)mi->summary->folder;
+ gboolean hacked_unread_folder = FALSE;
+
if (camel_debug("vfolderexp"))
printf("Expression for vfolder '%s' is '%s'\n", mi->summary->folder->full_name, g_strescape(vf->expression, ""));
- if (strstr(exp, vf->expression) && (vf->flags & CAMEL_STORE_VEE_FOLDER_SPECIAL) == 0)
- hacked_unread_folder = TRUE;
+ if (vf->priv->unread_vfolder == -1)
+ camel_vee_summary_load_check_unread_vfolder (mi->summary);
+
+ if (vf->priv->unread_vfolder == 1)
+ hacked_unread_folder = TRUE;
+ else {
+ char *meta = camel_object_meta_get (mi->summary->folder, "vfolder:unread");
+ if (meta && strcmp (meta, "true") == 0)
+ hacked_unread_folder = TRUE;
+ g_free(meta);
+ }
if (mi->uid) {
guint32 old_visible, old_unread, old_deleted, old_junked, old_junked_not_deleted;
@@ -225,11 +262,11 @@ vee_info_set_flags(CamelMessageInfo *mi,
vsummary->fake_visible_count = mi->summary->visible_count;
/* Keep the summary in sync */
- mi->summary->unread_count += unread - old_unread;
- mi->summary->deleted_count += deleted - old_deleted;
- mi->summary->junk_count += junked - old_junked;
- mi->summary->junk_not_deleted_count += junked_not_deleted - old_junked_not_deleted;
- mi->summary->visible_count += visible - old_visible;
+ //mi->summary->unread_count += unread - old_unread;
+ //mi->summary->deleted_count += deleted - old_deleted;
+ //mi->summary->junk_count += junked - old_junked;
+ //mi->summary->junk_not_deleted_count += junked_not_deleted - old_junked_not_deleted;
+ //mi->summary->visible_count += visible - old_visible;
if (vsummary->fake_visible_count || hacked_unread_folder)
vsummary->fake_visible_count += visible - old_visible;
@@ -418,6 +455,7 @@ camel_vee_summary_add(CamelVeeSummary *s
CamelVeeMessageInfo *mi;
char *vuid;
+ GHashTable * fcache;
vuid = g_malloc(strlen(uid)+9);
memcpy(vuid, hash, 8);
strcpy(vuid+8, uid);
@@ -440,6 +478,8 @@ camel_vee_summary_add(CamelVeeSummary *s
mi = (CamelVeeMessageInfo *)camel_message_info_new(&s->summary);
mi->summary = summary;
+ fcache = camel_folder_summary_get_flag_cache(summary);
+ mi->old_flags = GPOINTER_TO_UINT(g_hash_table_lookup (fcache, uid));
/* We would do lazy loading of flags, when the folders are loaded to memory through folder_reloaded signal */
camel_object_ref (summary);
mi->info.uid = (char *) camel_pstring_strdup (vuid);
--- camel/camel-vee-summary.h 2008-10-15 00:00:49.000000000 +0530
+++ camel/camel-vee-summary.h 2009-02-04 10:11:35.000000000 +0530
@@ -62,6 +62,7 @@ CamelFolderSummary *camel_vee_summary_ne
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]);
+void camel_vee_summary_load_check_unread_vfolder (CamelVeeSummary *vs);
G_END_DECLS
--- camel/camel-vtrash-folder.c 2008-11-07 10:04:23.000000000 +0530
+++ camel/camel-vtrash-folder.c 2009-02-04 10:11:35.000000000 +0530
@@ -151,7 +151,7 @@ vtrash_getv(CamelObject *object, CamelEx
guint32 flags;
vinfo = (CamelVeeMessageInfo *) info;
- flags = vinfo->old_flags ? vinfo->old_flags : camel_message_info_flags(info);
+ flags = vinfo->old_flags;// ? vinfo->old_flags : camel_message_info_flags(info);
if ((flags & (CAMEL_MESSAGE_SEEN)) == 0)
unread++;
--- camel/providers/imap/camel-imap-folder.c 2009-02-04 09:13:36.000000000 +0530
+++ camel/providers/imap/camel-imap-folder.c 2009-02-04 10:11:35.000000000 +0530
@@ -964,6 +964,13 @@ imap_rescan (CamelFolder *folder, int ex
continue;
info = camel_folder_summary_uid (folder->summary, uid);
+ if (!info) {
+ if (g_getenv("CRASH_IMAP")) { /* Debug logs to tackle on hard to get imap crasher */
+ printf("CRASH: %s: %s", folder->full_name, uid);
+ g_assert(0);
+ } else
+ continue;
+ }
iinfo = (CamelImapMessageInfo *)info;
@@ -2941,9 +2948,26 @@ imap_get_message (CamelFolder *folder, c
&& retry < 2
&& camel_exception_get_id(ex) == CAMEL_EXCEPTION_SERVICE_UNAVAILABLE);
-done: /* FIXME, this shouldn't be done this way. */
- if (msg)
+done:
+ if (msg) {
+ /* FIXME, this shouldn't be done this way. */
camel_medium_set_header (CAMEL_MEDIUM (msg), "X-Evolution-Source", store->base_url);
+
+ if (!mi->info.mlist || !*mi->info.mlist) {
+ /* update mailing list information, if necessary */
+ char *mlist = camel_header_raw_check_mailing_list (&(CAMEL_MIME_PART (msg)->headers));
+
+ if (mlist) {
+ if (mi->info.mlist)
+ camel_pstring_free (mi->info.mlist);
+ mi->info.mlist = camel_pstring_add (mlist, TRUE);
+ mi->info.dirty = TRUE;
+
+ if (mi->info.summary)
+ camel_folder_summary_touch (mi->info.summary);
+ }
+ }
+ }
fail:
camel_message_info_free(&mi->info);
--- camel/providers/imap/camel-imap-journal.c 2008-10-13 13:37:30.000000000 +0530
+++ camel/providers/imap/camel-imap-journal.c 2009-02-04 10:11:35.000000000 +0530
@@ -160,6 +160,25 @@ free_uids (GPtrArray *array)
}
static GPtrArray *
+copy_uids_array (GPtrArray *array)
+{
+ GPtrArray *res;
+ guint i, sz;
+
+ if (!array)
+ return NULL;
+
+ sz = array->len;
+ res = g_ptr_array_sized_new (sz);
+
+ for (i = 0; i < sz; i++) {
+ g_ptr_array_add (res, g_strdup (g_ptr_array_index (array, i)));
+ }
+
+ return res;
+}
+
+static GPtrArray *
decode_uids (FILE *file)
{
GPtrArray *uids;
@@ -413,20 +432,20 @@ camel_imap_journal_log (CamelOfflineJour
{
GPtrArray *uids = va_arg (ap, GPtrArray *);
- entry->uids = uids;
+ entry->uids = copy_uids_array (uids);
break;
}
case CAMEL_IMAP_JOURNAL_ENTRY_APPEND:
{
char *uid = va_arg (ap, char *);
- entry->append_uid = uid;
+ entry->append_uid = g_strdup (uid);
break;
}
case CAMEL_IMAP_JOURNAL_ENTRY_TRANSFER:
{
CamelFolder *dest = va_arg (ap, CamelFolder *);
- entry->uids = va_arg (ap, GPtrArray *);
+ entry->uids = copy_uids_array (va_arg (ap, GPtrArray *));
entry->move = va_arg (ap, gboolean);
entry->dest_folder_name = g_strdup (dest->full_name);
break;
--- camel/providers/imap/camel-imap-summary.c 2008-10-15 12:22:20.000000000 +0530
+++ camel/providers/imap/camel-imap-summary.c 2009-02-04 10:11:35.000000000 +0530
@@ -163,6 +163,22 @@ sort_uid_cmp (void *enc, int len1, void
return (a1 < a1) ? -1 : (a1 > a2) ? 1 : 0;
}
+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;
+}
+
/**
* camel_imap_summary_new:
* @folder: Parent folder.
@@ -181,7 +197,8 @@ camel_imap_summary_new (struct _CamelFol
camel_exception_init (&ex);
summary->folder = folder;
- if (folder) {
+ /* Don't do DB sort. Its pretty slow to load */
+ if (folder && 0) {
camel_db_set_collate (folder->parent_store->cdb_r, "uid", "imap_uid_sort", (CamelDBCollate)sort_uid_cmp);
summary->sort_by = "uid";
summary->collate = "imap_uid_sort";
@@ -199,6 +216,8 @@ camel_imap_summary_new (struct _CamelFol
camel_exception_clear (&ex);
}
+ g_ptr_array_sort (summary->uids, (GCompareFunc) uid_compare);
+
return summary;
}
--- camel/providers/local/camel-local-private.h 2008-10-13 13:37:37.000000000 +0530
+++ camel/providers/local/camel-local-private.h 2009-02-04 10:11:35.000000000 +0530
@@ -42,6 +42,8 @@ struct _CamelLocalFolderPrivate {
#define CAMEL_LOCAL_FOLDER_LOCK(f, l) (g_mutex_lock(((CamelLocalFolder *)f)->priv->l))
#define CAMEL_LOCAL_FOLDER_UNLOCK(f, l) (g_mutex_unlock(((CamelLocalFolder *)f)->priv->l))
+int camel_local_frompos_sort (void *enc, int len1, void * data1, int len2, void *data2);
+
G_END_DECLS
#endif /* CAMEL_LOCAL_PRIVATE_H */
--- camel/providers/local/camel-local-summary.c 2008-10-14 11:00:40.000000000 +0530
+++ camel/providers/local/camel-local-summary.c 2009-02-04 10:11:35.000000000 +0530
@@ -484,6 +484,7 @@ local_summary_add(CamelLocalSummary *cls
update_summary (s, (CamelMessageInfoBase *) mi, (CamelMessageInfoBase *) info);
mi->info.flags |= (camel_message_info_flags(info) & 0xffff);
+ camel_folder_summary_update_flag_cache (s, mi->info.uid, mi->info.flags);
mi->info.size = camel_message_info_size(info);
}
--- camel/providers/local/camel-mbox-summary.c 2008-10-14 11:00:40.000000000 +0530
+++ camel/providers/local/camel-mbox-summary.c 2009-02-04 10:11:35.000000000 +0530
@@ -46,6 +46,7 @@
#include "camel-string-utils.h"
#include "camel-store.h"
#include "camel-folder.h"
+#include "camel-local-private.h"
#define io(x)
#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/
@@ -211,29 +212,6 @@ camel_mbox_summary_finalise(CamelObject
{
/*CamelMboxSummary *mbs = CAMEL_MBOX_SUMMARY(obj);*/
}
-static int
-frompos_sort (void *enc, int len1, void * data1, int len2, void *data2)
-{
- static char *sa1=NULL, *sa2=NULL;
- static int l1=0, l2=0;
- int a1, a2;
-
- if (l1 < len1+1) {
- sa1 = g_realloc (sa1, len1+1);
- l1 = len1+1;
- }
- if (l2 < len2+1) {
- sa2 = g_realloc (sa2, len2+1);
- l2 = len2+1;
- }
- strncpy (sa1, data1, len1);sa1[len1] = 0;
- strncpy (sa2, data2, len2);sa2[len2] = 0;
-
- a1 = strtoul (sa1, NULL, 10);
- a2 = strtoul (sa2, NULL, 10);
-
- return (a1 < a1) ? -1 : (a1 > a2) ? 1 : 0;
-}
/**
* camel_mbox_summary_new:
@@ -252,7 +230,7 @@ camel_mbox_summary_new(struct _CamelFold
CamelFolderSummary *summary = (CamelFolderSummary *)new;
/* Set the functions for db sorting */
- camel_db_set_collate (folder->parent_store->cdb_r, "bdata", "mbox_frompos_sort", (CamelDBCollate)frompos_sort);
+ camel_db_set_collate (folder->parent_store->cdb_r, "bdata", "mbox_frompos_sort", (CamelDBCollate)camel_local_frompos_sort);
summary->sort_by = "bdata";
summary->collate = "mbox_frompos_sort";
--- camel/providers/local/camel-spool-summary.c 2008-10-14 11:00:40.000000000 +0530
+++ camel/providers/local/camel-spool-summary.c 2009-02-04 10:11:35.000000000 +0530
@@ -41,6 +41,7 @@
#include "camel-store.h"
#include "camel-spool-summary.h"
+#include "camel-local-private.h"
#define io(x)
#define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/
@@ -107,30 +108,6 @@ camel_spool_summary_finalise(CamelObject
/*CamelSpoolSummary *mbs = CAMEL_SPOOL_SUMMARY(obj);*/
}
-static int
-frompos_sort (void *enc, int len1, void * data1, int len2, void *data2)
-{
- static char *sa1=NULL, *sa2=NULL;
- static int l1=0, l2=0;
- int a1, a2;
-
- if (l1 < len1+1) {
- sa1 = g_realloc (sa1, len1+1);
- l1 = len1+1;
- }
- if (l2 < len2+1) {
- sa2 = g_realloc (sa2, len2+1);
- l2 = len2+1;
- }
- strncpy (sa1, data1, len1);sa1[len1] = 0;
- strncpy (sa2, data2, len2);sa2[len2] = 0;
-
- a1 = strtoul (sa1, NULL, 10);
- a2 = strtoul (sa2, NULL, 10);
-
- return (a1 < a1) ? -1 : (a1 > a2) ? 1 : 0;
-}
-
CamelSpoolSummary *
camel_spool_summary_new(struct _CamelFolder *folder, const char *mbox_name)
{
@@ -138,7 +115,7 @@ camel_spool_summary_new(struct _CamelFol
((CamelFolderSummary *)new)->folder = folder;
if (folder) {
- camel_db_set_collate (folder->parent_store->cdb_r, "bdata", "spool_frompos_sort", (CamelDBCollate)frompos_sort);
+ camel_db_set_collate (folder->parent_store->cdb_r, "bdata", "spool_frompos_sort", (CamelDBCollate)camel_local_frompos_sort);
((CamelFolderSummary *)new)->sort_by = "bdata";
((CamelFolderSummary *)new)->collate = "spool_frompos_sort";
}
--- camel/providers/local/Makefile.am 2008-10-13 13:37:37.000000000 +0530
+++ camel/providers/local/Makefile.am 2009-02-04 10:11:35.000000000 +0530
@@ -29,6 +29,7 @@ libcamellocal_la_SOURCES = \
camel-local-folder.c \
camel-local-store.c \
camel-local-summary.c \
+ camel-local-private.c \
camel-local-provider.c \
camel-mbox-folder.c \
camel-mbox-store.c \
--- libedataserver/e-sexp.c 2008-10-13 13:38:18.000000000 +0530
+++ libedataserver/e-sexp.c 2009-02-04 10:11:35.000000000 +0530
@@ -706,7 +706,7 @@ e_sexp_term_eval(struct _ESExp *f, struc
r->value.time = t->value.time;
break;
case ESEXP_TERM_IFUNC:
- if (t->value.func.sym->f.ifunc)
+ if (t->value.func.sym && t->value.func.sym->f.ifunc)
r = t->value.func.sym->f.ifunc(f, t->value.func.termcount, t->value.func.terms, t->value.func.sym->data);
break;
case ESEXP_TERM_FUNC:
--- /dev/null 2008-12-03 11:26:56.000000000 +0530
+++ camel/providers/local/camel-local-private.c 2009-01-29 08:42:09.000000000 +0530
@@ -0,0 +1,53 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; fill-column: 160 -*-
+ *
+ * Copyright (C) 2008 Novell, Inc. (www.novell.com)
+ *
+ * Authors: Srinivsa Ragavan <sragavan@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
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <string.h>
+#include <stdlib.h>
+#include "camel-local-private.h"
+
+int
+camel_local_frompos_sort (void *enc, int len1, void * data1, int len2, void *data2)
+{
+ static char *sa1=NULL, *sa2=NULL;
+ static int l1=0, l2=0;
+ int a1, a2;
+
+ if (l1 < len1+1) {
+ sa1 = g_realloc (sa1, len1+1);
+ l1 = len1+1;
+ }
+ if (l2 < len2+1) {
+ sa2 = g_realloc (sa2, len2+1);
+ l2 = len2+1;
+ }
+ strncpy (sa1, data1, len1);sa1[len1] = 0;
+ strncpy (sa2, data2, len2);sa2[len2] = 0;
+
+ a1 = strtoul (sa1, NULL, 10);
+ a2 = strtoul (sa2, NULL, 10);
+
+ return a1 - a2;
+}