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 "gtk/inputdialog.h"
34 #include "gtk/manage_window.h"
35 #include "alertpanel.h"
39 #include "mainwindow.h"
40 #include "managesieve.h"
41 #include "sieve_editor.h"
42 #include "sieve_prefs.h"
43 #include "sieve_manager.h"
52 SieveManagerPage *page;
58 SieveManagerPage *page;
62 static void filter_got_load_error(SieveSession *session, gpointer data);
63 static void account_changed(GtkWidget *widget, SieveManagerPage *page);
64 static void sieve_manager_close(GtkWidget *widget, SieveManagerPage *page);
65 static gboolean sieve_manager_deleted(GtkWidget *widget, GdkEvent *event,
66 SieveManagerPage *page);
67 static void filter_set_active(SieveManagerPage *page, gchar *filter_name);
68 gboolean filter_find_by_name (GtkTreeModel *model, GtkTreeIter *iter,
70 static void got_session_error(SieveSession *session, const gchar *msg,
71 SieveManagerPage *page);
73 static GSList *manager_pages = NULL;
76 * Perform a command on all manager pages for a given session
78 #define manager_sessions_foreach(cur, session, page) \
79 for(cur = manager_pages; cur != NULL; cur = cur->next) \
80 if ((page = (SieveManagerPage *)cur->data) && \
81 page->active_session == session)
83 void sieve_managers_done()
85 GSList *list = manager_pages;
87 g_slist_free_full(list, (GDestroyNotify)sieve_manager_done);
90 static void filters_list_clear(SieveManagerPage *page)
92 GtkListStore *list_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(page->filters_list)));
93 gtk_list_store_clear(list_store);
94 page->got_list = FALSE;
97 static void filters_list_delete_filter(SieveManagerPage *page, gchar *name)
100 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(page->filters_list));
102 if (!filter_find_by_name(model, &iter, name))
105 gtk_list_store_remove(GTK_LIST_STORE(model), &iter);
109 static void filters_list_rename_filter(SieveManagerPage *page,
110 gchar *name_old, char *name_new)
113 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(page->filters_list));
115 if (!filter_find_by_name(model, &iter, name_old))
118 gtk_list_store_set(GTK_LIST_STORE(model), &iter,
119 FILTER_NAME, name_new,
123 static void filters_list_insert_filter(SieveManagerPage *page,
126 GtkListStore *list_store = GTK_LIST_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(page->filters_list)));
129 gtk_list_store_append(list_store, &iter);
130 gtk_list_store_set(list_store, &iter,
131 FILTER_NAME, filter->name,
132 FILTER_ACTIVE, filter->active,
136 static gchar *filters_list_get_selected_filter(GtkWidget *list_view)
138 GtkTreeSelection *selector;
143 selector = gtk_tree_view_get_selection(GTK_TREE_VIEW(list_view));
145 if (!gtk_tree_selection_get_selected(selector, &model, &iter))
148 gtk_tree_model_get(model, &iter, FILTER_NAME, &res, -1);
153 static void filter_add(GtkWidget *widget, SieveManagerPage *page)
155 SieveSession *session = page->active_session;
156 SieveEditorPage *editor;
159 gchar *filter_name = input_dialog(_("Add Sieve script"),
160 _("Enter name for a new Sieve filter script."), "");
161 if (!filter_name || !filter_name[0])
164 editor = sieve_editor_get(session, filter_name);
166 /* TODO: show error that filter already exists */
167 sieve_editor_present(editor);
169 sieve_editor_load(editor,
170 (sieve_session_cb_fn)filter_got_load_error, page);
172 editor = sieve_editor_new(session, filter_name);
173 editor->is_new = TRUE;
174 sieve_editor_show(editor);
178 static void filter_got_load_error(SieveSession *session, gpointer data)
180 SieveManagerPage *page = data;
182 got_session_error(session, _("Unable to get script contents"), page);
185 static void filter_edit(GtkWidget *widget, SieveManagerPage *page)
187 SieveEditorPage *editor;
188 SieveSession *session = page->active_session;
194 filter_name = filters_list_get_selected_filter(page->filters_list);
198 editor = sieve_editor_get(session, filter_name);
200 sieve_editor_present(editor);
202 editor = sieve_editor_new(session, filter_name);
203 sieve_editor_load(editor,
204 (sieve_session_cb_fn)filter_got_load_error, page);
210 static void filter_renamed(SieveSession *session, gboolean abort,
211 gboolean success, CommandDataRename *data)
213 SieveManagerPage *page = data->page;
217 } else if (!success) {
218 got_session_error(session, "Unable to rename script", page);
220 manager_sessions_foreach(cur, session, page) {
221 filters_list_rename_filter(page, data->name_old,
225 g_free(data->name_old);
226 g_free(data->name_new);
230 static void filter_rename(GtkWidget *widget, SieveManagerPage *page)
232 CommandDataRename *cmd_data;
233 gchar *name_old, *name_new;
234 SieveSession *session;
236 name_old = filters_list_get_selected_filter(page->filters_list);
240 session = page->active_session;
244 name_new = input_dialog(_("Add Sieve script"),
245 _("Enter new name for the script."), name_old);
249 cmd_data = g_new(CommandDataRename, 1);
250 cmd_data->name_new = name_new;
251 cmd_data->name_old = name_old;
252 cmd_data->page = page;
253 sieve_session_rename_script(session, name_old, name_new,
254 (sieve_session_data_cb_fn)filter_renamed, (gpointer)cmd_data);
257 static void filter_activated(SieveSession *session, gboolean abort,
258 const gchar *err, CommandDataName *cmd_data)
260 SieveManagerPage *page = cmd_data->page;
265 got_session_error(session, err, page);
267 manager_sessions_foreach(cur, session, page) {
268 filter_set_active(page, cmd_data->filter_name);
271 g_free(cmd_data->filter_name);
275 static void sieve_set_active_filter(SieveManagerPage *page, gchar *filter_name)
277 SieveSession *session;
278 CommandDataName *cmd_data;
280 session = page->active_session;
281 cmd_data = g_new(CommandDataName, 1);
282 cmd_data->filter_name = filter_name;
283 cmd_data->page = page;
285 sieve_session_set_active_script(session, filter_name,
286 (sieve_session_data_cb_fn)filter_activated, cmd_data);
289 static void filter_deleted(SieveSession *session, gboolean abort,
290 const gchar *err_msg,
291 CommandDataName *cmd_data)
293 SieveManagerPage *page = cmd_data->page;
297 } else if (err_msg) {
298 got_session_error(session, err_msg, page);
300 manager_sessions_foreach(cur, session, page) {
301 filters_list_delete_filter(page,
302 cmd_data->filter_name);
305 g_free(cmd_data->filter_name);
310 static void filter_delete(GtkWidget *widget, SieveManagerPage *page)
314 SieveSession *session;
315 CommandDataName *cmd_data;
317 filter_name = filters_list_get_selected_filter(page->filters_list);
318 if (filter_name == NULL)
321 session = page->active_session;
325 g_snprintf(buf, sizeof(buf),
326 _("Do you really want to delete the filter '%s'?"), filter_name);
327 if (alertpanel_full(_("Delete filter"), buf,
328 GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_FIRST, FALSE,
329 NULL, ALERT_WARNING) != G_ALERTALTERNATE)
332 cmd_data = g_new(CommandDataName, 1);
333 cmd_data->filter_name = filter_name;
334 cmd_data->page = page;
336 sieve_session_delete_script(session, filter_name,
337 (sieve_session_data_cb_fn)filter_deleted, cmd_data);
341 * select a filter in the list
343 * return TRUE is successfully selected, FALSE otherwise
346 static gboolean filter_select (GtkWidget *list_view, GtkTreeModel *model,
349 GtkTreeSelection *selection;
352 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list_view));
353 gtk_tree_selection_select_iter(selection, iter);
354 path = gtk_tree_model_get_path(model, iter);
355 if (path == NULL) return FALSE;
356 gtk_tree_view_set_cursor(GTK_TREE_VIEW(list_view), path, NULL, FALSE);
357 gtk_tree_path_free(path);
362 * find matching filter. return FALSE on match
364 static gboolean filter_search_equal_fn (GtkTreeModel *model, gint column,
365 const gchar *key, GtkTreeIter *iter, gpointer search_data)
367 SieveManagerPage *page = (SieveManagerPage *)search_data;
370 if (!key) return TRUE;
372 gtk_tree_model_get (model, iter, FILTER_NAME, &filter_name, -1);
374 if (strncmp (key, filter_name, strlen(key)) != 0) return TRUE;
375 return !filter_select(page->filters_list, model, iter);
379 * search for a filter row by its name. return true if found.
381 gboolean filter_find_by_name (GtkTreeModel *model, GtkTreeIter *iter,
386 if (!gtk_tree_model_get_iter_first (model, iter))
390 gtk_tree_model_get (model, iter, FILTER_NAME, &name, -1);
391 if (strcmp(filter_name, name) == 0) {
394 } while (gtk_tree_model_iter_next (model, iter));
398 static gboolean filter_set_inactive(GtkTreeModel *model,
399 GtkTreePath *path, GtkTreeIter *iter, gpointer data)
401 gtk_list_store_set(GTK_LIST_STORE(model), iter,
402 FILTER_ACTIVE, FALSE,
408 * Set the active filter in the table.
409 * @param filter_name The filter to make active (may be null)
411 static void filter_set_active(SieveManagerPage *page, gchar *filter_name)
414 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(page->filters_list));
416 /* Deactivate all filters */
417 gtk_tree_model_foreach(model, filter_set_inactive, NULL);
419 /* Set active filter */
421 if (!filter_find_by_name (model, &iter, filter_name))
424 gtk_list_store_set(GTK_LIST_STORE(model), &iter,
430 static void filter_active_toggled(GtkCellRendererToggle *widget,
432 SieveManagerPage *page)
437 GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(page->filters_list));
439 if (!gtk_tree_model_get_iter_from_string(model, &iter, path))
442 /* get existing value */
443 gtk_tree_model_get(model, &iter,
444 FILTER_NAME, &filter_name,
445 FILTER_ACTIVE, &active,
448 sieve_set_active_filter(page, active ? NULL : filter_name);
451 static void filter_double_clicked(GtkTreeView *list_view,
452 GtkTreePath *path, GtkTreeViewColumn *column,
453 SieveManagerPage *page)
455 filter_edit(GTK_WIDGET(list_view), page);
458 static void filters_create_list_view_columns(SieveManagerPage *page,
459 GtkWidget *list_view)
461 GtkTreeViewColumn *column;
462 GtkCellRenderer *renderer;
466 renderer = gtk_cell_renderer_text_new();
467 column = gtk_tree_view_column_new_with_attributes
468 (_("Name"), renderer,
471 gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);
472 gtk_tree_view_column_set_expand(column, TRUE);
475 renderer = gtk_cell_renderer_toggle_new();
476 g_object_set(renderer,
480 column = gtk_tree_view_column_new_with_attributes
481 (_("Active"), renderer,
482 "active", FILTER_ACTIVE,
484 gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);
485 gtk_tree_view_column_set_alignment (column, 0.5);
487 /* the column header needs a widget to have a tooltip */
488 label = gtk_label_new(gtk_tree_view_column_get_title(column));
489 gtk_widget_show(label);
490 gtk_tree_view_column_set_widget(column, label);
492 _("An account can only have one active script at a time."));
494 g_signal_connect(G_OBJECT(renderer), "toggled",
495 G_CALLBACK(filter_active_toggled), page);
497 gtk_tree_view_set_search_column(GTK_TREE_VIEW(list_view), FILTER_NAME);
498 gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(list_view),
499 filter_search_equal_fn, page, NULL);
503 static GtkListStore* filters_create_data_store(void)
505 return gtk_list_store_new(N_FILTER_COLUMNS,
506 G_TYPE_STRING, /* FILTER_NAME */
507 G_TYPE_BOOLEAN, /* FILTER_ACTIVE */
511 static GtkWidget *filters_list_view_create(SieveManagerPage *page)
513 GtkTreeView *list_view;
514 GtkTreeSelection *selector;
515 GtkListStore *store = filters_create_data_store();
517 list_view = GTK_TREE_VIEW(gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)));
518 g_object_unref(G_OBJECT(store));
520 selector = gtk_tree_view_get_selection(list_view);
521 gtk_tree_selection_set_mode(selector, GTK_SELECTION_BROWSE);
523 /* create the columns */
524 filters_create_list_view_columns(page, GTK_WIDGET(list_view));
526 /* set a double click listener */
527 g_signal_connect(G_OBJECT(list_view), "row_activated",
528 G_CALLBACK(filter_double_clicked),
531 return GTK_WIDGET(list_view);
534 static gboolean manager_key_pressed(GtkWidget *widget, GdkEventKey *event,
537 SieveManagerPage* page = (SieveManagerPage *) data;
539 if (event && event->keyval == GDK_KEY_Escape)
540 sieve_manager_done(page);
545 static void size_allocate_cb(GtkWidget *widget, GtkAllocation *allocation)
547 cm_return_if_fail(allocation != NULL);
549 sieve_config.manager_win_width = allocation->width;
550 sieve_config.manager_win_height = allocation->height;
553 static void got_session_error(SieveSession *session, const gchar *msg,
554 SieveManagerPage *page)
556 if (!g_slist_find(manager_pages, page))
558 if (page->active_session != session)
560 gtk_label_set_text(GTK_LABEL(page->status_text), msg);
563 static void sieve_manager_on_error(SieveSession *session,
564 const gchar *msg, gpointer user_data)
566 SieveManagerPage *page = (SieveManagerPage *)user_data;
567 got_session_error(session, msg, page);
570 static void sieve_manager_on_connected(SieveSession *session,
571 gboolean connected, gpointer user_data)
573 SieveManagerPage *page = (SieveManagerPage *)user_data;
574 if (page->active_session != session)
577 gtk_widget_set_sensitive(GTK_WIDGET(page->vbox_buttons), FALSE);
578 gtk_label_set_text(GTK_LABEL(page->status_text),
579 _("Unable to connect"));
583 static void got_filter_listed(SieveSession *session, gboolean abort,
584 SieveScript *script, SieveManagerPage *page)
589 got_session_error(session, "Unable to list scripts", page);
593 /* done receiving list */
594 page->got_list = TRUE;
595 gtk_widget_set_sensitive(GTK_WIDGET(page->vbox_buttons), TRUE);
596 gtk_label_set_text(GTK_LABEL(page->status_text), "");
599 filters_list_insert_filter(page, script);
603 * An account was selected from the menu. Get its list of scripts.
605 static void account_changed(GtkWidget *widget, SieveManagerPage *page)
608 PrefsAccount *account;
609 SieveSession *session;
611 if (page->accounts_menu == NULL)
614 account_id = combobox_get_active_data(GTK_COMBO_BOX(page->accounts_menu));
615 account = account_find_from_id(account_id);
618 session = page->active_session = sieve_session_get_for_account(account);
619 sieve_session_handle_status(session,
620 sieve_manager_on_error,
621 sieve_manager_on_connected,
623 filters_list_clear(page);
624 if (session_is_connected(SESSION(session))) {
625 gtk_label_set_text(GTK_LABEL(page->status_text),
626 _("Listing scripts..."));
628 gtk_label_set_text(GTK_LABEL(page->status_text),
631 sieve_session_list_scripts(session,
632 (sieve_session_data_cb_fn)got_filter_listed, (gpointer)page);
635 static SieveManagerPage *sieve_manager_page_new()
637 SieveManagerPage *page;
639 GtkWidget *hbox, *vbox, *vbox_allbuttons, *vbox_buttons;
640 GtkWidget *accounts_menu;
642 GtkWidget *scrolledwin;
643 GtkWidget *list_view;
645 GtkWidget *status_text;
648 GList *account_list, *cur;
650 SieveAccountConfig *config;
651 PrefsAccount *default_account = NULL;
653 static GdkGeometry geometry;
655 page = g_new0(SieveManagerPage, 1);
659 window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "sievemanager");
660 gtk_container_set_border_width (GTK_CONTAINER (window), 8);
661 gtk_window_set_title (GTK_WINDOW (window), _("Manage Sieve Filters"));
662 MANAGE_WINDOW_SIGNALS_CONNECT (window);
664 g_signal_connect (G_OBJECT (window), "key_press_event",
665 G_CALLBACK (manager_key_pressed), page);
666 g_signal_connect (G_OBJECT(window), "size_allocate",
667 G_CALLBACK (size_allocate_cb), NULL);
668 g_signal_connect (G_OBJECT(window), "delete_event",
669 G_CALLBACK (sieve_manager_deleted), page);
671 if (!geometry.min_height) {
672 geometry.min_width = 350;
673 geometry.min_height = 280;
676 gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
678 gtk_widget_set_size_request(window, sieve_config.manager_win_width,
679 sieve_config.manager_win_height);
680 gtk_window_set_type_hint(GTK_WINDOW(window),
681 GDK_WINDOW_TYPE_HINT_DIALOG);
683 vbox = gtk_vbox_new (FALSE, 10);
684 gtk_container_add (GTK_CONTAINER (window), vbox);
686 hbox = gtk_hbox_new (FALSE, 8);
687 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
691 label = gtk_label_new (_("Account"));
692 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
694 accounts_menu = gtkut_sc_combobox_create(NULL, FALSE);
695 menu = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(accounts_menu)));
696 gtk_box_pack_start (GTK_BOX (hbox), accounts_menu, FALSE, FALSE, 0);
697 g_signal_connect (G_OBJECT(accounts_menu), "changed",
698 G_CALLBACK (account_changed), page);
700 account_list = account_get_list();
701 for (cur = account_list; cur != NULL; cur = cur->next) {
702 ap = (PrefsAccount *)cur->data;
703 config = sieve_prefs_account_get_config(ap);
704 if (config->enable) {
705 COMBOBOX_ADD (menu, ap->account_name, ap->account_id);
706 if (!default_account || ap->is_default)
707 default_account = ap;
711 if (!default_account) {
712 gtk_widget_destroy(label);
713 gtk_widget_destroy(accounts_menu);
714 accounts_menu = NULL;
718 status_text = gtk_label_new ("");
719 gtk_box_pack_start (GTK_BOX (hbox), status_text, FALSE, FALSE, 0);
720 gtk_label_set_justify (GTK_LABEL (status_text), GTK_JUSTIFY_LEFT);
724 hbox = gtk_hbox_new (FALSE, 8);
725 gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
726 gtk_container_set_border_width (GTK_CONTAINER (hbox), 2);
730 scrolledwin = gtk_scrolled_window_new (NULL, NULL);
731 gtk_box_pack_start (GTK_BOX (hbox), scrolledwin, TRUE, TRUE, 0);
732 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwin),
733 GTK_POLICY_AUTOMATIC,
734 GTK_POLICY_AUTOMATIC);
736 list_view = filters_list_view_create(page);
737 gtk_container_add(GTK_CONTAINER(scrolledwin), list_view);
741 vbox_allbuttons = gtk_vbox_new (FALSE, 8);
742 gtk_box_pack_start (GTK_BOX (hbox), vbox_allbuttons, FALSE, FALSE, 0);
744 /* buttons that depend on there being a connection */
745 vbox_buttons = gtk_vbox_new (FALSE, 8);
746 gtk_widget_set_sensitive(vbox_buttons, FALSE);
747 gtk_box_pack_start (GTK_BOX (vbox_allbuttons), vbox_buttons, FALSE, FALSE, 0);
750 btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
751 gtk_box_pack_start (GTK_BOX (vbox_buttons), btn, FALSE, FALSE, 0);
752 g_signal_connect (G_OBJECT(btn), "clicked",
753 G_CALLBACK (filter_add), page);
756 btn = gtk_button_new_from_stock (GTK_STOCK_EDIT);
757 gtk_box_pack_start (GTK_BOX (vbox_buttons), btn, FALSE, FALSE, 0);
758 g_signal_connect (G_OBJECT(btn), "clicked",
759 G_CALLBACK (filter_edit), page);
762 btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
763 gtk_box_pack_start (GTK_BOX (vbox_buttons), btn, FALSE, FALSE, 0);
764 g_signal_connect (G_OBJECT(btn), "clicked",
765 G_CALLBACK (filter_delete), page);
768 btn = gtk_button_new_with_label(_("Rename"));
769 gtk_box_pack_start (GTK_BOX (vbox_buttons), btn, FALSE, FALSE, 0);
770 g_signal_connect (G_OBJECT(btn), "clicked",
771 G_CALLBACK (filter_rename), page);
774 btn = gtk_button_new_from_stock(GTK_STOCK_REFRESH);
775 gtk_box_pack_end (GTK_BOX (vbox_allbuttons), btn, FALSE, FALSE, 0);
776 g_signal_connect (G_OBJECT(btn), "clicked",
777 G_CALLBACK (account_changed), page);
779 /* bottom area stuff */
781 gtkut_stock_button_set_create(&hbox,
782 &btn, GTK_STOCK_CLOSE,
783 NULL, NULL, NULL, NULL);
786 gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
787 gtk_widget_grab_default (btn);
788 g_signal_connect (G_OBJECT (btn), "clicked",
789 G_CALLBACK (sieve_manager_close), page);
791 page->window = window;
792 page->accounts_menu = accounts_menu;
793 page->filters_list = list_view;
794 page->status_text = status_text;
795 page->vbox_buttons = vbox_buttons;
797 /* select default (first) account */
798 if (default_account) {
799 combobox_select_by_data(GTK_COMBO_BOX(accounts_menu),
800 default_account->account_id);
802 gtk_label_set_text(GTK_LABEL(status_text),
803 _("To use Sieve, enable it in an account's preferences."));
809 static gboolean sieve_manager_deleted(GtkWidget *widget, GdkEvent *event,
810 SieveManagerPage *page)
812 sieve_manager_done(page);
816 static void sieve_manager_close(GtkWidget *widget, SieveManagerPage *page)
818 sieve_manager_done(page);
821 void sieve_manager_done(SieveManagerPage *page)
823 manager_pages = g_slist_remove(manager_pages, page);
824 sieve_sessions_discard_callbacks(page);
825 gtk_widget_destroy(page->window);
829 void sieve_manager_show()
831 SieveManagerPage *page = sieve_manager_page_new();
832 manager_pages = g_slist_prepend(manager_pages, page);
833 gtk_widget_show_all(page->window);
836 void sieve_manager_script_created(SieveSession *session, const gchar *name)
838 SieveManagerPage *page;
839 SieveScript script = {.name = (gchar *)name};
842 manager_sessions_foreach(cur, session, page) {
843 filters_list_insert_filter(page, &script);