1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 1999-2015 Hiroyuki Yamamoto and the Claws Mail team
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19 
20 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #include "claws-features.h"
23 #endif
24 
25 #include "defs.h"
26 
27 #include <glib.h>
28 #include <glib/gi18n.h>
29 #include <gtk/gtk.h>
30 #include <gdk/gdkkeysyms.h>
31 #include <stdio.h>
32 #include <errno.h>
33 
34 #include "main.h"
35 #include "mainwindow.h"
36 #include "folderview.h"
37 #include "folder.h"
38 #include "account.h"
39 #include "prefs_gtk.h"
40 #include "prefs_account.h"
41 #include "prefs_common.h"
42 #include "folder_item_prefs.h"
43 #include "compose.h"
44 #include "manage_window.h"
45 #include "stock_pixmap.h"
46 #include "inc.h"
47 #include "gtkutils.h"
48 #include "utils.h"
49 #include "alertpanel.h"
50 #include "procheader.h"
51 #include "customheader.h"
52 #include "remotefolder.h"
53 #include "manual.h"
54 #include "filtering.h"
55 #include "prefs_actions.h"
56 #include "hooks.h"
57 #include "passwordstore.h"
58 #include "file-utils.h"
59 
60 enum {
61 	ACCOUNT_IS_DEFAULT,
62 	ACCOUNT_ENABLE_GET_ALL,
63 	ACCOUNT_NAME,
64 	ACCOUNT_PROTOCOL,
65 	ACCOUNT_SERVER,
66 	ACCOUNT_DATA,
67 	N_ACCOUNT_COLUMNS
68 };
69 
70 
71 typedef enum
72 {
73 	COL_DEFAULT	= 0,
74 	COL_GETALL,
75 	COL_NAME,
76 	COL_PROTOCOL,
77 	COL_SERVER,
78 	N_EDIT_ACCOUNT_COLS
79 } EditAccountColumnPos;
80 
81 PrefsAccount *cur_account;
82 
83 static GList *account_list = NULL;
84 static gboolean account_list_dirty = FALSE;
85 
86 static struct EditAccount {
87 	GtkWidget *window;
88 	GtkWidget *list_view;
89 	GtkWidget *close_btn;
90 } edit_account;
91 
92 static void account_edit_create		(void);
93 static void	      account_destroy		(PrefsAccount	*ac_prefs);
94 static void	      account_set_as_default	(PrefsAccount	*ac_prefs);
95 static void	      account_set_menu		(void);
96 
97 static void account_edit_prefs		(GtkWidget *widget, gpointer data);
98 static void account_delete		(GtkWidget *widget, gpointer data);
99 static void account_clone		(GtkWidget *widget, gpointer data);
100 
101 static void account_up			(GtkWidget *widget, gpointer data);
102 static void account_down		(GtkWidget *widget, gpointer data);
103 
104 static void account_set_default		(GtkWidget *widget, gpointer data);
105 
106 static void account_edit_close		(GtkWidget *widget, gpointer data);
107 
108 static gint account_delete_event	(GtkWidget	*widget,
109 					 GdkEventAny	*event,
110 					 gpointer	 data);
111 static void account_size_allocate_cb(GtkWidget *widget,
112 					 GtkAllocation *allocation);
113 static gboolean account_key_pressed	(GtkWidget	*widget,
114 					 GdkEventKey	*event,
115 					 gpointer	 data);
116 static gboolean account_search_func_cb (GtkTreeModel *model, gint column,
117 						const gchar *key, GtkTreeIter *iter,
118 						gpointer search_data);
119 static void account_list_view_set	(void);
120 
121 static void account_list_set		(void);
122 
123 typedef struct FindAccountInStore {
124 	gint		 account_id;
125 	GtkTreePath	*path;
126 	GtkTreeIter	 iter;
127 } FindAccountInStore;
128 
129 static GtkListStore* account_create_data_store	(void);
130 
131 static void account_list_store_insert_account_item (GtkListStore	*list_store,
132 						   PrefsAccount *account_data);
133 
134 static GtkWidget *account_list_view_create	(void);
135 static void account_create_list_view_columns	(GtkWidget *list_view);
136 
137 static gint account_list_view_get_selected_account_id		(GtkWidget *list_view);
138 static GtkTreePath *account_list_view_get_selected_account_path	(GtkWidget *list_view);
139 static PrefsAccount *account_list_view_get_selected_account		(GtkWidget *list_view);
140 static gboolean account_list_view_select_account			(GtkWidget *list_view,
141 								 gint	    account_id);
142 
143 static void account_list_view_set_default_by_id(GtkWidget *list_view,
144 						gint account_id);
145 
146 static gboolean set_new_default_account		(GtkTreeModel *model,
147 						 GtkTreePath  *path,
148 						 GtkTreeIter  *iter,
149 						 gint	      *account_id);
150 
151 static gboolean find_account_in_store		(GtkTreeModel *model,
152 						 GtkTreePath  *path,
153 						 GtkTreeIter  *iter,
154 						 FindAccountInStore *data);
155 
156 static void account_get_all_toggled		(GtkCellRendererToggle	*widget,
157 						 gchar			*path,
158 						 GtkWidget		*list_view);
159 
160 static void account_double_clicked		(GtkTreeView		*list_view,
161 						 GtkTreePath		*path,
162 						 GtkTreeViewColumn	*column,
163 						 gpointer		 data);
164 
165 static void drag_begin				(GtkTreeView *list_view,
166 						 GdkDragContext *context,
167 						 gpointer data);
168 
169 static void drag_end				(GtkTreeView *list_view,
170 						 GdkDragContext *context,
171 						 gpointer data);
172 
173 static void account_row_changed_while_drag_drop	(GtkTreeModel *model,
174 						 GtkTreePath  *path,
175 						 GtkTreeIter  *iter,
176 						 gpointer      arg3,
177 						 GtkTreeView  *list_view);
178 
account_flush_state(void)179 static void account_flush_state(void)
180 {
181 	account_set_menu();
182 	main_window_reflect_prefs_all();
183 
184 	account_list_dirty = FALSE;
185 }
186 
account_read_config_all(void)187 void account_read_config_all(void)
188 {
189 	GSList *ac_label_list = NULL, *cur;
190 	gchar *rcpath;
191 	FILE *fp;
192 	gchar buf[PREFSBUFSIZE];
193 	PrefsAccount *ac_prefs;
194 
195 	debug_print("Reading all config for each account...\n");
196 
197 	rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ACCOUNT_RC, NULL);
198 	if ((fp = claws_fopen(rcpath, "rb")) == NULL) {
199 		if (ENOENT != errno) FILE_OP_ERROR(rcpath, "claws_fopen");
200 		g_free(rcpath);
201 		return;
202 	}
203 	g_free(rcpath);
204 
205 	while (claws_fgets(buf, sizeof(buf), fp) != NULL) {
206 		if (!strncmp(buf, "[Account: ", 10)) {
207 			strretchomp(buf);
208 			memmove(buf, buf + 1, sizeof(buf) - 1);
209 			buf[strlen(buf) - 1] = '\0';
210 			debug_print("Found label: %s\n", buf);
211 			ac_label_list = g_slist_append(ac_label_list,
212 						       g_strdup(buf));
213 		}
214 	}
215 	claws_fclose(fp);
216 
217 	/* read config data from file */
218 	cur_account = NULL;
219 	for (cur = ac_label_list; cur != NULL; cur = cur->next) {
220 		ac_prefs = prefs_account_new_from_config((gchar *)cur->data);
221 		account_list = g_list_append(account_list, ac_prefs);
222 		if (ac_prefs->is_default)
223 			cur_account = ac_prefs;
224 	}
225 	/* if default is not set, assume first account as default */
226 	if (!cur_account && account_list) {
227 		ac_prefs = (PrefsAccount *)account_list->data;
228 		account_set_as_default(ac_prefs);
229 		cur_account = ac_prefs;
230 	}
231 
232 	account_set_menu();
233 	main_window_reflect_prefs_all_now();
234 
235 	while (ac_label_list) {
236 		g_free(ac_label_list->data);
237 		ac_label_list = g_slist_remove(ac_label_list,
238 					       ac_label_list->data);
239 	}
240 }
241 
account_write_config_all(void)242 void account_write_config_all(void)
243 {
244 	prefs_account_write_config_all(account_list);
245 }
246 
247 /*
248  * account_find_all_from_address:
249  * @ac_list: initial list of accounts. NULL to create a new one.
250  * Accounts found in the @address will be appended to this list.
251  * @address: Email address string.
252  *
253  * Find all the mail (not news) accounts within the specified address.
254  *
255  * Return value: the original accounts list with the found accounts appended.
256  */
account_find_all_from_address(GList * ac_list,const gchar * address)257 GList *account_find_all_from_address(GList *ac_list, const gchar *address)
258 {
259 	GList *cur;
260 	PrefsAccount *ac;
261 
262 	if (address == NULL)
263 		return ac_list;
264 
265 	for (cur = account_list; cur != NULL; cur = cur->next) {
266 		ac = (PrefsAccount *)cur->data;
267 		if (ac->protocol != A_NNTP && ac->address &&
268 		    strcasestr(address, ac->address) != NULL)
269 			ac_list = g_list_append(ac_list, ac);
270 	}
271 	return ac_list;
272 }
273 
account_find_all(void)274 GList *account_find_all(void)
275 {
276 	GList *cur;
277 	PrefsAccount *ac;
278 	GList *ac_list = NULL;
279 
280 	for (cur = account_list; cur != NULL; cur = cur->next) {
281 		ac = (PrefsAccount *)cur->data;
282 		ac_list = g_list_append(ac_list, ac);
283 	}
284 	return ac_list;
285 }
286 
account_find_from_smtp_server(const gchar * address,const gchar * smtp_server)287 PrefsAccount *account_find_from_smtp_server(const gchar *address,
288 					    const gchar *smtp_server)
289 {
290 	GList *cur;
291 	PrefsAccount *ac;
292 
293 	cm_return_val_if_fail(address != NULL, NULL);
294 	cm_return_val_if_fail(smtp_server != NULL, NULL);
295 
296 	for (cur = account_list; cur != NULL; cur = cur->next) {
297 		ac = (PrefsAccount *)cur->data;
298 		if (!g_strcmp0(address, ac->address) &&
299 		    !g_strcmp0(smtp_server, ac->smtp_server))
300 			return ac;
301 	}
302 
303 	return NULL;
304 }
305 
306 /*
307  * account_find_from_address:
308  * @address: Email address string.
309  *
310  * Find a mail (not news if newsgroups_ok is FALSE) account with the specified email address.
311  *
312  * Return value: The found account, or NULL if not found.
313  */
account_find_from_address(const gchar * address,gboolean newsgroups_ok)314 PrefsAccount *account_find_from_address(const gchar *address, gboolean newsgroups_ok)
315 {
316 	GList *cur;
317 	PrefsAccount *ac;
318 
319 	cm_return_val_if_fail(address != NULL, NULL);
320 
321 	for (cur = account_list; cur != NULL; cur = cur->next) {
322 		ac = (PrefsAccount *)cur->data;
323 		if ((ac->protocol != A_NNTP || newsgroups_ok) && ac->address &&
324 		    g_ascii_strcasecmp(address, ac->address) == 0)
325 			return ac;
326 	}
327 
328 	return NULL;
329 }
330 
account_find_from_id(gint id)331 PrefsAccount *account_find_from_id(gint id)
332 {
333 	GList *cur;
334 	PrefsAccount *ac;
335 
336 	for (cur = account_list; cur != NULL; cur = cur->next) {
337 		ac = (PrefsAccount *)cur->data;
338 		if (id == ac->account_id)
339 			return ac;
340 	}
341 
342 	return NULL;
343 }
344 
account_find_from_item(FolderItem * item)345 PrefsAccount *account_find_from_item(FolderItem *item)
346 {
347 	PrefsAccount *ac;
348 
349 	cm_return_val_if_fail(item != NULL, NULL);
350 
351 	ac = item->account;
352 	if (!ac) {
353 		FolderItem *cur_item = folder_item_parent(item);
354 		while (cur_item != NULL) {
355 			if (cur_item->account && cur_item->apply_sub) {
356 				ac = cur_item->account;
357 				break;
358 			}
359 			cur_item = folder_item_parent(cur_item);
360 		}
361 	}
362 	if (!ac)
363 		ac = item->folder->account;
364 
365 	return ac;
366 }
367 
account_set_menu(void)368 static void account_set_menu(void)
369 {
370 	main_window_set_account_menu(account_list);
371 }
372 
account_set_menu_only_toolbar(void)373 void account_set_menu_only_toolbar(void)
374 {
375 	main_window_set_account_menu_only_toolbar(account_list);
376 }
377 
account_get_list(void)378 GList *account_get_list(void)
379 {
380 	return account_list;
381 }
382 
account_edit_focus(void)383 void account_edit_focus(void)
384 {
385 	if (edit_account.window == NULL) {
386 		return;
387 	}
388 	manage_window_set_transient(GTK_WINDOW(edit_account.window));
389 	gtk_widget_grab_focus(edit_account.close_btn);
390 	gtk_widget_show(edit_account.window);
391 	gtk_window_set_modal(GTK_WINDOW(edit_account.window), TRUE);
392 	manage_window_focus_in(edit_account.window, NULL, NULL);
393 }
394 
account_edit_open(gpointer a,gpointer b)395 void account_edit_open(gpointer a, gpointer b)
396 {
397 	inc_lock();
398 
399 	account_list_dirty = FALSE;
400 
401 	if (compose_get_compose_list()) {
402 		alertpanel_error(_("Some composing windows are open.\n"
403 				   "Please close all the composing "
404 				   "windows before editing accounts."));
405 		inc_unlock();
406 		return;
407 	}
408 
409 	debug_print("Opening account edit window...\n");
410 
411 	if (!edit_account.window)
412 		account_edit_create();
413 
414 	account_list_view_set();
415 
416 	account_edit_focus();
417 }
418 
account_add(void)419 void account_add(void)
420 {
421 	PrefsAccount *ac_prefs;
422 
423 	ac_prefs = prefs_account_open(NULL, &account_list_dirty);
424 
425 	if (!ac_prefs) return;
426 
427 	account_edit_focus();
428 
429 	account_list = g_list_append(account_list, ac_prefs);
430 
431 	if (ac_prefs->is_default)
432 		account_set_as_default(ac_prefs);
433 
434 	account_list_view_set();
435 
436 	if (ac_prefs->protocol == A_IMAP4 || ac_prefs->protocol == A_NNTP) {
437 		Folder *folder;
438 
439 		if (ac_prefs->protocol == A_IMAP4) {
440 			folder = folder_new(folder_get_class_from_string("imap"), ac_prefs->account_name,
441 					    ac_prefs->recv_server);
442 		} else {
443 			folder = folder_new(folder_get_class_from_string("news"), ac_prefs->account_name,
444 					    ac_prefs->nntp_server);
445 		}
446 		if (folder == NULL) {
447 			alertpanel_error(_("Can't create folder."));
448 			return;
449 		}
450 		folder->account = ac_prefs;
451 		ac_prefs->folder = folder;
452 		folder_add(folder);
453 		if (ac_prefs->protocol == A_IMAP4)
454 			folder->klass->create_tree(folder);
455 		folderview_set_all();
456 		folder_write_list();
457 	}
458 }
459 
account_open(PrefsAccount * ac_prefs,gboolean called_from_acc_list)460 void account_open(PrefsAccount *ac_prefs, gboolean called_from_acc_list)
461 {
462 	gboolean prev_default;
463 	gchar *ac_name, *old_prefix, *new_prefix;
464 	gboolean account_dirty = FALSE;
465 
466 	cm_return_if_fail(ac_prefs != NULL);
467 
468 	if (compose_get_compose_list()) {
469 		alertpanel_error(_("Some composing windows are open.\n"
470 				   "Please close all the composing "
471 				   "windows before editing accounts."));
472 		return;
473 	}
474 
475 	prev_default = ac_prefs->is_default;
476 	Xstrdup_a(ac_name, ac_prefs->account_name ? ac_prefs->account_name : "",
477 		  return);
478 
479 	prefs_account_open(ac_prefs, &account_dirty);
480 
481 	if (called_from_acc_list)
482 		account_edit_focus();
483 
484 	if (account_dirty) {
485 		if (!prev_default && ac_prefs->is_default)
486 			account_set_as_default(ac_prefs);
487 
488 		if (ac_prefs->folder && g_strcmp0(ac_name, ac_prefs->account_name) != 0) {
489 			old_prefix = folder_get_identifier(FOLDER(ac_prefs->folder));
490 			folder_set_name(FOLDER(ac_prefs->folder),
491 					ac_prefs->account_name);
492 			folderview_set_all();
493 			folder_prefs_save_config_recursive(FOLDER(ac_prefs->folder));
494 			new_prefix = folder_get_identifier(FOLDER(ac_prefs->folder));
495 
496 			account_rename_path(old_prefix, new_prefix);
497 			prefs_filtering_rename_path(old_prefix, new_prefix);
498 			prefs_actions_rename_path(old_prefix, new_prefix);
499 
500 			g_free(old_prefix);
501 			g_free(new_prefix);
502 		}
503 
504 		account_write_config_all();
505 
506 		account_flush_state();
507 	}
508 }
509 
account_set_as_default(PrefsAccount * ac_prefs)510 static void account_set_as_default(PrefsAccount *ac_prefs)
511 {
512 	PrefsAccount *ap;
513 	GList *cur;
514 
515 	for (cur = account_list; cur != NULL; cur = cur->next) {
516 		ap = (PrefsAccount *)cur->data;
517 		if (ap->is_default)
518 			ap->is_default = FALSE;
519 	}
520 
521 	ac_prefs->is_default = TRUE;
522 }
523 
account_get_default(void)524 PrefsAccount *account_get_default(void)
525 {
526 	PrefsAccount *ap;
527 	GList *cur;
528 
529 	for (cur = account_list; cur != NULL; cur = cur->next) {
530 		ap = (PrefsAccount *)cur->data;
531 		if (ap->is_default)
532 			return ap;
533 	}
534 
535 	return NULL;
536 }
537 
account_set_missing_folder(void)538 void account_set_missing_folder(void)
539 {
540 	PrefsAccount *ap;
541 	GList *cur;
542 
543 	for (cur = account_list; cur != NULL; cur = cur->next) {
544 		ap = (PrefsAccount *)cur->data;
545 		if ((ap->protocol == A_IMAP4 || ap->protocol == A_NNTP) &&
546 		    !ap->folder) {
547 			Folder *folder;
548 
549 			if (ap->protocol == A_IMAP4) {
550 				folder = folder_new(folder_get_class_from_string("imap"), ap->account_name,
551 						    ap->recv_server);
552 			} else {
553 				folder = folder_new(folder_get_class_from_string("news"), ap->account_name,
554 						    ap->nntp_server);
555 			}
556 			if (folder == NULL)
557 				return;
558 			folder->account = ap;
559 			ap->folder = folder;
560 			folder_add(folder);
561 			if (ap->protocol == A_IMAP4)
562 				folder->klass->create_tree(folder);
563 			folder_write_list();
564 
565 		}
566 	}
567 }
568 
569 #define CHECK_CHANGE_FOLDER(folder) {						\
570 	if (folder && !strncmp(folder, old_id, strlen(old_id))) {		\
571 		if (strlen(folder) == strlen(old_id)) {				\
572 			g_free(folder);						\
573 			folder = g_strdup(new_id);				\
574 		} else if (strlen(folder) > strlen(old_id)			\
575 		  && folder[strlen(old_id)] == G_DIR_SEPARATOR) {		\
576 			gchar *new_path = g_strdup_printf("%s%s",		\
577 					new_id, (folder + strlen(old_id)));	\
578 			g_free(folder);						\
579 			folder = new_path;					\
580 		} 								\
581 	}									\
582 }
583 
account_rename_path(const gchar * old_id,const gchar * new_id)584 void account_rename_path(const gchar *old_id, const gchar *new_id)
585 {
586 	GList *cur = account_list;
587 	for (; cur != NULL; cur = g_list_next(cur)) {
588 		PrefsAccount *ap = (PrefsAccount *)cur->data;
589 		CHECK_CHANGE_FOLDER(ap->inbox);
590 		CHECK_CHANGE_FOLDER(ap->local_inbox);
591 		CHECK_CHANGE_FOLDER(ap->queue_folder);
592 		CHECK_CHANGE_FOLDER(ap->sent_folder);
593 		CHECK_CHANGE_FOLDER(ap->draft_folder);
594 		CHECK_CHANGE_FOLDER(ap->trash_folder);
595 	}
596 }
597 
account_get_special_folder(PrefsAccount * ac_prefs,SpecialFolderItemType type)598 FolderItem *account_get_special_folder(PrefsAccount *ac_prefs,
599 				       SpecialFolderItemType type)
600 {
601 	FolderItem *item = NULL;
602 
603 	cm_return_val_if_fail(ac_prefs != NULL, NULL);
604 
605 	switch (type) {
606 	case F_INBOX:
607 		if (ac_prefs->folder)
608 			item = FOLDER(ac_prefs->folder)->inbox;
609 		if (!item)
610 			item = folder_get_default_inbox();
611 		break;
612 	case F_OUTBOX:
613 		if (ac_prefs->set_sent_folder && ac_prefs->sent_folder) {
614 			item = folder_find_item_from_identifier
615 				(ac_prefs->sent_folder);
616 		}
617 		if (!item) {
618 			if (ac_prefs->folder)
619 				item = FOLDER(ac_prefs->folder)->outbox;
620 			if (!item)
621 				item = folder_get_default_outbox_for_class(F_MH);
622 			if (!item)
623 				item = folder_get_default_outbox();
624 		}
625 		break;
626 	case F_DRAFT:
627 		if (ac_prefs->set_draft_folder && ac_prefs->draft_folder) {
628 			item = folder_find_item_from_identifier
629 				(ac_prefs->draft_folder);
630 		}
631 		if (!item) {
632 			if (ac_prefs->folder)
633 				item = FOLDER(ac_prefs->folder)->draft;
634 			if (!item)
635 				item = folder_get_default_draft_for_class(F_MH);
636 			if (!item)
637 				item = folder_get_default_draft();
638 		}
639 		break;
640 	case F_QUEUE:
641 		if (ac_prefs->set_queue_folder && ac_prefs->queue_folder) {
642 			item = folder_find_item_from_identifier
643 				(ac_prefs->queue_folder);
644 		}
645 		if (!item) {
646 			if (ac_prefs->folder)
647 				item = FOLDER(ac_prefs->folder)->queue;
648 			if (!item)
649 				item = folder_get_default_queue_for_class(F_MH);
650 			if (!item)
651 				item = folder_get_default_queue();
652 		}
653 		break;
654 	case F_TRASH:
655 		if (ac_prefs->set_trash_folder && ac_prefs->trash_folder) {
656 			item = folder_find_item_from_identifier
657 				(ac_prefs->trash_folder);
658 		}
659 		if (!item) {
660 			if (ac_prefs->folder)
661 				item = FOLDER(ac_prefs->folder)->trash;
662 			if (!item)
663 				item = folder_get_default_trash_for_class(F_MH);
664 			if (!item)
665 				item = folder_get_default_trash();
666 		}
667 		break;
668 	default:
669 		break;
670 	}
671 
672 	return item;
673 }
674 
account_destroy(PrefsAccount * ac_prefs)675 void account_destroy(PrefsAccount *ac_prefs)
676 {
677 	cm_return_if_fail(ac_prefs != NULL);
678 
679 	folder_unref_account_all(ac_prefs);
680 
681 	account_list = g_list_remove(account_list, ac_prefs);
682 
683 	if (cur_account == ac_prefs) cur_account = NULL;
684 	if (!cur_account && account_list) {
685 		cur_account = account_get_default();
686 		if (!cur_account) {
687 			ac_prefs = (PrefsAccount *)account_list->data;
688 			account_set_as_default(ac_prefs);
689 			cur_account = ac_prefs;
690 		}
691 	}
692 }
693 
694 /*!
695  *\brief	Save Gtk object size to prefs dataset
696  */
account_size_allocate_cb(GtkWidget * widget,GtkAllocation * allocation)697 static void account_size_allocate_cb(GtkWidget *widget,
698 					 GtkAllocation *allocation)
699 {
700 	cm_return_if_fail(allocation != NULL);
701 
702 	prefs_common.accountswin_width = allocation->width;
703 	prefs_common.accountswin_height = allocation->height;
704 }
705 
account_edit_create(void)706 static void account_edit_create(void)
707 {
708 	GtkWidget *window;
709 	GtkWidget *vbox;
710 	GtkWidget *label;
711 	GtkWidget *hbox;
712 	GtkWidget *scrolledwin;
713 	GtkWidget *list_view;
714 
715 	GtkWidget *vbox2;
716 	GtkWidget *add_btn;
717 	GtkWidget *edit_btn;
718 	GtkWidget *del_btn;
719 	GtkWidget *clone_btn;
720 	GtkWidget *up_btn;
721 	GtkWidget *down_btn;
722 
723 	GtkWidget *default_btn;
724 
725 	GtkWidget *confirm_area;
726 	GtkWidget *help_btn;
727 	GtkWidget *close_btn;
728 
729 	static GdkGeometry geometry;
730 
731 	debug_print("Creating account edit window...\n");
732 
733 	window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "account");
734 	gtk_container_set_border_width (GTK_CONTAINER (window), 8);
735 	gtk_window_set_title (GTK_WINDOW (window), _("Edit accounts"));
736 	g_signal_connect (G_OBJECT (window), "delete_event",
737 			  G_CALLBACK (account_delete_event), NULL);
738 	g_signal_connect (G_OBJECT (window), "key_press_event",
739 			  G_CALLBACK (account_key_pressed), NULL);
740 	MANAGE_WINDOW_SIGNALS_CONNECT (window);
741 	gtk_widget_realize(window);
742 
743 	vbox = gtk_vbox_new (FALSE, 10);
744 	gtk_widget_show (vbox);
745 	gtk_container_add (GTK_CONTAINER (window), vbox);
746 
747 	hbox = gtk_hbox_new (FALSE, 0);
748 	gtk_widget_show (hbox);
749 	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
750 
751 	label = gtk_label_new
752 		(_("Using 'Get Mail' will retrieve messages from your Accounts "
753 		   "in the order given, the checkbox indicates which accounts "
754 		   "will be included. Bold text indicates the default account."));
755 	gtk_widget_show (label);
756 	gtk_widget_set_size_request(GTK_WIDGET(label),
757 				    prefs_common.accountswin_width-8, -1);
758 	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 4);
759 	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
760 	gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
761 
762 	hbox = gtk_hbox_new (FALSE, 8);
763 	gtk_widget_show (hbox);
764 	gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
765 	gtk_container_set_border_width (GTK_CONTAINER (hbox), 2);
766 
767 	scrolledwin = gtk_scrolled_window_new (NULL, NULL);
768 	gtk_widget_show (scrolledwin);
769 	gtk_box_pack_start (GTK_BOX (hbox), scrolledwin, TRUE, TRUE, 0);
770 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwin),
771 					GTK_POLICY_AUTOMATIC,
772 					GTK_POLICY_AUTOMATIC);
773 
774 	list_view = account_list_view_create();
775 	gtk_widget_show(list_view);
776 	gtk_container_add(GTK_CONTAINER(scrolledwin), list_view);
777 
778 	vbox2 = gtk_vbox_new (FALSE, 0);
779 	gtk_widget_show (vbox2);
780 	gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 0);
781 
782 	add_btn = gtk_button_new_from_stock(GTK_STOCK_NEW);
783 	gtk_widget_show (add_btn);
784 	gtk_box_pack_start (GTK_BOX (vbox2), add_btn, FALSE, FALSE, 4);
785 	g_signal_connect (G_OBJECT(add_btn), "clicked",
786 			  G_CALLBACK (account_add), NULL);
787 
788 	edit_btn = gtk_button_new_from_stock (GTK_STOCK_EDIT);
789 	gtk_widget_show (edit_btn);
790 	gtk_box_pack_start (GTK_BOX (vbox2), edit_btn, FALSE, FALSE, 4);
791 	g_signal_connect (G_OBJECT(edit_btn), "clicked",
792 			  G_CALLBACK (account_edit_prefs), NULL);
793 
794 	del_btn = gtk_button_new_from_stock(GTK_STOCK_DELETE);
795 	gtk_widget_show (del_btn);
796 	gtk_box_pack_start (GTK_BOX (vbox2), del_btn, FALSE, FALSE, 4);
797 	g_signal_connect (G_OBJECT(del_btn), "clicked",
798 			  G_CALLBACK (account_delete), NULL);
799 
800 	clone_btn = gtk_button_new_from_stock(GTK_STOCK_COPY);
801 	gtk_widget_show (clone_btn);
802 	gtk_box_pack_start (GTK_BOX (vbox2), clone_btn, FALSE, FALSE, 4);
803 	g_signal_connect(G_OBJECT(clone_btn), "clicked",
804 			 G_CALLBACK(account_clone), NULL);
805 
806 	down_btn = gtk_button_new_from_stock(GTK_STOCK_GO_DOWN);
807 	gtk_widget_show (down_btn);
808 	gtk_box_pack_end (GTK_BOX (vbox2), down_btn, FALSE, FALSE, 4);
809 	g_signal_connect (G_OBJECT(down_btn), "clicked",
810 			  G_CALLBACK (account_down), NULL);
811 
812 	up_btn = gtk_button_new_from_stock(GTK_STOCK_GO_UP);
813 	gtk_widget_show (up_btn);
814 	gtk_box_pack_end (GTK_BOX (vbox2), up_btn, FALSE, FALSE, 4);
815 	g_signal_connect (G_OBJECT(up_btn), "clicked",
816 			  G_CALLBACK (account_up), NULL);
817 
818 	hbox = gtk_hbox_new (FALSE, 8);
819 	gtk_widget_show (hbox);
820 	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
821 
822 	default_btn = gtk_button_new_with_mnemonic
823 		(_(" _Set as default account "));
824 	gtk_widget_show (default_btn);
825 	gtk_box_pack_start (GTK_BOX (hbox), default_btn, FALSE, FALSE, 0);
826 	g_signal_connect (G_OBJECT(default_btn), "clicked",
827 			  G_CALLBACK (account_set_default), NULL);
828 
829 	gtkut_stock_button_set_create_with_help(&confirm_area, &help_btn,
830 			&close_btn, GTK_STOCK_CLOSE,
831 			NULL, NULL, NULL, NULL);
832 	gtk_widget_show(confirm_area);
833 
834 	gtk_box_pack_end (GTK_BOX (hbox), confirm_area, FALSE, FALSE, 0);
835 	gtk_widget_grab_default (close_btn);
836 
837 	g_signal_connect (G_OBJECT (close_btn), "clicked",
838 			  G_CALLBACK (account_edit_close),
839 			  NULL);
840 	g_signal_connect(G_OBJECT(help_btn), "clicked",
841 			G_CALLBACK(manual_open_with_anchor_cb),
842 			MANUAL_ANCHOR_ACCOUNTPREFS);
843 
844 
845 	g_signal_connect(G_OBJECT(window), "size_allocate",
846 			 G_CALLBACK(account_size_allocate_cb), NULL);
847 
848 	if (!geometry.min_height) {
849 		geometry.min_width = 500;
850 		geometry.min_height = 380;
851 	}
852 
853 	gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
854 				      GDK_HINT_MIN_SIZE);
855 	gtk_widget_set_size_request(window, prefs_common.accountswin_width,
856 				    prefs_common.accountswin_height);
857 #ifdef G_OS_WIN32
858 	gtk_window_move(GTK_WINDOW(window), 48, 48);
859 #endif
860 
861 	edit_account.window    = window;
862 	edit_account.list_view = list_view;
863 	edit_account.close_btn = close_btn;
864 }
865 
account_edit_prefs(GtkWidget * widget,gpointer data)866 static void account_edit_prefs(GtkWidget *widget, gpointer data)
867 {
868 	PrefsAccount *ac_prefs;
869 
870 	ac_prefs = account_list_view_get_selected_account(edit_account.list_view);
871 
872 	if (ac_prefs) {
873 		account_open(ac_prefs, TRUE);
874 		account_list_view_set();
875 	}
876 }
877 
account_delete_references_func(GNode * node,gpointer data)878 static gboolean account_delete_references_func(GNode *node, gpointer data)
879 {
880 	FolderItem *item;
881 	gint account;
882 
883 	cm_return_val_if_fail(node->data != NULL, FALSE);
884 
885 	item = FOLDER_ITEM(node->data);
886 	account = GPOINTER_TO_INT(data);
887 
888 	if(!item->prefs) /* && item->prefs->stype == F_NORMAL */
889 		return FALSE;
890 	if(item->prefs->default_account != account)
891 		return FALSE;
892 
893 	item->prefs->enable_default_account = FALSE;
894 	item->prefs->default_account = 0;
895 	folder_item_prefs_save_config(item);
896 
897 	return FALSE;
898 }
899 
900 
901 #define ACP_FDUP(fld) ac_clon->fld = ((ac_prefs->fld) != NULL)?\
902 				     g_strdup(ac_prefs->fld): NULL
903 #define ACP_FASSIGN(fld) ac_clon->fld = ac_prefs->fld
account_clone(GtkWidget * widget,gpointer data)904 static void account_clone(GtkWidget *widget, gpointer data)
905 {
906 	PrefsAccount *ac_prefs, *ac_clon;
907 	GSList *hdrs = NULL;
908 	CustomHeader *cch = NULL, *ch = NULL;
909 
910 	ac_prefs = account_list_view_get_selected_account(edit_account.list_view);
911 	if (ac_prefs == NULL)
912 		return;
913 
914 	if (ac_prefs->protocol == A_IMAP4 || ac_prefs->protocol == A_NNTP) {
915 		alertpanel_error(_("Accounts with remote folders cannot be copied."));
916 		return;
917 	}
918 	account_list_dirty = TRUE;
919 
920 	ac_clon = prefs_account_new();
921 	/* copy fields */
922 	ac_clon->account_name = g_strdup_printf(_("Copy of %s"),
923 						ac_prefs->account_name);
924 	/* personal */
925 	ACP_FDUP(name);
926 	ACP_FDUP(address);
927 	ACP_FDUP(organization);
928 
929 	/* server */
930 	ACP_FASSIGN(protocol);
931 	ACP_FDUP(recv_server);
932 	ACP_FDUP(smtp_server);
933 	ACP_FDUP(nntp_server);
934 	ACP_FASSIGN(use_nntp_auth);
935 	ACP_FASSIGN(use_nntp_auth_onconnect);
936 	ACP_FDUP(userid);
937 	ACP_FDUP(passwd);
938 
939 	ACP_FDUP(local_mbox);
940 	ACP_FASSIGN(use_mail_command);
941 	ACP_FDUP(mail_command);
942 
943 	ACP_FASSIGN(ssl_pop);
944 	ACP_FASSIGN(ssl_imap);
945 	ACP_FASSIGN(ssl_nntp);
946 	ACP_FASSIGN(ssl_smtp);
947 	ACP_FASSIGN(ssl_certs_auto_accept);
948 	ACP_FASSIGN(use_nonblocking_ssl);
949 	ACP_FASSIGN(use_tls_sni);
950 	ACP_FASSIGN(in_ssl_client_cert_file);
951 	ACP_FASSIGN(in_ssl_client_cert_pass);
952 	ACP_FASSIGN(out_ssl_client_cert_file);
953 	ACP_FASSIGN(out_ssl_client_cert_pass);
954 
955 	/* receive */
956 	ACP_FASSIGN(use_pop_auth);
957     ACP_FASSIGN(pop_auth_type);
958 	ACP_FASSIGN(rmmail);
959 	ACP_FASSIGN(msg_leave_time);
960 	ACP_FASSIGN(msg_leave_hour);
961 	ACP_FASSIGN(recv_at_getall);
962 	ACP_FASSIGN(sd_rmmail_on_download);
963 	ACP_FASSIGN(enable_size_limit);
964 	ACP_FASSIGN(size_limit);
965 	ACP_FASSIGN(filter_on_recv);
966 	ACP_FASSIGN(filterhook_on_recv);
967 	ACP_FDUP(inbox);
968 	ACP_FDUP(local_inbox);
969 	ACP_FASSIGN(max_articles);
970 	ACP_FASSIGN(autochk_use_default);
971 	ACP_FASSIGN(autochk_use_custom);
972 	ACP_FASSIGN(autochk_itv);
973 	ac_clon->autocheck_timer = 0;
974 
975 	ACP_FASSIGN(imap_auth_type);
976 
977 	/* send */
978 	ACP_FASSIGN(gen_msgid);
979 	ACP_FASSIGN(gen_xmailer);
980 	ACP_FASSIGN(add_customhdr);
981 	ACP_FASSIGN(use_smtp_auth);
982 	ACP_FASSIGN(smtp_auth_type);
983 	ACP_FDUP(smtp_userid);
984 	ACP_FDUP(smtp_passwd);
985 
986 	ACP_FASSIGN(pop_before_smtp);
987 	ACP_FASSIGN(pop_before_smtp_timeout);
988 	ACP_FASSIGN(last_pop_login_time);
989 
990 	ac_clon->customhdr_list = NULL;
991 	hdrs = ac_prefs->customhdr_list;
992 	while (hdrs != NULL) {
993 		ch = (CustomHeader *)hdrs->data;
994 
995 		cch = g_new0(CustomHeader, 1);
996 		cch->account_id = ac_clon->account_id;
997 		cch->name = (ch->name != NULL) ? g_strdup(ch->name) : NULL;
998 		cch->value = (ch->value != NULL) ? g_strdup(ch->value) : NULL;
999 
1000 		ac_clon->customhdr_list = g_slist_append(ac_clon->customhdr_list, cch);
1001 
1002 		hdrs = g_slist_next(hdrs);
1003 	}
1004 
1005 	/* compose */
1006         ACP_FASSIGN(sig_type);
1007         ACP_FDUP(sig_path);
1008         ACP_FASSIGN(auto_sig);
1009         ACP_FDUP(sig_sep);
1010         ACP_FASSIGN(set_autocc);
1011         ACP_FDUP(auto_cc);
1012         ACP_FASSIGN(set_autobcc);
1013         ACP_FDUP(auto_bcc);
1014         ACP_FASSIGN(set_autoreplyto);
1015         ACP_FDUP(auto_replyto);
1016 	ACP_FASSIGN(enable_default_dictionary);
1017 	ACP_FDUP(default_dictionary);
1018 	ACP_FASSIGN(enable_default_alt_dictionary);
1019 	ACP_FDUP(default_alt_dictionary);
1020 	ACP_FASSIGN(compose_with_format);
1021 	ACP_FDUP(compose_subject_format);
1022 	ACP_FDUP(compose_body_format);
1023 	ACP_FASSIGN(reply_with_format);
1024 	ACP_FDUP(reply_quotemark);
1025 	ACP_FDUP(reply_body_format);
1026 	ACP_FASSIGN(forward_with_format);
1027 	ACP_FDUP(forward_quotemark);
1028 	ACP_FDUP(forward_body_format);
1029 
1030         /* privacy */
1031 	ACP_FDUP(default_privacy_system);
1032         ACP_FASSIGN(default_encrypt);
1033 	ACP_FASSIGN(default_encrypt_reply);
1034         ACP_FASSIGN(default_sign);
1035 	ACP_FASSIGN(default_sign_reply);
1036 	ACP_FASSIGN(save_encrypted_as_clear_text);
1037 	ACP_FASSIGN(encrypt_to_self);
1038 
1039         /* advanced */
1040         ACP_FASSIGN(set_smtpport);
1041         ACP_FASSIGN(smtpport);
1042         ACP_FASSIGN(set_popport);
1043         ACP_FASSIGN(popport);
1044         ACP_FASSIGN(set_imapport);
1045         ACP_FASSIGN(imapport);
1046         ACP_FASSIGN(set_nntpport);
1047         ACP_FASSIGN(nntpport);
1048         ACP_FASSIGN(set_domain);
1049         ACP_FDUP(domain);
1050         ACP_FASSIGN(mark_crosspost_read);
1051         ACP_FASSIGN(crosspost_col);
1052 
1053 #ifndef G_OS_WIN32
1054         ACP_FASSIGN(set_tunnelcmd);
1055         ACP_FDUP(tunnelcmd);
1056 #endif
1057 
1058         ACP_FDUP(imap_dir);
1059 	ACP_FASSIGN(imap_subsonly);
1060 	ACP_FASSIGN(low_bandwidth);
1061 
1062         ACP_FASSIGN(set_sent_folder);
1063         ACP_FDUP(sent_folder);
1064 	ACP_FASSIGN(set_queue_folder);
1065 	ACP_FDUP(queue_folder);
1066         ACP_FASSIGN(set_draft_folder);
1067         ACP_FDUP(draft_folder);
1068         ACP_FASSIGN(set_trash_folder);
1069         ACP_FDUP(trash_folder);
1070 	/* don't want two default accounts */
1071 	ac_clon->is_default = FALSE;
1072 	ACP_FASSIGN(folder);
1073 
1074 	ACP_FASSIGN(config_version);
1075 
1076 	ACP_FASSIGN(use_proxy);
1077 	ACP_FASSIGN(use_default_proxy);
1078 	ACP_FASSIGN(use_proxy_for_send);
1079 	ACP_FASSIGN(proxy_info.proxy_type);
1080 	ACP_FDUP(proxy_info.proxy_host);
1081 	ACP_FASSIGN(proxy_info.proxy_port);
1082 	ACP_FASSIGN(proxy_info.use_proxy_auth);
1083 	ACP_FDUP(proxy_info.proxy_name);
1084 	ACP_FDUP(proxy_info.proxy_pass);
1085 
1086 	account_list = g_list_append(account_list, ac_clon);
1087 	account_list_view_set();
1088 }
1089 #undef ACP_FDUP
1090 #undef ACP_FASSIGN
1091 
account_empty_cache(PrefsAccount * ac_prefs)1092 static void account_empty_cache(PrefsAccount *ac_prefs)
1093 {
1094 	gchar *cache_dir;
1095 
1096 	cache_dir = prefs_account_cache_dir(ac_prefs, FALSE);
1097 	if (cache_dir == NULL)
1098 		return; /* no cache dir, nothing to do */
1099 
1100 	if (is_dir_exist(cache_dir) && remove_dir_recursive(cache_dir) < 0) {
1101 		g_warning("can't remove directory '%s'", cache_dir);
1102 	} else {
1103 		gchar *server_dir =  prefs_account_cache_dir(ac_prefs, TRUE);
1104 		if (g_rmdir(server_dir) == 0)
1105 			debug_print("Removed empty cache server directory\n");
1106 		else
1107 			debug_print("Cache server directory not empty: not removed\n");
1108 		g_free(server_dir);
1109 	}
1110 	g_free(cache_dir);
1111 }
1112 
account_delete(GtkWidget * widget,gpointer data)1113 static void account_delete(GtkWidget *widget, gpointer data)
1114 {
1115 	PrefsAccount *ac_prefs;
1116 	gchar buf[BUFFSIZE];
1117 	GList *list;
1118 	Folder *folder;
1119 	GSList *cur;
1120 
1121  	ac_prefs = account_list_view_get_selected_account(edit_account.list_view);
1122  	if (ac_prefs == NULL)
1123  		return;
1124 
1125 	g_snprintf(buf, sizeof(buf),
1126 		   _("Do you really want to delete the account '%s'?"),
1127 		   ac_prefs->account_name ? ac_prefs->account_name :
1128 		   _("(Untitled)"));
1129 	if (alertpanel_full(_("Delete account"), buf,
1130 		 	    GTK_STOCK_CANCEL, GTK_STOCK_DELETE, NULL, ALERTFOCUS_FIRST, FALSE,
1131 			    NULL, ALERT_WARNING) != G_ALERTALTERNATE)
1132 		return;
1133 	account_list_dirty = TRUE;
1134 
1135 	if (ac_prefs->folder) {
1136 		FolderItem *item;
1137 
1138 		item = mainwindow_get_mainwindow()->summaryview->folder_item;
1139 		if (item && item->folder == FOLDER(ac_prefs->folder))
1140 			summary_clear_all(mainwindow_get_mainwindow()->summaryview);
1141 		folder_destroy(FOLDER(ac_prefs->folder));
1142 		folderview_set_all();
1143 	}
1144 
1145 	inc_account_autocheck_timer_remove(ac_prefs);
1146 
1147 	account_destroy(ac_prefs);
1148 	account_list_view_set();
1149 
1150 	debug_print("Removing deleted account references for all the folders...\n");
1151 	list = folder_get_list();
1152 	for (; list != NULL; list = list->next) {
1153 		folder = FOLDER(list->data);
1154 		if (folder->node)  /* && folder->type == F_? */
1155 			g_node_traverse(folder->node, G_PRE_ORDER,
1156 				G_TRAVERSE_ALL, -1,
1157 				account_delete_references_func,
1158 				GINT_TO_POINTER(ac_prefs->account_id));
1159 	}
1160 
1161 	gchar *uid = g_strdup_printf("%d", ac_prefs->account_id);
1162 	passwd_store_delete_block(PWS_ACCOUNT, uid);
1163 	g_free(uid);
1164 
1165 	debug_print("Removing filter rules relative to this account...\n");
1166 	for(cur = filtering_rules ; cur != NULL ;) {
1167 		FilteringProp * prop = (FilteringProp *) cur->data;
1168 
1169 		if (prop && (prop->account_id == ac_prefs->account_id)) {
1170 			/* get next item before we kill the current one */
1171 			cur = g_slist_next(cur);
1172 
1173 			/* unallocate filteringprop and unchain it from the list */
1174 			filteringprop_free(prop);
1175 			filtering_rules = g_slist_remove(filtering_rules, prop);
1176 		} else {
1177 			cur = g_slist_next(cur);
1178 		}
1179 	}
1180 
1181 	debug_print("Removing cache directory of this account...\n");
1182 	account_empty_cache(ac_prefs);
1183 
1184 	folder_write_list();
1185 }
1186 
account_up(GtkWidget * widget,gpointer data)1187 static void account_up(GtkWidget *widget, gpointer data)
1188 {
1189 	GtkTreePath *sel = account_list_view_get_selected_account_path
1190 				(edit_account.list_view),
1191 		    *up;
1192 	GtkTreeIter isel, iup;
1193 	GtkTreeModel *model = gtk_tree_view_get_model
1194 				(GTK_TREE_VIEW(edit_account.list_view));
1195 
1196 	if (!sel)
1197 		return;
1198 	account_list_dirty = TRUE;
1199 
1200 	up = gtk_tree_path_copy(sel);
1201 	if (!up) {
1202 		gtk_tree_path_free(sel);
1203 		return;
1204 	}
1205 
1206 	if (!gtk_tree_path_prev(up)) {
1207 		gtk_tree_path_free(up);
1208 		gtk_tree_path_free(sel);
1209 		return;
1210 	}
1211 
1212 	if (!gtk_tree_model_get_iter(model, &isel, sel)
1213 	||  !gtk_tree_model_get_iter(model, &iup,  up)) {
1214 		gtk_tree_path_free(up);
1215 		gtk_tree_path_free(sel);
1216 		return;
1217 	}
1218 
1219 	gtk_list_store_swap(GTK_LIST_STORE(model), &isel, &iup);
1220 
1221 	account_list_set();
1222 
1223 	gtk_tree_path_free(up);
1224 	gtk_tree_path_free(sel);
1225 }
1226 
account_down(GtkWidget * widget,gpointer data)1227 static void account_down(GtkWidget *widget, gpointer data)
1228 {
1229 	GtkTreePath *sel = account_list_view_get_selected_account_path
1230 				(edit_account.list_view),
1231 		    *dn;
1232 	GtkTreeIter isel, idn;
1233 	GtkTreeModel *model = gtk_tree_view_get_model
1234 				(GTK_TREE_VIEW(edit_account.list_view));
1235 
1236 	if (!sel)
1237 		return;
1238 	account_list_dirty = TRUE;
1239 
1240 	dn = gtk_tree_path_copy(sel);
1241 	if (!dn) {
1242 		gtk_tree_path_free(sel);
1243 		return;
1244 	}
1245 
1246 	/* XXX no check possible??? however, if down but at bottom, then
1247 	 * nothing seems to happen much anyway, so the following seems to
1248 	 * be okay */
1249 	gtk_tree_path_next(dn);
1250 
1251 	if (!gtk_tree_model_get_iter(model, &isel, sel)
1252 	||  !gtk_tree_model_get_iter(model, &idn,  dn)) {
1253 		gtk_tree_path_free(dn);
1254 		gtk_tree_path_free(sel);
1255 		return;
1256 	}
1257 
1258 	gtk_list_store_swap(GTK_LIST_STORE(model), &isel, &idn);
1259 
1260 	account_list_set();
1261 
1262 	gtk_tree_path_free(dn);
1263 	gtk_tree_path_free(sel);
1264 }
1265 
account_set_default(GtkWidget * widget,gpointer data)1266 static void account_set_default(GtkWidget *widget, gpointer data)
1267 {
1268 	PrefsAccount *ac_prefs;
1269 
1270 	if (NULL == (ac_prefs = account_list_view_get_selected_account
1271 					(edit_account.list_view)))
1272 		return;
1273 
1274 	/* we need to change the store variables by resetting everything
1275 	 * and setting the new default one */
1276 	account_list_view_set_default_by_id(edit_account.list_view,
1277 					    ac_prefs->account_id);
1278 
1279 	account_set_as_default(ac_prefs);
1280 	account_list_view_set();
1281 
1282 	cur_account = ac_prefs;
1283 	account_flush_state();
1284 }
1285 
account_edit_close(GtkWidget * widget,gpointer data)1286 static void account_edit_close(GtkWidget *widget, gpointer data)
1287 {
1288 	account_list_set();
1289 	account_write_config_all();
1290 
1291 	if (!cur_account && account_list) {
1292 		PrefsAccount *ac_prefs = (PrefsAccount *)account_list->data;
1293 		account_set_as_default(ac_prefs);
1294 		cur_account = ac_prefs;
1295 	}
1296 
1297 	if (account_list_dirty)
1298 		account_flush_state();
1299 
1300 	gtk_widget_hide(edit_account.window);
1301 	gtk_window_set_modal(GTK_WINDOW(edit_account.window), FALSE);
1302 	inc_unlock();
1303 }
1304 
account_delete_event(GtkWidget * widget,GdkEventAny * event,gpointer data)1305 static gint account_delete_event(GtkWidget *widget, GdkEventAny *event,
1306 				 gpointer data)
1307 {
1308 	account_edit_close(NULL, NULL);
1309 	return TRUE;
1310 }
1311 
account_key_pressed(GtkWidget * widget,GdkEventKey * event,gpointer data)1312 static gboolean account_key_pressed(GtkWidget *widget, GdkEventKey *event,
1313 				    gpointer data)
1314 {
1315 	if (event && event->keyval == GDK_KEY_Escape)
1316 		account_edit_close(NULL, NULL);
1317 	return FALSE;
1318 }
1319 
account_search_func_cb(GtkTreeModel * model,gint column,const gchar * key,GtkTreeIter * iter,gpointer search_data)1320 static gboolean account_search_func_cb (GtkTreeModel *model, gint column, const gchar *key,
1321 						GtkTreeIter *iter, gpointer search_data)
1322 {
1323 	gboolean retval;
1324 	PrefsAccount *ac;
1325 
1326 	gtk_tree_model_get (model, iter, ACCOUNT_DATA, &ac, -1);
1327 
1328 	if (!ac->name || !key) return FALSE;
1329 
1330 	retval = (strncmp (key, ac->account_name, strlen(key)) != 0);
1331 
1332 	debug_print("selecting row\n");
1333 	account_list_view_select_account(edit_account.list_view, ac->account_id);
1334 
1335 	return retval;
1336 }
1337 
account_list_view_set(void)1338 static void account_list_view_set(void)
1339 {
1340 	GList *cur;
1341 	gint prev_sel_account;
1342 	GtkListStore *store;
1343 
1344 	store = GTK_LIST_STORE(gtk_tree_view_get_model
1345 		(GTK_TREE_VIEW(edit_account.list_view)));
1346 
1347 	prev_sel_account = account_list_view_get_selected_account_id
1348 		(edit_account.list_view);
1349 
1350 	gtk_list_store_clear(store);
1351 
1352 	for (cur = account_list; cur != NULL; cur = cur->next) {
1353 		account_list_store_insert_account_item(store, (PrefsAccount *)cur->data);
1354 		if ((PrefsAccount *)cur->data == cur_account)
1355 			account_list_view_select_account
1356 				(edit_account.list_view,
1357 				 cur_account->account_id);
1358 	}
1359 
1360 	if (prev_sel_account >= 0)
1361 		account_list_view_select_account(edit_account.list_view,
1362 						 prev_sel_account);
1363 }
1364 
1365 /* set account list from CList */
account_list_set(void)1366 static void account_list_set(void)
1367 {
1368 	/* want to make sure we iterate *IN ORDER*, so therefore using
1369 	 * gtk_tree_model_XXXX_nth_child() */
1370 	gint row, n_rows;
1371 	PrefsAccount *ac_prefs;
1372 	GtkTreeModel *model = gtk_tree_view_get_model
1373 				(GTK_TREE_VIEW(edit_account.list_view));
1374 
1375 	while (account_list)
1376 		account_list = g_list_remove(account_list, account_list->data);
1377 
1378 	n_rows = gtk_tree_model_iter_n_children(model, NULL);
1379 
1380 	for (row = 0; row < n_rows; row++) {
1381 		GtkTreeIter iter;
1382 
1383 		if (!gtk_tree_model_iter_nth_child(model, &iter, NULL, row)) {
1384 			g_warning("%s(%d) - no iter found???", __FILE__, __LINE__);
1385 			continue;
1386 		}
1387 
1388 		ac_prefs = NULL;
1389 		gtk_tree_model_get(model, &iter,
1390 				   ACCOUNT_DATA, &ac_prefs,
1391 				   -1);
1392 		if (ac_prefs)
1393 			account_list = g_list_append(account_list, ac_prefs);
1394 	}
1395 }
1396 
1397 /*!
1398  *\brief	finds the PrefsAccounts which should be used to answer a mail
1399  *
1400  *\param	msginfo The message to be answered
1401  *\param	reply_autosel Indicates whether reply account autoselection is on
1402  *
1403  *\return	PrefsAccount * the correct account, NULL if not found
1404  */
account_get_reply_account(MsgInfo * msginfo,gboolean reply_autosel)1405 PrefsAccount *account_get_reply_account(MsgInfo *msginfo, gboolean reply_autosel)
1406 {
1407 	PrefsAccount *account = NULL;
1408 	/* select the account set in folderitem's property (if enabled) */
1409 	if (msginfo->folder->prefs && msginfo->folder->prefs->enable_default_account)
1410 		account = account_find_from_id(msginfo->folder->prefs->default_account);
1411 	else if (folder_has_parent_of_type(msginfo->folder, F_QUEUE) ||
1412 		 folder_has_parent_of_type(msginfo->folder, F_OUTBOX) ||
1413 		 folder_has_parent_of_type(msginfo->folder, F_DRAFT)) {
1414 			gchar *from = NULL;
1415 			if (!procheader_get_header_from_msginfo
1416 				(msginfo, &from, "From:")) {
1417 				gchar *buf = from + strlen("From:");
1418 		        	extract_address(buf);
1419 		        	account = account_find_from_address(buf, FALSE);
1420 		        g_free(from);
1421 			}
1422 	}
1423 	/* select account by to: and cc: header if enabled */
1424 	if (reply_autosel) {
1425 		gchar * field = NULL;
1426 		int fieldno = 0;
1427 		for (field = msginfo->to; fieldno++ < 2; field = msginfo->cc) {
1428 			if (!account && field) {
1429 				gchar *f = g_strdup(field);
1430 				if (f) {
1431 					gchar *cur = f;
1432 					gchar *next = NULL;
1433 					gchar *to = NULL;
1434 					do {
1435 						next = strchr_with_skip_quote(cur, '"', ',');
1436 						if (next)
1437 							(*next) = 0;
1438 						Xstrdup_a(to, cur, return NULL);
1439 						extract_address(to);
1440 						account = account_find_from_address(to, FALSE);
1441 						if (next)
1442 							cur = next + 1;
1443 						else
1444 							break;
1445 					} while (!account);
1446 					g_free(f);
1447 				}
1448 			}
1449 		}
1450 		if (!account) {
1451 			gchar *deliveredto = NULL;
1452 			if (!procheader_get_header_from_msginfo
1453 				(msginfo, &deliveredto, "Delivered-To:")) {
1454 				gchar *buf = deliveredto + strlen("Delivered-To:");
1455 		        	extract_address(buf);
1456 		        	account = account_find_from_address(buf, FALSE);
1457 		        g_free(deliveredto);
1458 			}
1459 		}
1460 	}
1461 
1462 	/* select the account for the whole folder (IMAP / NNTP) */
1463 	if (!account)
1464 		/* FIXME: this is not right, because folder may be nested. we should
1465 		 * ascend the tree until we find a parent with proper account
1466 		 * information */
1467 		account = msginfo->folder->folder->account;
1468 
1469 	/* select current account */
1470 	if (!account) account = cur_account;
1471 
1472 	return account;
1473 }
1474 
1475 /*!
1476  *\brief	Create data store
1477  */
account_create_data_store(void)1478 static GtkListStore* account_create_data_store(void)
1479 {
1480 	return gtk_list_store_new(N_ACCOUNT_COLUMNS,
1481 				 G_TYPE_INT,		/* ACCOUNT_IS_DEFAULT */
1482 				 G_TYPE_BOOLEAN,	/* ACCOUNT_ENABLE_GET_ALL */
1483 				 G_TYPE_STRING,		/* ACCOUNT_NAME */
1484 				 G_TYPE_STRING,		/* ACCOUNT_PROTOCOL */
1485 				 G_TYPE_STRING,		/* ACCOUNT_SERVER */
1486 				 G_TYPE_POINTER,	/* ACCOUNT_DATA */
1487 				 -1);
1488 }
1489 
1490 /*!
1491  *\brief	Insert an account item in the list.
1492  *
1493  *\return	GtkTreeRowReference * A tree row reference, which is guaranteed to
1494  *		stable whatever operations are performed on the list.
1495  */
account_list_store_insert_account_item(GtkListStore * list_store,PrefsAccount * ac_prefs)1496 static void account_list_store_insert_account_item(GtkListStore *list_store,
1497 						  PrefsAccount *ac_prefs)
1498 {
1499 	GtkTreeIter iter;
1500 	gboolean is_get_all = (ac_prefs->protocol == A_POP3 ||
1501 			ac_prefs->protocol == A_IMAP4 ||
1502 			ac_prefs->protocol == A_NNTP  ||
1503 			ac_prefs->protocol == A_LOCAL) &&
1504 		ac_prefs->recv_at_getall;
1505 	gchar *protocol, *server;
1506 
1507 #ifdef USE_GNUTLS
1508 	protocol = ac_prefs->protocol == A_POP3 ?
1509 		  (ac_prefs->ssl_pop == SSL_TUNNEL ?
1510 		   "POP (SSL/TLS)" :
1511 		   ac_prefs->ssl_pop == SSL_STARTTLS ?
1512 		   "POP (STARTTLS)" : "POP") :
1513 		   ac_prefs->protocol == A_IMAP4 ?
1514 		  (ac_prefs->ssl_imap == SSL_TUNNEL ?
1515 		   "IMAP (SSL/TLS)" :
1516 		   ac_prefs->ssl_imap == SSL_STARTTLS ?
1517 		   "IMAP (STARTTLS)" : "IMAP") :
1518 		   ac_prefs->protocol == A_NNTP ?
1519 		  (ac_prefs->ssl_nntp == SSL_TUNNEL ?
1520 		   "NNTP (SSL/TLS)" : "NNTP") :
1521 		   ac_prefs->protocol == A_LOCAL ? "Local" :
1522 		   ac_prefs->protocol == A_NONE ?  "SMTP" : "-";
1523 #else
1524 	protocol = ac_prefs->protocol == A_POP3  ? "POP" :
1525 		   ac_prefs->protocol == A_IMAP4 ? "IMAP" :
1526 		   ac_prefs->protocol == A_LOCAL ? "Local" :
1527 		   ac_prefs->protocol == A_NNTP  ? "NNTP" :
1528 		   ac_prefs->protocol == A_NONE ?  "SMTP" : "-";
1529 #endif
1530 
1531 	server= ac_prefs->protocol == A_NNTP ? ac_prefs->nntp_server :
1532 		   ac_prefs->protocol == A_LOCAL ?  "-" :
1533 		   ac_prefs->protocol == A_NONE ? ac_prefs->smtp_server :
1534 		   ac_prefs->recv_server;
1535 
1536 	gtk_list_store_append(list_store, &iter);
1537 	gtk_list_store_set(list_store, &iter,
1538 			   ACCOUNT_IS_DEFAULT,     ac_prefs->is_default ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
1539 			   ACCOUNT_ENABLE_GET_ALL, is_get_all,
1540 			   ACCOUNT_NAME,	   ac_prefs->account_name,
1541 			   ACCOUNT_PROTOCOL,	   protocol,
1542 			   ACCOUNT_SERVER,	   server,
1543 			   ACCOUNT_DATA,	   ac_prefs,
1544 			   -1);
1545 }
1546 
1547 /*!
1548  *\brief	Create and set up account list view, including tasks like
1549  *		creating the data store (\ref account_create_data_store()),
1550  *		and setting up the account list's individual columns (\ref
1551  *		account_create_list_view_columns()).
1552  *
1553  *\return	GtkWidget * The created list view widget.
1554  */
account_list_view_create(void)1555 static GtkWidget *account_list_view_create(void)
1556 {
1557 	GtkTreeView *list_view;
1558 	GtkTreeSelection *selector;
1559 	GtkListStore *store = account_create_data_store();
1560 
1561 	list_view = GTK_TREE_VIEW(gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)));
1562 	g_object_unref(G_OBJECT(store));
1563 #ifdef GENERIC_UMPC
1564 	g_object_set(list_view, "allow-checkbox-mode", FALSE, NULL);
1565 #endif
1566 	gtk_tree_view_set_rules_hint(list_view, prefs_common.use_stripes_everywhere);
1567 	gtk_tree_view_set_reorderable(list_view, TRUE);
1568 
1569 	selector = gtk_tree_view_get_selection(list_view);
1570 	gtk_tree_selection_set_mode(selector, GTK_SELECTION_BROWSE);
1571 
1572 	/* create the columns */
1573 	account_create_list_view_columns(GTK_WIDGET(list_view));
1574 
1575 	/* set a double click listener */
1576 	g_signal_connect(G_OBJECT(list_view), "row_activated",
1577 	                 G_CALLBACK(account_double_clicked),
1578 			 list_view);
1579 
1580 	g_signal_connect(G_OBJECT(list_view), "drag_begin",
1581 			 G_CALLBACK(drag_begin),
1582 			 list_view);
1583 
1584 	g_signal_connect(G_OBJECT(list_view), "drag_end",
1585 			 G_CALLBACK(drag_end),
1586 			 list_view);
1587 
1588 	gtk_tree_view_set_reorderable(list_view, TRUE);
1589 	return GTK_WIDGET(list_view);
1590 }
1591 
account_create_list_view_columns(GtkWidget * list_view)1592 static void account_create_list_view_columns(GtkWidget *list_view)
1593 {
1594 	GtkTreeViewColumn *column;
1595 	GtkCellRenderer *renderer;
1596 
1597 	renderer = gtk_cell_renderer_toggle_new();
1598 	g_object_set(renderer,
1599 		     "radio", FALSE,
1600 		     "activatable", TRUE,
1601 		      NULL);
1602 	column = gtk_tree_view_column_new_with_attributes
1603 		(C_("Accounts List Get Column Name", "G"), renderer,
1604 		 "active", ACCOUNT_ENABLE_GET_ALL,
1605 		 NULL);
1606 	gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);
1607 	gtk_tree_view_column_set_alignment (column, 0.5);
1608 	CLAWS_SET_TIP(gtk_tree_view_column_get_widget(column),
1609 			_("'Get Mail' retrieves mail from the checked accounts"));
1610 	g_signal_connect(G_OBJECT(renderer), "toggled",
1611 			 G_CALLBACK(account_get_all_toggled),
1612 			 list_view);
1613 
1614 	renderer = gtk_cell_renderer_text_new();
1615 	column = gtk_tree_view_column_new_with_attributes
1616 		(_("Name"), renderer,
1617 		 "text", ACCOUNT_NAME,
1618 		 "weight", ACCOUNT_IS_DEFAULT,
1619 		 NULL);
1620 	gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);
1621 
1622 	renderer = gtk_cell_renderer_text_new();
1623 	column = gtk_tree_view_column_new_with_attributes
1624 		(_("Protocol"), renderer,
1625 		 "text", ACCOUNT_PROTOCOL,
1626 		 "weight", ACCOUNT_IS_DEFAULT,
1627 		 NULL);
1628 	gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);
1629 
1630 	renderer = gtk_cell_renderer_text_new();
1631 	column = gtk_tree_view_column_new_with_attributes
1632 		(_("Server"), renderer,
1633 		 "text", ACCOUNT_SERVER,
1634 		 "weight", ACCOUNT_IS_DEFAULT,
1635 		 NULL);
1636 	gtk_tree_view_set_search_column(GTK_TREE_VIEW(list_view), ACCOUNT_NAME);
1637 	gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(list_view), account_search_func_cb , NULL, NULL);
1638 	gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);
1639 }
1640 
1641 /*!
1642  *\brief	Get currently selected account (by its unique ID)
1643  */
account_list_view_get_selected_account_id(GtkWidget * list_view)1644 static gint account_list_view_get_selected_account_id(GtkWidget *list_view)
1645 {
1646 	PrefsAccount *res = NULL;
1647 
1648 	res = (PrefsAccount *)gtkut_tree_view_get_selected_pointer(
1649 			GTK_TREE_VIEW(list_view), ACCOUNT_DATA,
1650 			NULL, NULL, NULL);
1651 
1652 	return (res != NULL ? res->account_id : -1);
1653 }
1654 
1655 /*!
1656  *\brief	Get the tree path of the currently selected account
1657  */
account_list_view_get_selected_account_path(GtkWidget * list_view)1658 static GtkTreePath *account_list_view_get_selected_account_path(GtkWidget *list_view)
1659 {
1660 	GtkTreeSelection *selector;
1661 	GtkTreeModel *model;
1662 	GtkTreeIter iter;
1663 
1664 	selector = gtk_tree_view_get_selection(GTK_TREE_VIEW(list_view));
1665 
1666 	if (!gtk_tree_selection_get_selected(selector, &model, &iter))
1667 		return NULL;
1668 
1669 	return gtk_tree_model_get_path(gtk_tree_view_get_model
1670 		(GTK_TREE_VIEW(list_view)), &iter);
1671 }
1672 
1673 /*!
1674  *\brief	Get the account data of the currently selected account
1675  */
account_list_view_get_selected_account(GtkWidget * list_view)1676 static PrefsAccount *account_list_view_get_selected_account(GtkWidget *list_view)
1677 {
1678 	PrefsAccount *res =
1679 		(PrefsAccount *)gtkut_tree_view_get_selected_pointer(
1680 			GTK_TREE_VIEW(list_view), ACCOUNT_DATA,
1681 			NULL, NULL, NULL);
1682 
1683 	return res;
1684 }
1685 
1686 /*!
1687  *\brief	Select a row by the account it represents
1688  *
1689  *\return	gboolean TRUE if found and selected, FALSE if not.
1690  */
account_list_view_select_account(GtkWidget * list_view,gint account_id)1691 static gboolean account_list_view_select_account(GtkWidget *list_view, gint account_id)
1692 {
1693 	FindAccountInStore fis;
1694 	GtkTreeModel *model;
1695 
1696 	fis.account_id = account_id;
1697 	fis.path = NULL;
1698 
1699 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(list_view));
1700 
1701 	gtk_tree_model_foreach(model, (GtkTreeModelForeachFunc) find_account_in_store,
1702 			       &fis);
1703 
1704 	if (fis.path) {
1705 		GtkTreeSelection *selection;
1706 		GtkTreePath* path;
1707 
1708 		selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list_view));
1709 		gtk_tree_selection_select_iter(selection, &fis.iter);
1710 		path = gtk_tree_model_get_path(model, &fis.iter);
1711 		/* XXX returned path may not be valid??? create new one to be sure */
1712 		gtk_tree_view_set_cursor(GTK_TREE_VIEW(list_view), path, NULL, FALSE);
1713 		gtk_tree_path_free(path);
1714 	}
1715 
1716 	return fis.path != NULL;
1717 }
1718 
1719 /*!
1720  *\brief	Set a new default account by its ID. (There is only one
1721  *		default account.)
1722  */
account_list_view_set_default_by_id(GtkWidget * list_view,gint account_id)1723 static void account_list_view_set_default_by_id(GtkWidget *list_view,
1724 						gint account_id)
1725 {
1726 	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(list_view));
1727 
1728 	gtk_tree_model_foreach
1729 		(model, (GtkTreeModelForeachFunc) set_new_default_account,
1730 		 &account_id);
1731 }
1732 
set_new_default_account(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gint * account_id)1733 static gboolean set_new_default_account(GtkTreeModel *model,
1734 					GtkTreePath  *path,
1735 					GtkTreeIter  *iter,
1736 					gint	     *account_id)
1737 {
1738 	PrefsAccount *account = NULL;
1739 	PangoWeight weight;
1740 
1741 	gtk_tree_model_get(model, iter,
1742 			   ACCOUNT_DATA, &account,
1743 			   -1);
1744 
1745 	if (*account_id == account->account_id)
1746 		weight = PANGO_WEIGHT_NORMAL;
1747 	else
1748 		weight = PANGO_WEIGHT_BOLD;
1749 
1750 	gtk_list_store_set(GTK_LIST_STORE(model), iter,
1751 			   ACCOUNT_IS_DEFAULT, weight, -1);
1752 
1753 	return FALSE;
1754 }
1755 
find_account_in_store(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,FindAccountInStore * data)1756 static gboolean find_account_in_store(GtkTreeModel *model,
1757 				      GtkTreePath  *path,
1758 				      GtkTreeIter  *iter,
1759 				      FindAccountInStore *data)
1760 {
1761 	PrefsAccount *account = NULL;
1762 	gtk_tree_model_get(model, iter, ACCOUNT_DATA, &account, -1);
1763 
1764 	if (data->account_id == account->account_id) {
1765 		data->path = path; /* signal we found it */
1766 		data->iter = *iter;
1767 		return TRUE;
1768 	}
1769 
1770 	return FALSE;
1771 }
1772 
1773 /*!
1774  *\brief	Triggered when "get all" column is activated or de-activated
1775  */
account_get_all_toggled(GtkCellRendererToggle * widget,gchar * path,GtkWidget * list_view)1776 static void account_get_all_toggled(GtkCellRendererToggle *widget,
1777 				    gchar *path,
1778 				    GtkWidget *list_view)
1779 {
1780 	GtkTreeIter iter;
1781 	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(list_view));
1782 	PrefsAccount *ac = NULL;
1783 	gboolean get_all;
1784 
1785 	if (!gtk_tree_model_get_iter_from_string(model, &iter, path))
1786 		return;
1787 
1788 	gtk_tree_model_get(model, &iter,
1789 			   ACCOUNT_DATA, &ac,
1790 			   ACCOUNT_ENABLE_GET_ALL, &get_all,
1791 			   -1);
1792 
1793 	/* check if the account has a selectable get all checkbox anyway... */
1794 	if (!(ac->protocol == A_POP3  ||
1795 	      ac->protocol == A_IMAP4 ||
1796 	      ac->protocol == A_NNTP  ||
1797 	      ac->protocol == A_LOCAL))
1798 		return;
1799 
1800 	/* set value in store */
1801 	gtk_list_store_set(GTK_LIST_STORE(model), &iter,
1802 			   ACCOUNT_ENABLE_GET_ALL, !get_all,
1803 			   -1);
1804 
1805 	/* set value in account */
1806 	ac->recv_at_getall ^= TRUE;
1807 }
1808 
account_double_clicked(GtkTreeView * list_view,GtkTreePath * path,GtkTreeViewColumn * column,gpointer data)1809 static void account_double_clicked(GtkTreeView		*list_view,
1810 				   GtkTreePath		*path,
1811 				   GtkTreeViewColumn	*column,
1812 				   gpointer		 data)
1813 {
1814 	account_edit_prefs(NULL, NULL);
1815 }
1816 
drag_begin(GtkTreeView * list_view,GdkDragContext * context,gpointer data)1817 static void drag_begin(GtkTreeView *list_view,
1818 		      GdkDragContext *context,
1819 		      gpointer data)
1820 {
1821 	/* XXX unfortunately a completed drag & drop does not emit
1822 	 * a "rows_reordered" signal, but a "row_changed" signal.
1823 	 * So during drag and drop, listen to "row_changed", and
1824 	 * update the account list accordingly */
1825 
1826 	GtkTreeModel *model = gtk_tree_view_get_model(list_view);
1827 	g_signal_connect(G_OBJECT(model), "row_changed",
1828 			 G_CALLBACK(account_row_changed_while_drag_drop),
1829 			 list_view);
1830 }
1831 
drag_end(GtkTreeView * list_view,GdkDragContext * context,gpointer data)1832 static void drag_end(GtkTreeView *list_view,
1833 		    GdkDragContext *context,
1834 		    gpointer data)
1835 {
1836 	GtkTreeModel *model = gtk_tree_view_get_model(list_view);
1837 	g_signal_handlers_disconnect_by_func(G_OBJECT(model),
1838 					     G_CALLBACK(account_row_changed_while_drag_drop),
1839 					     list_view);
1840 }
1841 
account_row_changed_while_drag_drop(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer arg3,GtkTreeView * list_view)1842 static void account_row_changed_while_drag_drop(GtkTreeModel *model,
1843 				   GtkTreePath  *path,
1844 				   GtkTreeIter  *iter,
1845 				   gpointer      arg3,
1846 				   GtkTreeView  *list_view)
1847 {
1848 	account_list_set();
1849 }
1850 
account_get_signature_str(PrefsAccount * account)1851 gchar *account_get_signature_str(PrefsAccount *account)
1852 {
1853 	gchar *sig_body = NULL;
1854 	gchar *sig_str = NULL;
1855 	gchar *utf8_sig_str = NULL;
1856 
1857 	cm_return_val_if_fail(account != NULL, NULL);
1858 
1859 	if (!account->sig_path)
1860 		return NULL;
1861 
1862 	if (account->sig_type == SIG_FILE) {
1863 		gchar *sig_full_path;
1864 		if (!g_path_is_absolute(account->sig_path)) {
1865 			sig_full_path = g_build_filename(get_home_dir(), account->sig_path, NULL);
1866 		} else {
1867 			sig_full_path = g_strdup(account->sig_path);
1868 		}
1869 
1870 		if (!is_file_or_fifo_exist(sig_full_path)) {
1871 			g_warning("can't open signature file: '%s'", sig_full_path);
1872 			g_free(sig_full_path);
1873 			return NULL;
1874 		}
1875 
1876 		debug_print("Reading signature from file '%s'\n", sig_full_path);
1877 		gchar *tmp = file_read_to_str(sig_full_path);
1878 		g_free(sig_full_path);
1879 
1880 		if (!tmp)
1881 			return NULL;
1882 
1883 		sig_body = normalize_newlines(tmp);
1884 		g_free(tmp);
1885 	} else {
1886 		sig_body = get_command_output(account->sig_path);
1887 	}
1888 
1889 	if (account->sig_sep) {
1890 		sig_str = g_strconcat("\n", account->sig_sep, "\n", sig_body,
1891 				      NULL);
1892 		g_free(sig_body);
1893 	} else
1894 		sig_str = g_strconcat("\n", sig_body, NULL);
1895 
1896 	if (sig_str) {
1897 		if (g_utf8_validate(sig_str, -1, NULL) == TRUE)
1898 			utf8_sig_str = sig_str;
1899 		else {
1900 			utf8_sig_str = conv_codeset_strdup
1901 				(sig_str, conv_get_locale_charset_str_no_utf8(),
1902 				 CS_INTERNAL);
1903 			g_free(sig_str);
1904 		}
1905 	}
1906 
1907 	return utf8_sig_str;
1908 }
1909 
account_get_cur_account(void)1910 PrefsAccount *account_get_cur_account (void)
1911 {
1912 	return cur_account;
1913 }
1914 
password_get(const gchar * user,const gchar * server,const gchar * protocol,guint16 port,gchar ** password)1915 gboolean password_get(const gchar *user,
1916 		    const gchar *server,
1917 		    const gchar *protocol,
1918 		    guint16 port,
1919 		    gchar **password)
1920 {
1921 	PasswordRequest req;
1922 
1923 	/* all have to be set */
1924 	cm_return_val_if_fail(user != NULL, FALSE);
1925 	cm_return_val_if_fail(server != NULL, FALSE);
1926 	cm_return_val_if_fail(protocol != NULL, FALSE);
1927 	cm_return_val_if_fail(port != 0, FALSE);
1928 
1929 	req.user = user;
1930 	req.server = server;
1931 	req.protocol = protocol;
1932 	req.port = port;
1933 
1934 	if (hooks_invoke(PASSWORD_GET_HOOKLIST, &req)) {
1935 		*password = req.password;
1936 		return TRUE;
1937 	}
1938 	return FALSE;
1939 }
1940 
1941 static GSList *account_sigsep_list = NULL;
1942 
1943 /* create a list of unique signatures from accounts list */
account_sigsep_matchlist_create(void)1944 void account_sigsep_matchlist_create(void)
1945 {
1946 	GList *cur_ac = NULL;
1947 	PrefsAccount *ac_prefs = NULL;
1948 
1949 	if (account_sigsep_list)
1950 		return;
1951 
1952 	account_sigsep_list = g_slist_prepend(account_sigsep_list, g_strdup("-- "));
1953 	for (cur_ac = account_get_list();
1954 		 cur_ac != NULL;
1955 		 cur_ac = g_list_next(cur_ac)) {
1956 		ac_prefs = (PrefsAccount *)cur_ac->data;
1957 
1958 		if (ac_prefs->sig_sep && *ac_prefs->sig_sep != '\0') {
1959 			if (!g_slist_find_custom(account_sigsep_list, ac_prefs->sig_sep,
1960 					(GCompareFunc)g_strcmp0)) {
1961 				account_sigsep_list = g_slist_prepend(account_sigsep_list,
1962 						g_strdup(ac_prefs->sig_sep));
1963 			}
1964 		}
1965 	}
1966 }
1967 
1968 /* delete the list of signatures created by account_sigsep_matchlist_create() */
account_sigsep_matchlist_delete(void)1969 void account_sigsep_matchlist_delete(void)
1970 {
1971 	if (account_sigsep_list) {
1972 		slist_free_strings_full(account_sigsep_list);
1973 		account_sigsep_list = NULL;
1974 	}
1975 }
1976 
1977 /* match a string against all signatures in list, using the specified format */
account_sigsep_matchlist_str_found(const gchar * str,const gchar * format)1978 gboolean account_sigsep_matchlist_str_found(const gchar *str, const gchar *format)
1979 {
1980 	gchar *tmp = NULL;
1981 	gboolean found = FALSE;
1982 	GSList *item;
1983 
1984 	for (item = account_sigsep_list;
1985 		 item != NULL && !found;
1986 		 item = g_slist_next(item)) {
1987 		tmp = g_strdup_printf(format, (gchar *)item->data);
1988 		if (tmp) {
1989 			found = (strcmp(tmp, str) == 0);
1990 			g_free(tmp);
1991 		} else {
1992 			g_warning("account_sigsep_matchlist_str_found: g_strdup_printf failed, check format '%s'",
1993 				format);
1994 			return FALSE;
1995 		}
1996 	}
1997 	return found;
1998 }
1999 
2000 /* match M first char of a string against all signatures in list, using the specified format */
account_sigsep_matchlist_nchar_found(const gchar * str,const gchar * format)2001 gboolean account_sigsep_matchlist_nchar_found(const gchar *str, const gchar *format)
2002 {
2003 	gchar *tmp = NULL;
2004 	gboolean found = FALSE;
2005 	GSList *item;
2006 	gint len;
2007 
2008 	for (item = account_sigsep_list;
2009 		 item != NULL && !found;
2010 		 item = g_slist_next(item)) {
2011 		tmp = g_strdup_printf(format, (gchar *)item->data);
2012 		if (tmp) {
2013 			len = strlen(tmp);
2014 			found = (strncmp(tmp, str, len) == 0);
2015 			g_free(tmp);
2016 		} else {
2017 			g_warning("account_sigsep_matchlist_nchar_found: g_strdup_printf failed, check format '%s'",
2018 				format);
2019 			return FALSE;
2020 		}
2021 	}
2022 	return found;
2023 }
2024