2006-08-10 [colin] 2.4.0cvs39
[claws.git] / src / imap.c
index 7ded57318316dbf569f1cacbadfdbcc7e61bfa4e..1116b7a588f855f74d9ab5c2f9c718e08e2dcc0a 100644 (file)
@@ -68,6 +68,7 @@
 #include "statusbar.h"
 #include "msgcache.h"
 #include "imap-thread.h"
+#include "account.h"
 
 typedef struct _IMAPFolder     IMAPFolder;
 typedef struct _IMAPSession    IMAPSession;
@@ -307,7 +308,6 @@ static gint imap_cmd_login  (IMAPSession    *session,
                                 const gchar    *user,
                                 const gchar    *pass,
                                 const gchar    *type);
-static gint imap_cmd_logout    (IMAPSession    *session);
 static gint imap_cmd_noop      (IMAPSession    *session);
 #if USE_OPENSSL
 static gint imap_cmd_starttls  (IMAPSession    *session);
@@ -538,18 +538,24 @@ static void imap_reset_uid_lists(Folder *folder)
        g_node_traverse(folder->node, G_IN_ORDER, G_TRAVERSE_ALL, -1, imap_reset_uid_lists_func, NULL); 
 }
 
-void imap_get_capabilities(IMAPSession *session)
+int imap_get_capabilities(IMAPSession *session)
 {
        struct mailimap_capability_data *capabilities = NULL;
        clistiter *cur;
+       int result = -1;
 
        if (session->capability != NULL)
-               return;
+               return MAILIMAP_NO_ERROR;
 
-       capabilities = imap_threaded_capability(session->folder);
+       capabilities = imap_threaded_capability(session->folder, &result);
 
-       if (capabilities == NULL)
-               return;
+       if (result != MAILIMAP_NO_ERROR) {
+               return MAILIMAP_ERROR_CAPABILITY;
+       }
+
+       if (capabilities == NULL) {
+               return MAILIMAP_NO_ERROR;
+       }
 
        for(cur = clist_begin(capabilities->cap_list) ; cur != NULL ;
            cur = clist_next(cur)) {
@@ -563,6 +569,7 @@ void imap_get_capabilities(IMAPSession *session)
                debug_print("got capa %s\n", cap->cap_data.cap_name);
        }
        mailimap_capability_data_free(capabilities);
+       return MAILIMAP_NO_ERROR;
 }
 
 gboolean imap_has_capability(IMAPSession *session, const gchar *cap) 
@@ -580,8 +587,10 @@ static gint imap_auth(IMAPSession *session, const gchar *user, const gchar *pass
 {
        gint ok = IMAP_ERROR;
        static time_t last_login_err = 0;
+       gchar *ext_info = "";
        
-       imap_get_capabilities(session);
+       if (imap_get_capabilities(session) != MAILIMAP_NO_ERROR)
+               return IMAP_ERROR;
 
        switch(type) {
        case IMAP_AUTH_ANON:
@@ -606,19 +615,16 @@ static gint imap_auth(IMAPSession *session, const gchar *user, const gchar *pass
                if (ok == IMAP_ERROR) /* we always try LOGIN before giving up */
                        ok = imap_cmd_login(session, user, pass, "LOGIN");
        }
+
        if (ok == IMAP_SUCCESS)
                session->authenticated = TRUE;
        else {
-               gchar *ext_info = NULL;
-               
                if (type == IMAP_AUTH_CRAM_MD5) {
                        ext_info = _("\n\nCRAM-MD5 logins only work if libetpan has been "
                                     "compiled with SASL support and the "
                                     "CRAM-MD5 SASL plugin is installed.");
-               } else {
-                       ext_info = "";
-               }
-               
+               } 
+
                if (time(NULL) - last_login_err > 10) {
                        if (!prefs_common.no_recv_err_panel) {
                                alertpanel_error(_("Connection to %s failed: "
@@ -681,7 +687,6 @@ static IMAPSession *imap_session_get(Folder *folder)
 {
        RemoteFolder *rfolder = REMOTE_FOLDER(folder);
        IMAPSession *session = NULL;
-       static time_t last_failure = 0;
 
        g_return_val_if_fail(folder != NULL, NULL);
        g_return_val_if_fail(FOLDER_CLASS(folder) == &imap_class, NULL);
@@ -703,12 +708,12 @@ static IMAPSession *imap_session_get(Folder *folder)
                } */
        } else {
                imap_reset_uid_lists(folder);
-               if (time(NULL) - last_failure <= 2)
+               if (time(NULL) - rfolder->last_failure <= 2)
                        return NULL;
                session = imap_session_new(folder, folder->account);
        }
        if(session == NULL) {
-               last_failure = time(NULL);
+               rfolder->last_failure = time(NULL);
                return NULL;
        }
 
@@ -717,9 +722,11 @@ static IMAPSession *imap_session_get(Folder *folder)
                imap_session_authenticate(IMAP_SESSION(session), folder->account);
        
        if (!IMAP_SESSION(session)->authenticated) {
+               imap_threaded_disconnect(session->folder);
+               SESSION(session)->state = SESSION_DISCONNECTED;
                session_destroy(SESSION(session));
                rfolder->session = NULL;
-               last_failure = time(NULL);
+               rfolder->last_failure = time(NULL);
                return NULL;
        }
 
@@ -750,7 +757,7 @@ static IMAPSession *imap_session_new(Folder * folder,
        IMAPSession *session;
        gushort port;
        int r;
-       int authenticated;
+       int authenticated = FALSE;
        
 #ifdef USE_OPENSSL
        /* FIXME: IMAP over SSL only... */ 
@@ -862,11 +869,13 @@ static IMAPSession *imap_session_new(Folder * folder,
 static void imap_session_authenticate(IMAPSession *session, 
                                      const PrefsAccount *account)
 {
-       gchar *pass;
+       gchar *pass, *acc_pass;
+       gboolean failed = FALSE;
 
        g_return_if_fail(account->userid != NULL);
-
-       pass = account->passwd;
+       acc_pass = account->passwd;
+try_again:
+       pass = acc_pass;
        if (!pass && account->imap_auth_type != IMAP_AUTH_ANON) {
                gchar *tmp_pass;
                tmp_pass = input_dialog_query_password(account->recv_server, account->userid);
@@ -880,14 +889,22 @@ static void imap_session_authenticate(IMAPSession *session,
        statusbar_print_all(_("Connecting to IMAP4 server %s...\n"),
                                account->recv_server);
        if (imap_auth(session, account->userid, pass, account->imap_auth_type) != IMAP_SUCCESS) {
-               imap_threaded_disconnect(session->folder);
-               imap_cmd_logout(session);
                statusbar_pop_all();
                
+               if (!failed) {
+                       acc_pass = NULL;
+                       failed = TRUE;
+                       goto try_again;
+               } else {
+                       alertpanel_error(_("Couldn't login to IMAP server %s."), account->recv_server);
+               }               
+
                return;
-       }
+       } 
+
        statusbar_pop_all();
        session->authenticated = TRUE;
+       return;
 }
 
 static void imap_session_destroy(Session *session)
@@ -958,10 +975,10 @@ static gchar *imap_fetch_msg_full(Folder *folder, FolderItem *item, gint uid,
 
                if (cached)
                        debug_print("message %d has been already %scached (%d/%d).\n", uid,
-                               have_size == cached->size ? "fully ":"",
+                               have_size >= cached->size ? "fully ":"",
                                have_size, (int)cached->size);
                
-               if (cached && (cached->size == have_size || !body)) {
+               if (cached && (cached->size <= have_size || !body)) {
                        procmsg_msginfo_free(cached);
                        procmsg_msginfo_free(msginfo);
                        file_strip_crs(filename);
@@ -1120,8 +1137,9 @@ static gint imap_add_msgs(Folder *folder, FolderItem *dest, GSList *file_list,
                if (new_uid == 0) {
                        new_uid = dest->last_num+1;
                }
-               if (last_uid < new_uid)
+               if (last_uid < new_uid) {
                        last_uid = new_uid;
+               }
 
                g_free(real_file);
        }
@@ -2463,6 +2481,37 @@ static gint imap_cmd_login(IMAPSession *session,
        int r;
        gint ok;
 
+       if (!strcmp(type, "LOGIN") && imap_has_capability(session, "LOGINDISABLED")) {
+               gint ok = IMAP_ERROR;
+               if (imap_has_capability(session, "STARTTLS")) {
+#if USE_OPENSSL
+                       log_warning(_("Server requires TLS to log in.\n"));
+                       ok = imap_cmd_starttls(session);
+                       if (ok != IMAP_SUCCESS) {
+                               log_warning(_("Can't start TLS session.\n"));
+                               return IMAP_ERROR;
+                       } else {
+                               /* refresh capas */
+                               imap_free_capabilities(session);
+                               if (imap_get_capabilities(session) != MAILIMAP_NO_ERROR) {
+                                       log_warning(_("Can't refresh capabilities.\n"));
+                                       return IMAP_ERROR;
+                               }
+                       }
+#else          
+                       log_error(_("Connection to %s failed: "
+                                       "server requires TLS, but Sylpheed-Claws "
+                                       "has been compiled without OpenSSL "
+                                       "support.\n"),
+                                       SESSION(session)->server);
+                       return IMAP_ERROR;
+#endif
+               } else {
+                       log_error(_("Server logins are disabled.\n"));
+                       return IMAP_ERROR;
+               }
+       }
+
        log_print("IMAP4> Logging %s to %s using %s\n", 
                        user,
                        SESSION(session)->server,
@@ -2480,13 +2529,6 @@ static gint imap_cmd_login(IMAPSession *session,
        return ok;
 }
 
-static gint imap_cmd_logout(IMAPSession *session)
-{
-       imap_threaded_disconnect(session->folder);
-
-       return IMAP_SUCCESS;
-}
-
 static gint imap_cmd_noop(IMAPSession *session)
 {
        int r;
@@ -2662,7 +2704,7 @@ static gint imap_cmd_append(IMAPSession *session, const gchar *destfolder,
 
        flag_list = imap_flag_to_lep(flags);
        r = imap_threaded_append(session->folder, destfolder,
-                        file, flag_list, new_uid);
+                        file, flag_list, (int *)new_uid);
        mailimap_flag_list_free(flag_list);
 
        if (r != MAILIMAP_NO_ERROR) {
@@ -3076,7 +3118,8 @@ gint imap_get_num_list(Folder *folder, FolderItem *_item, GSList **msgnum_list,
 {
        IMAPFolderItem *item = (IMAPFolderItem *)_item;
        IMAPSession *session;
-       gint ok, nummsgs = 0, exists, uid_val, uid_next = 0;
+       gint ok, nummsgs = 0, exists;
+       guint32 uid_next = 0, uid_val = 0;
        GSList *uidlist = NULL;
        gchar *dir;
        gboolean selected_folder;
@@ -3144,7 +3187,8 @@ gint imap_get_num_list(Folder *folder, FolderItem *_item, GSList **msgnum_list,
                else {
                        *old_uids_valid = FALSE;
 
-                       debug_print("Freeing imap uid cache\n");
+                       debug_print("Freeing imap uid cache (%d != %d)\n",
+                                       (int)item->item.mtime, uid_val);
                        item->lastuid = 0;
                        g_slist_free(item->uid_list);
                        item->uid_list = NULL;
@@ -3687,12 +3731,12 @@ static /*gint*/ void *imap_get_flags_thread(void *data)
                imapset = cur->data;
                if (reverse_seen) {
                        r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_SEEN,
-                                                imapset, &lep_uidlist);
+                                                full_search ? NULL:imapset, &lep_uidlist);
                }
                else {
                        r = imap_threaded_search(folder,
                                                 IMAP_SEARCH_TYPE_UNSEEN,
-                                                imapset, &lep_uidlist);
+                                                full_search ? NULL:imapset, &lep_uidlist);
                }
                if (r == MAILIMAP_NO_ERROR) {
                        GSList * uidlist;
@@ -3704,7 +3748,7 @@ static /*gint*/ void *imap_get_flags_thread(void *data)
                }
                
                r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_FLAGGED,
-                                        imapset, &lep_uidlist);
+                                        full_search ? NULL:imapset, &lep_uidlist);
                if (r == MAILIMAP_NO_ERROR) {
                        GSList * uidlist;
 
@@ -3716,7 +3760,7 @@ static /*gint*/ void *imap_get_flags_thread(void *data)
 
                if (item->opened || item->processing_pending || item == folder->inbox) {
                        r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_ANSWERED,
-                                                imapset, &lep_uidlist);
+                                                full_search ? NULL:imapset, &lep_uidlist);
                        if (r == MAILIMAP_NO_ERROR) {
                                GSList * uidlist;
 
@@ -3727,7 +3771,7 @@ static /*gint*/ void *imap_get_flags_thread(void *data)
                        }
 
                        r = imap_threaded_search(folder, IMAP_SEARCH_TYPE_DELETED,
-                                                imapset, &lep_uidlist);
+                                                full_search ? NULL:imapset, &lep_uidlist);
                        if (r == MAILIMAP_NO_ERROR) {
                                GSList * uidlist;
 
@@ -4238,6 +4282,24 @@ void imap_folder_ref(Folder *folder)
        ((IMAPFolder *)folder)->refcnt++;
 }
 
+void imap_disconnect_all(void)
+{
+       GList *list;
+       for (list = account_get_list(); list != NULL; list = list->next) {
+               PrefsAccount *account = list->data;
+               if (account->protocol == A_IMAP4) {
+                       RemoteFolder *folder = (RemoteFolder *)account->folder;
+                       if (folder && folder->session) {
+                               IMAPSession *session = (IMAPSession *)folder->session;
+                               imap_threaded_disconnect(FOLDER(folder));
+                               SESSION(session)->state = SESSION_DISCONNECTED;
+                               session_destroy(SESSION(session));
+                               folder->session = NULL;
+                       }
+               }
+       }
+}
+
 void imap_folder_unref(Folder *folder)
 {
        if (((IMAPFolder *)folder)->refcnt > 0)
@@ -4299,6 +4361,11 @@ FolderClass *imap_get_class(void)
 
        return &imap_class;
 }
+
+void imap_disconnect_all(void)
+{
+}
+
 #endif
 
 void imap_synchronise(FolderItem *item)