c3387065024916b47ab0725e982327b076da3892
[claws.git] / src / plugins / managesieve / sieve_manager.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 <gdk/gdkkeysyms.h>
28 #include <glib.h>
29 #include <glib/gi18n.h>
30
31 #include "defs.h"
32 #include "gtk/gtkutils.h"
33 #include "gtk/combobox.h"
34 #include "gtk/inputdialog.h"
35 #include "gtk/manage_window.h"
36 #include "alertpanel.h"
37 #include "utils.h"
38 #include "prefs.h"
39 #include "account.h"
40 #include "mainwindow.h"
41 #include "managesieve.h"
42 #include "sieve_editor.h"
43 #include "sieve_prefs.h"
44 #include "sieve_manager.h"
45
46 enum {
47         FILTER_NAME,
48         FILTER_ACTIVE,
49         N_FILTER_COLUMNS
50 };
51
52 typedef struct {
53         SieveManagerPage *page;
54         gchar *name_old;
55         gchar *name_new;
56 } CommandDataRename;
57
58 typedef struct {
59         SieveManagerPage *page;
60         gchar *filter_name;
61 } CommandDataName;
62
63 static void filter_got_load_error(SieveSession *session, gpointer data);
64 static void account_changed(GtkWidget *widget, SieveManagerPage *page);
65 static void sieve_manager_close(GtkWidget *widget, SieveManagerPage *page);
66 static gboolean sieve_manager_deleted(GtkWidget *widget, GdkEvent *event,
67                 SieveManagerPage *page);
68 static void filter_set_active(SieveManagerPage *page, gchar *filter_name);
69 gboolean filter_find_by_name (GtkTreeModel *model, GtkTreeIter *iter,
70                 gchar *filter_name);
71 static void got_session_error(SieveSession *session, const gchar *msg,
72                 SieveManagerPage *page);
73
74 static GSList *manager_pages = NULL;
75
76 /*
77  * Perform a command on all manager pages for a given session
78  */
79 #define manager_sessions_foreach(cur, session, page) \
80         for(cur = manager_pages; cur != NULL; cur = cur->next) \
81                 if ((page = (SieveManagerPage *)cur->data) && \
82                         page->active_session == session)
83
84 void sieve_managers_done()
85 {
86         GSList *list = manager_pages;
87         manager_pages = NULL;
88         g_slist_free_full(list, (GDestroyNotify)sieve_manager_done);
89 }
90
91 static void filters_list_clear(SieveManagerPage *page)
92 {
93         GtkListStore *list_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(page->filters_list)));
94         gtk_list_store_clear(list_store);
95         page->got_list = FALSE;
96 }
97
98 static void filters_list_delete_filter(SieveManagerPage *page, gchar *name)
99 {
100         GtkTreeIter iter;
101         GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(page->filters_list));
102
103         if (!filter_find_by_name(model, &iter, name))
104                 return;
105
106         gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
107 }
108
109
110 static void filters_list_rename_filter(SieveManagerPage *page,
111                 gchar *name_old, char *name_new)
112 {
113         GtkTreeIter iter;
114         GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(page->filters_list));
115
116         if (!filter_find_by_name(model, &iter, name_old))
117                 return;
118
119         gtk_list_store_set(GTK_LIST_STORE(model), &iter,
120                         FILTER_NAME, name_new,
121                         -1);
122 }
123
124 static void filters_list_insert_filter(SieveManagerPage *page,
125                 SieveScript *filter)
126 {
127         GtkListStore *list_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(page->filters_list)));
128         GtkTreeIter iter;
129
130         gtk_list_store_append(list_store, &iter);
131         gtk_list_store_set(list_store, &iter,
132                         FILTER_NAME, filter->name,
133                         FILTER_ACTIVE, filter->active,
134                         -1);
135 }
136
137 static gchar *filters_list_get_selected_filter(GtkWidget *list_view)
138 {
139         GtkTreeSelection *selector;
140         GtkTreeModel *model;
141         GtkTreeIter iter;
142         gchar *res = NULL;
143
144         selector = gtk_tree_view_get_selection(GTK_TREE_VIEW(list_view));
145
146         if (!gtk_tree_selection_get_selected(selector, &model, &iter))
147                 return NULL;
148
149         gtk_tree_model_get(model, &iter, FILTER_NAME, &res, -1);
150
151         return res;
152 }
153
154 static void filter_add(GtkWidget *widget, SieveManagerPage *page)
155 {
156         SieveSession *session = page->active_session;
157         SieveEditorPage *editor;
158         if (!session)
159                 return;
160         gchar *filter_name = input_dialog(_("Add Sieve script"),
161                         _("Enter name for a new Sieve filter script."), "");
162         if (!filter_name || !filter_name[0])
163                 return;
164
165         editor = sieve_editor_get(session, filter_name);
166         if (editor) {
167                 /* TODO: show error that filter already exists */
168                 sieve_editor_present(editor);
169                 g_free(filter_name);
170                 sieve_editor_load(editor,
171                         (sieve_session_cb_fn)filter_got_load_error, page);
172         } else {
173                 editor = sieve_editor_new(session, filter_name);
174                 editor->is_new = TRUE;
175                 sieve_editor_show(editor);
176         }
177 }
178
179 static void filter_got_load_error(SieveSession *session, gpointer data)
180 {
181         SieveManagerPage *page = data;
182
183         got_session_error(session, _("Unable to get script contents"), page);
184 }
185
186 static void filter_edit(GtkWidget *widget, SieveManagerPage *page)
187 {
188         SieveEditorPage *editor;
189         SieveSession *session = page->active_session;
190         gchar *filter_name;
191
192         if (!session)
193                 return;
194
195         filter_name = filters_list_get_selected_filter(page->filters_list);
196         if (!filter_name)
197                 return;
198
199         editor = sieve_editor_get(session, filter_name);
200         if (editor) {
201                 sieve_editor_present(editor);
202                 g_free(filter_name);
203         } else {
204                 editor = sieve_editor_new(session, filter_name);
205                 /* filter_name becomes ownership of newly created
206                  * SieveEditorPage, so we do not need to free it here. */
207                 sieve_editor_load(editor,
208                         (sieve_session_cb_fn)filter_got_load_error, page);
209         }
210 }
211
212 static void filter_renamed(SieveSession *session, gboolean abort,
213                 gboolean success, CommandDataRename *data)
214 {
215         SieveManagerPage *page = data->page;
216         GSList *cur;
217
218         if (abort) {
219         } else if (!success) {
220                 got_session_error(session, "Unable to rename script", page);
221         } else {
222                 manager_sessions_foreach(cur, session, page) {
223                         filters_list_rename_filter(page, data->name_old,
224                                         data->name_new);
225                 }
226         }
227         g_free(data->name_old);
228         g_free(data->name_new);
229         g_free(data);
230 }
231
232 static void filter_rename(GtkWidget *widget, SieveManagerPage *page)
233 {
234         CommandDataRename *cmd_data;
235         gchar *name_old, *name_new;
236         SieveSession *session;
237
238         name_old = filters_list_get_selected_filter(page->filters_list);
239         if (!name_old)
240                 return;
241
242         session = page->active_session;
243         if (!session)
244                 return;
245
246         name_new = input_dialog(_("Add Sieve script"),
247                         _("Enter new name for the script."), name_old);
248         if (!name_new)
249                 return;
250
251         cmd_data = g_new(CommandDataRename, 1);
252         cmd_data->name_new = name_new;
253         cmd_data->name_old = name_old;
254         cmd_data->page = page;
255         sieve_session_rename_script(session, name_old, name_new,
256                         (sieve_session_data_cb_fn)filter_renamed, (gpointer)cmd_data);
257 }
258
259 static void filter_activated(SieveSession *session, gboolean abort,
260                 const gchar *err, CommandDataName *cmd_data)
261 {
262         SieveManagerPage *page = cmd_data->page;
263         GSList *cur;
264
265         if (abort) {
266         } else if (err) {
267                 got_session_error(session, err, page);
268         } else {
269                 manager_sessions_foreach(cur, session, page) {
270                         filter_set_active(page, cmd_data->filter_name);
271                 }
272         }
273         g_free(cmd_data->filter_name);
274         g_free(cmd_data);
275 }
276
277 static void sieve_set_active_filter(SieveManagerPage *page, gchar *filter_name)
278 {
279         SieveSession *session;
280         CommandDataName *cmd_data;
281
282         session = page->active_session;
283         cmd_data = g_new(CommandDataName, 1);
284         cmd_data->filter_name = filter_name;
285         cmd_data->page = page;
286
287         sieve_session_set_active_script(session, filter_name,
288                         (sieve_session_data_cb_fn)filter_activated, cmd_data);
289 }
290
291 static void filter_deleted(SieveSession *session, gboolean abort,
292                 const gchar *err_msg,
293                 CommandDataName *cmd_data)
294 {
295         SieveManagerPage *page = cmd_data->page;
296         GSList *cur;
297
298         if (abort) {
299         } else if (err_msg) {
300                 got_session_error(session, err_msg, page);
301         } else {
302                 manager_sessions_foreach(cur, session, page) {
303                         filters_list_delete_filter(page,
304                                         cmd_data->filter_name);
305                 }
306         }
307         g_free(cmd_data->filter_name);
308         g_free(cmd_data);
309 }
310
311
312 static void filter_delete(GtkWidget *widget, SieveManagerPage *page)
313 {
314         gchar buf[256];
315         gchar *filter_name;
316         SieveSession *session;
317         CommandDataName *cmd_data;
318
319         filter_name = filters_list_get_selected_filter(page->filters_list);
320         if (filter_name == NULL)
321                 return;
322
323         session = page->active_session;
324         if (!session)
325                 return;
326
327         g_snprintf(buf, sizeof(buf),
328                    _("Do you really want to delete the filter '%s'?"), filter_name);
329         if (alertpanel_full(_("Delete filter"), buf,
330                                 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_FIRST, FALSE,
331                                 NULL, ALERT_WARNING) != G_ALERTALTERNATE)
332                 return;
333
334         cmd_data = g_new(CommandDataName, 1);
335         cmd_data->filter_name = filter_name;
336         cmd_data->page = page;
337
338         sieve_session_delete_script(session, filter_name,
339                         (sieve_session_data_cb_fn)filter_deleted, cmd_data);
340 }
341
342 /*
343  * select a filter in the list
344  *
345  * return TRUE is successfully selected, FALSE otherwise
346  */
347
348 static gboolean filter_select (GtkWidget *list_view, GtkTreeModel *model,
349                 GtkTreeIter *iter)
350 {
351         GtkTreeSelection *selection;
352         GtkTreePath* path;
353
354         selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list_view));
355         gtk_tree_selection_select_iter(selection, iter);
356         path = gtk_tree_model_get_path(model, iter);
357         if (path == NULL) return FALSE;
358         gtk_tree_view_set_cursor(GTK_TREE_VIEW(list_view), path, NULL, FALSE);
359         gtk_tree_path_free(path);
360         return TRUE;
361 }
362
363 /*
364  * find matching filter. return FALSE on match
365  */
366 static gboolean filter_search_equal_fn (GtkTreeModel *model, gint column,
367                 const gchar *key, GtkTreeIter *iter, gpointer search_data)
368 {
369         SieveManagerPage *page = (SieveManagerPage *)search_data;
370         gchar *filter_name;
371
372         if (!key) return TRUE;
373
374         gtk_tree_model_get (model, iter, FILTER_NAME, &filter_name, -1);
375
376         if (strncmp (key, filter_name, strlen(key)) != 0) return TRUE;
377         return !filter_select(page->filters_list, model, iter);
378 }
379
380 /*
381  * search for a filter row by its name. return true if found.
382  */
383 gboolean filter_find_by_name (GtkTreeModel *model, GtkTreeIter *iter,
384                 gchar *filter_name)
385 {
386         gchar *name;
387
388         if (!gtk_tree_model_get_iter_first (model, iter))
389                 return FALSE;
390
391         do {
392                 gtk_tree_model_get (model, iter, FILTER_NAME, &name, -1);
393                 if (strcmp(filter_name, name) == 0) {
394                         return TRUE;
395                 }
396         } while (gtk_tree_model_iter_next (model, iter));
397         return FALSE;
398 }
399
400 static gboolean filter_set_inactive(GtkTreeModel *model,
401                 GtkTreePath *path, GtkTreeIter *iter, gpointer data)
402 {
403         gtk_list_store_set(GTK_LIST_STORE(model), iter,
404                         FILTER_ACTIVE, FALSE,
405                         -1);
406         return FALSE;
407 }
408
409 /*
410  * Set the active filter in the table.
411  * @param filter_name The filter to make active (may be null)
412  */
413 static void filter_set_active(SieveManagerPage *page, gchar *filter_name)
414 {
415         GtkTreeIter iter;
416         GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(page->filters_list));
417
418         /* Deactivate all filters */
419         gtk_tree_model_foreach(model, filter_set_inactive, NULL);
420
421         /* Set active filter */
422         if (filter_name) {
423                 if (!filter_find_by_name (model, &iter, filter_name))
424                         return;
425
426                 gtk_list_store_set(GTK_LIST_STORE(model), &iter,
427                                 FILTER_ACTIVE, TRUE,
428                                 -1);
429         }
430 }
431
432 static void filter_active_toggled(GtkCellRendererToggle *widget,
433                                     gchar *path,
434                                     SieveManagerPage *page)
435 {
436         GtkTreeIter iter;
437         gchar *filter_name;
438         gboolean active;
439         GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(page->filters_list));
440
441         if (!gtk_tree_model_get_iter_from_string(model, &iter, path))
442                 return;
443
444         /* get existing value */
445         gtk_tree_model_get(model, &iter,
446                         FILTER_NAME, &filter_name,
447                         FILTER_ACTIVE, &active,
448                         -1);
449
450         sieve_set_active_filter(page, active ? NULL : filter_name);
451 }
452
453 static void filter_double_clicked(GtkTreeView *list_view,
454                                    GtkTreePath *path, GtkTreeViewColumn *column,
455                                    SieveManagerPage *page)
456 {
457         filter_edit(GTK_WIDGET(list_view), page);
458 }
459
460 static void filters_create_list_view_columns(SieveManagerPage *page,
461                 GtkWidget *list_view)
462 {
463         GtkTreeViewColumn *column;
464         GtkCellRenderer *renderer;
465         GtkWidget *label;
466
467         /* Name */
468         renderer = gtk_cell_renderer_text_new();
469         column = gtk_tree_view_column_new_with_attributes
470                 (_("Name"), renderer,
471                  "text", FILTER_NAME,
472                  NULL);
473         gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);
474         gtk_tree_view_column_set_expand(column, TRUE);
475
476         /* Active */
477         renderer = gtk_cell_renderer_toggle_new();
478         g_object_set(renderer,
479                      "radio", TRUE,
480                      "activatable", TRUE,
481                       NULL);
482         column = gtk_tree_view_column_new_with_attributes
483                 (_("Active"), renderer,
484                  "active", FILTER_ACTIVE,
485                  NULL);
486         gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);
487         gtk_tree_view_column_set_alignment (column, 0.5);
488
489         /* the column header needs a widget to have a tooltip */
490         label = gtk_label_new(gtk_tree_view_column_get_title(column));
491         gtk_widget_show(label);
492         gtk_tree_view_column_set_widget(column, label);
493         CLAWS_SET_TIP(label,
494                         _("An account can only have one active script at a time."));
495
496         g_signal_connect(G_OBJECT(renderer), "toggled",
497                          G_CALLBACK(filter_active_toggled), page);
498
499         gtk_tree_view_set_search_column(GTK_TREE_VIEW(list_view), FILTER_NAME);
500         gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(list_view),
501                         filter_search_equal_fn, page, NULL);
502 }
503
504
505 static GtkListStore* filters_create_data_store(void)
506 {
507         return gtk_list_store_new(N_FILTER_COLUMNS,
508                         G_TYPE_STRING,  /* FILTER_NAME */
509                         G_TYPE_BOOLEAN, /* FILTER_ACTIVE */
510                         -1);
511 }
512
513 static GtkWidget *filters_list_view_create(SieveManagerPage *page)
514 {
515         GtkTreeView *list_view;
516         GtkTreeSelection *selector;
517         GtkListStore *store = filters_create_data_store();
518
519         list_view = GTK_TREE_VIEW(gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)));
520         g_object_unref(G_OBJECT(store));
521
522         selector = gtk_tree_view_get_selection(list_view);
523         gtk_tree_selection_set_mode(selector, GTK_SELECTION_BROWSE);
524
525         /* create the columns */
526         filters_create_list_view_columns(page, GTK_WIDGET(list_view));
527
528         /* set a double click listener */
529         g_signal_connect(G_OBJECT(list_view), "row_activated",
530                         G_CALLBACK(filter_double_clicked),
531                         page);
532
533         return GTK_WIDGET(list_view);
534 }
535
536 static gboolean manager_key_pressed(GtkWidget *widget, GdkEventKey *event,
537                                     gpointer data)
538 {
539         SieveManagerPage* page = (SieveManagerPage *) data;
540
541         if (event && event->keyval == GDK_KEY_Escape)
542                 sieve_manager_done(page);
543
544         return FALSE;
545 }
546
547 static void size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation)
548 {
549         cm_return_if_fail(allocation != NULL);
550
551         sieve_config.manager_win_width = allocation->width;
552         sieve_config.manager_win_height = allocation->height;
553 }
554
555 static void got_session_error(SieveSession *session, const gchar *msg,
556                 SieveManagerPage *page)
557 {
558         if (!g_slist_find(manager_pages, page))
559                 return;
560         if (page->active_session != session)
561                 return;
562         gtk_label_set_text(GTK_LABEL(page->status_text), msg);
563 }
564
565 static void sieve_manager_on_error(SieveSession *session,
566                 const gchar *msg, gpointer user_data)
567 {
568         SieveManagerPage *page = (SieveManagerPage *)user_data;
569         got_session_error(session, msg, page);
570 }
571
572 static void sieve_manager_on_connected(SieveSession *session,
573                 gboolean connected, gpointer user_data)
574 {
575         SieveManagerPage *page = (SieveManagerPage *)user_data;
576         if (page->active_session != session)
577                 return;
578         if (!connected) {
579                 gtk_widget_set_sensitive(GTK_WIDGET(page->vbox_buttons), FALSE);
580                 gtk_label_set_text(GTK_LABEL(page->status_text),
581                                 _("Unable to connect"));
582         }
583 }
584
585 static void got_filter_listed(SieveSession *session, gboolean abort,
586                 SieveScript *script, SieveManagerPage *page)
587 {
588         if (abort)
589                 return;
590         if (!script) {
591                 got_session_error(session, "Unable to list scripts", page);
592                 return;
593         }
594         if (!script->name) {
595                 /* done receiving list */
596                 page->got_list = TRUE;
597                 gtk_widget_set_sensitive(GTK_WIDGET(page->vbox_buttons), TRUE);
598                 gtk_label_set_text(GTK_LABEL(page->status_text), "");
599                 return;
600         }
601         filters_list_insert_filter(page, script);
602 }
603
604 /*
605  * An account was selected from the menu. Get its list of scripts.
606  */
607 static void account_changed(GtkWidget *widget, SieveManagerPage *page)
608 {
609         gint account_id;
610         PrefsAccount *account;
611         SieveSession *session;
612
613         if (page->accounts_menu == NULL)
614                 return;
615
616         account_id = combobox_get_active_data(GTK_COMBO_BOX(page->accounts_menu));
617         account = account_find_from_id(account_id);
618         if (!account)
619                 return;
620         session = page->active_session = sieve_session_get_for_account(account);
621         sieve_session_handle_status(session,
622                         sieve_manager_on_error,
623                         sieve_manager_on_connected,
624                         page);
625         filters_list_clear(page);
626         if (session_is_connected(SESSION(session))) {
627                 gtk_label_set_text(GTK_LABEL(page->status_text),
628                                 _("Listing scripts..."));
629         } else {
630                 gtk_label_set_text(GTK_LABEL(page->status_text),
631                                 _("Connecting..."));
632         }
633         sieve_session_list_scripts(session,
634                         (sieve_session_data_cb_fn)got_filter_listed, (gpointer)page);
635 }
636
637 static SieveManagerPage *sieve_manager_page_new()
638 {
639         SieveManagerPage *page;
640         GtkWidget *window;
641         GtkWidget *hbox, *vbox, *vbox_allbuttons, *vbox_buttons;
642         GtkWidget *accounts_menu;
643         GtkWidget *label;
644         GtkWidget *scrolledwin;
645         GtkWidget *list_view;
646         GtkWidget *btn;
647         GtkWidget *status_text;
648         GtkTreeIter iter;
649         GtkListStore *menu;
650         GList *account_list, *cur;
651         PrefsAccount *ap;
652         SieveAccountConfig *config;
653         PrefsAccount *default_account = NULL;
654
655         static GdkGeometry geometry;
656
657         page = g_new0(SieveManagerPage, 1);
658
659         /* Manage Window */
660
661         window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "sievemanager");
662         gtk_container_set_border_width (GTK_CONTAINER (window), 8);
663         gtk_window_set_title (GTK_WINDOW (window), _("Manage Sieve Filters"));
664         MANAGE_WINDOW_SIGNALS_CONNECT (window);
665
666         g_signal_connect (G_OBJECT (window), "key_press_event",
667                         G_CALLBACK (manager_key_pressed), page);
668         g_signal_connect (G_OBJECT(window), "size_allocate",
669                          G_CALLBACK (size_allocate_cb), NULL);
670         g_signal_connect (G_OBJECT(window), "delete_event",
671                          G_CALLBACK (sieve_manager_deleted), page);
672
673         if (!geometry.min_height) {
674                 geometry.min_width = 350;
675                 geometry.min_height = 280;
676         }
677
678         gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
679                                       GDK_HINT_MIN_SIZE);
680         gtk_widget_set_size_request(window, sieve_config.manager_win_width,
681                         sieve_config.manager_win_height);
682         gtk_window_set_type_hint(GTK_WINDOW(window),
683                         GDK_WINDOW_TYPE_HINT_DIALOG);
684
685         vbox = gtk_vbox_new (FALSE, 10);
686         gtk_container_add (GTK_CONTAINER (window), vbox);
687
688         hbox = gtk_hbox_new (FALSE, 8);
689         gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
690
691         /* Accounts list */
692
693         label = gtk_label_new (_("Account"));
694         gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
695
696         accounts_menu = gtkut_sc_combobox_create(NULL, FALSE);
697         menu = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(accounts_menu)));
698         gtk_box_pack_start (GTK_BOX (hbox), accounts_menu, FALSE, FALSE, 0);
699         g_signal_connect (G_OBJECT(accounts_menu), "changed",
700                           G_CALLBACK (account_changed), page);
701
702         account_list = account_get_list();
703         for (cur = account_list; cur != NULL; cur = cur->next) {
704                 ap = (PrefsAccount *)cur->data;
705                 config = sieve_prefs_account_get_config(ap);
706                 if (config->enable) {
707                         COMBOBOX_ADD (menu, ap->account_name, ap->account_id);
708                         if (!default_account || ap->is_default)
709                                 default_account = ap;
710                 }
711         }
712
713         if (!default_account) {
714                 gtk_widget_destroy(label);
715                 gtk_widget_destroy(accounts_menu);
716                 accounts_menu = NULL;
717         }
718
719         /* status */
720         status_text = gtk_label_new ("");
721         gtk_box_pack_start (GTK_BOX (hbox), status_text, FALSE, FALSE, 0);
722         gtk_label_set_justify (GTK_LABEL (status_text), GTK_JUSTIFY_LEFT);
723
724         /* Filters list */
725
726         hbox = gtk_hbox_new (FALSE, 8);
727         gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
728         gtk_container_set_border_width (GTK_CONTAINER (hbox), 2);
729
730         /* Table */
731
732         scrolledwin = gtk_scrolled_window_new (NULL, NULL);
733         gtk_box_pack_start (GTK_BOX (hbox), scrolledwin, TRUE, TRUE, 0);
734         gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwin),
735                                         GTK_POLICY_AUTOMATIC,
736                                         GTK_POLICY_AUTOMATIC);
737
738         list_view = filters_list_view_create(page);
739         gtk_container_add(GTK_CONTAINER(scrolledwin), list_view);
740
741         /* Buttons */
742
743         vbox_allbuttons = gtk_vbox_new (FALSE, 8);
744         gtk_box_pack_start (GTK_BOX (hbox), vbox_allbuttons, FALSE, FALSE, 0);
745
746         /* buttons that depend on there being a connection */
747         vbox_buttons = gtk_vbox_new (FALSE, 8);
748         gtk_widget_set_sensitive(vbox_buttons, FALSE);
749         gtk_box_pack_start (GTK_BOX (vbox_allbuttons), vbox_buttons, FALSE, FALSE, 0);
750
751         /* new */
752         btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
753         gtk_box_pack_start (GTK_BOX (vbox_buttons), btn, FALSE, FALSE, 0);
754         g_signal_connect (G_OBJECT(btn), "clicked",
755                           G_CALLBACK (filter_add), page);
756
757         /* edit */
758         btn = gtk_button_new_from_stock (GTK_STOCK_EDIT);
759         gtk_box_pack_start (GTK_BOX (vbox_buttons), btn, FALSE, FALSE, 0);
760         g_signal_connect (G_OBJECT(btn), "clicked",
761                         G_CALLBACK (filter_edit), page);
762
763         /* delete */
764         btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
765         gtk_box_pack_start (GTK_BOX (vbox_buttons), btn, FALSE, FALSE, 0);
766         g_signal_connect (G_OBJECT(btn), "clicked",
767                         G_CALLBACK (filter_delete), page);
768
769         /* rename */
770         btn = gtk_button_new_with_label(_("Rename"));
771         gtk_box_pack_start (GTK_BOX (vbox_buttons), btn, FALSE, FALSE, 0);
772         g_signal_connect (G_OBJECT(btn), "clicked",
773                         G_CALLBACK (filter_rename), page);
774
775         /* refresh */
776         btn = gtk_button_new_from_stock(GTK_STOCK_REFRESH);
777         gtk_box_pack_end (GTK_BOX (vbox_allbuttons), btn, FALSE, FALSE, 0);
778         g_signal_connect (G_OBJECT(btn), "clicked",
779                         G_CALLBACK (account_changed), page);
780
781         /* bottom area stuff */
782
783         gtkut_stock_button_set_create(&hbox,
784                         &btn, GTK_STOCK_CLOSE,
785                         NULL, NULL, NULL, NULL);
786
787         /* close */
788         gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
789         gtk_widget_grab_default (btn);
790         g_signal_connect (G_OBJECT (btn), "clicked",
791                           G_CALLBACK (sieve_manager_close), page);
792
793         page->window = window;
794         page->accounts_menu = accounts_menu;
795         page->filters_list = list_view;
796         page->status_text = status_text;
797         page->vbox_buttons = vbox_buttons;
798
799         /* select default (first) account */
800         if (default_account) {
801                 combobox_select_by_data(GTK_COMBO_BOX(accounts_menu),
802                                 default_account->account_id);
803         } else {
804                 gtk_label_set_text(GTK_LABEL(status_text),
805                                 _("To use Sieve, enable it in an account's preferences."));
806         }
807
808         return page;
809 }
810
811 static gboolean sieve_manager_deleted(GtkWidget *widget, GdkEvent *event,
812                 SieveManagerPage *page)
813 {
814         sieve_manager_done(page);
815         return FALSE;
816 }
817
818 static void sieve_manager_close(GtkWidget *widget, SieveManagerPage *page)
819 {
820         sieve_manager_done(page);
821 }
822
823 void sieve_manager_done(SieveManagerPage *page)
824 {
825         manager_pages = g_slist_remove(manager_pages, page);
826         sieve_sessions_discard_callbacks(page);
827         gtk_widget_destroy(page->window);
828         g_free(page);
829 }
830
831 void sieve_manager_show()
832 {
833         SieveManagerPage *page = sieve_manager_page_new();
834         manager_pages = g_slist_prepend(manager_pages, page);
835         gtk_widget_show_all(page->window);
836 }
837
838 void sieve_manager_script_created(SieveSession *session, const gchar *name)
839 {
840         SieveManagerPage *page;
841         SieveScript script = {.name = (gchar *)name};
842         GSList *cur;
843
844         manager_sessions_foreach(cur, session, page) {
845                 filters_list_insert_filter(page, &script);
846         }
847 }