0.8.11claws12
[claws.git] / src / imap.c
index d77b3f7d648b19c3cd7cd4b81d5055f4d61a262a..5eb74f23949b8b9c56d34c96e9c27508b1d4001a 100644 (file)
@@ -74,6 +74,7 @@ struct _IMAPFolderItem
        FolderItem item;
 
        guint lastuid;
+       guint uid_next;
        GSList *uid_list;
 };
 
@@ -298,12 +299,30 @@ FolderClass imap_class =
 {
        F_IMAP,
        "imap",
+       "IMAP4",
 
+       /* Folder functions */
+       imap_folder_new,
+       imap_folder_destroy,
+       imap_scan_tree,
+       imap_create_tree,
+
+       /* FolderItem functions */
        imap_folder_item_new,
        imap_folder_item_destroy,
-       imap_fetch_msg,
+       imap_create_folder,
+       imap_rename_folder,
+       imap_remove_folder,
+       imap_get_num_list,
+       NULL,
+       NULL,
+       NULL,
+       imap_check_msgnum_validity,
+
+       /* Message functions */
        imap_get_msginfo,
        imap_get_msginfos,
+       imap_fetch_msg,
        imap_add_msg,
        imap_move_msg,
        NULL,
@@ -314,20 +333,13 @@ FolderClass imap_class =
        imap_remove_all_msg,
        imap_is_msg_changed,
        NULL,
-       imap_get_num_list,
-       imap_scan_tree,
-       imap_create_tree,
-       imap_create_folder,
-       imap_rename_folder,
-       imap_remove_folder,
-       imap_folder_destroy,
-       NULL,
-       NULL,
-       NULL,
-       NULL,
-       imap_check_msgnum_validity,
 };
 
+FolderClass *imap_get_class()
+{
+       return &imap_class;
+}
+
 Folder *imap_folder_new(const gchar *name, const gchar *path)
 {
        Folder *folder;
@@ -363,6 +375,7 @@ static FolderItem *imap_folder_item_new(Folder *folder)
        
        item = g_new0(IMAPFolderItem, 1);
        item->lastuid = 0;
+       item->uid_next = 0;
        item->uid_list = NULL;
 
        return (FolderItem *)item;
@@ -383,6 +396,7 @@ static gboolean imap_reset_uid_lists_func(GNode *node, gpointer data)
        IMAPFolderItem *item = (IMAPFolderItem *)node->data;
        
        item->lastuid = 0;
+       item->uid_next = 0;
        g_slist_free(item->uid_list);
        item->uid_list = NULL;
        
@@ -405,7 +419,7 @@ static IMAPSession *imap_session_get(Folder *folder)
        gushort port;
 
        g_return_val_if_fail(folder != NULL, NULL);
-       g_return_val_if_fail(FOLDER_TYPE(folder) == F_IMAP, NULL);
+       g_return_val_if_fail(FOLDER_CLASS(folder) == &imap_class, NULL);
        g_return_val_if_fail(folder->account != NULL, NULL);
 
 #if USE_OPENSSL
@@ -691,7 +705,7 @@ static gint imap_do_copy(Folder *folder, FolderItem *dest, MsgInfo *msginfo,
        gint ok;
     
        g_return_val_if_fail(folder != NULL, -1);
-       g_return_val_if_fail(FOLDER_TYPE(folder) == F_IMAP, -1);
+       g_return_val_if_fail(FOLDER_CLASS(folder) == &imap_class, -1);
        g_return_val_if_fail(dest != NULL, -1);
        g_return_val_if_fail(msginfo != NULL, -1);
 
@@ -935,7 +949,7 @@ gint imap_remove_msg(Folder *folder, FolderItem *item, gint uid)
        gchar *dir;
 
        g_return_val_if_fail(folder != NULL, -1);
-       g_return_val_if_fail(FOLDER_TYPE(folder) == F_IMAP, -1);
+       g_return_val_if_fail(FOLDER_CLASS(folder) == &imap_class, -1);
        g_return_val_if_fail(item != NULL, -1);
 
        session = imap_session_get(folder);
@@ -978,7 +992,7 @@ gint imap_remove_msgs(Folder *folder, FolderItem *item, GSList *msglist)
        guint32 uid;
 
        g_return_val_if_fail(folder != NULL, -1);
-       g_return_val_if_fail(FOLDER_TYPE(folder) == F_IMAP, -1);
+       g_return_val_if_fail(FOLDER_CLASS(folder) == &imap_class, -1);
        g_return_val_if_fail(item != NULL, -1);
        g_return_val_if_fail(msglist != NULL, -1);
 
@@ -1605,7 +1619,7 @@ static GSList *imap_get_uncached_messages(IMAPSession *session,
        g_return_val_if_fail(session != NULL, NULL);
        g_return_val_if_fail(item != NULL, NULL);
        g_return_val_if_fail(item->folder != NULL, NULL);
-       g_return_val_if_fail(FOLDER_TYPE(item->folder) == F_IMAP, NULL);
+       g_return_val_if_fail(FOLDER_CLASS(item->folder) == &imap_class, NULL);
        g_return_val_if_fail(first_uid <= last_uid, NULL);
 
        if (imap_cmd_envelope(SESSION(session)->sock, first_uid, last_uid)
@@ -1670,7 +1684,7 @@ static void imap_delete_all_cached_messages(FolderItem *item)
 
        g_return_if_fail(item != NULL);
        g_return_if_fail(item->folder != NULL);
-       g_return_if_fail(FOLDER_TYPE(item->folder) == F_IMAP);
+       g_return_if_fail(FOLDER_CLASS(item->folder) == &imap_class);
 
        debug_print("Deleting all cached messages...\n");
 
@@ -2204,7 +2218,7 @@ gint imap_msg_set_perm_flags(MsgInfo *msginfo, MsgPermFlags flags)
        g_return_val_if_fail(msginfo->folder->folder != NULL, -1);
 
        folder = msginfo->folder->folder;
-       g_return_val_if_fail(FOLDER_TYPE(folder) == F_IMAP, -1);
+       g_return_val_if_fail(FOLDER_CLASS(folder) == &imap_class, -1);
 
        session = imap_session_get(folder);
        if (!session) return -1;
@@ -2240,7 +2254,7 @@ gint imap_msg_unset_perm_flags(MsgInfo *msginfo, MsgPermFlags flags)
        g_return_val_if_fail(msginfo->folder->folder != NULL, -1);
 
        folder = msginfo->folder->folder;
-       g_return_val_if_fail(FOLDER_TYPE(folder) == F_IMAP, -1);
+       g_return_val_if_fail(FOLDER_CLASS(folder) == &imap_class, -1);
 
        session = imap_session_get(folder);
        if (!session) return -1;
@@ -3290,26 +3304,55 @@ gint imap_get_num_list(Folder *folder, FolderItem *_item, GSList **msgnum_list)
 {
        IMAPFolderItem *item = (IMAPFolderItem *)_item;
        IMAPSession *session;
-       gint ok, lastuid_old, nummsgs = 0, exists, resent, unseen, uid_val;
+       gint ok, lastuid_old, nummsgs = 0, exists, recent, unseen, uid_val, uid_next;
        GSList *uidlist, *elem;
        gchar *dir, *cmd_buf;
 
        g_return_val_if_fail(folder != NULL, -1);
        g_return_val_if_fail(item != NULL, -1);
        g_return_val_if_fail(item->item.path != NULL, -1);
-       g_return_val_if_fail(FOLDER_TYPE(folder) == F_IMAP, -1);
+       g_return_val_if_fail(FOLDER_CLASS(folder) == &imap_class, -1);
        g_return_val_if_fail(folder->account != NULL, -1);
 
        session = imap_session_get(folder);
        g_return_val_if_fail(session != NULL, -1);
 
-       ok = imap_select(session, IMAP_FOLDER(folder), item->item.path,
-                        &exists, &resent, &unseen, &uid_val);
+       ok = imap_status(session, IMAP_FOLDER(folder), item->item.path,
+                        &exists, &recent, &uid_next, &uid_val, &unseen);
        if (ok != IMAP_SUCCESS)
                return -1;
 
-       if (exists == 0)
+       /* If old uid_next matches new uid_next we can be sure no message
+          was added to the folder */
+       if (uid_next == item->uid_next) {
+               nummsgs = g_slist_length(item->uid_list);
+               
+               /* If number of messages is still the same we
+                   know our caches message numbers are still valid,
+                   otherwise if the number of messages has decrease
+                  we discard our cache to start a new scan to find
+                  out which numbers have been removed */
+               if (exists == nummsgs) {
+                       *msgnum_list = g_slist_copy(item->uid_list);
+                       return nummsgs;
+               } else if (exists < nummsgs) {
+                       debug_print("Freeing imap uid cache");
+                       item->lastuid = 0;
+                       g_slist_free(item->uid_list);
+                       item->uid_list = NULL;
+               }
+       }
+       item->uid_next = uid_next;
+
+       if (exists == 0) {
+               *msgnum_list = NULL;
                return 0;
+       }
+
+       ok = imap_select(session, IMAP_FOLDER(folder), item->item.path,
+                        &exists, &recent, &unseen, &uid_val);
+       if (ok != IMAP_SUCCESS)
+               return -1;
 
        cmd_buf = g_strdup_printf("UID %d:*", item->lastuid + 1);
        ok = imap_cmd_search(SESSION(session)->sock, cmd_buf, &uidlist);
@@ -3350,6 +3393,7 @@ gint imap_get_num_list(Folder *folder, FolderItem *_item, GSList **msgnum_list)
 
        lastuid_old = item->lastuid;
        *msgnum_list = g_slist_copy(item->uid_list);
+       nummsgs = g_slist_length(*msgnum_list);
        debug_print("Got %d uids from cache\n", g_slist_length(item->uid_list));
 
        for (elem = uidlist; elem != NULL; elem = g_slist_next(elem)) {
@@ -3367,9 +3411,11 @@ gint imap_get_num_list(Folder *folder, FolderItem *_item, GSList **msgnum_list)
        }
        g_slist_free(uidlist);
 
-       if (g_slist_length(item->uid_list) != exists) {
+       if (nummsgs != exists) {
                /* Cache contains more messages then folder, we have cached
-                   an old UID of a message that was removed */
+                   an old UID of a message that was removed and new messages
+                   have been added too, otherwise the uid_next check would
+                  not have failed */
                debug_print("Freeing imap uid cache");
                item->lastuid = 0;
                g_slist_free(item->uid_list);
@@ -3532,7 +3578,7 @@ gboolean imap_check_msgnum_validity(Folder *folder, FolderItem *_item)
        g_return_val_if_fail(folder != NULL, FALSE);
        g_return_val_if_fail(item != NULL, FALSE);
        g_return_val_if_fail(item->item.folder != NULL, FALSE);
-       g_return_val_if_fail(FOLDER_TYPE(item->item.folder) == F_IMAP, FALSE);
+       g_return_val_if_fail(FOLDER_CLASS(item->item.folder) == &imap_class, FALSE);
 
        session = imap_session_get(folder);
        g_return_val_if_fail(session != NULL, FALSE);