Managesieve: fix memory leak when saving password from account prefs
[claws.git] / src / plugins / managesieve / sieve_prefs.c
1 /*
2  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2004-2015 the Claws Mail team
4  * Copyright (C) 2014-2015 Charles Lehner
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <http://www.gnu.org/licenses/>.
18  * 
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #include "claws-features.h"
24 #endif
25
26 #include <gtk/gtk.h>
27 #include <glib.h>
28 #include <glib/gi18n.h>
29
30 #include "defs.h"
31 #include "gtk/gtkutils.h"
32 #include "gtk/combobox.h"
33 #include "alertpanel.h"
34 #include "passcrypt.h"
35 #include "password.h"
36 #include "passwordstore.h"
37 #include "utils.h"
38 #include "prefs.h"
39 #include "prefs_gtk.h"
40 #include "sieve_prefs.h"
41 #include "managesieve.h"
42
43 #define PREFS_BLOCK_NAME "ManageSieve"
44
45 SieveConfig sieve_config;
46
47 static PrefParam prefs[] = {
48         {"manager_win_width", "-1", &sieve_config.manager_win_width,
49                 P_INT, NULL, NULL, NULL},
50         {"manager_win_height", "-1", &sieve_config.manager_win_height,
51                 P_INT, NULL, NULL, NULL},
52         {0,0,0,0}
53 };
54
55 #define PACK_HBOX(hbox, vbox) \
56 { \
57         hbox = gtk_hbox_new (FALSE, 5); \
58         gtk_widget_show (hbox); \
59         gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); \
60 }
61
62 #define RADIO_ADD(radio, group, hbox, vbox, label) \
63 { \
64         PACK_HBOX(hbox, vbox); \
65         gtk_container_set_border_width(GTK_CONTAINER (hbox), 0); \
66         radio = gtk_radio_button_new_with_label(group, label); \
67         group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio)); \
68         gtk_widget_show(radio); \
69         gtk_box_pack_start(GTK_BOX(hbox), radio, FALSE, FALSE, 0); \
70 }
71
72 struct SieveAccountPage
73 {
74         PrefsPage page;
75
76         GtkWidget *enable_checkbtn;
77         GtkWidget *serv_frame;
78         GtkWidget *auth_frame;
79         GtkWidget *host_checkbtn, *host_entry;
80         GtkWidget *port_checkbtn, *port_spinbtn;
81         GtkWidget *tls_radio_no, *tls_radio_maybe, *tls_radio_yes;
82         GtkWidget *auth_radio_noauth, *auth_radio_reuse, *auth_radio_custom;
83         GtkWidget *auth_custom_vbox, *auth_method_hbox;
84         GtkWidget *uid_entry;
85         GtkWidget *pass_entry;
86         GtkWidget *auth_menu;
87
88         PrefsAccount *account;
89 };
90
91 static struct SieveAccountPage account_page;
92
93 static void update_auth_sensitive(struct SieveAccountPage *page)
94 {
95         gboolean use_auth, custom;
96
97         custom = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->auth_radio_custom));
98         use_auth = custom || gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->auth_radio_reuse));
99
100         gtk_widget_set_sensitive(GTK_WIDGET(page->auth_custom_vbox), custom);
101         gtk_widget_set_sensitive(GTK_WIDGET(page->auth_method_hbox), use_auth);
102 }
103
104 static void auth_toggled(GtkToggleButton *togglebutton,
105                 gpointer user_data)
106 {
107         struct SieveAccountPage *page = (struct SieveAccountPage *) user_data;
108         update_auth_sensitive(page);
109 }
110
111 static void sieve_prefs_account_create_widget_func(PrefsPage *_page,
112                                                  GtkWindow *window,
113                                                  gpointer data)
114 {
115         struct SieveAccountPage *page = (struct SieveAccountPage *) _page;
116         PrefsAccount *account = (PrefsAccount *) data;
117         SieveAccountConfig *config;
118         gchar *pass;
119
120         GtkWidget *page_vbox, *sieve_vbox;
121         GtkWidget *hbox;
122         GtkWidget *hbox_spc;
123
124         GtkWidget *enable_checkbtn;
125         GtkWidget *serv_vbox, *tls_frame;
126         GtkWidget *tls_vbox, *serv_frame;
127         GtkWidget *auth_vbox, *auth_frame;
128         GtkWidget *auth_custom_vbox, *auth_method_hbox;
129         GtkSizeGroup *size_group;
130         GtkWidget *host_checkbtn, *host_entry;
131         GtkWidget *port_checkbtn, *port_spinbtn;
132         GSList *tls_group = NULL;
133         GSList *auth_group = NULL;
134         GtkWidget *tls_radio_no, *tls_radio_maybe, *tls_radio_yes;
135         GtkWidget *auth_radio_noauth, *auth_radio_reuse, *auth_radio_custom;
136         GtkWidget *label;
137         GtkWidget *uid_entry;
138         GtkWidget *pass_entry;
139         GtkWidget *auth_menu;
140         GtkListStore *menu;
141         GtkTreeIter iter;
142
143         page_vbox = gtk_vbox_new (FALSE, VSPACING);
144         gtk_widget_show (page_vbox);
145         gtk_container_set_border_width (GTK_CONTAINER (page_vbox), VBOX_BORDER);
146
147         /* Enable/disable */
148         PACK_CHECK_BUTTON (page_vbox, enable_checkbtn,
149                            _("Enable Sieve"));
150
151         sieve_vbox = gtk_vbox_new (FALSE, VSPACING);
152         gtk_widget_show (sieve_vbox);
153         gtk_box_pack_start (GTK_BOX (page_vbox), sieve_vbox, FALSE, FALSE, 0);
154
155         /* Server info */
156         serv_vbox = gtkut_get_options_frame(sieve_vbox, &serv_frame, _("Server information"));
157         gtk_widget_show (serv_vbox);
158         gtk_box_pack_start (GTK_BOX (page_vbox), serv_vbox, FALSE, FALSE, 0);
159
160         SET_TOGGLE_SENSITIVITY (enable_checkbtn, sieve_vbox);
161         size_group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
162
163         /* Server name */
164         PACK_HBOX (hbox, serv_vbox);
165         PACK_CHECK_BUTTON (hbox, host_checkbtn, _("Server name"));
166         gtk_size_group_add_widget(size_group, host_checkbtn);
167
168         host_entry = gtk_entry_new();
169         gtk_entry_set_max_length(GTK_ENTRY(host_entry), 255);
170         gtk_widget_show (host_entry);
171         gtk_box_pack_start (GTK_BOX (hbox), host_entry, TRUE, TRUE, 0);
172         SET_TOGGLE_SENSITIVITY (host_checkbtn, host_entry);
173         CLAWS_SET_TIP(hbox,
174                 _("Connect to this host instead of the host used for receiving mail"));
175
176         /* Port */
177         PACK_HBOX (hbox, serv_vbox);
178         PACK_CHECK_BUTTON (hbox, port_checkbtn, _("Server port"));
179         port_spinbtn = gtk_spin_button_new_with_range(1, 65535, 1);
180         gtk_widget_show (port_spinbtn);
181         gtk_box_pack_start (GTK_BOX (hbox), port_spinbtn, FALSE, FALSE, 0);
182         SET_TOGGLE_SENSITIVITY (port_checkbtn, port_spinbtn);
183         gtk_size_group_add_widget(size_group, port_checkbtn);
184         CLAWS_SET_TIP(hbox,
185                 _("Connect to this port instead of the default"));
186
187         /* Encryption */
188
189         tls_vbox = gtkut_get_options_frame(sieve_vbox, &tls_frame, _("Encryption"));
190         gtk_widget_show (tls_vbox);
191         gtk_box_pack_start (GTK_BOX (page_vbox), tls_vbox, FALSE, FALSE, 0);
192
193         RADIO_ADD(tls_radio_no, tls_group, hbox, tls_vbox,
194                         _("No encryption"));
195         RADIO_ADD(tls_radio_maybe, tls_group, hbox, tls_vbox,
196                         _("Use STARTTLS when available"));
197         RADIO_ADD(tls_radio_yes, tls_group, hbox, tls_vbox,
198                         _("Require STARTTLS"));
199
200         /* Authentication */
201
202         auth_vbox = gtkut_get_options_frame(sieve_vbox, &auth_frame,
203                         _("Authentication"));
204
205         RADIO_ADD(auth_radio_noauth, auth_group, hbox, auth_vbox,
206                 _("No authentication"));
207         RADIO_ADD(auth_radio_reuse, auth_group, hbox, auth_vbox,
208                 _("Use same authentication as for receiving mail"));
209         RADIO_ADD(auth_radio_custom, auth_group, hbox, auth_vbox,
210                 _("Specify authentication"));
211
212         g_signal_connect(G_OBJECT(auth_radio_custom), "toggled",
213                         G_CALLBACK(auth_toggled), page);
214         g_signal_connect(G_OBJECT(auth_radio_reuse), "toggled",
215                         G_CALLBACK(auth_toggled), page);
216
217         /* Custom Auth Settings */
218
219         hbox = gtk_hbox_new (FALSE, 0);
220         gtk_widget_show (hbox);
221         gtk_box_pack_start (GTK_BOX (auth_vbox), hbox, FALSE, FALSE, 0);
222
223         hbox_spc = gtk_hbox_new (FALSE, 0);
224         gtk_widget_show (hbox_spc);
225         gtk_box_pack_start (GTK_BOX (hbox), hbox_spc, FALSE, FALSE, 0);
226         gtk_widget_set_size_request (hbox_spc, 12, -1);
227
228         auth_custom_vbox = gtk_vbox_new (FALSE, VSPACING/2);
229         gtk_widget_show (auth_custom_vbox);
230         gtk_container_set_border_width (GTK_CONTAINER (auth_custom_vbox), 0);
231         gtk_box_pack_start (GTK_BOX (hbox), auth_custom_vbox, TRUE, TRUE, 0);
232
233         /* User ID + Password */
234
235         hbox = gtk_hbox_new (FALSE, 8);
236         gtk_widget_show (hbox);
237         gtk_box_pack_start (GTK_BOX (auth_custom_vbox), hbox, FALSE, FALSE, 0);
238
239         /* User ID*/
240         label = gtk_label_new (_("User ID"));
241         gtk_widget_show (label);
242         gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
243
244         uid_entry = gtk_entry_new ();
245         gtk_widget_show (uid_entry);
246         gtk_widget_set_size_request (uid_entry, DEFAULT_ENTRY_WIDTH, -1);
247         gtk_box_pack_start (GTK_BOX (hbox), uid_entry, TRUE, TRUE, 0);
248
249         /* Password */
250         label = gtk_label_new (_("Password"));
251         gtk_widget_show (label);
252         gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
253
254         pass_entry = gtk_entry_new ();
255         gtk_widget_show (pass_entry);
256         gtk_widget_set_size_request (pass_entry, DEFAULT_ENTRY_WIDTH, -1);
257         gtk_entry_set_visibility (GTK_ENTRY (pass_entry), FALSE);
258         gtk_box_pack_start (GTK_BOX (hbox), pass_entry, TRUE, TRUE, 0);
259
260         /* Authentication method */
261
262         auth_method_hbox = gtk_hbox_new (FALSE, 8);
263         gtk_widget_show (auth_method_hbox);
264         gtk_box_pack_start (GTK_BOX (auth_vbox), auth_method_hbox, FALSE, FALSE, 0);
265
266         label = gtk_label_new (_("Authentication method"));
267         gtk_widget_show (label);
268         gtk_box_pack_start (GTK_BOX (auth_method_hbox), label, FALSE, FALSE, 0);
269
270         auth_menu = gtkut_sc_combobox_create(NULL, FALSE);
271         menu = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(auth_menu)));
272         gtk_widget_show (auth_menu);
273         gtk_box_pack_start (GTK_BOX (auth_method_hbox), auth_menu, FALSE, FALSE, 0);
274
275         COMBOBOX_ADD (menu, _("Automatic"), SIEVEAUTH_AUTO);
276         COMBOBOX_ADD (menu, NULL, 0);
277         COMBOBOX_ADD (menu, "PLAIN", SIEVEAUTH_PLAIN);
278         COMBOBOX_ADD (menu, "LOGIN", SIEVEAUTH_LOGIN);
279         COMBOBOX_ADD (menu, "CRAM-MD5", SIEVEAUTH_CRAM_MD5);
280
281         /* Populate config */
282
283         config = sieve_prefs_account_get_config(account);
284
285         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(enable_checkbtn), config->enable);
286         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(host_checkbtn), config->use_host);
287         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(port_checkbtn), config->use_port);
288         gtk_spin_button_set_value(GTK_SPIN_BUTTON(port_spinbtn), (float) config->port);
289
290         if (config->host != NULL)
291                 gtk_entry_set_text(GTK_ENTRY(host_entry), config->host);
292         if (config->userid != NULL)
293                 gtk_entry_set_text(GTK_ENTRY(uid_entry), config->userid);
294         if ((pass = passwd_store_get_account(account->account_id,
295                                      "sieve")) != NULL) {
296                 gtk_entry_set_text(GTK_ENTRY(pass_entry), pass);
297                 memset(pass, 0, strlen(pass));
298                 g_free(pass);
299         }
300
301         combobox_select_by_data(GTK_COMBO_BOX(auth_menu), config->auth_type);
302
303         /* Add items to page struct */
304         page->account = account;
305         page->enable_checkbtn = enable_checkbtn;
306         page->serv_frame = serv_frame;
307         page->auth_frame = auth_frame;
308         page->auth_custom_vbox = auth_custom_vbox;
309         page->auth_method_hbox = auth_method_hbox;
310         page->host_checkbtn = host_checkbtn;
311         page->host_entry = host_entry;
312         page->port_checkbtn = port_checkbtn;
313         page->port_spinbtn = port_spinbtn;
314         page->auth_radio_noauth = auth_radio_noauth;
315         page->auth_radio_reuse = auth_radio_reuse;
316         page->auth_radio_custom = auth_radio_custom;
317         page->tls_radio_no = tls_radio_no;
318         page->tls_radio_maybe = tls_radio_maybe;
319         page->tls_radio_yes = tls_radio_yes;
320         page->uid_entry = uid_entry;
321         page->pass_entry = pass_entry;
322         page->auth_menu = auth_menu;
323         page->page.widget = page_vbox;
324
325         /* Update things */
326
327         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
328                                 config->tls_type == SIEVE_TLS_NO ? tls_radio_no :
329                                 config->tls_type == SIEVE_TLS_MAYBE ? tls_radio_maybe :
330                                 tls_radio_yes), TRUE);
331
332         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
333                                 config->auth == SIEVEAUTH_REUSE ? auth_radio_reuse :
334                                 config->auth == SIEVEAUTH_CUSTOM ? auth_radio_custom :
335                                 auth_radio_noauth), TRUE);
336
337         update_auth_sensitive(page);
338
339         /* Free things */
340         g_object_unref(G_OBJECT(size_group));
341
342         sieve_prefs_account_free_config(config);
343 }
344
345 static void sieve_prefs_account_destroy_widget_func(PrefsPage *_page)
346 {
347 }
348
349 static gint sieve_prefs_account_apply(struct SieveAccountPage *page)
350 {
351         SieveAccountConfig *config;
352
353         config = sieve_prefs_account_get_config(page->account);
354
355         config->enable = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->enable_checkbtn));
356         config->use_port = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->port_checkbtn));
357         config->use_host = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->host_checkbtn));
358         config->port = (gushort)gtk_spin_button_get_value_as_int
359                         (GTK_SPIN_BUTTON(page->port_spinbtn));
360
361         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->auth_radio_noauth)))
362                 config->auth = SIEVEAUTH_NONE;
363         else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->auth_radio_reuse)))
364                 config->auth = SIEVEAUTH_REUSE;
365         else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->auth_radio_custom)))
366                 config->auth = SIEVEAUTH_CUSTOM;
367
368         config->tls_type =
369                 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->tls_radio_no)) ?
370                         SIEVE_TLS_NO :
371                 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->tls_radio_maybe)) ?
372                         SIEVE_TLS_MAYBE :
373                         SIEVE_TLS_YES;
374
375         g_free(config->host);
376         g_free(config->userid);
377
378         config->host = gtk_editable_get_chars(GTK_EDITABLE(page->host_entry), 0, -1);
379         config->userid = gtk_editable_get_chars(GTK_EDITABLE(page->uid_entry), 0, -1);
380         gchar *pwd = gtk_editable_get_chars(GTK_EDITABLE(page->pass_entry), 0, -1);
381         passwd_store_set_account(page->account->account_id, "sieve", pwd, FALSE);
382         memset(pwd, 0, strlen(pwd));
383         g_free(pwd);
384         config->auth_type = combobox_get_active_data(GTK_COMBO_BOX(page->auth_menu));
385
386         sieve_prefs_account_set_config(page->account, config);
387         sieve_prefs_account_free_config(config);
388         return TRUE;
389 }
390
391 static gboolean sieve_prefs_account_check(struct SieveAccountPage *page)
392 {
393         if (strchr(gtk_entry_get_text(GTK_ENTRY(page->host_entry)), ' ')) {
394                 alertpanel_error(_("Sieve server must not contain a space."));
395                 return FALSE;
396         }
397
398         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->host_checkbtn)) &&
399                         *gtk_entry_get_text(GTK_ENTRY(page->host_entry)) == '\0') {
400                 alertpanel_error(_("Sieve server is not entered."));
401                 return FALSE;
402         }
403
404         return TRUE;
405 }
406
407 static void sieve_prefs_account_save_func(PrefsPage *_page)
408 {
409         struct SieveAccountPage *page = (struct SieveAccountPage *) _page;
410         if (sieve_prefs_account_check(page)) {
411                 sieve_prefs_account_apply(page);
412         }
413 }
414
415 static gboolean sieve_prefs_account_can_close(PrefsPage *_page)
416 {
417         struct SieveAccountPage *page = (struct SieveAccountPage *) _page;
418         return sieve_prefs_account_check(page);
419 }
420
421 void sieve_prefs_init()
422 {
423         gchar *rcpath;
424
425         /* Account prefs */
426         static gchar *path[3];
427         path[0] = _("Plugins");
428         path[1] = _("Sieve");
429         path[2] = NULL;
430
431         account_page.page.path = path;
432         account_page.page.create_widget = sieve_prefs_account_create_widget_func;
433         account_page.page.destroy_widget = sieve_prefs_account_destroy_widget_func;
434         account_page.page.save_page = sieve_prefs_account_save_func;
435         account_page.page.can_close = sieve_prefs_account_can_close;
436         account_page.page.weight = 30.0;
437         prefs_account_register_page((PrefsPage *) &account_page);
438
439         /* Common prefs */
440         prefs_set_default(prefs);
441         rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL);
442         prefs_read_config(prefs, PREFS_BLOCK_NAME, rcpath, NULL);
443         g_free(rcpath);
444 }
445
446 void sieve_prefs_done(void)
447 {
448         PrefFile *pref_file;
449         gchar *rc_file_path;
450
451         prefs_account_unregister_page((PrefsPage *) &account_page);
452
453         rc_file_path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
454                                    COMMON_RC, NULL);
455         pref_file = prefs_write_open(rc_file_path);
456         g_free(rc_file_path);
457
458         if (!pref_file || prefs_set_block_label(pref_file, PREFS_BLOCK_NAME) < 0)
459                 return;
460
461         if (prefs_write_param(prefs, pref_file->fp) < 0) {
462                 g_warning("failed to write ManageSieve Plugin configuration");
463                 prefs_file_close_revert(pref_file);
464                 return;
465         }
466
467         if (fprintf(pref_file->fp, "\n") < 0) {
468                 FILE_OP_ERROR(rc_file_path, "fprintf");
469                 prefs_file_close_revert(pref_file);
470         } else
471                 prefs_file_close(pref_file);
472 }
473
474 struct SieveAccountConfig *sieve_prefs_account_get_config(
475                 PrefsAccount *account)
476 {
477         SieveAccountConfig *config;
478         const gchar *confstr;
479         gchar enc_userid[256], enc_passwd[256];
480         gchar enable, use_host, use_port;
481         guchar tls_type, auth, auth_type;
482         gsize len;
483 #if defined(G_OS_WIN32) || defined(__OpenBSD__)
484         /* Windows sscanf() does not understand the %ms format yet, so we
485          * have to do the allocation of target buffer ourselves before
486          * calling sscanf(), and copy the host string to config->host.
487          */
488         gchar tmphost[256];
489 #endif
490
491         config = g_new0(SieveAccountConfig, 1);
492
493         config->enable = FALSE;
494         config->use_host = FALSE;
495         config->host = NULL;
496         config->use_port = FALSE;
497         config->port = 4190;
498         config->tls_type = SIEVE_TLS_YES;
499         config->auth = SIEVEAUTH_REUSE;
500         config->auth_type = SIEVEAUTH_AUTO;
501         config->userid = NULL;
502
503         confstr = prefs_account_get_privacy_prefs(account, "sieve");
504         if (confstr == NULL)
505                 return config;
506
507         enc_userid[0] = '\0';
508         enc_passwd[0] = '\0';
509 #if defined(G_OS_WIN32) || defined(__OpenBSD__)
510         sscanf(confstr, "%c%c %255s %c%hu %hhu %hhu %hhu %255s %255s",
511 #else
512         sscanf(confstr, "%c%c %ms %c%hu %hhu %hhu %hhu %255s %255s",
513 #endif
514                         &enable, &use_host,
515 #if defined(G_OS_WIN32) || defined(__OpenBSD__)
516                         tmphost,
517 #else
518                         &config->host,
519 #endif
520                         &use_port, &config->port,
521                         &tls_type,
522                         &auth,
523                         &auth_type,
524                         enc_userid,
525                         enc_passwd);
526
527         /* Scan enums separately, for endian purposes */
528         config->tls_type = tls_type;
529         config->auth = auth;
530         config->auth_type = auth_type;
531
532 #if defined(G_OS_WIN32) || defined(__OpenBSD__)
533         config->host = g_strndup(tmphost, 255);
534 #endif
535
536         config->enable = enable == 'y';
537         config->use_host = use_host == 'y';
538         config->use_port = use_port == 'y';
539
540         if (config->host[0] == '!' && !config->host[1]) {
541                 g_free(config->host);
542                 config->host = NULL;
543         }
544
545         config->userid = g_base64_decode(enc_userid, &len);
546         if (enc_passwd[0]) {
547                 // migrate password from passcrypt to passwordstore
548                 gchar *pass = g_base64_decode(enc_passwd, &len);
549                 passcrypt_decrypt(pass, len);
550                 passwd_store_set_account(account->account_id, "sieve",
551                                 pass, FALSE);
552                 g_free(pass);
553         }
554
555         return config;
556 }
557
558 void sieve_prefs_account_set_config(
559                 PrefsAccount *account, SieveAccountConfig *config)
560 {
561         gchar *confstr = NULL;
562         gchar *enc_userid = NULL;
563         gsize len;
564
565         if (config->userid) {
566                 len = strlen(config->userid);
567                 enc_userid = g_base64_encode(config->userid, len);
568         }
569
570         confstr = g_strdup_printf("%c%c %s %c%hu %hhu %hhu %hhu %s %s",
571                         config->enable ? 'y' : 'n',
572                         config->use_host ? 'y' : 'n',
573                         config->host && config->host[0] ? config->host : "!",
574                         config->use_port ? 'y' : 'n',
575                         config->port,
576                         config->tls_type,
577                         config->auth,
578                         config->auth_type,
579                         enc_userid ? enc_userid : "",
580                         "");
581
582         if (enc_userid)
583                 g_free(enc_userid);
584
585         prefs_account_set_privacy_prefs(account, "sieve", confstr);
586
587         g_free(confstr);
588
589         sieve_account_prefs_updated(account);
590 }
591
592 void sieve_prefs_account_free_config(SieveAccountConfig *config)
593 {
594         g_free(config->host);
595         g_free(config->userid);
596         g_free(config);
597 }
598