diff options
Diffstat (limited to 'camel/camel-folder.c')
-rw-r--r-- | camel/camel-folder.c | 186 |
1 files changed, 125 insertions, 61 deletions
diff --git a/camel/camel-folder.c b/camel/camel-folder.c index 674094ce42..af9edcfe5d 100644 --- a/camel/camel-folder.c +++ b/camel/camel-folder.c @@ -1328,6 +1328,12 @@ camel_folder_free_deep (CamelFolder *folder, GPtrArray *array) g_ptr_array_free (array, TRUE); } +struct _CamelFolderChangeInfoPrivate { + GHashTable *uid_stored; /* what we have stored, which array they're in */ + GHashTable *uid_source; /* used to create unique lists */ + struct _EMemPool *uid_pool; /* pool used to store copies of uid strings */ +}; + /** * camel_folder_change_info_new: * @void: @@ -1348,38 +1354,14 @@ camel_folder_change_info_new(void) info->uid_added = g_ptr_array_new(); info->uid_removed = g_ptr_array_new(); info->uid_changed = g_ptr_array_new(); - info->uid_source = NULL; - info->uid_pool = e_mempool_new(512, 256, E_MEMPOOL_ALIGN_BYTE); + info->priv = g_malloc0(sizeof(*info->priv)); + info->priv->uid_stored = g_hash_table_new(g_str_hash, g_str_equal); + info->priv->uid_source = NULL; + info->priv->uid_pool = e_mempool_new(512, 256, E_MEMPOOL_ALIGN_BYTE); return info; } -static void -change_info_add_uid(CamelFolderChangeInfo *info, GPtrArray *uids, const char *uid, int copy) -{ - int i; - - /* TODO: Check that it is in the other arrays and remove it from them/etc? */ - for (i=0;i<uids->len;i++) { - if (!strcmp(uids->pdata[i], uid)) - return; - } - if (copy) - g_ptr_array_add(uids, e_mempool_strdup(info->uid_pool, uid)); - else - g_ptr_array_add(uids, (char *)uid); -} - -static void -change_info_cat(CamelFolderChangeInfo *info, GPtrArray *uids, GPtrArray *source) -{ - int i; - - for (i=0;i<source->len;i++) { - change_info_add_uid(info, uids, source->pdata[i], TRUE); - } -} - /** * camel_folder_change_info_add_source: * @info: @@ -1390,11 +1372,13 @@ change_info_cat(CamelFolderChangeInfo *info, GPtrArray *uids, GPtrArray *source) void camel_folder_change_info_add_source(CamelFolderChangeInfo *info, const char *uid) { - if (info->uid_source == NULL) - info->uid_source = g_hash_table_new(g_str_hash, g_str_equal); + struct _CamelFolderChangeInfoPrivate *p = info->priv; + + if (p->uid_source == NULL) + p->uid_source = g_hash_table_new(g_str_hash, g_str_equal); - if (g_hash_table_lookup(info->uid_source, uid) == NULL) - g_hash_table_insert(info->uid_source, e_mempool_strdup(info->uid_pool, uid), (void *)1); + if (g_hash_table_lookup(p->uid_source, uid) == NULL) + g_hash_table_insert(p->uid_source, e_mempool_strdup(p->uid_pool, uid), (void *)1); } /** @@ -1408,15 +1392,16 @@ void camel_folder_change_info_add_source_list(CamelFolderChangeInfo *info, const GPtrArray *list) { int i; + struct _CamelFolderChangeInfoPrivate *p = info->priv; - if (info->uid_source == NULL) - info->uid_source = g_hash_table_new(g_str_hash, g_str_equal); + if (p->uid_source == NULL) + p->uid_source = g_hash_table_new(g_str_hash, g_str_equal); for (i=0;i<list->len;i++) { char *uid = list->pdata[i]; - if (g_hash_table_lookup(info->uid_source, uid) == NULL) - g_hash_table_insert(info->uid_source, e_mempool_strdup(info->uid_pool, uid), (void *)1); + if (g_hash_table_lookup(p->uid_source, uid) == NULL) + g_hash_table_insert(p->uid_source, e_mempool_strdup(p->uid_pool, uid), (void *)1); } } @@ -1432,16 +1417,17 @@ camel_folder_change_info_add_update(CamelFolderChangeInfo *info, const char *uid { char *key; int value; + struct _CamelFolderChangeInfoPrivate *p = info->priv; - if (info->uid_source == NULL) { - change_info_add_uid(info, info->uid_added, uid, TRUE); + if (p->uid_source == NULL) { + camel_folder_change_info_add_uid(info, uid); return; } - if (g_hash_table_lookup_extended(info->uid_source, uid, (void **)&key, (void **)&value)) { - g_hash_table_remove(info->uid_source, key); + if (g_hash_table_lookup_extended(p->uid_source, uid, (void **)&key, (void **)&value)) { + g_hash_table_remove(p->uid_source, key); } else { - change_info_add_uid(info, info->uid_added, uid, TRUE); + camel_folder_change_info_add_uid(info, uid); } } @@ -1457,16 +1443,31 @@ camel_folder_change_info_add_update_list(CamelFolderChangeInfo *info, const GPtr { int i; - for (i=0;i<list->len;i++) { + for (i=0;i<list->len;i++) camel_folder_change_info_add_update(info, list->pdata[i]); - } } static void change_info_remove(char *key, void *value, CamelFolderChangeInfo *info) { + struct _CamelFolderChangeInfoPrivate *p = info->priv; + GPtrArray *olduids; + char *olduid; + + if (g_hash_table_lookup_extended(p->uid_stored, key, (void **)&olduid, (void **)&olduids)) { + /* if it was added/changed them removed, then remove it */ + if (olduids != info->uid_removed) { + g_ptr_array_remove_fast(olduids, olduid); + g_ptr_array_add(info->uid_removed, olduid); + g_hash_table_insert(p->uid_stored, olduid, info->uid_removed); + } + return; + } + + /* we dont need to copy this, as they've already been copied into our pool */ - change_info_add_uid(info, info->uid_removed, key, FALSE); + g_ptr_array_add(info->uid_removed, key); + g_hash_table_insert(p->uid_stored, key, info->uid_removed); } /** @@ -1479,13 +1480,24 @@ change_info_remove(char *key, void *value, CamelFolderChangeInfo *info) void camel_folder_change_info_build_diff(CamelFolderChangeInfo *info) { - if (info->uid_source) { - g_hash_table_foreach(info->uid_source, (GHFunc)change_info_remove, info); - g_hash_table_destroy(info->uid_source); - info->uid_source = NULL; + struct _CamelFolderChangeInfoPrivate *p = info->priv; + + if (p->uid_source) { + g_hash_table_foreach(p->uid_source, (GHFunc)change_info_remove, info); + g_hash_table_destroy(p->uid_source); + p->uid_source = NULL; } } +static void +change_info_cat(CamelFolderChangeInfo *info, GPtrArray *source, void (*add)(CamelFolderChangeInfo *info, const char *uid)) +{ + int i; + + for (i=0;i<source->len;i++) + add(info, source->pdata[i]); +} + /** * camel_folder_change_info_cat: * @info: @@ -1497,9 +1509,9 @@ camel_folder_change_info_build_diff(CamelFolderChangeInfo *info) void camel_folder_change_info_cat(CamelFolderChangeInfo *info, CamelFolderChangeInfo *source) { - change_info_cat(info, info->uid_added, source->uid_added); - change_info_cat(info, info->uid_removed, source->uid_removed); - change_info_cat(info, info->uid_changed, source->uid_changed); + change_info_cat(info, source->uid_added, camel_folder_change_info_add_uid); + change_info_cat(info, source->uid_removed, camel_folder_change_info_remove_uid); + change_info_cat(info, source->uid_changed, camel_folder_change_info_change_uid); } /** @@ -1512,7 +1524,24 @@ camel_folder_change_info_cat(CamelFolderChangeInfo *info, CamelFolderChangeInfo void camel_folder_change_info_add_uid(CamelFolderChangeInfo *info, const char *uid) { - change_info_add_uid(info, info->uid_added, uid, TRUE); + struct _CamelFolderChangeInfoPrivate *p = info->priv; + GPtrArray *olduids; + char *olduid; + + if (g_hash_table_lookup_extended(p->uid_stored, uid, (void **)&olduid, (void **)&olduids)) { + /* if it was removed then added, promote it to a changed */ + /* if it was changed then added, leave as changed */ + if (olduids == info->uid_removed) { + g_ptr_array_remove_fast(olduids, olduid); + g_ptr_array_add(info->uid_changed, olduid); + g_hash_table_insert(p->uid_stored, olduid, info->uid_changed); + } + return; + } + + olduid = e_mempool_strdup(p->uid_pool, uid); + g_ptr_array_add(info->uid_added, olduid); + g_hash_table_insert(p->uid_stored, olduid, info->uid_added); } /** @@ -1525,7 +1554,23 @@ camel_folder_change_info_add_uid(CamelFolderChangeInfo *info, const char *uid) void camel_folder_change_info_remove_uid(CamelFolderChangeInfo *info, const char *uid) { - change_info_add_uid(info, info->uid_removed, uid, TRUE); + struct _CamelFolderChangeInfoPrivate *p = info->priv; + GPtrArray *olduids; + char *olduid; + + if (g_hash_table_lookup_extended(p->uid_stored, uid, (void **)&olduid, (void **)&olduids)) { + /* if it was added/changed them removed, then remove it */ + if (olduids != info->uid_removed) { + g_ptr_array_remove_fast(olduids, olduid); + g_ptr_array_add(info->uid_removed, olduid); + g_hash_table_insert(p->uid_stored, olduid, info->uid_removed); + } + return; + } + + olduid = e_mempool_strdup(p->uid_pool, uid); + g_ptr_array_add(info->uid_removed, olduid); + g_hash_table_insert(p->uid_stored, olduid, info->uid_removed); } /** @@ -1538,7 +1583,18 @@ camel_folder_change_info_remove_uid(CamelFolderChangeInfo *info, const char *uid void camel_folder_change_info_change_uid(CamelFolderChangeInfo *info, const char *uid) { - change_info_add_uid(info, info->uid_changed, uid, TRUE); + struct _CamelFolderChangeInfoPrivate *p = info->priv; + GPtrArray *olduids; + char *olduid; + + if (g_hash_table_lookup_extended(p->uid_stored, uid, (void **)&olduid, (void **)&olduids)) { + /* if we have it already, leave it as that */ + return; + } + + olduid = e_mempool_strdup(p->uid_pool, uid); + g_ptr_array_add(info->uid_changed, olduid); + g_hash_table_insert(p->uid_stored, olduid, info->uid_changed); } /** @@ -1564,14 +1620,18 @@ camel_folder_change_info_changed(CamelFolderChangeInfo *info) void camel_folder_change_info_clear(CamelFolderChangeInfo *info) { + struct _CamelFolderChangeInfoPrivate *p = info->priv; + g_ptr_array_set_size(info->uid_added, 0); g_ptr_array_set_size(info->uid_removed, 0); g_ptr_array_set_size(info->uid_changed, 0); - if (info->uid_source) { - g_hash_table_destroy(info->uid_source); - info->uid_source = NULL; + if (p->uid_source) { + g_hash_table_destroy(p->uid_source); + p->uid_source = NULL; } - e_mempool_flush(info->uid_pool, TRUE); + g_hash_table_destroy(p->uid_stored); + p->uid_stored = g_hash_table_new(g_str_hash, g_str_equal); + e_mempool_flush(p->uid_pool, TRUE); } /** @@ -1583,10 +1643,14 @@ camel_folder_change_info_clear(CamelFolderChangeInfo *info) void camel_folder_change_info_free(CamelFolderChangeInfo *info) { - if (info->uid_source) - g_hash_table_destroy(info->uid_source); + struct _CamelFolderChangeInfoPrivate *p = info->priv; + + if (p->uid_source) + g_hash_table_destroy(p->uid_source); - e_mempool_destroy(info->uid_pool); + g_hash_table_destroy(p->uid_stored); + e_mempool_destroy(p->uid_pool); + g_free(p); g_ptr_array_free(info->uid_added, TRUE); g_ptr_array_free(info->uid_removed, TRUE); |