* src/folder.c
[claws.git] / src / folder.c
index 33d1498d8b7cada21df8f1e641750c0dbefb5751..56f62db9e843a0f7175724a5e7764a5f8fb4eaf4 100644 (file)
@@ -324,7 +324,8 @@ void folder_tree_destroy(Folder *folder)
        prefs_filtering_clear();
 
        g_node_traverse(folder->node, G_POST_ORDER, G_TRAVERSE_ALL, -1, folder_tree_destroy_func, NULL);
-       g_node_destroy(folder->node);
+       if (folder->node)
+               g_node_destroy(folder->node);
 
        folder->inbox = NULL;
        folder->outbox = NULL;
@@ -873,20 +874,29 @@ void folder_item_set_default_flags(FolderItem *dest, MsgFlags *flags)
        }
 }
 
-typedef enum {
-    IN_CACHE  = 1 << 0,
-    IN_FOLDER = 1 << 1,
-} FolderScanInfo;
+static gint folder_sort_cache_list_by_msgnum(gconstpointer a, gconstpointer b)
+{
+       MsgInfo *msginfo_a = (MsgInfo *) a;
+       MsgInfo *msginfo_b = (MsgInfo *) b;
+
+       return (msginfo_a->msgnum - msginfo_b->msgnum);
+}
+
+static gint folder_sort_folder_list(gconstpointer a, gconstpointer b)
+{
+       guint gint_a = GPOINTER_TO_INT(a);
+       guint gint_b = GPOINTER_TO_INT(b);
+       
+       return (gint_a - gint_b);
+}
 
 gint folder_item_scan(FolderItem *item)
 {
        Folder *folder;
-       GSList *folder_list, *cache_list, *elem, *new_list = NULL;
-       gint i;
-       guint min = 0xffffffff, max = 0, cache_max = 0;
-       FolderScanInfo *folderscaninfo;
+       GSList *folder_list, *cache_list, *folder_list_cur, *cache_list_cur, *new_list = NULL;
        guint newcnt = 0, unreadcnt = 0, totalcnt = 0;
-       
+       guint cache_max_num, folder_max_num, cache_cur_num, folder_cur_num;
+
        g_return_val_if_fail(item != NULL, -1);
        if (item->path == NULL) return -1;
 
@@ -911,64 +921,55 @@ gint folder_item_scan(FolderItem *item)
        }
        folder_list = folder->get_num_list(item->folder, item);
 
-       /* Get min und max number in folder */
-       for (elem = cache_list; elem != NULL; elem = elem->next) {
-               MsgInfo *msginfo = (MsgInfo *)elem->data;
-
-               min = MIN(msginfo->msgnum, min);
-               max = MAX(msginfo->msgnum, max);
-       }
-       cache_max = max;
-       for (elem = folder_list; elem != NULL; elem = elem->next) {
-               guint num = GPOINTER_TO_INT(elem->data);
-
-               min = MIN(num, min);
-               max = MAX(num, max);
-       }
-
-       debug_print("Folder message number range from %d to %d\n", min, max);
+       /* Sort both lists */
+       cache_list = g_slist_sort(cache_list, folder_sort_cache_list_by_msgnum);
+       folder_list = g_slist_sort(folder_list, folder_sort_folder_list);
 
-       if (max == 0) {
-               for (elem = cache_list; elem != NULL; elem = elem->next) {
-                       MsgInfo *msginfo = (MsgInfo *)elem->data;
+       cache_list_cur = cache_list;
+       folder_list_cur = folder_list;
 
-                       procmsg_msginfo_free(msginfo);
-               }
-               g_slist_free(folder_list);
-               g_slist_free(cache_list);
-
-               return 0;
-       }
-
-       folderscaninfo = g_new0(FolderScanInfo, max - min + 1);
-
-       for (elem = folder_list; elem != NULL; elem = elem->next) {
-               guint num = GPOINTER_TO_INT(elem->data);
-
-               folderscaninfo[num - min] |= IN_FOLDER;
+       if (cache_list_cur != NULL) {
+               GSList *cache_list_last;
+       
+               cache_cur_num = ((MsgInfo *)cache_list_cur->data)->msgnum;
+               cache_list_last = g_slist_last(cache_list);
+               cache_max_num = ((MsgInfo *)cache_list_last->data)->msgnum;
+       } else {
+               cache_cur_num = G_MAXINT;
+               cache_max_num = 0;
        }
-       for (elem = cache_list; elem != NULL; elem = elem->next) {
-               MsgInfo *msginfo = (MsgInfo *)elem->data;
 
-               folderscaninfo[msginfo->msgnum - min] |= IN_CACHE;
-               procmsg_msginfo_free(msginfo);
+       if (folder_list_cur != NULL) {
+               GSList *folder_list_last;
+       
+               folder_cur_num = GPOINTER_TO_INT(folder_list_cur->data);
+               folder_list_last = g_slist_last(folder_list);
+               folder_max_num = GPOINTER_TO_INT(folder_list_last->data);
+       } else {
+               folder_cur_num = G_MAXINT;
+               folder_max_num = 0;
        }
 
-       for (i = max - min; i >= 0; i--) {
-               guint num;
-
-               num = i + min;
-               /* Add message to cache if in folder and not in cache */
-               if ( (folderscaninfo[i] & IN_FOLDER) && 
-                  !(folderscaninfo[i] & IN_CACHE)) {
+       while ((cache_cur_num != G_MAXINT) || (folder_cur_num != G_MAXINT)) {
+               /*
+                *  Message only exists in the folder
+                *  Remember message for fetching
+                */
+               if (folder_cur_num < cache_cur_num) {
                        gboolean add = FALSE;
 
                        switch(folder->type) {
                                case F_NEWS:
-                                       if ((num > cache_max) && 
-                                          ((prefs_common.max_articles == 0) ||
-                                           (max < prefs_common.max_articles) ||
-                                           (num > (max - prefs_common.max_articles)))) {
+                                       if (folder_cur_num < cache_max_num)
+                                               break;
+                                       
+                                       if (prefs_common.max_articles == 0) {
+                                               add = TRUE;
+                                       }
+
+                                       if (folder_max_num <= prefs_common.max_articles) {
+                                               add = TRUE;
+                                       } else if (folder_cur_num > (folder_max_num - prefs_common.max_articles)) {
                                                add = TRUE;
                                        }
                                        break;
@@ -978,28 +979,54 @@ gint folder_item_scan(FolderItem *item)
                        }
                        
                        if (add) {
-                               new_list = g_slist_prepend(new_list, GINT_TO_POINTER(num));
-                               debug_print("Remembered message %d for fetching\n", num);
+                               new_list = g_slist_prepend(new_list, GINT_TO_POINTER(folder_cur_num));
+                               debug_print("Remembered message %d for fetching\n", folder_cur_num);
                        }
+
+                       /* Move to next folder number */
+                       folder_list_cur = folder_list_cur->next;
+
+                       if (folder_list_cur != NULL)
+                               folder_cur_num = GPOINTER_TO_INT(folder_list_cur->data);
+                       else
+                               folder_cur_num = G_MAXINT;
+
+                       continue;
                }
-               /* Remove message from cache if not in folder and in cache */
-               if (!(folderscaninfo[i] & IN_FOLDER) && 
-                   (folderscaninfo[i] & IN_CACHE)) {
-                       msgcache_remove_msg(item->cache, i + min);
-                       debug_print("Removed message %d from cache.\n", num);
+
+               /*
+                *  Message only exists in the cache
+                *  Remove the message from the cache
+                */
+               if (cache_cur_num < folder_cur_num) {
+                       msgcache_remove_msg(item->cache, cache_cur_num);
+                       debug_print("Removed message %d from cache.\n", cache_cur_num);
+
+                       /* Move to next cache number */
+                       cache_list_cur = cache_list_cur->next;
+
+                       if (cache_list_cur != NULL)
+                               cache_cur_num = ((MsgInfo *)cache_list_cur->data)->msgnum;
+                       else
+                               cache_cur_num = G_MAXINT;
+
+                       continue;
                }
-               /* Check if msginfo needs update if in cache and in folder */
-               if ((folderscaninfo[i] & IN_FOLDER) && 
-                  (folderscaninfo[i] & IN_CACHE)) {
+
+               /*
+                *  Message number exists in folder and cache!
+                *  Check if the message has been modified
+                */
+               if (cache_cur_num == folder_cur_num) {
                        MsgInfo *msginfo;
 
-                       msginfo = msgcache_get_msg(item->cache, num);
+                       msginfo = msgcache_get_msg(item->cache, folder_cur_num);
                        if (folder->is_msg_changed && folder->is_msg_changed(folder, item, msginfo)) {
                                MsgInfo *newmsginfo;
 
                                msgcache_remove_msg(item->cache, msginfo->msgnum);
 
-                               if (NULL != (newmsginfo = folder->fetch_msginfo(folder, item, num))) {
+                               if (NULL != (newmsginfo = folder->fetch_msginfo(folder, item, folder_cur_num))) {
                                        msgcache_add_msg(item->cache, newmsginfo);
                                        if (MSG_IS_NEW(newmsginfo->flags) && !MSG_IS_IGNORE_THREAD(newmsginfo->flags))
                                                newcnt++;
@@ -1008,7 +1035,7 @@ gint folder_item_scan(FolderItem *item)
                                        procmsg_msginfo_free(newmsginfo);
                                }                                       
 
-                               debug_print("Updated msginfo for message %d.\n", num);
+                               debug_print("Updated msginfo for message %d.\n", folder_cur_num);
                        } else {
                                if (MSG_IS_NEW(msginfo->flags) && !MSG_IS_IGNORE_THREAD(msginfo->flags))
                                        newcnt++;
@@ -1017,10 +1044,34 @@ gint folder_item_scan(FolderItem *item)
                        }
                        totalcnt++;
                        procmsg_msginfo_free(msginfo);
+
+                       /* Move to next folder and cache number */
+                       cache_list_cur = cache_list_cur->next;
+                       folder_list_cur = folder_list_cur->next;
+
+                       if (cache_list_cur != NULL)
+                               cache_cur_num = ((MsgInfo *)cache_list_cur->data)->msgnum;
+                       else
+                               cache_cur_num = G_MAXINT;
+
+                       if (folder_list_cur != NULL)
+                               folder_cur_num = GPOINTER_TO_INT(folder_list_cur->data);
+                       else
+                               folder_cur_num = G_MAXINT;
+
+                       continue;
                }
        }
 
+       for(cache_list_cur = cache_list; cache_list_cur != NULL; cache_list_cur = g_slist_next(cache_list_cur)) {
+               procmsg_msginfo_free((MsgInfo *) cache_list_cur->data);
+       }
+
+       g_slist_free(cache_list);
+       g_slist_free(folder_list);
+
        if (folder->fetch_msginfos) {
+               GSList *elem;
                GSList *newmsg_list;
                MsgInfo *msginfo;
                
@@ -1040,6 +1091,8 @@ gint folder_item_scan(FolderItem *item)
                        folderview_update_item(item, FALSE);
                }
        } else if (folder->fetch_msginfo) {
+               GSList *elem;
+       
                for (elem = new_list; elem != NULL; elem = g_slist_next(elem)) {
                        MsgInfo *msginfo;
                        guint num;
@@ -1064,10 +1117,7 @@ gint folder_item_scan(FolderItem *item)
        item->unread = unreadcnt;
        item->total = totalcnt;
        
-       g_slist_free(folder_list);
-       g_slist_free(cache_list);
        g_slist_free(new_list);
-       g_free(folderscaninfo);
 
        folderview_update_item(item, FALSE);
 
@@ -2027,7 +2077,7 @@ static gchar *folder_get_list_path(void)
 static void folder_write_list_recursive(GNode *node, gpointer data)
 {
        FILE *fp = (FILE *)data;
-       FolderItem *item = FOLDER_ITEM(node->data);
+       FolderItem *item;
        gint i, depth;
        static gchar *folder_type_str[] = {"mh", "mbox", "maildir", "imap",
                                           "news", "unknown"};
@@ -2036,7 +2086,10 @@ static void folder_write_list_recursive(GNode *node, gpointer data)
        static gchar *sort_key_str[] = {"none", "number", "size", "date",
                                        "from", "subject", "score", "label",
                                        "mark", "unread", "mime", "locked" };
+       g_return_if_fail(node != NULL);
+       g_return_if_fail(fp != NULL);
 
+       item = FOLDER_ITEM(node->data);
        g_return_if_fail(item != NULL);
 
        depth = g_node_depth(node);