Fix CID 1491365: resource leak.
[claws.git] / src / imap.c
index cdf15378dd380ce3f8bb4c5609bc09ec97a30e18..fdd048be63a484eda351e4ad57eac65aada6410f 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
- * Copyright (C) 1999-2020 the Claws Mail team and Hiroyuki Yamamoto
+ * Copyright (C) 1999-2021 the Claws Mail team and Hiroyuki Yamamoto
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -72,6 +72,7 @@
 #include "main.h"
 #include "passwordstore.h"
 #include "file-utils.h"
+#include "oauth2.h"
 
 typedef struct _IMAPFolder     IMAPFolder;
 typedef struct _IMAPSession    IMAPSession;
@@ -123,6 +124,8 @@ struct _IMAPSession
        gboolean cancelled;
        gboolean sens_update_block;
        gboolean do_destroy;
+
+    gint scan_tree_recurs_depth;
 };
 
 struct _IMAPNameSpace
@@ -278,6 +281,9 @@ static gint imap_auth                       (IMAPSession    *session,
 static gint imap_scan_tree_recursive   (IMAPSession    *session,
                                         FolderItem     *item,
                                         gboolean        subs_only);
+static gint imap_scan_tree_recursive_dive      (IMAPSession    *session,
+                                        FolderItem     *item,
+                                        gboolean        subs_only);
 
 static void imap_create_missing_folders        (Folder         *folder);
 static FolderItem *imap_create_special_folder
@@ -742,7 +748,7 @@ static void imap_handle_error(Session *session, const gchar *server, int libetpa
                break;
 #ifdef USE_GNUTLS
        case MAILIMAP_ERROR_SSL:
-               MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("SSL/TLS error"), "\n", NULL), session_server)
+               MY_LOG_WARNING(g_strconcat(_("IMAP error on %s:"), " ", _("TLS error"), "\n", NULL), session_server)
                break;
 #endif
        default:
@@ -907,6 +913,9 @@ static gint imap_auth(IMAPSession *session, const gchar *user, const gchar *pass
        case IMAP_AUTH_PLAIN:
                ok = imap_cmd_login(session, user, pass, "PLAIN");
                break;
+       case IMAP_AUTH_OAUTH2:
+               ok = imap_cmd_login(session, user, pass, "XOAUTH2");
+               break;
        case IMAP_AUTH_LOGIN:
                ok = imap_cmd_login(session, user, pass, "LOGIN");
                break;
@@ -923,6 +932,7 @@ static gint imap_auth(IMAPSession *session, const gchar *user, const gchar *pass
                                "\t DIGEST-MD5 %d\n"
                                "\t SCRAM-SHA-1 %d\n"
                                "\t PLAIN %d\n"
+                               "\t OAUTH2 %d\n"
                                "\t LOGIN %d\n"
                                "\t GSSAPI %d\n", 
                        imap_has_capability(session, "ANONYMOUS"),
@@ -930,6 +940,7 @@ static gint imap_auth(IMAPSession *session, const gchar *user, const gchar *pass
                        imap_has_capability(session, "DIGEST-MD5"),
                        imap_has_capability(session, "SCRAM-SHA-1"),
                        imap_has_capability(session, "PLAIN"),
+                       imap_has_capability(session, "XOAUTH2"),
                        imap_has_capability(session, "LOGIN"),
                        imap_has_capability(session, "GSSAPI"));
                if (imap_has_capability(session, "CRAM-MD5"))
@@ -946,6 +957,8 @@ static gint imap_auth(IMAPSession *session, const gchar *user, const gchar *pass
                        ok = imap_cmd_login(session, user, pass, "GSSAPI");
                if (ok == MAILIMAP_ERROR_LOGIN) /* we always try plaintext login before giving up */
                        ok = imap_cmd_login(session, user, pass, "plaintext");
+               if (ok == MAILIMAP_ERROR_LOGIN && imap_has_capability(session, "XOAUTH2"))
+                       ok = imap_cmd_login(session, user, pass, "XOAUTH2");
        }
 
        if (ok == MAILIMAP_NO_ERROR)
@@ -981,6 +994,11 @@ static gint imap_auth(IMAPSession *session, const gchar *user, const gchar *pass
                                     "LOGIN SASL plugin is installed.");
                }
 
+               if (type == IMAP_AUTH_OAUTH2) {
+                       ext_info = _("\n\nOAuth2 error. Check and correct your OAuth2 "
+                                    "account preferences.");
+               } 
+
                if (time(NULL) - last_login_err > 10) {
                        if (!prefs_common.no_recv_err_panel) {
                                alertpanel_error_log(_("Connection to %s failed: "
@@ -1157,7 +1175,7 @@ static IMAPSession *imap_session_new(Folder * folder,
        if (account->ssl_imap != SSL_NONE) {
                if (alertpanel_full(_("Insecure connection"),
                        _("This connection is configured to be secured "
-                         "using SSL/TLS, but SSL/TLS is not available "
+                         "using TLS, but TLS is not available "
                          "in this build of Claws Mail. \n\n"
                          "Do you want to continue connecting to this "
                          "server? The communication would not be "
@@ -1230,7 +1248,7 @@ static IMAPSession *imap_session_new(Folder * folder,
        else {
 #ifdef USE_GNUTLS
                if (r == MAILIMAP_ERROR_SSL)
-                       log_error(LOG_PROTOCOL, _("SSL/TLS handshake failed\n"));
+                       log_error(LOG_PROTOCOL, _("TLS handshake failed\n"));
                else
 #endif
                        imap_handle_error(NULL, account->recv_server, r);
@@ -1276,6 +1294,8 @@ static IMAPSession *imap_session_new(Folder * folder,
                                SESSION(session)->sock = NULL;
                                imap_safe_destroy(session);
                        }
+                       imap_session_destroy(session);
+            session_destroy(SESSION(session));
                        return NULL;
                }
 
@@ -1303,6 +1323,9 @@ static gint imap_session_authenticate(IMAPSession *session,
        gint ok = MAILIMAP_NO_ERROR;
        g_return_val_if_fail(account->userid != NULL, MAILIMAP_ERROR_BAD_STATE);
 
+       if(account->imap_auth_type == IMAP_AUTH_OAUTH2)
+               oauth2_check_passwds (account);
+       
        if (!password_get(account->userid, account->recv_server, "imap",
                         SESSION(session)->port, &acc_pass)) {
                acc_pass = passwd_store_get_account(account->account_id,
@@ -1931,7 +1954,7 @@ static gint imap_do_copy_msgs(Folder *folder, FolderItem *dest,
        msginfo = (MsgInfo *)msglist->data;
        src = msginfo->folder;
        if (!same_dest_ok && src == dest) {
-               g_warning("the src folder is identical to the dest.");
+               g_warning("the src folder is identical to the dest");
                return -1;
        }
 
@@ -2498,9 +2521,16 @@ static gint      search_msgs             (Folder                 *folder,
        if (result == MAILIMAP_ERROR_PROTOCOL) {
                debug_print("Server side search unavailable, using local search\n");
                imap_handle_error(SESSION(session), NULL, result);
-               return folder_item_search_msgs_local(folder, container, msgs, NULL,
+               result = folder_item_search_msgs_local(folder, container, msgs, NULL,
                                                       predicate, progress_cb, progress_data);
-       } 
+               if (result < 0) {
+                       debug_print("search_msgs - got protocol error, aborting\n");
+                       alertpanel_error_log(_("Search failed due to server error."));
+                       return -1;
+               }
+
+               return result;
+       }
        
        if (result == MAILIMAP_NO_ERROR) {
                gint result = 0;
@@ -2744,6 +2774,14 @@ static gint imap_scan_tree(Folder *folder)
 }
 
 static gint imap_scan_tree_recursive(IMAPSession *session, FolderItem *item, gboolean subs_only)
+{
+    /* reset recursion depth counter */
+    session->scan_tree_recurs_depth = 0;
+
+    return imap_scan_tree_recursive_dive(session, item, subs_only);
+}
+
+static gint imap_scan_tree_recursive_dive(IMAPSession *session, FolderItem *item, gboolean subs_only)
 {
        Folder *folder;
        IMAPFolder *imapfolder;
@@ -2761,6 +2799,15 @@ static gint imap_scan_tree_recursive(IMAPSession *session, FolderItem *item, gbo
        g_return_val_if_fail(item->folder != NULL, -1);
        g_return_val_if_fail(item->no_sub == FALSE, -1);
 
+    /* recursion depth limiter */
+    if(session->scan_tree_recurs_depth >= prefs_common.imap_scan_tree_recurs_limit) {
+        g_warning("IMAP scan tree recursion limit reached (%d, folder '%s')",
+                prefs_common.imap_scan_tree_recurs_limit, item->folder->name);
+        return -1;
+    }
+    /* entering recursion func: increase depth counter */
+    session->scan_tree_recurs_depth++;
+
        folder = item->folder;
        imapfolder = IMAP_FOLDER(folder);
 
@@ -2888,8 +2935,15 @@ static gint imap_scan_tree_recursive(IMAPSession *session, FolderItem *item, gbo
                        g_free(base);
                }
 
-               if (new_item->no_sub == FALSE)
-                       imap_scan_tree_recursive(session, new_item, subs_only);
+               if (new_item->no_sub == FALSE) {
+                       imap_scan_tree_recursive_dive(session, new_item, subs_only);
+
+            /* entering recursion func: increase depth counter */
+            session->scan_tree_recurs_depth--;
+            if (session->scan_tree_recurs_depth < 0)
+                g_error("IMAP scan tree recursion underflow (%d)",
+                        session->scan_tree_recurs_depth);
+        }
        }
 
        g_slist_free(item_list);
@@ -3065,12 +3119,12 @@ static FolderItem *imap_create_special_folder(Folder *folder,
        new_item = imap_create_folder(folder, item, name);
 
        if (!new_item) {
-               g_warning("Can't create '%s'", name);
+               g_warning("can't create '%s'", name);
                if (!folder->inbox) return NULL;
 
                new_item = imap_create_folder(folder, folder->inbox, name);
                if (!new_item)
-                       g_warning("Can't create '%s' under INBOX", name);
+                       g_warning("can't create '%s' under INBOX", name);
                else
                        new_item->stype = stype;
        } else
@@ -3174,9 +3228,11 @@ static FolderItem *imap_create_folder(Folder *folder, FolderItem *parent,
                gchar *cached_msg = imap_get_cached_filename(parent, to_number(name));
                if (is_file_exist(cached_msg)) {
                        if (claws_unlink(cached_msg) != 0) {
+                               g_free(cached_msg);
                                return NULL;
                        }
                }
+               g_free(cached_msg);
        }
 
        debug_print("getting session...\n");
@@ -3214,6 +3270,7 @@ static FolderItem *imap_create_folder(Folder *folder, FolderItem *parent,
 
        separator = imap_get_path_separator(session, IMAP_FOLDER(folder), imap_path, &ok);
        if (is_fatal(ok)) {
+               g_free(dirpath);
                g_free(imap_path);
                return NULL;
        }
@@ -3332,8 +3389,7 @@ static gint imap_rename_folder(Folder *folder, FolderItem *item,
 
        if (strchr(name, imap_get_path_separator(session, IMAP_FOLDER(folder), item->path, &ok)) != NULL ||
                is_fatal(ok)) {
-               g_warning("New folder name must not contain the namespace "
-                           "path separator");
+               g_warning("new folder name must not contain the namespace path separator");
                return -1;
        }