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,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 
update_auth_sensitive(struct SieveAccountPage * page)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 
auth_toggled(GtkToggleButton * togglebutton,gpointer user_data)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 
sieve_prefs_account_create_widget_func(PrefsPage * _page,GtkWindow * window,gpointer data)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 
158 	SET_TOGGLE_SENSITIVITY (enable_checkbtn, sieve_vbox);
159 	size_group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
160 
161 	/* Server name */
162 	PACK_HBOX (hbox, serv_vbox);
163 	PACK_CHECK_BUTTON (hbox, host_checkbtn, _("Server name"));
164 	gtk_size_group_add_widget(size_group, host_checkbtn);
165 
166 	host_entry = gtk_entry_new();
167 	gtk_entry_set_max_length(GTK_ENTRY(host_entry), 255);
168 	gtk_widget_show (host_entry);
169 	gtk_box_pack_start (GTK_BOX (hbox), host_entry, TRUE, TRUE, 0);
170 	SET_TOGGLE_SENSITIVITY (host_checkbtn, host_entry);
171 	CLAWS_SET_TIP(hbox,
172 		_("Connect to this host instead of the host used for receiving mail"));
173 
174 	/* Port */
175 	PACK_HBOX (hbox, serv_vbox);
176 	PACK_CHECK_BUTTON (hbox, port_checkbtn, _("Server port"));
177 	port_spinbtn = gtk_spin_button_new_with_range(1, 65535, 1);
178 	gtk_widget_show (port_spinbtn);
179 	gtk_box_pack_start (GTK_BOX (hbox), port_spinbtn, FALSE, FALSE, 0);
180 	SET_TOGGLE_SENSITIVITY (port_checkbtn, port_spinbtn);
181 	gtk_size_group_add_widget(size_group, port_checkbtn);
182 	CLAWS_SET_TIP(hbox,
183 		_("Connect to this port instead of the default"));
184 
185 	/* Encryption */
186 
187 	tls_vbox = gtkut_get_options_frame(sieve_vbox, &tls_frame, _("Encryption"));
188 
189 	RADIO_ADD(tls_radio_no, tls_group, hbox, tls_vbox,
190 			_("No encryption"));
191 	RADIO_ADD(tls_radio_maybe, tls_group, hbox, tls_vbox,
192 			_("Use STARTTLS when available"));
193 	RADIO_ADD(tls_radio_yes, tls_group, hbox, tls_vbox,
194 			_("Require STARTTLS"));
195 
196 	/* Authentication */
197 
198 	auth_vbox = gtkut_get_options_frame(sieve_vbox, &auth_frame,
199 			_("Authentication"));
200 
201 	RADIO_ADD(auth_radio_noauth, auth_group, hbox, auth_vbox,
202 		_("No authentication"));
203 	RADIO_ADD(auth_radio_reuse, auth_group, hbox, auth_vbox,
204 		_("Use same authentication as for receiving mail"));
205 	RADIO_ADD(auth_radio_custom, auth_group, hbox, auth_vbox,
206 		_("Specify authentication"));
207 
208 	g_signal_connect(G_OBJECT(auth_radio_custom), "toggled",
209 			G_CALLBACK(auth_toggled), page);
210 	g_signal_connect(G_OBJECT(auth_radio_reuse), "toggled",
211 			G_CALLBACK(auth_toggled), page);
212 
213 	/* Custom Auth Settings */
214 
215 	hbox = gtk_hbox_new (FALSE, 0);
216 	gtk_widget_show (hbox);
217 	gtk_box_pack_start (GTK_BOX (auth_vbox), hbox, FALSE, FALSE, 0);
218 
219 	hbox_spc = gtk_hbox_new (FALSE, 0);
220 	gtk_widget_show (hbox_spc);
221 	gtk_box_pack_start (GTK_BOX (hbox), hbox_spc, FALSE, FALSE, 0);
222 	gtk_widget_set_size_request (hbox_spc, 12, -1);
223 
224 	auth_custom_vbox = gtk_vbox_new (FALSE, VSPACING/2);
225 	gtk_widget_show (auth_custom_vbox);
226 	gtk_container_set_border_width (GTK_CONTAINER (auth_custom_vbox), 0);
227 	gtk_box_pack_start (GTK_BOX (hbox), auth_custom_vbox, TRUE, TRUE, 0);
228 
229 	/* User ID + Password */
230 
231 	hbox = gtk_hbox_new (FALSE, 8);
232 	gtk_widget_show (hbox);
233 	gtk_box_pack_start (GTK_BOX (auth_custom_vbox), hbox, FALSE, FALSE, 0);
234 
235 	/* User ID*/
236 	label = gtk_label_new (_("User ID"));
237 	gtk_widget_show (label);
238 	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
239 
240 	uid_entry = gtk_entry_new ();
241 	gtk_widget_show (uid_entry);
242 	gtk_widget_set_size_request (uid_entry, DEFAULT_ENTRY_WIDTH, -1);
243 	gtk_box_pack_start (GTK_BOX (hbox), uid_entry, TRUE, TRUE, 0);
244 
245 	/* Password */
246 	label = gtk_label_new (_("Password"));
247 	gtk_widget_show (label);
248 	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
249 
250 	pass_entry = gtk_entry_new ();
251 	gtk_widget_show (pass_entry);
252 	gtk_widget_set_size_request (pass_entry, DEFAULT_ENTRY_WIDTH, -1);
253 	gtk_entry_set_visibility (GTK_ENTRY (pass_entry), FALSE);
254 	gtk_box_pack_start (GTK_BOX (hbox), pass_entry, TRUE, TRUE, 0);
255 
256 	/* Authentication method */
257 
258 	auth_method_hbox = gtk_hbox_new (FALSE, 8);
259 	gtk_widget_show (auth_method_hbox);
260 	gtk_box_pack_start (GTK_BOX (auth_vbox), auth_method_hbox, FALSE, FALSE, 0);
261 
262 	label = gtk_label_new (_("Authentication method"));
263 	gtk_widget_show (label);
264 	gtk_box_pack_start (GTK_BOX (auth_method_hbox), label, FALSE, FALSE, 0);
265 
266 	auth_menu = gtkut_sc_combobox_create(NULL, FALSE);
267 	menu = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(auth_menu)));
268 	gtk_widget_show (auth_menu);
269 	gtk_box_pack_start (GTK_BOX (auth_method_hbox), auth_menu, FALSE, FALSE, 0);
270 
271 	COMBOBOX_ADD (menu, _("Automatic"), SIEVEAUTH_AUTO);
272 	COMBOBOX_ADD (menu, NULL, 0);
273 	COMBOBOX_ADD (menu, "PLAIN", SIEVEAUTH_PLAIN);
274 	COMBOBOX_ADD (menu, "LOGIN", SIEVEAUTH_LOGIN);
275 	COMBOBOX_ADD (menu, "CRAM-MD5", SIEVEAUTH_CRAM_MD5);
276 
277 	/* Populate config */
278 
279 	config = sieve_prefs_account_get_config(account);
280 
281 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(enable_checkbtn), config->enable);
282 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(host_checkbtn), config->use_host);
283 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(port_checkbtn), config->use_port);
284 	gtk_spin_button_set_value(GTK_SPIN_BUTTON(port_spinbtn), (float) config->port);
285 
286 	if (config->host != NULL)
287 		gtk_entry_set_text(GTK_ENTRY(host_entry), config->host);
288 	if (config->userid != NULL)
289 		gtk_entry_set_text(GTK_ENTRY(uid_entry), config->userid);
290 	if ((pass = passwd_store_get_account(account->account_id,
291 				     "sieve")) != NULL) {
292 		gtk_entry_set_text(GTK_ENTRY(pass_entry), pass);
293 		memset(pass, 0, strlen(pass));
294 		g_free(pass);
295 	}
296 
297 	combobox_select_by_data(GTK_COMBO_BOX(auth_menu), config->auth_type);
298 
299 	/* Add items to page struct */
300 	page->account = account;
301 	page->enable_checkbtn = enable_checkbtn;
302 	page->serv_frame = serv_frame;
303 	page->auth_frame = auth_frame;
304 	page->auth_custom_vbox = auth_custom_vbox;
305 	page->auth_method_hbox = auth_method_hbox;
306 	page->host_checkbtn = host_checkbtn;
307 	page->host_entry = host_entry;
308 	page->port_checkbtn = port_checkbtn;
309 	page->port_spinbtn = port_spinbtn;
310 	page->auth_radio_noauth = auth_radio_noauth;
311 	page->auth_radio_reuse = auth_radio_reuse;
312 	page->auth_radio_custom = auth_radio_custom;
313 	page->tls_radio_no = tls_radio_no;
314 	page->tls_radio_maybe = tls_radio_maybe;
315 	page->tls_radio_yes = tls_radio_yes;
316 	page->uid_entry = uid_entry;
317 	page->pass_entry = pass_entry;
318 	page->auth_menu = auth_menu;
319 	page->page.widget = page_vbox;
320 
321 	/* Update things */
322 
323 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
324 				config->tls_type == SIEVE_TLS_NO ? tls_radio_no :
325 				config->tls_type == SIEVE_TLS_MAYBE ? tls_radio_maybe :
326 				tls_radio_yes), TRUE);
327 
328 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
329 				config->auth == SIEVEAUTH_REUSE ? auth_radio_reuse :
330 				config->auth == SIEVEAUTH_CUSTOM ? auth_radio_custom :
331 				auth_radio_noauth), TRUE);
332 
333 	update_auth_sensitive(page);
334 
335 	/* Free things */
336 	g_object_unref(G_OBJECT(size_group));
337 
338 	sieve_prefs_account_free_config(config);
339 }
340 
sieve_prefs_account_destroy_widget_func(PrefsPage * _page)341 static void sieve_prefs_account_destroy_widget_func(PrefsPage *_page)
342 {
343 }
344 
sieve_prefs_account_apply(struct SieveAccountPage * page)345 static gint sieve_prefs_account_apply(struct SieveAccountPage *page)
346 {
347 	SieveAccountConfig *config;
348 
349 	config = sieve_prefs_account_get_config(page->account);
350 
351 	config->enable = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->enable_checkbtn));
352 	config->use_port = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->port_checkbtn));
353 	config->use_host = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->host_checkbtn));
354 	config->port = (gushort)gtk_spin_button_get_value_as_int
355 			(GTK_SPIN_BUTTON(page->port_spinbtn));
356 
357 	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->auth_radio_noauth)))
358 		config->auth = SIEVEAUTH_NONE;
359 	else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->auth_radio_reuse)))
360 		config->auth = SIEVEAUTH_REUSE;
361 	else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->auth_radio_custom)))
362 		config->auth = SIEVEAUTH_CUSTOM;
363 
364 	config->tls_type =
365 		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->tls_radio_no)) ?
366 			SIEVE_TLS_NO :
367 		gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->tls_radio_maybe)) ?
368 			SIEVE_TLS_MAYBE :
369 			SIEVE_TLS_YES;
370 
371 	g_free(config->host);
372 	g_free(config->userid);
373 
374 	config->host = gtk_editable_get_chars(GTK_EDITABLE(page->host_entry), 0, -1);
375 	config->userid = gtk_editable_get_chars(GTK_EDITABLE(page->uid_entry), 0, -1);
376 	gchar *pwd = gtk_editable_get_chars(GTK_EDITABLE(page->pass_entry), 0, -1);
377 	passwd_store_set_account(page->account->account_id, "sieve", pwd, FALSE);
378 	memset(pwd, 0, strlen(pwd));
379 	g_free(pwd);
380 	config->auth_type = combobox_get_active_data(GTK_COMBO_BOX(page->auth_menu));
381 
382 	sieve_prefs_account_set_config(page->account, config);
383 	sieve_prefs_account_free_config(config);
384 	return TRUE;
385 }
386 
sieve_prefs_account_check(struct SieveAccountPage * page)387 static gboolean sieve_prefs_account_check(struct SieveAccountPage *page)
388 {
389 	if (strchr(gtk_entry_get_text(GTK_ENTRY(page->host_entry)), ' ')) {
390 		alertpanel_error(_("Sieve server must not contain a space."));
391 		return FALSE;
392 	}
393 
394 	if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->host_checkbtn)) &&
395 			*gtk_entry_get_text(GTK_ENTRY(page->host_entry)) == '\0') {
396 		alertpanel_error(_("Sieve server is not entered."));
397 		return FALSE;
398 	}
399 
400 	return TRUE;
401 }
402 
sieve_prefs_account_save_func(PrefsPage * _page)403 static void sieve_prefs_account_save_func(PrefsPage *_page)
404 {
405 	struct SieveAccountPage *page = (struct SieveAccountPage *) _page;
406 	if (sieve_prefs_account_check(page)) {
407 		sieve_prefs_account_apply(page);
408 	}
409 }
410 
sieve_prefs_account_can_close(PrefsPage * _page)411 static gboolean sieve_prefs_account_can_close(PrefsPage *_page)
412 {
413 	struct SieveAccountPage *page = (struct SieveAccountPage *) _page;
414 	return sieve_prefs_account_check(page);
415 }
416 
sieve_prefs_init()417 void sieve_prefs_init()
418 {
419 	gchar *rcpath;
420 
421 	/* Account prefs */
422 	static gchar *path[3];
423 	path[0] = _("Plugins");
424 	path[1] = _("Sieve");
425 	path[2] = NULL;
426 
427 	account_page.page.path = path;
428 	account_page.page.create_widget = sieve_prefs_account_create_widget_func;
429 	account_page.page.destroy_widget = sieve_prefs_account_destroy_widget_func;
430 	account_page.page.save_page = sieve_prefs_account_save_func;
431 	account_page.page.can_close = sieve_prefs_account_can_close;
432 	account_page.page.weight = 30.0;
433 	prefs_account_register_page((PrefsPage *) &account_page);
434 
435 	/* Common prefs */
436 	prefs_set_default(prefs);
437 	rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, COMMON_RC, NULL);
438 	prefs_read_config(prefs, PREFS_BLOCK_NAME, rcpath, NULL);
439 	g_free(rcpath);
440 }
441 
sieve_prefs_done(void)442 void sieve_prefs_done(void)
443 {
444 	PrefFile *pref_file;
445 	gchar *rc_file_path;
446 
447 	prefs_account_unregister_page((PrefsPage *) &account_page);
448 
449 	rc_file_path = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S,
450 				   COMMON_RC, NULL);
451 	pref_file = prefs_write_open(rc_file_path);
452 	g_free(rc_file_path);
453 
454 	if (!pref_file || prefs_set_block_label(pref_file, PREFS_BLOCK_NAME) < 0)
455 		return;
456 
457 	if (prefs_write_param(prefs, pref_file->fp) < 0) {
458 		g_warning("failed to write ManageSieve Plugin configuration");
459 		prefs_file_close_revert(pref_file);
460 		return;
461 	}
462 
463 	if (fprintf(pref_file->fp, "\n") < 0) {
464 		FILE_OP_ERROR(rc_file_path, "fprintf");
465 		prefs_file_close_revert(pref_file);
466 	} else
467 		prefs_file_close(pref_file);
468 }
469 
sieve_prefs_account_get_config(PrefsAccount * account)470 struct SieveAccountConfig *sieve_prefs_account_get_config(
471 		PrefsAccount *account)
472 {
473 	SieveAccountConfig *config;
474 	const gchar *confstr;
475 	gchar enc_userid[256], enc_passwd[256];
476 	gchar enable, use_host, use_port;
477 	guchar tls_type, auth, auth_type;
478 	gsize len;
479 	gint num;
480 #if defined(G_OS_WIN32) || defined(__OpenBSD__) || defined(__FreeBSD__)
481 	/* Non-GNU sscanf() does not understand the %ms format, so we
482 	 * have to do the allocation of target buffer ourselves before
483 	 * calling sscanf(), and copy the host string to config->host.
484 	 */
485 	gchar tmphost[256];
486 #endif
487 
488 	config = g_new0(SieveAccountConfig, 1);
489 
490 	config->enable = FALSE;
491 	config->use_host = FALSE;
492 	config->host = NULL;
493 	config->use_port = FALSE;
494 	config->port = 4190;
495 	config->tls_type = SIEVE_TLS_YES;
496 	config->auth = SIEVEAUTH_REUSE;
497 	config->auth_type = SIEVEAUTH_AUTO;
498 	config->userid = NULL;
499 
500 	confstr = prefs_account_get_privacy_prefs(account, "sieve");
501 	if (confstr == NULL)
502 		return config;
503 
504 	enc_userid[0] = '\0';
505 	enc_passwd[0] = '\0';
506 #if defined(G_OS_WIN32) || defined(__OpenBSD__) || defined(__FreeBSD__)
507 	if ((num = sscanf(confstr, "%c%c %255s %c%hu %hhu %hhu %hhu %255s %255s",
508 #else
509 	if ((num = sscanf(confstr, "%c%c %ms %c%hu %hhu %hhu %hhu %255s %255s",
510 #endif
511 			&enable, &use_host,
512 #if defined(G_OS_WIN32) || defined(__OpenBSD__) || defined(__FreeBSD__)
513 			tmphost,
514 #else
515 			&config->host,
516 #endif
517 			&use_port, &config->port,
518 			&tls_type,
519 			&auth,
520 			&auth_type,
521 			enc_userid,
522 			enc_passwd)) != 10) {
523 			/* This (10th element missing) will happen on any recent
524 			 * configuration, where the password is already in
525 			 * passwordstore, and not in this config string. We have
526 			 * to read the 10th element in order not to break older
527 			 * configurations, and to move the password to password
528 			 * store.
529 			 * The userid may be missing if it is unset.
530 			 * If there are not 10, 9 or 8 elements, something is wrong. */
531 		if (num != 9 && num != 8) {
532 			g_warning("failed reading Sieve config elements");
533 		}
534 	}
535 	debug_print("Read %d Sieve config elements\n", num);
536 
537 	/* Scan enums separately, for endian purposes */
538 	config->tls_type = tls_type;
539 	config->auth = auth;
540 	config->auth_type = auth_type;
541 
542 #if defined(G_OS_WIN32) || defined(__OpenBSD__) || defined(__FreeBSD__)
543 	config->host = g_strndup(tmphost, 255);
544 #endif
545 
546 	config->enable = enable == 'y';
547 	config->use_host = use_host == 'y';
548 	config->use_port = use_port == 'y';
549 
550 	if (config->host != NULL && config->host[0] == '!' && !config->host[1]) {
551 		g_free(config->host);
552 		config->host = NULL;
553 	}
554 
555 	config->userid = g_base64_decode(enc_userid, &len);
556 
557 	/* migrate password from passcrypt to passwordstore, if
558 	 * it's not there yet */
559 	if (enc_passwd[0] != '\0' &&
560 			!passwd_store_has_password_account(account->account_id, "sieve")) {
561 		gchar *pass = g_base64_decode(enc_passwd, &len);
562 		passcrypt_decrypt(pass, len);
563 		passwd_store_set_account(account->account_id, "sieve",
564 				pass, FALSE);
565 		g_free(pass);
566 	}
567 
568 	return config;
569 }
570 
sieve_prefs_account_set_config(PrefsAccount * account,SieveAccountConfig * config)571 void sieve_prefs_account_set_config(
572 		PrefsAccount *account, SieveAccountConfig *config)
573 {
574 	gchar *confstr = NULL;
575 	gchar *enc_userid = NULL;
576 	gsize len;
577 
578 	if (config->userid) {
579 		len = strlen(config->userid);
580 		enc_userid = g_base64_encode(config->userid, len);
581 	}
582 
583 	confstr = g_strdup_printf("%c%c %s %c%hu %hu %hu %hu %s",
584 			config->enable ? 'y' : 'n',
585 			config->use_host ? 'y' : 'n',
586 			config->host && config->host[0] ? config->host : "!",
587 			config->use_port ? 'y' : 'n',
588 			config->port,
589 			config->tls_type,
590 			config->auth,
591 			config->auth_type,
592 			enc_userid ? enc_userid : "");
593 
594 	if (enc_userid)
595 		g_free(enc_userid);
596 
597 	prefs_account_set_privacy_prefs(account, "sieve", confstr);
598 
599 	g_free(confstr);
600 
601 	sieve_account_prefs_updated(account);
602 }
603 
sieve_prefs_account_free_config(SieveAccountConfig * config)604 void sieve_prefs_account_free_config(SieveAccountConfig *config)
605 {
606 	g_free(config->host);
607 	g_free(config->userid);
608 	g_free(config);
609 }
610 
611