Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Evergreen:11.1:kernel-2.6.32
evolution-data-server
bnc-472719-eds-disk-summary-patches.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
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; +}
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor