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
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.
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.
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/>.
23 #include "claws-features.h"
28 #include <glib/gi18n.h>
31 #include "gtk/gtkutils.h"
32 #include "gtk/combobox.h"
33 #include "alertpanel.h"
34 #include "passcrypt.h"
37 #include "prefs_gtk.h"
38 #include "sieve_prefs.h"
39 #include "managesieve.h"
41 #define PACK_HBOX(hbox, vbox) \
43 hbox = gtk_hbox_new (FALSE, 5); \
44 gtk_widget_show (hbox); \
45 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); \
48 #define RADIO_ADD(radio, group, hbox, vbox, label) \
50 PACK_HBOX(hbox, vbox); \
51 gtk_container_set_border_width(GTK_CONTAINER (hbox), 0); \
52 radio = gtk_radio_button_new_with_label(group, label); \
53 group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio)); \
54 gtk_widget_show(radio); \
55 gtk_box_pack_start(GTK_BOX(hbox), radio, FALSE, FALSE, 0); \
58 struct SieveAccountPage
62 GtkWidget *enable_checkbtn;
63 GtkWidget *serv_frame;
64 GtkWidget *auth_frame;
65 GtkWidget *host_checkbtn, *host_entry;
66 GtkWidget *port_checkbtn, *port_spinbtn;
67 GtkWidget *tls_radio_no, *tls_radio_maybe, *tls_radio_yes;
68 GtkWidget *auth_radio_noauth, *auth_radio_reuse, *auth_radio_custom;
69 GtkWidget *auth_custom_vbox, *auth_method_hbox;
71 GtkWidget *pass_entry;
74 PrefsAccount *account;
77 static struct SieveAccountPage account_page;
79 static void update_auth_sensitive(struct SieveAccountPage *page)
81 gboolean use_auth, custom;
83 custom = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->auth_radio_custom));
84 use_auth = custom || gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->auth_radio_reuse));
86 gtk_widget_set_sensitive(GTK_WIDGET(page->auth_custom_vbox), custom);
87 gtk_widget_set_sensitive(GTK_WIDGET(page->auth_method_hbox), use_auth);
90 static void auth_toggled(GtkToggleButton *togglebutton,
93 struct SieveAccountPage *page = (struct SieveAccountPage *) user_data;
94 update_auth_sensitive(page);
97 static void sieve_prefs_account_create_widget_func(PrefsPage *_page,
101 struct SieveAccountPage *page = (struct SieveAccountPage *) _page;
102 PrefsAccount *account = (PrefsAccount *) data;
103 SieveAccountConfig *config;
105 GtkWidget *page_vbox, *sieve_vbox;
109 GtkWidget *enable_checkbtn;
110 GtkWidget *serv_vbox, *tls_frame;
111 GtkWidget *tls_vbox, *serv_frame;
112 GtkWidget *auth_vbox, *auth_frame;
113 GtkWidget *auth_custom_vbox, *auth_method_hbox;
114 GtkSizeGroup *size_group;
115 GtkWidget *host_checkbtn, *host_entry;
116 GtkWidget *port_checkbtn, *port_spinbtn;
117 GSList *tls_group = NULL;
118 GSList *auth_group = NULL;
119 GtkWidget *tls_radio_no, *tls_radio_maybe, *tls_radio_yes;
120 GtkWidget *auth_radio_noauth, *auth_radio_reuse, *auth_radio_custom;
122 GtkWidget *uid_entry;
123 GtkWidget *pass_entry;
124 GtkWidget *auth_menu;
128 page_vbox = gtk_vbox_new (FALSE, VSPACING);
129 gtk_widget_show (page_vbox);
130 gtk_container_set_border_width (GTK_CONTAINER (page_vbox), VBOX_BORDER);
133 PACK_CHECK_BUTTON (page_vbox, enable_checkbtn,
136 sieve_vbox = gtk_vbox_new (FALSE, VSPACING);
137 gtk_widget_show (sieve_vbox);
138 gtk_box_pack_start (GTK_BOX (page_vbox), sieve_vbox, FALSE, FALSE, 0);
141 serv_vbox = gtkut_get_options_frame(sieve_vbox, &serv_frame, _("Server information"));
142 gtk_widget_show (serv_vbox);
143 gtk_box_pack_start (GTK_BOX (page_vbox), serv_vbox, FALSE, FALSE, 0);
145 SET_TOGGLE_SENSITIVITY (enable_checkbtn, sieve_vbox);
146 size_group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
149 PACK_HBOX (hbox, serv_vbox);
150 PACK_CHECK_BUTTON (hbox, host_checkbtn, _("Server name"));
151 gtk_size_group_add_widget(size_group, host_checkbtn);
153 host_entry = gtk_entry_new();
154 gtk_entry_set_max_length(GTK_ENTRY(host_entry), 255);
155 gtk_widget_show (host_entry);
156 gtk_box_pack_start (GTK_BOX (hbox), host_entry, TRUE, TRUE, 0);
157 SET_TOGGLE_SENSITIVITY (host_checkbtn, host_entry);
159 _("Connect to this host instead of the host used for receiving mail"));
162 PACK_HBOX (hbox, serv_vbox);
163 PACK_CHECK_BUTTON (hbox, port_checkbtn, _("Server port"));
164 port_spinbtn = gtk_spin_button_new_with_range(1, 65535, 1);
165 gtk_widget_show (port_spinbtn);
166 gtk_box_pack_start (GTK_BOX (hbox), port_spinbtn, FALSE, FALSE, 0);
167 SET_TOGGLE_SENSITIVITY (port_checkbtn, port_spinbtn);
168 gtk_size_group_add_widget(size_group, port_checkbtn);
170 _("Connect to this port instead of the default"));
174 tls_vbox = gtkut_get_options_frame(sieve_vbox, &tls_frame, _("Encryption"));
175 gtk_widget_show (tls_vbox);
176 gtk_box_pack_start (GTK_BOX (page_vbox), tls_vbox, FALSE, FALSE, 0);
178 RADIO_ADD(tls_radio_no, tls_group, hbox, tls_vbox,
180 RADIO_ADD(tls_radio_maybe, tls_group, hbox, tls_vbox,
181 _("Use TLS when available"));
182 RADIO_ADD(tls_radio_yes, tls_group, hbox, tls_vbox,
187 auth_vbox = gtkut_get_options_frame(sieve_vbox, &auth_frame,
188 _("Authentication"));
190 RADIO_ADD(auth_radio_noauth, auth_group, hbox, auth_vbox,
191 _("No authentication"));
192 RADIO_ADD(auth_radio_reuse, auth_group, hbox, auth_vbox,
193 _("Use same authentication as for receiving mail"));
194 RADIO_ADD(auth_radio_custom, auth_group, hbox, auth_vbox,
195 _("Specify authentication"));
197 g_signal_connect(G_OBJECT(auth_radio_custom), "toggled",
198 G_CALLBACK(auth_toggled), page);
199 g_signal_connect(G_OBJECT(auth_radio_reuse), "toggled",
200 G_CALLBACK(auth_toggled), page);
202 /* Custom Auth Settings */
204 hbox = gtk_hbox_new (FALSE, 0);
205 gtk_widget_show (hbox);
206 gtk_box_pack_start (GTK_BOX (auth_vbox), hbox, FALSE, FALSE, 0);
208 hbox_spc = gtk_hbox_new (FALSE, 0);
209 gtk_widget_show (hbox_spc);
210 gtk_box_pack_start (GTK_BOX (hbox), hbox_spc, FALSE, FALSE, 0);
211 gtk_widget_set_size_request (hbox_spc, 12, -1);
213 auth_custom_vbox = gtk_vbox_new (FALSE, VSPACING/2);
214 gtk_widget_show (auth_custom_vbox);
215 gtk_container_set_border_width (GTK_CONTAINER (auth_custom_vbox), 0);
216 gtk_box_pack_start (GTK_BOX (hbox), auth_custom_vbox, TRUE, TRUE, 0);
218 /* User ID + Password */
220 hbox = gtk_hbox_new (FALSE, 8);
221 gtk_widget_show (hbox);
222 gtk_box_pack_start (GTK_BOX (auth_custom_vbox), hbox, FALSE, FALSE, 0);
225 label = gtk_label_new (_("User ID"));
226 gtk_widget_show (label);
227 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
229 uid_entry = gtk_entry_new ();
230 gtk_widget_show (uid_entry);
231 gtk_widget_set_size_request (uid_entry, DEFAULT_ENTRY_WIDTH, -1);
232 gtk_box_pack_start (GTK_BOX (hbox), uid_entry, TRUE, TRUE, 0);
235 label = gtk_label_new (_("Password"));
236 gtk_widget_show (label);
237 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
239 pass_entry = gtk_entry_new ();
240 gtk_widget_show (pass_entry);
241 gtk_widget_set_size_request (pass_entry, DEFAULT_ENTRY_WIDTH, -1);
242 gtk_entry_set_visibility (GTK_ENTRY (pass_entry), FALSE);
243 gtk_box_pack_start (GTK_BOX (hbox), pass_entry, TRUE, TRUE, 0);
245 /* Authentication method */
247 auth_method_hbox = gtk_hbox_new (FALSE, 8);
248 gtk_widget_show (auth_method_hbox);
249 gtk_box_pack_start (GTK_BOX (auth_vbox), auth_method_hbox, FALSE, FALSE, 0);
251 label = gtk_label_new (_("Authentication method"));
252 gtk_widget_show (label);
253 gtk_box_pack_start (GTK_BOX (auth_method_hbox), label, FALSE, FALSE, 0);
255 auth_menu = gtkut_sc_combobox_create(NULL, FALSE);
256 menu = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(auth_menu)));
257 gtk_widget_show (auth_menu);
258 gtk_box_pack_start (GTK_BOX (auth_method_hbox), auth_menu, FALSE, FALSE, 0);
260 COMBOBOX_ADD (menu, _("Automatic"), SIEVEAUTH_AUTO);
261 COMBOBOX_ADD (menu, NULL, 0);
262 COMBOBOX_ADD (menu, "PLAIN", SIEVEAUTH_PLAIN);
263 COMBOBOX_ADD (menu, "LOGIN", SIEVEAUTH_LOGIN);
264 COMBOBOX_ADD (menu, "CRAM-MD5", SIEVEAUTH_CRAM_MD5);
266 /* Populate config */
268 config = sieve_prefs_account_get_config(account);
270 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(enable_checkbtn), config->enable);
271 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(host_checkbtn), config->use_host);
272 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(port_checkbtn), config->use_port);
273 gtk_spin_button_set_value(GTK_SPIN_BUTTON(port_spinbtn), (float) config->port);
275 if (config->host != NULL)
276 gtk_entry_set_text(GTK_ENTRY(host_entry), config->host);
277 if (config->userid != NULL)
278 gtk_entry_set_text(GTK_ENTRY(uid_entry), config->userid);
279 if (config->passwd != NULL)
280 gtk_entry_set_text(GTK_ENTRY(pass_entry), config->passwd);
282 combobox_select_by_data(GTK_COMBO_BOX(auth_menu), config->auth_type);
284 /* Add items to page struct */
285 page->account = account;
286 page->enable_checkbtn = enable_checkbtn;
287 page->serv_frame = serv_frame;
288 page->auth_frame = auth_frame;
289 page->auth_custom_vbox = auth_custom_vbox;
290 page->auth_method_hbox = auth_method_hbox;
291 page->host_checkbtn = host_checkbtn;
292 page->host_entry = host_entry;
293 page->port_checkbtn = port_checkbtn;
294 page->port_spinbtn = port_spinbtn;
295 page->auth_radio_noauth = auth_radio_noauth;
296 page->auth_radio_reuse = auth_radio_reuse;
297 page->auth_radio_custom = auth_radio_custom;
298 page->tls_radio_no = tls_radio_no;
299 page->tls_radio_maybe = tls_radio_maybe;
300 page->tls_radio_yes = tls_radio_yes;
301 page->uid_entry = uid_entry;
302 page->pass_entry = pass_entry;
303 page->auth_menu = auth_menu;
304 page->page.widget = page_vbox;
308 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
309 config->tls_type == SIEVE_TLS_NO ? tls_radio_no :
310 config->tls_type == SIEVE_TLS_MAYBE ? tls_radio_maybe :
311 tls_radio_yes), TRUE);
313 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
314 config->auth == SIEVEAUTH_REUSE ? auth_radio_reuse :
315 config->auth == SIEVEAUTH_CUSTOM ? auth_radio_custom :
316 auth_radio_noauth), TRUE);
318 update_auth_sensitive(page);
321 g_object_unref(G_OBJECT(size_group));
324 static void sieve_prefs_account_destroy_widget_func(PrefsPage *_page)
328 static gint sieve_prefs_account_apply(struct SieveAccountPage *page)
330 SieveAccountConfig *config;
332 config = sieve_prefs_account_get_config(page->account);
334 config->enable = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->enable_checkbtn));
335 config->use_port = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->port_checkbtn));
336 config->use_host = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->host_checkbtn));
337 config->port = (gushort)gtk_spin_button_get_value_as_int
338 (GTK_SPIN_BUTTON(page->port_spinbtn));
340 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->auth_radio_noauth)))
341 config->auth = SIEVEAUTH_NONE;
342 else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->auth_radio_reuse)))
343 config->auth = SIEVEAUTH_REUSE;
344 else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->auth_radio_custom)))
345 config->auth = SIEVEAUTH_CUSTOM;
348 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->tls_radio_no)) ?
350 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->tls_radio_maybe)) ?
354 config->host = gtk_editable_get_chars(GTK_EDITABLE(page->host_entry), 0, -1);
355 config->userid = gtk_editable_get_chars(GTK_EDITABLE(page->uid_entry), 0, -1);
356 config->passwd = gtk_editable_get_chars(GTK_EDITABLE(page->pass_entry), 0, -1);
357 config->auth_type = combobox_get_active_data(GTK_COMBO_BOX(page->auth_menu));
359 sieve_prefs_account_set_config(page->account, config);
360 sieve_prefs_account_free_config(config);
364 static gboolean sieve_prefs_account_check(struct SieveAccountPage *page)
366 if (strchr(gtk_entry_get_text(GTK_ENTRY(page->host_entry)), ' ')) {
367 alertpanel_error(_("Sieve server must not contain a space."));
371 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->host_checkbtn)) &&
372 *gtk_entry_get_text(GTK_ENTRY(page->host_entry)) == '\0') {
373 alertpanel_error(_("Sieve server is not entered."));
380 static void sieve_prefs_account_save_func(PrefsPage *_page)
382 struct SieveAccountPage *page = (struct SieveAccountPage *) _page;
383 if (sieve_prefs_account_check(page)) {
384 sieve_prefs_account_apply(page);
388 static gboolean sieve_prefs_account_can_close(PrefsPage *_page)
390 struct SieveAccountPage *page = (struct SieveAccountPage *) _page;
391 return sieve_prefs_account_check(page);
394 void sieve_prefs_init()
396 static gchar *path[3];
397 path[0] = _("Plugins");
398 path[1] = _("Sieve");
401 account_page.page.path = path;
402 account_page.page.create_widget = sieve_prefs_account_create_widget_func;
403 account_page.page.destroy_widget = sieve_prefs_account_destroy_widget_func;
404 account_page.page.save_page = sieve_prefs_account_save_func;
405 account_page.page.can_close = sieve_prefs_account_can_close;
406 account_page.page.weight = 30.0;
407 prefs_account_register_page((PrefsPage *) &account_page);
410 void sieve_prefs_done(void)
412 prefs_account_unregister_page((PrefsPage *) &account_page);
415 struct SieveAccountConfig *sieve_prefs_account_get_config(
416 PrefsAccount *account)
418 SieveAccountConfig *config;
419 const gchar *confstr;
420 gchar enc_userid[256], enc_passwd[256];
421 gchar enable, use_host, use_port;
424 /* Windows sscanf() does not understand the %ms format yet, so we
425 * have to do the allocation of target buffer ourselves before
426 * calling sscanf(), and copy the host string to config->host.
431 config = g_new0(SieveAccountConfig, 1);
433 config->enable = FALSE;
434 config->use_host = FALSE;
436 config->use_port = FALSE;
438 config->tls_type = SIEVE_TLS_YES;
439 config->auth = SIEVEAUTH_REUSE;
440 config->auth_type = SIEVEAUTH_AUTO;
441 config->userid = NULL;
442 config->passwd = NULL;
444 confstr = prefs_account_get_privacy_prefs(account, "sieve");
449 sscanf(confstr, "%c%c %255s %c%hu %hhu %hhu %hhu %255s %255s",
451 sscanf(confstr, "%c%c %ms %c%hu %hhu %hhu %hhu %255s %255s",
459 &use_port, &config->port,
460 (char *)&config->tls_type,
461 (char *)&config->auth,
462 (char *)&config->auth_type,
467 config->host = g_strndup(tmphost, 255);
470 config->enable = enable == 'y';
471 config->use_host = use_host == 'y';
472 config->use_port = use_port == 'y';
474 if (config->host[0] == '!' && !config->host[1]) {
475 g_free(config->host);
479 config->userid = g_base64_decode(enc_userid, &len);
480 config->passwd = g_base64_decode(enc_passwd, &len);
481 passcrypt_decrypt(config->passwd, len);
486 void sieve_prefs_account_set_config(
487 PrefsAccount *account, SieveAccountConfig *config)
489 gchar *confstr = NULL;
490 gchar *enc_userid = NULL;
491 gchar *enc_passwd = NULL;
495 if (config->userid) {
496 len = strlen(config->userid);
497 enc_userid = g_base64_encode(config->userid, len);
500 if (config->passwd) {
501 tmp = g_strdup(config->passwd);
503 passcrypt_encrypt(tmp, len);
504 enc_passwd = g_base64_encode(tmp, len);
508 confstr = g_strdup_printf("%c%c %s %c%hu %hhu %hhu %hhu %s %s",
509 config->enable ? 'y' : 'n',
510 config->use_host ? 'y' : 'n',
511 config->host && config->host[0] ? config->host : "!",
512 config->use_port ? 'y' : 'n',
517 enc_userid ? enc_userid : "",
518 enc_passwd ? enc_passwd : "");
525 prefs_account_set_privacy_prefs(account, "sieve", confstr);
529 sieve_account_prefs_updated(account);
532 void sieve_prefs_account_free_config(SieveAccountConfig *config)
534 g_free(config->host);
535 g_free(config->userid);
536 g_free(config->passwd);