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 
sieve_managers_done()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 
filters_list_clear(SieveManagerPage * page)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 
filters_list_delete_filter(SieveManagerPage * page,gchar * name)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 
filters_list_rename_filter(SieveManagerPage * page,gchar * name_old,char * name_new)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 
filters_list_insert_filter(SieveManagerPage * page,SieveScript * filter)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 
filters_list_get_selected_filter(GtkWidget * list_view)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 
filter_add(GtkWidget * widget,SieveManagerPage * page)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 
filter_got_load_error(SieveSession * session,gpointer data)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 
filter_edit(GtkWidget * widget,SieveManagerPage * page)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 
filter_renamed(SieveSession * session,gboolean abort,gboolean success,CommandDataRename * data)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 
filter_rename(GtkWidget * widget,SieveManagerPage * page)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 
filter_activated(SieveSession * session,gboolean abort,const gchar * err,CommandDataName * cmd_data)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 
sieve_set_active_filter(SieveManagerPage * page,gchar * filter_name)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 
filter_deleted(SieveSession * session,gboolean abort,const gchar * err_msg,CommandDataName * cmd_data)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 
filter_delete(GtkWidget * widget,SieveManagerPage * page)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 
filter_select(GtkWidget * list_view,GtkTreeModel * model,GtkTreeIter * iter)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  */
filter_search_equal_fn(GtkTreeModel * model,gint column,const gchar * key,GtkTreeIter * iter,gpointer search_data)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  */
filter_find_by_name(GtkTreeModel * model,GtkTreeIter * iter,gchar * filter_name)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 
filter_set_inactive(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)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  */
filter_set_active(SieveManagerPage * page,gchar * filter_name)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 
filter_active_toggled(GtkCellRendererToggle * widget,gchar * path,SieveManagerPage * page)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 
filter_double_clicked(GtkTreeView * list_view,GtkTreePath * path,GtkTreeViewColumn * column,SieveManagerPage * page)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 
filters_create_list_view_columns(SieveManagerPage * page,GtkWidget * list_view)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 
filters_create_data_store(void)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 
filters_list_view_create(SieveManagerPage * page)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 
manager_key_pressed(GtkWidget * widget,GdkEventKey * event,gpointer data)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 
size_allocate_cb(GtkWidget * widget,GtkAllocation * allocation)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 
got_session_error(SieveSession * session,const gchar * msg,SieveManagerPage * page)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 
sieve_manager_on_error(SieveSession * session,const gchar * msg,gpointer user_data)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 
sieve_manager_on_connected(SieveSession * session,gboolean connected,gpointer user_data)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 
got_filter_listed(SieveSession * session,gboolean abort,SieveScript * script,SieveManagerPage * page)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  */
account_changed(GtkWidget * widget,SieveManagerPage * page)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 
sieve_manager_page_new()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 	gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_DIALOG);
665 	MANAGE_WINDOW_SIGNALS_CONNECT (window);
666 
667 	g_signal_connect (G_OBJECT (window), "key_press_event",
668 			G_CALLBACK (manager_key_pressed), page);
669 	g_signal_connect (G_OBJECT(window), "size_allocate",
670 			 G_CALLBACK (size_allocate_cb), NULL);
671 	g_signal_connect (G_OBJECT(window), "delete_event",
672 			 G_CALLBACK (sieve_manager_deleted), page);
673 
674 	if (!geometry.min_height) {
675 		geometry.min_width = 350;
676 		geometry.min_height = 280;
677 	}
678 
679 	gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
680 				      GDK_HINT_MIN_SIZE);
681 	gtk_widget_set_size_request(window, sieve_config.manager_win_width,
682 			sieve_config.manager_win_height);
683 	gtk_window_set_type_hint(GTK_WINDOW(window),
684 			GDK_WINDOW_TYPE_HINT_DIALOG);
685 
686 	vbox = gtk_vbox_new (FALSE, 10);
687 	gtk_container_add (GTK_CONTAINER (window), vbox);
688 
689 	hbox = gtk_hbox_new (FALSE, 8);
690 	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
691 
692 	/* Accounts list */
693 
694 	label = gtk_label_new (_("Account"));
695 	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
696 
697 	accounts_menu = gtkut_sc_combobox_create(NULL, FALSE);
698 	menu = GTK_LIST_STORE(gtk_combo_box_get_model(GTK_COMBO_BOX(accounts_menu)));
699 	gtk_box_pack_start (GTK_BOX (hbox), accounts_menu, FALSE, FALSE, 0);
700 	g_signal_connect (G_OBJECT(accounts_menu), "changed",
701 			  G_CALLBACK (account_changed), page);
702 
703 	account_list = account_get_list();
704 	for (cur = account_list; cur != NULL; cur = cur->next) {
705 		ap = (PrefsAccount *)cur->data;
706 		config = sieve_prefs_account_get_config(ap);
707 		if (config->enable) {
708 			COMBOBOX_ADD (menu, ap->account_name, ap->account_id);
709 			if (!default_account || ap->is_default)
710 				default_account = ap;
711 		}
712 	}
713 
714 	if (!default_account) {
715 		gtk_widget_destroy(label);
716 		gtk_widget_destroy(accounts_menu);
717 		accounts_menu = NULL;
718 	}
719 
720 	/* status */
721 	status_text = gtk_label_new ("");
722 	gtk_box_pack_start (GTK_BOX (hbox), status_text, FALSE, FALSE, 0);
723 	gtk_label_set_justify (GTK_LABEL (status_text), GTK_JUSTIFY_LEFT);
724 
725 	/* Filters list */
726 
727 	hbox = gtk_hbox_new (FALSE, 8);
728 	gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
729 	gtk_container_set_border_width (GTK_CONTAINER (hbox), 2);
730 
731 	/* Table */
732 
733 	scrolledwin = gtk_scrolled_window_new (NULL, NULL);
734 	gtk_box_pack_start (GTK_BOX (hbox), scrolledwin, TRUE, TRUE, 0);
735 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwin),
736 					GTK_POLICY_AUTOMATIC,
737 					GTK_POLICY_AUTOMATIC);
738 
739 	list_view = filters_list_view_create(page);
740 	gtk_container_add(GTK_CONTAINER(scrolledwin), list_view);
741 
742 	/* Buttons */
743 
744 	vbox_allbuttons = gtk_vbox_new (FALSE, 8);
745 	gtk_box_pack_start (GTK_BOX (hbox), vbox_allbuttons, FALSE, FALSE, 0);
746 
747 	/* buttons that depend on there being a connection */
748 	vbox_buttons = gtk_vbox_new (FALSE, 8);
749 	gtk_widget_set_sensitive(vbox_buttons, FALSE);
750 	gtk_box_pack_start (GTK_BOX (vbox_allbuttons), vbox_buttons, FALSE, FALSE, 0);
751 
752 	/* new */
753 	btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
754 	gtk_box_pack_start (GTK_BOX (vbox_buttons), btn, FALSE, FALSE, 0);
755 	g_signal_connect (G_OBJECT(btn), "clicked",
756 			  G_CALLBACK (filter_add), page);
757 
758 	/* edit */
759 	btn = gtk_button_new_from_stock (GTK_STOCK_EDIT);
760 	gtk_box_pack_start (GTK_BOX (vbox_buttons), btn, FALSE, FALSE, 0);
761 	g_signal_connect (G_OBJECT(btn), "clicked",
762 			G_CALLBACK (filter_edit), page);
763 
764 	/* delete */
765 	btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
766 	gtk_box_pack_start (GTK_BOX (vbox_buttons), btn, FALSE, FALSE, 0);
767 	g_signal_connect (G_OBJECT(btn), "clicked",
768 			G_CALLBACK (filter_delete), page);
769 
770 	/* rename */
771 	btn = gtk_button_new_with_label(_("Rename"));
772 	gtk_box_pack_start (GTK_BOX (vbox_buttons), btn, FALSE, FALSE, 0);
773 	g_signal_connect (G_OBJECT(btn), "clicked",
774 			G_CALLBACK (filter_rename), page);
775 
776 	/* refresh */
777 	btn = gtk_button_new_from_stock(GTK_STOCK_REFRESH);
778 	gtk_box_pack_end (GTK_BOX (vbox_allbuttons), btn, FALSE, FALSE, 0);
779 	g_signal_connect (G_OBJECT(btn), "clicked",
780 			G_CALLBACK (account_changed), page);
781 
782 	/* bottom area stuff */
783 
784 	gtkut_stock_button_set_create(&hbox,
785 			&btn, GTK_STOCK_CLOSE,
786 			NULL, NULL, NULL, NULL);
787 
788 	/* close */
789 	gtk_box_pack_end (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
790 	gtk_widget_grab_default (btn);
791 	g_signal_connect (G_OBJECT (btn), "clicked",
792 			  G_CALLBACK (sieve_manager_close), page);
793 
794 	page->window = window;
795 	page->accounts_menu = accounts_menu;
796 	page->filters_list = list_view;
797 	page->status_text = status_text;
798 	page->vbox_buttons = vbox_buttons;
799 
800 	/* select default (first) account */
801 	if (default_account) {
802 		combobox_select_by_data(GTK_COMBO_BOX(accounts_menu),
803 				default_account->account_id);
804 	} else {
805 		gtk_label_set_text(GTK_LABEL(status_text),
806 				_("To use Sieve, enable it in an account's preferences."));
807 	}
808 
809 	return page;
810 }
811 
sieve_manager_deleted(GtkWidget * widget,GdkEvent * event,SieveManagerPage * page)812 static gboolean sieve_manager_deleted(GtkWidget *widget, GdkEvent *event,
813 		SieveManagerPage *page)
814 {
815 	sieve_manager_done(page);
816 	return FALSE;
817 }
818 
sieve_manager_close(GtkWidget * widget,SieveManagerPage * page)819 static void sieve_manager_close(GtkWidget *widget, SieveManagerPage *page)
820 {
821 	sieve_manager_done(page);
822 }
823 
sieve_manager_done(SieveManagerPage * page)824 void sieve_manager_done(SieveManagerPage *page)
825 {
826 	manager_pages = g_slist_remove(manager_pages, page);
827 	sieve_sessions_discard_callbacks(page);
828 	gtk_widget_destroy(page->window);
829 	g_free(page);
830 }
831 
sieve_manager_show()832 void sieve_manager_show()
833 {
834 	SieveManagerPage *page = sieve_manager_page_new();
835 	manager_pages = g_slist_prepend(manager_pages, page);
836 	gtk_widget_show_all(page->window);
837 }
838 
sieve_manager_script_created(SieveSession * session,const gchar * name)839 void sieve_manager_script_created(SieveSession *session, const gchar *name)
840 {
841 	SieveManagerPage *page;
842 	SieveScript script = {.name = (gchar *)name};
843 	GSList *cur;
844 
845 	manager_sessions_foreach(cur, session, page) {
846 		filters_list_insert_filter(page, &script);
847 	}
848 }
849