Allow Sieve config without userid without warning
[claws.git] / src / plugins / managesieve / sieve_prefs.c
index 0bd3e41df5aa19c43815f115e8deb981d95c2da1..2e2d0e9b8b475e01cbe22406e421fba59a4155c1 100644 (file)
 #include "gtk/combobox.h"
 #include "alertpanel.h"
 #include "passcrypt.h"
+#include "password.h"
+#include "passwordstore.h"
 #include "utils.h"
 #include "prefs.h"
 #include "prefs_gtk.h"
 #include "sieve_prefs.h"
 #include "managesieve.h"
 
+#define PREFS_BLOCK_NAME "ManageSieve"
+
+SieveConfig sieve_config;
+
+static PrefParam prefs[] = {
+        {"manager_win_width", "-1", &sieve_config.manager_win_width,
+               P_INT, NULL, NULL, NULL},
+        {"manager_win_height", "-1", &sieve_config.manager_win_height,
+               P_INT, NULL, NULL, NULL},
+        {0,0,0,0,0,0,0}
+};
+
 #define PACK_HBOX(hbox, vbox) \
 { \
        hbox = gtk_hbox_new (FALSE, 5); \
@@ -101,6 +115,7 @@ static void sieve_prefs_account_create_widget_func(PrefsPage *_page,
        struct SieveAccountPage *page = (struct SieveAccountPage *) _page;
        PrefsAccount *account = (PrefsAccount *) data;
        SieveAccountConfig *config;
+       gchar *pass;
 
        GtkWidget *page_vbox, *sieve_vbox;
        GtkWidget *hbox;
@@ -139,8 +154,6 @@ static void sieve_prefs_account_create_widget_func(PrefsPage *_page,
 
        /* Server info */
        serv_vbox = gtkut_get_options_frame(sieve_vbox, &serv_frame, _("Server information"));
-       gtk_widget_show (serv_vbox);
-       gtk_box_pack_start (GTK_BOX (page_vbox), serv_vbox, FALSE, FALSE, 0);
 
        SET_TOGGLE_SENSITIVITY (enable_checkbtn, sieve_vbox);
        size_group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
@@ -172,15 +185,13 @@ static void sieve_prefs_account_create_widget_func(PrefsPage *_page,
        /* Encryption */
 
        tls_vbox = gtkut_get_options_frame(sieve_vbox, &tls_frame, _("Encryption"));
-       gtk_widget_show (tls_vbox);
-       gtk_box_pack_start (GTK_BOX (page_vbox), tls_vbox, FALSE, FALSE, 0);
 
        RADIO_ADD(tls_radio_no, tls_group, hbox, tls_vbox,
-                       _("No TLS"));
+                       _("No encryption"));
        RADIO_ADD(tls_radio_maybe, tls_group, hbox, tls_vbox,
-                       _("Use TLS when available"));
+                       _("Use STARTTLS when available"));
        RADIO_ADD(tls_radio_yes, tls_group, hbox, tls_vbox,
-                       _("Require TLS"));
+                       _("Require STARTTLS"));
 
        /* Authentication */
 
@@ -276,8 +287,12 @@ static void sieve_prefs_account_create_widget_func(PrefsPage *_page,
                gtk_entry_set_text(GTK_ENTRY(host_entry), config->host);
        if (config->userid != NULL)
                gtk_entry_set_text(GTK_ENTRY(uid_entry), config->userid);
-       if (config->passwd != NULL)
-               gtk_entry_set_text(GTK_ENTRY(pass_entry), config->passwd);
+       if ((pass = passwd_store_get_account(account->account_id,
+                                    "sieve")) != NULL) {
+               gtk_entry_set_text(GTK_ENTRY(pass_entry), pass);
+               memset(pass, 0, strlen(pass));
+               g_free(pass);
+       }
 
        combobox_select_by_data(GTK_COMBO_BOX(auth_menu), config->auth_type);
 
@@ -319,6 +334,8 @@ static void sieve_prefs_account_create_widget_func(PrefsPage *_page,
 
        /* Free things */
        g_object_unref(G_OBJECT(size_group));
+
+       sieve_prefs_account_free_config(config);
 }
 
 static void sieve_prefs_account_destroy_widget_func(PrefsPage *_page)
@@ -351,9 +368,15 @@ static gint sieve_prefs_account_apply(struct SieveAccountPage *page)
                        SIEVE_TLS_MAYBE :
                        SIEVE_TLS_YES;
 
+       g_free(config->host);
+       g_free(config->userid);
+
        config->host = gtk_editable_get_chars(GTK_EDITABLE(page->host_entry), 0, -1);
        config->userid = gtk_editable_get_chars(GTK_EDITABLE(page->uid_entry), 0, -1);
-       config->passwd = gtk_editable_get_chars(GTK_EDITABLE(page->pass_entry), 0, -1);
+       gchar *pwd = gtk_editable_get_chars(GTK_EDITABLE(page->pass_entry), 0, -1);
+       passwd_store_set_account(page->account->account_id, "sieve", pwd, FALSE);
+       memset(pwd, 0, strlen(pwd));
+       g_free(pwd);
        config->auth_type = combobox_get_active_data(GTK_COMBO_BOX(page->auth_menu));
 
        sieve_prefs_account_set_config(page->account, config);
@@ -393,6 +416,9 @@ static gboolean sieve_prefs_account_can_close(PrefsPage *_page)
 
 void sieve_prefs_init()
 {
+       gchar *rcpath;
+
+       /* Account prefs */
        static gchar *path[3];
        path[0] = _("Plugins");
        path[1] = _("Sieve");
@@ -405,11 +431,40 @@ void sieve_prefs_init()
        account_page.page.can_close = sieve_prefs_account_can_close;
        account_page.page.weight = 30.0;
        prefs_account_register_page((PrefsPage *) &account_page);
+
+       /* Common prefs */
+       prefs_set_default(prefs);
+       rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL);
+       prefs_read_config(prefs, PREFS_BLOCK_NAME, rcpath, NULL);
+       g_free(rcpath);
 }
 
 void sieve_prefs_done(void)
 {
+       PrefFile *pref_file;
+       gchar *rc_file_path;
+
        prefs_account_unregister_page((PrefsPage *) &account_page);
+
+       rc_file_path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
+                                  COMMON_RC, NULL);
+       pref_file = prefs_write_open(rc_file_path);
+       g_free(rc_file_path);
+
+       if (!pref_file || prefs_set_block_label(pref_file, PREFS_BLOCK_NAME) < 0)
+               return;
+
+       if (prefs_write_param(prefs, pref_file->fp) < 0) {
+               g_warning("failed to write ManageSieve Plugin configuration");
+               prefs_file_close_revert(pref_file);
+               return;
+       }
+
+       if (fprintf(pref_file->fp, "\n") < 0) {
+               FILE_OP_ERROR(rc_file_path, "fprintf");
+               prefs_file_close_revert(pref_file);
+       } else
+               prefs_file_close(pref_file);
 }
 
 struct SieveAccountConfig *sieve_prefs_account_get_config(
@@ -419,9 +474,11 @@ struct SieveAccountConfig *sieve_prefs_account_get_config(
        const gchar *confstr;
        gchar enc_userid[256], enc_passwd[256];
        gchar enable, use_host, use_port;
+       guchar tls_type, auth, auth_type;
        gsize len;
-#ifdef G_OS_WIN32
-       /* Windows sscanf() does not understand the %ms format yet, so we
+       gint num;
+#if defined(G_OS_WIN32) || defined(__OpenBSD__) || defined(__FreeBSD__)
+       /* Non-GNU sscanf() does not understand the %ms format, so we
         * have to do the allocation of target buffer ourselves before
         * calling sscanf(), and copy the host string to config->host.
         */
@@ -439,31 +496,50 @@ struct SieveAccountConfig *sieve_prefs_account_get_config(
        config->auth = SIEVEAUTH_REUSE;
        config->auth_type = SIEVEAUTH_AUTO;
        config->userid = NULL;
-       config->passwd = NULL;
 
        confstr = prefs_account_get_privacy_prefs(account, "sieve");
        if (confstr == NULL)
                return config;
 
-#ifdef G_OS_WIN32
-       sscanf(confstr, "%c%c %255s %c%hu %hhu %hhu %hhu %255s %255s",
+       enc_userid[0] = '\0';
+       enc_passwd[0] = '\0';
+#if defined(G_OS_WIN32) || defined(__OpenBSD__) || defined(__FreeBSD__)
+       if ((num = sscanf(confstr, "%c%c %255s %c%hu %hhu %hhu %hhu %255s %255s",
 #else
-       sscanf(confstr, "%c%c %ms %c%hu %hhu %hhu %hhu %255s %255s",
+       if ((num = sscanf(confstr, "%c%c %ms %c%hu %hhu %hhu %hhu %255s %255s",
 #endif
                        &enable, &use_host,
-#ifdef G_OS_WIN32
+#if defined(G_OS_WIN32) || defined(__OpenBSD__) || defined(__FreeBSD__)
                        tmphost,
 #else
                        &config->host,
 #endif
                        &use_port, &config->port,
-                       (char *)&config->tls_type,
-                       (char *)&config->auth,
-                       (char *)&config->auth_type,
+                       &tls_type,
+                       &auth,
+                       &auth_type,
                        enc_userid,
-                       enc_passwd);
+                       enc_passwd)) != 10) {
+                       /* This (10th element missing) will happen on any recent
+                        * configuration, where the password is already in
+                        * passwordstore, and not in this config string. We have
+                        * to read the 10th element in order not to break older
+                        * configurations, and to move the password to password
+                        * store.
+                        * The userid may be missing if it is unset.
+                        * If there are not 10, 9 or 8 elements, something is wrong. */
+               if (num != 9 && num != 8) {
+                       g_warning("failed reading Sieve config elements");
+               }
+       }
+       debug_print("Read %d Sieve config elements\n", num);
+
+       /* Scan enums separately, for endian purposes */
+       config->tls_type = tls_type;
+       config->auth = auth;
+       config->auth_type = auth_type;
 
-#ifdef G_OS_WIN32
+#if defined(G_OS_WIN32) || defined(__OpenBSD__) || defined(__FreeBSD__)
        config->host = g_strndup(tmphost, 255);
 #endif
 
@@ -471,14 +547,23 @@ struct SieveAccountConfig *sieve_prefs_account_get_config(
        config->use_host = use_host == 'y';
        config->use_port = use_port == 'y';
 
-       if (config->host[0] == '!' && !config->host[1]) {
+       if (config->host != NULL && config->host[0] == '!' && !config->host[1]) {
                g_free(config->host);
                config->host = NULL;
        }
 
        config->userid = g_base64_decode(enc_userid, &len);
-       config->passwd = g_base64_decode(enc_passwd, &len);
-       passcrypt_decrypt(config->passwd, len);
+
+       /* migrate password from passcrypt to passwordstore, if
+        * it's not there yet */
+       if (enc_passwd[0] != '\0' &&
+                       !passwd_store_has_password_account(account->account_id, "sieve")) {
+               gchar *pass = g_base64_decode(enc_passwd, &len);
+               passcrypt_decrypt(pass, len);
+               passwd_store_set_account(account->account_id, "sieve",
+                               pass, FALSE);
+               g_free(pass);
+       }
 
        return config;
 }
@@ -488,8 +573,6 @@ void sieve_prefs_account_set_config(
 {
        gchar *confstr = NULL;
        gchar *enc_userid = NULL;
-       gchar *enc_passwd = NULL;
-       gchar *tmp;
        gsize len;
 
        if (config->userid) {
@@ -497,15 +580,7 @@ void sieve_prefs_account_set_config(
                enc_userid = g_base64_encode(config->userid, len);
        }
 
-       if (config->passwd) {
-               tmp = g_strdup(config->passwd);
-               len = strlen(tmp);
-               passcrypt_encrypt(tmp, len);
-               enc_passwd = g_base64_encode(tmp, len);
-               g_free(tmp);
-       }
-
-       confstr = g_strdup_printf("%c%c %s %c%hu %hhu %hhu %hhu %s %s",
+       confstr = g_strdup_printf("%c%c %s %c%hu %hu %hu %hu %s",
                        config->enable ? 'y' : 'n',
                        config->use_host ? 'y' : 'n',
                        config->host && config->host[0] ? config->host : "!",
@@ -514,13 +589,10 @@ void sieve_prefs_account_set_config(
                        config->tls_type,
                        config->auth,
                        config->auth_type,
-                       enc_userid ? enc_userid : "",
-                       enc_passwd ? enc_passwd : "");
+                       enc_userid ? enc_userid : "");
 
        if (enc_userid)
                g_free(enc_userid);
-       if (enc_passwd)
-               g_free(enc_passwd);
 
        prefs_account_set_privacy_prefs(account, "sieve", confstr);
 
@@ -533,7 +605,6 @@ void sieve_prefs_account_free_config(SieveAccountConfig *config)
 {
        g_free(config->host);
        g_free(config->userid);
-       g_free(config->passwd);
        g_free(config);
 }