Mark string for translation which is already translated
[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 "utils.h"
36 #include "prefs.h"
37 #include "prefs_gtk.h"
38 #include "sieve_prefs.h"
39 #include "managesieve.h"
40
41 #define PACK_HBOX(hbox, vbox) \
42 { \
43         hbox = gtk_hbox_new (FALSE, 5); \
44         gtk_widget_show (hbox); \
45         gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); \
46 }
47
48 #define RADIO_ADD(radio, group, hbox, vbox, label) \
49 { \
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); \
56 }
57
58 struct SieveAccountPage
59 {
60         PrefsPage page;
61
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;
70         GtkWidget *uid_entry;
71         GtkWidget *pass_entry;
72         GtkWidget *auth_menu;
73
74         PrefsAccount *account;
75 };
76
77 static struct SieveAccountPage account_page;
78
79 static void update_auth_sensitive(struct SieveAccountPage *page)
80 {
81         gboolean use_auth, custom;
82
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));
85
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);
88 }
89
90 static void auth_toggled(GtkToggleButton *togglebutton,
91                 gpointer user_data)
92 {
93         struct SieveAccountPage *page = (struct SieveAccountPage *) user_data;
94         update_auth_sensitive(page);
95 }
96
97 static void sieve_prefs_account_create_widget_func(PrefsPage *_page,
98                                                  GtkWindow *window,
99                                                  gpointer data)
100 {
101         struct SieveAccountPage *page = (struct SieveAccountPage *) _page;
102         PrefsAccount *account = (PrefsAccount *) data;
103         SieveAccountConfig *config;
104
105         GtkWidget *page_vbox, *sieve_vbox;
106         GtkWidget *hbox;
107         GtkWidget *hbox_spc;
108
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;
121         GtkWidget *label;
122         GtkWidget *uid_entry;
123         GtkWidget *pass_entry;
124         GtkWidget *auth_menu;
125         GtkListStore *menu;
126         GtkTreeIter iter;
127
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);
131
132         /* Enable/disable */
133         PACK_CHECK_BUTTON (page_vbox, enable_checkbtn,
134                            _("Enable Sieve"));
135
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);
139
140         /* Server info */
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);
144
145         SET_TOGGLE_SENSITIVITY (enable_checkbtn, sieve_vbox);
146         size_group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL);
147
148         /* Server name */
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);
152
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);
158         CLAWS_SET_TIP(hbox,
159                 _("Connect to this host instead of the host used for receiving mail"));
160
161         /* Port */
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);
169         CLAWS_SET_TIP(hbox,
170                 _("Connect to this port instead of the default"));
171
172         /* Encryption */
173
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);
177
178         RADIO_ADD(tls_radio_no, tls_group, hbox, tls_vbox,
179                         _("No TLS"));
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,
183                         _("Require TLS"));
184
185         /* Authentication */
186
187         auth_vbox = gtkut_get_options_frame(sieve_vbox, &auth_frame,
188                         _("Authentication"));
189
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"));
196
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);
201
202         /* Custom Auth Settings */
203
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);
207
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);
212
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);
217
218         /* User ID + Password */
219
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);
223
224         /* User ID*/
225         label = gtk_label_new (_("User ID"));
226         gtk_widget_show (label);
227         gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
228
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);
233
234         /* Password */
235         label = gtk_label_new (_("Password"));
236         gtk_widget_show (label);
237         gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
238
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);
244
245         /* Authentication method */
246
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);
250
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);
254
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);
259
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);
265
266         /* Populate config */
267
268         config = sieve_prefs_account_get_config(account);
269
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);
274
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);
281
282         combobox_select_by_data(GTK_COMBO_BOX(auth_menu), config->auth_type);
283
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;
305
306         /* Update things */
307
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);
312
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);
317
318         update_auth_sensitive(page);
319
320         /* Free things */
321         g_object_unref(G_OBJECT(size_group));
322 }
323
324 static void sieve_prefs_account_destroy_widget_func(PrefsPage *_page)
325 {
326 }
327
328 static gint sieve_prefs_account_apply(struct SieveAccountPage *page)
329 {
330         SieveAccountConfig *config;
331
332         config = sieve_prefs_account_get_config(page->account);
333
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));
339
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;
346
347         config->tls_type =
348                 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->tls_radio_no)) ?
349                         SIEVE_TLS_NO :
350                 gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(page->tls_radio_maybe)) ?
351                         SIEVE_TLS_MAYBE :
352                         SIEVE_TLS_YES;
353
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));
358
359         sieve_prefs_account_set_config(page->account, config);
360         sieve_prefs_account_free_config(config);
361         return TRUE;
362 }
363
364 static gboolean sieve_prefs_account_check(struct SieveAccountPage *page)
365 {
366         if (strchr(gtk_entry_get_text(GTK_ENTRY(page->host_entry)), ' ')) {
367                 alertpanel_error(_("Sieve server must not contain a space."));
368                 return FALSE;
369         }
370
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."));
374                 return FALSE;
375         }
376
377         return TRUE;
378 }
379
380 static void sieve_prefs_account_save_func(PrefsPage *_page)
381 {
382         struct SieveAccountPage *page = (struct SieveAccountPage *) _page;
383         if (sieve_prefs_account_check(page)) {
384                 sieve_prefs_account_apply(page);
385         }
386 }
387
388 static gboolean sieve_prefs_account_can_close(PrefsPage *_page)
389 {
390         struct SieveAccountPage *page = (struct SieveAccountPage *) _page;
391         return sieve_prefs_account_check(page);
392 }
393
394 void sieve_prefs_init()
395 {
396         static gchar *path[3];
397         path[0] = _("Plugins");
398         path[1] = _("Sieve");
399         path[2] = NULL;
400
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);
408 }
409
410 void sieve_prefs_done(void)
411 {
412         prefs_account_unregister_page((PrefsPage *) &account_page);
413 }
414
415 struct SieveAccountConfig *sieve_prefs_account_get_config(
416                 PrefsAccount *account)
417 {
418         SieveAccountConfig *config;
419         const gchar *confstr;
420         gchar enc_userid[256], enc_passwd[256];
421         gchar enable, use_host, use_port;
422         gsize len;
423 #ifdef G_OS_WIN32
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.
427          */
428         gchar tmphost[256];
429 #endif
430
431         config = g_new0(SieveAccountConfig, 1);
432
433         config->enable = FALSE;
434         config->use_host = FALSE;
435         config->host = NULL;
436         config->use_port = FALSE;
437         config->port = 4190;
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;
443
444         confstr = prefs_account_get_privacy_prefs(account, "sieve");
445         if (confstr == NULL)
446                 return config;
447
448 #ifdef G_OS_WIN32
449         sscanf(confstr, "%c%c %255s %c%hu %hhu %hhu %hhu %255s %255s",
450 #else
451         sscanf(confstr, "%c%c %ms %c%hu %hhu %hhu %hhu %255s %255s",
452 #endif
453                         &enable, &use_host,
454 #ifdef G_OS_WIN32
455                         tmphost,
456 #else
457                         &config->host,
458 #endif
459                         &use_port, &config->port,
460                         (char *)&config->tls_type,
461                         (char *)&config->auth,
462                         (char *)&config->auth_type,
463                         enc_userid,
464                         enc_passwd);
465
466 #ifdef G_OS_WIN32
467         config->host = g_strndup(tmphost, 255);
468 #endif
469
470         config->enable = enable == 'y';
471         config->use_host = use_host == 'y';
472         config->use_port = use_port == 'y';
473
474         if (config->host[0] == '!' && !config->host[1]) {
475                 g_free(config->host);
476                 config->host = NULL;
477         }
478
479         config->userid = g_base64_decode(enc_userid, &len);
480         config->passwd = g_base64_decode(enc_passwd, &len);
481         passcrypt_decrypt(config->passwd, len);
482
483         return config;
484 }
485
486 void sieve_prefs_account_set_config(
487                 PrefsAccount *account, SieveAccountConfig *config)
488 {
489         gchar *confstr = NULL;
490         gchar *enc_userid = NULL;
491         gchar *enc_passwd = NULL;
492         gchar *tmp;
493         gsize len;
494
495         if (config->userid) {
496                 len = strlen(config->userid);
497                 enc_userid = g_base64_encode(config->userid, len);
498         }
499
500         if (config->passwd) {
501                 tmp = g_strdup(config->passwd);
502                 len = strlen(tmp);
503                 passcrypt_encrypt(tmp, len);
504                 enc_passwd = g_base64_encode(tmp, len);
505                 g_free(tmp);
506         }
507
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',
513                         config->port,
514                         config->tls_type,
515                         config->auth,
516                         config->auth_type,
517                         enc_userid ? enc_userid : "",
518                         enc_passwd ? enc_passwd : "");
519
520         if (enc_userid)
521                 g_free(enc_userid);
522         if (enc_passwd)
523                 g_free(enc_passwd);
524
525         prefs_account_set_privacy_prefs(account, "sieve", confstr);
526
527         g_free(confstr);
528
529         sieve_account_prefs_updated(account);
530 }
531
532 void sieve_prefs_account_free_config(SieveAccountConfig *config)
533 {
534         g_free(config->host);
535         g_free(config->userid);
536         g_free(config->passwd);
537         g_free(config);
538 }
539