0.8.8claws46
[claws.git] / src / imap.c
index c4f60b4bf62b8401bc7b49de575ea21630809f4d..5e8fd8344a218355604652a3ee80a528196f2d53 100644 (file)
@@ -95,7 +95,8 @@ static gint imap_scan_tree_recursive  (IMAPSession    *session,
                                         FolderItem     *item);
 static GSList *imap_parse_list         (Folder         *folder,
                                         IMAPSession    *session,
-                                        const gchar    *real_path);
+                                        const gchar    *real_path,
+                                        gchar          *separator);
 
 static void imap_create_missing_folders        (Folder                 *folder);
 static FolderItem *imap_create_special_folder
@@ -172,6 +173,8 @@ static gint imap_status                     (IMAPSession    *session,
 
 static void imap_parse_namespace               (IMAPSession    *session,
                                                 IMAPFolder     *folder);
+static void imap_get_namespace_by_list         (IMAPSession    *session,
+                                                IMAPFolder     *folder);
 static IMAPNameSpace *imap_find_namespace      (IMAPFolder     *folder,
                                                 const gchar    *path);
 static gchar imap_get_path_separator           (IMAPFolder     *folder,
@@ -395,6 +398,7 @@ static void imap_reset_uid_lists(Folder *folder)
 static IMAPSession *imap_session_get(Folder *folder)
 {
        RemoteFolder *rfolder = REMOTE_FOLDER(folder);
+       Session *session = NULL;
        gushort port;
 
        g_return_val_if_fail(folder != NULL, NULL);
@@ -410,25 +414,29 @@ static IMAPSession *imap_session_get(Folder *folder)
                : IMAP4_PORT;
 #endif
 
-       if (!rfolder->session) {
-               rfolder->session =
-                       imap_session_new(folder->account);
-               if (rfolder->session) {
-                       if (!IMAP_SESSION(rfolder->session)->authenticated)
-                               imap_session_authenticate(IMAP_SESSION(rfolder->session), folder->account);
-                       if (IMAP_SESSION(rfolder->session)->authenticated) {
-                               imap_parse_namespace(IMAP_SESSION(rfolder->session),
-                                                    IMAP_FOLDER(folder));
-                               rfolder->session->last_access_time = time(NULL);
-                               imap_reset_uid_lists(folder);
-                       } else {
-                               session_destroy(rfolder->session);
-                               rfolder->session = NULL;
-                       }
-               }
-               return IMAP_SESSION(rfolder->session);
+       /* Make sure we have a session */
+       if (rfolder->session != NULL) {
+               session = rfolder->session;
+       } else {
+               imap_reset_uid_lists(folder);
+               session = imap_session_new(folder->account);
+       }
+       if(session == NULL)
+               return NULL;
+
+       /* Make sure session is authenticated */
+       if (!IMAP_SESSION(session)->authenticated)
+               imap_session_authenticate(IMAP_SESSION(session), folder->account);
+       if (!IMAP_SESSION(session)->authenticated) {
+               session_destroy(session);
+               rfolder->session = NULL;
+               return NULL;
        }
 
+       /* Make sure we have parsed the IMAP namespace */
+       imap_parse_namespace(IMAP_SESSION(session),
+                            IMAP_FOLDER(folder));
+
        /* I think the point of this code is to avoid sending a
         * keepalive if we've used the session recently and therefore
         * think it's still alive.  Unfortunately, most of the code
@@ -437,36 +445,36 @@ static IMAPSession *imap_session_get(Folder *folder)
         * A better solution than sending a NOOP every time would be
         * for every command to be prepared to retry until it is
         * successfully sent. -- mbp */
-       if (time(NULL) - rfolder->session->last_access_time < SESSION_TIMEOUT) {
-               rfolder->session->last_access_time = time(NULL);
-               return IMAP_SESSION(rfolder->session);
-       }
-
-       if (imap_cmd_noop(rfolder->session->sock) != IMAP_SUCCESS) {
-               log_warning(_("IMAP4 connection to %s:%d has been"
-                             " disconnected. Reconnecting...\n"),
-                           folder->account->recv_server, port);
-               session_destroy(rfolder->session);
-               rfolder->session =
-                       imap_session_new(folder->account);
-               if (rfolder->session) {
-                       if (!IMAP_SESSION(rfolder->session)->authenticated)
-                               imap_session_authenticate(IMAP_SESSION(rfolder->session), folder->account);
-                       if (IMAP_SESSION(rfolder->session)->authenticated) {
-                               imap_parse_namespace(IMAP_SESSION(rfolder->session),
-                                                    IMAP_FOLDER(folder));
-                               rfolder->session->last_access_time = time(NULL);
-                               imap_reset_uid_lists(folder);
+       if (time(NULL) - session->last_access_time > SESSION_TIMEOUT) {
+               /* verify that the session is still alive */
+               if (imap_cmd_noop(session->sock) != IMAP_SUCCESS) {
+                       /* Check if this is the first try to establish a
+                          connection, if yes we don't try to reconnect */
+                       if (rfolder->session == NULL) {
+                               log_warning(_("Connecting %s:%d failed"),
+                                           folder->account->recv_server, port);
+                               session_destroy(session);
+                               session = NULL;
                        } else {
-                               session_destroy(rfolder->session);
+                               log_warning(_("IMAP4 connection to %s:%d has been"
+                                             " disconnected. Reconnecting...\n"),
+                                           folder->account->recv_server, port);
+                               session_destroy(session);
+                               /* Clear folders session to make imap_session_get create
+                                  a new session, because of rfolder->session == NULL
+                                  it will not try to reconnect again and so avoid an
+                                  endless loop */
                                rfolder->session = NULL;
+                               session = SESSION(imap_session_get(folder));
                        }
                }
        }
 
-       if (rfolder->session)
-               rfolder->session->last_access_time = time(NULL);
-       return IMAP_SESSION(rfolder->session);
+       rfolder->session = session;
+       if (session) {
+               session->last_access_time = time(NULL);
+       }
+       return IMAP_SESSION(session);
 }
 
 Session *imap_session_new(const PrefsAccount *account)
@@ -515,11 +523,14 @@ Session *imap_session_new(const PrefsAccount *account)
        }
 
        /* Only need to log in if the connection was not PREAUTH */
-       imap_greeting(imap_sock, &is_preauth);
+       if (imap_greeting(imap_sock, &is_preauth) != IMAP_SUCCESS) {
+               sock_close(imap_sock);
+               return NULL;
+       }
        log_message("IMAP connection is %s-authenticated\n",
                    (is_preauth) ? "pre" : "un");
-       session = g_new(IMAPSession, 1);
 
+       session = g_new(IMAPSession, 1);
        SESSION(session)->type             = SESSION_IMAP;
        SESSION(session)->server           = g_strdup(account->recv_server);
        SESSION(session)->sock             = imap_sock;
@@ -556,7 +567,6 @@ void imap_session_authenticate(IMAPSession *session, const PrefsAccount *account
 
        if (imap_cmd_login(SESSION(session)->sock, account->userid, pass) != IMAP_SUCCESS) {
                imap_cmd_logout(SESSION(session)->sock);
-               sock_close(SESSION(session)->sock);
                return;
        }
 
@@ -1231,7 +1241,7 @@ static gint imap_scan_tree_recursive(IMAPSession *session, FolderItem *item)
                          wildcard_path);
 
        strtailchomp(real_path, separator);
-       item_list = imap_parse_list(folder, session, real_path);
+       item_list = imap_parse_list(folder, session, real_path, NULL);
        g_free(real_path);
 
        for (cur = item_list; cur != NULL; cur = cur->next) {
@@ -1273,11 +1283,12 @@ static gint imap_scan_tree_recursive(IMAPSession *session, FolderItem *item)
        return IMAP_SUCCESS;
 }
 
-static GSList *imap_parse_list(Folder *folder, IMAPSession *session, const gchar *real_path)
+static GSList *imap_parse_list(Folder *folder, IMAPSession *session,
+                              const gchar *real_path, gchar *separator)
 {
        gchar buf[IMAPBUFSIZE];
        gchar flags[256];
-       gchar separator[16];
+       gchar separator_str[16];
        gchar *p;
        gchar *name;
        gchar *loc_name, *loc_path;
@@ -1313,11 +1324,13 @@ static GSList *imap_parse_list(Folder *folder, IMAPSession *session, const gchar
                if (!p) continue;
                while (*p == ' ') p++;
 
-               p = strchr_cpy(p, ' ', separator, sizeof(separator));
+               p = strchr_cpy(p, ' ', separator_str, sizeof(separator_str));
                if (!p) continue;
-               extract_quote(separator, '"');
-               if (!strcmp(separator, "NIL"))
-                       separator[0] = '\0';
+               extract_quote(separator_str, '"');
+               if (!strcmp(separator_str, "NIL"))
+                       separator_str[0] = '\0';
+               if (separator)
+                       *separator = separator_str[0];
 
                buf[0] = '\0';
                while (*p == ' ') p++;
@@ -1326,12 +1339,12 @@ static GSList *imap_parse_list(Folder *folder, IMAPSession *session, const gchar
                                            buf, sizeof(buf), str);
                else
                        strncpy2(buf, p, sizeof(buf));
-               strtailchomp(buf, separator[0]);
+               strtailchomp(buf, separator_str[0]);
                if (buf[0] == '\0') continue;
                if (!strcmp(buf, real_path)) continue;
 
-               if (separator[0] != '\0')
-                       subst_char(buf, separator[0], '/');
+               if (separator_str[0] != '\0')
+                       subst_char(buf, separator_str[0], '/');
                name = g_basename(buf);
                if (name[0] == '.') continue;
 
@@ -1922,6 +1935,7 @@ static void imap_parse_namespace(IMAPSession *session, IMAPFolder *folder)
        if (imap_cmd_namespace(SESSION(session)->sock, &ns_str)
            != IMAP_SUCCESS) {
                log_warning(_("can't get namespace\n"));
+               imap_get_namespace_by_list(session, folder);
                return;
        }
 
@@ -1936,6 +1950,32 @@ static void imap_parse_namespace(IMAPSession *session, IMAPFolder *folder)
        g_free(ns_str);
 }
 
+static void imap_get_namespace_by_list(IMAPSession *session, IMAPFolder *folder)
+{
+       GSList *item_list, *cur;
+       gchar separator = '\0';
+       IMAPNameSpace *namespace;
+
+       g_return_if_fail(session != NULL);
+       g_return_if_fail(folder != NULL);
+
+       if (folder->ns_personal != NULL ||
+           folder->ns_others   != NULL ||
+           folder->ns_shared   != NULL)
+               return;
+
+       imap_cmd_gen_send(SESSION(session)->sock, "LIST \"\" \"\"");
+       item_list = imap_parse_list(NULL, session, "", &separator);
+       for (cur = item_list; cur != NULL; cur = cur->next)
+               folder_item_destroy(FOLDER_ITEM(cur->data));
+       g_slist_free(item_list);
+
+       namespace = g_new(IMAPNameSpace, 1);
+       namespace->name = g_strdup("");
+       namespace->separator = separator;
+       folder->ns_personal = g_list_append(NULL, namespace);
+}
+
 static IMAPNameSpace *imap_find_namespace_from_list(GList *ns_list,
                                                    const gchar *path)
 {