talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

account.c (41254B)


      1 /*
      2  * Claws Mail -- a GTK based, lightweight, and fast e-mail client
      3  * Copyright (C) 1999-2025 the Claws Mail team and Hiroyuki Yamamoto
      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 #include "defs.h"
     20 
     21 #include <glib.h>
     22 #include <glib/gi18n.h>
     23 #include <gtk/gtk.h>
     24 #include <gdk/gdkkeysyms.h>
     25 #include <stdio.h>
     26 #include <errno.h>
     27 
     28 #include "mainwindow.h"
     29 #include "folderview.h"
     30 #include "folder.h"
     31 #include "account.h"
     32 #include "prefs_gtk.h"
     33 #include "prefs_account.h"
     34 #include "prefs_common.h"
     35 #include "folder_item_prefs.h"
     36 #include "compose.h"
     37 #include "manage_window.h"
     38 #include "stock_pixmap.h"
     39 #include "inc.h"
     40 #include "gtkutils.h"
     41 #include "utils.h"
     42 #include "alertpanel.h"
     43 #include "procheader.h"
     44 #include "customheader.h"
     45 #include "remotefolder.h"
     46 #include "manual.h"
     47 #include "prefs_actions.h"
     48 #include "hooks.h"
     49 #include "passwordstore.h"
     50 
     51 enum {
     52 	ACCOUNT_IS_DEFAULT,
     53 	ACCOUNT_ENABLE_GET_ALL,
     54 	ACCOUNT_NAME,
     55 	ACCOUNT_PROTOCOL,
     56 	ACCOUNT_SERVER,
     57 	ACCOUNT_DATA,
     58 	N_ACCOUNT_COLUMNS
     59 };
     60 
     61 
     62 typedef enum
     63 {
     64 	COL_DEFAULT	= 0,
     65 	COL_GETALL,
     66 	COL_NAME,
     67 	COL_PROTOCOL,
     68 	COL_SERVER,
     69 	N_EDIT_ACCOUNT_COLS
     70 } EditAccountColumnPos;
     71 
     72 PrefsAccount *cur_account;
     73 
     74 static GList *account_list = NULL;
     75 static gboolean account_list_dirty = FALSE;
     76 
     77 static struct EditAccount {
     78 	GtkWidget *window;
     79 	GtkWidget *list_view;
     80 	GtkWidget *close_btn;
     81 } edit_account;
     82 
     83 static void account_edit_create		(void);
     84 static void	      account_destroy		(PrefsAccount	*ac_prefs);
     85 static void	      account_set_as_default	(PrefsAccount	*ac_prefs);
     86 static void	      account_set_menu		(void);
     87 
     88 static void account_edit_prefs		(GtkWidget *widget, gpointer data);
     89 static void account_delete		(GtkWidget *widget, gpointer data);
     90 
     91 static void account_up			(GtkWidget *widget, gpointer data);
     92 static void account_down		(GtkWidget *widget, gpointer data);
     93 
     94 static void account_set_default		(GtkWidget *widget, gpointer data);
     95 
     96 static void account_edit_close		(GtkWidget *widget, gpointer data);
     97 
     98 static gint account_delete_event	(GtkWidget	*widget,
     99 					 GdkEventAny	*event,
    100 					 gpointer	 data);
    101 static void account_size_allocate_cb(GtkWidget *widget,
    102 					 GtkAllocation *allocation);
    103 
    104 static gboolean account_search_func_cb (GtkTreeModel *model, gint column,
    105 						const gchar *key, GtkTreeIter *iter,
    106 						gpointer search_data);
    107 static void account_list_view_set	(void);
    108 
    109 static void account_list_set		(void);
    110 
    111 typedef struct FindAccountInStore {
    112 	gint		 account_id;
    113 	GtkTreePath	*path;
    114 	GtkTreeIter	 iter;
    115 } FindAccountInStore;
    116 
    117 static GtkListStore* account_create_data_store	(void);
    118 
    119 static void account_list_store_insert_account_item (GtkListStore	*list_store,
    120 						   PrefsAccount *account_data);
    121 
    122 static GtkWidget *account_list_view_create	(void);
    123 static void account_create_list_view_columns	(GtkWidget *list_view);
    124 
    125 static gint account_list_view_get_selected_account_id		(GtkWidget *list_view);
    126 static GtkTreePath *account_list_view_get_selected_account_path	(GtkWidget *list_view);
    127 static PrefsAccount *account_list_view_get_selected_account		(GtkWidget *list_view);
    128 static gboolean account_list_view_select_account			(GtkWidget *list_view,
    129 								 gint	    account_id);
    130 
    131 static void account_list_view_set_default_by_id(GtkWidget *list_view,
    132 						gint account_id);
    133 
    134 static gboolean set_new_default_account		(GtkTreeModel *model,
    135 						 GtkTreePath  *path,
    136 						 GtkTreeIter  *iter,
    137 						 gint	      *account_id);
    138 
    139 static gboolean find_account_in_store		(GtkTreeModel *model,
    140 						 GtkTreePath  *path,
    141 						 GtkTreeIter  *iter,
    142 						 FindAccountInStore *data);
    143 
    144 static void account_get_all_toggled		(GtkCellRendererToggle	*widget,
    145 						 gchar			*path,
    146 						 GtkWidget		*list_view);
    147 
    148 static void account_double_clicked		(GtkTreeView		*list_view,
    149 						 GtkTreePath		*path,
    150 						 GtkTreeViewColumn	*column,
    151 						 gpointer		 data);
    152 
    153 static void account_flush_state(void)
    154 {
    155 	account_set_menu();
    156 	main_window_reflect_prefs_all();
    157 
    158 	account_list_dirty = FALSE;
    159 }
    160 
    161 void account_read_config_all(void)
    162 {
    163 	GSList *ac_label_list = NULL, *cur;
    164 	gchar *rcpath;
    165 	FILE *fp;
    166 	gchar buf[PREFSBUFSIZE];
    167 	PrefsAccount *ac_prefs;
    168 
    169 	debug_print("Reading all config for each account...\n");
    170 
    171 	rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ACCOUNT_RC, NULL);
    172 	if ((fp = g_fopen(rcpath, "rb")) == NULL) {
    173 		if (ENOENT != errno) FILE_OP_ERROR(rcpath, "g_fopen");
    174 		g_free(rcpath);
    175 		return;
    176 	}
    177 	g_free(rcpath);
    178 
    179 	while (fgets(buf, sizeof(buf), fp) != NULL) {
    180 		if (!strncmp(buf, "[Account: ", 10)) {
    181 			strretchomp(buf);
    182 			memmove(buf, buf + 1, sizeof(buf) - 1);
    183 			buf[strlen(buf) - 1] = '\0';
    184 			debug_print("Found label: %s\n", buf);
    185 			ac_label_list = g_slist_append(ac_label_list,
    186 						       g_strdup(buf));
    187 		}
    188 	}
    189 	fclose(fp);
    190 
    191 	/* read config data from file */
    192 	cur_account = NULL;
    193 	for (cur = ac_label_list; cur != NULL; cur = cur->next) {
    194 		ac_prefs = prefs_account_new_from_config((gchar *)cur->data);
    195 		account_list = g_list_append(account_list, ac_prefs);
    196 		if (ac_prefs->is_default)
    197 			cur_account = ac_prefs;
    198 	}
    199 	/* if default is not set, assume first account as default */
    200 	if (!cur_account && account_list) {
    201 		ac_prefs = (PrefsAccount *)account_list->data;
    202 		account_set_as_default(ac_prefs);
    203 		cur_account = ac_prefs;
    204 	}
    205 
    206 	account_set_menu();
    207 	main_window_reflect_prefs_all_now();
    208 
    209 	while (ac_label_list) {
    210 		g_free(ac_label_list->data);
    211 		ac_label_list = g_slist_remove(ac_label_list,
    212 					       ac_label_list->data);
    213 	}
    214 }
    215 
    216 void account_write_config_all(void)
    217 {
    218 	prefs_account_write_config_all(account_list);
    219 }
    220 
    221 /*
    222  * account_find_all_from_address:
    223  * @ac_list: initial list of accounts. NULL to create a new one.
    224  * Accounts found in the @address will be appended to this list.
    225  * @address: Email address string.
    226  *
    227  * Find all the mail (not news) accounts within the specified address.
    228  *
    229  * Return value: the original accounts list with the found accounts appended.
    230  */
    231 GList *account_find_all_from_address(GList *ac_list, const gchar *address)
    232 {
    233 	GList *cur;
    234 	PrefsAccount *ac;
    235 
    236 	if (address == NULL)
    237 		return ac_list;
    238 
    239 	for (cur = account_list; cur != NULL; cur = cur->next) {
    240 		ac = (PrefsAccount *)cur->data;
    241 		if (ac->address &&
    242 		    strcasestr(address, ac->address) != NULL)
    243 			ac_list = g_list_append(ac_list, ac);
    244 	}
    245 	return ac_list;
    246 }
    247 
    248 GList *account_find_all(void)
    249 {
    250 	GList *cur;
    251 	PrefsAccount *ac;
    252 	GList *ac_list = NULL;
    253 
    254 	for (cur = account_list; cur != NULL; cur = cur->next) {
    255 		ac = (PrefsAccount *)cur->data;
    256 		ac_list = g_list_append(ac_list, ac);
    257 	}
    258 	return ac_list;
    259 }
    260 
    261 PrefsAccount *account_find_from_smtp_server(const gchar *address,
    262 					    const gchar *smtp_server)
    263 {
    264 	GList *cur;
    265 	PrefsAccount *ac;
    266 
    267 	cm_return_val_if_fail(address != NULL, NULL);
    268 	cm_return_val_if_fail(smtp_server != NULL, NULL);
    269 
    270 	for (cur = account_list; cur != NULL; cur = cur->next) {
    271 		ac = (PrefsAccount *)cur->data;
    272 		if (!g_strcmp0(address, ac->address) &&
    273 		    !g_strcmp0(smtp_server, ac->smtp_server))
    274 			return ac;
    275 	}
    276 
    277 	return NULL;
    278 }
    279 
    280 /*
    281  * account_find_from_address:
    282  * @address: Email address string.
    283  *
    284  * Find a mail account with the specified email address.
    285  *
    286  * Return value: The found account, or NULL if not found.
    287  */
    288 PrefsAccount *account_find_from_address(const gchar *address)
    289 {
    290 	GList *cur;
    291 	PrefsAccount *ac;
    292 
    293 	cm_return_val_if_fail(address != NULL, NULL);
    294 
    295 	for (cur = account_list; cur != NULL; cur = cur->next) {
    296 		ac = (PrefsAccount *)cur->data;
    297 		if (ac->address && g_ascii_strcasecmp(address, ac->address) == 0)
    298 			return ac;
    299 	}
    300 
    301 	return NULL;
    302 }
    303 
    304 PrefsAccount *account_find_from_id(gint id)
    305 {
    306 	GList *cur;
    307 	PrefsAccount *ac;
    308 
    309 	for (cur = account_list; cur != NULL; cur = cur->next) {
    310 		ac = (PrefsAccount *)cur->data;
    311 		if (id == ac->account_id)
    312 			return ac;
    313 	}
    314 
    315 	return NULL;
    316 }
    317 
    318 PrefsAccount *account_find_from_item(FolderItem *item)
    319 {
    320 	PrefsAccount *ac;
    321 
    322 	cm_return_val_if_fail(item != NULL, NULL);
    323 
    324 	ac = item->account;
    325 	if (!ac) {
    326 		FolderItem *cur_item = folder_item_parent(item);
    327 		while (cur_item != NULL) {
    328 			if (cur_item->account && cur_item->apply_sub) {
    329 				ac = cur_item->account;
    330 				break;
    331 			}
    332 			cur_item = folder_item_parent(cur_item);
    333 		}
    334 	}
    335 	if (!ac)
    336 		ac = item->folder->account;
    337 
    338 	return ac;
    339 }
    340 
    341 static void account_set_menu(void)
    342 {
    343 	main_window_set_account_menu(account_list);
    344 }
    345 
    346 void account_set_menu_only_toolbar(void)
    347 {
    348 	main_window_set_account_menu_only_toolbar(account_list);
    349 }
    350 
    351 GList *account_get_list(void)
    352 {
    353 	return account_list;
    354 }
    355 
    356 void account_edit_focus(void)
    357 {
    358 	if (edit_account.window == NULL) {
    359 		return;
    360 	}
    361 	manage_window_set_transient(GTK_WINDOW(edit_account.window));
    362 	gtk_widget_grab_focus(edit_account.close_btn);
    363 	gtk_widget_show(edit_account.window);
    364 	gtk_window_set_modal(GTK_WINDOW(edit_account.window), TRUE);
    365 	manage_window_focus_in(edit_account.window, NULL, NULL);
    366 }
    367 
    368 void account_edit_open(gpointer a, gpointer b)
    369 {
    370 	inc_lock();
    371 
    372 	account_list_dirty = FALSE;
    373 
    374 	if (compose_get_compose_list()) {
    375 		alertpanel_error(_("Some writing windows are open.\n"
    376 				   "Please close all the writing "
    377 				   "windows before editing accounts."));
    378 		inc_unlock();
    379 		return;
    380 	}
    381 
    382 	debug_print("Opening account edit window...\n");
    383 
    384 	if (!edit_account.window)
    385 		account_edit_create();
    386 
    387 	account_list_view_set();
    388 
    389 	account_edit_focus();
    390 }
    391 
    392 void account_add(void)
    393 {
    394 	PrefsAccount *ac_prefs;
    395 
    396 	ac_prefs = prefs_account_open(NULL, &account_list_dirty);
    397 
    398 	if (!ac_prefs) return;
    399 
    400 	account_edit_focus();
    401 
    402 	account_list = g_list_append(account_list, ac_prefs);
    403 
    404 	if (ac_prefs->is_default)
    405 		account_set_as_default(ac_prefs);
    406 
    407 	account_list_view_set();
    408 
    409 	if (ac_prefs->protocol == A_IMAP4) {
    410 		Folder *folder;
    411 		folder = folder_new(folder_get_class_from_string("imap"), ac_prefs->account_name, ac_prefs->recv_server);
    412 		if (folder == NULL) {
    413 			alertpanel_error(_("Can't create folder."));
    414 			return;
    415 		}
    416 		folder->account = ac_prefs;
    417 		ac_prefs->folder = folder;
    418 		folder_add(folder);
    419 		folder->klass->create_tree(folder);
    420 		folderview_set_all();
    421 		folder_write_list();
    422 	}
    423 }
    424 
    425 void account_open(PrefsAccount *ac_prefs, gboolean called_from_acc_list)
    426 {
    427 	gboolean prev_default;
    428 	gchar *ac_name, *old_prefix, *new_prefix;
    429 	gboolean account_dirty = FALSE;
    430 
    431 	cm_return_if_fail(ac_prefs != NULL);
    432 
    433 	if (compose_get_compose_list()) {
    434 		alertpanel_error(_("Some writing windows are open.\n"
    435 				   "Please close all the writing "
    436 				   "windows before editing accounts."));
    437 		return;
    438 	}
    439 
    440 	prev_default = ac_prefs->is_default;
    441 	Xstrdup_a(ac_name, ac_prefs->account_name ? ac_prefs->account_name : "",
    442 		  return);
    443 
    444 	prefs_account_open(ac_prefs, &account_dirty);
    445 
    446 	if (called_from_acc_list)
    447 		account_edit_focus();
    448 
    449 	if (account_dirty) {
    450 		if (!prev_default && ac_prefs->is_default)
    451 			account_set_as_default(ac_prefs);
    452 
    453 		if (ac_prefs->folder && g_strcmp0(ac_name, ac_prefs->account_name) != 0) {
    454 			old_prefix = folder_get_identifier(FOLDER(ac_prefs->folder));
    455 			folder_set_name(FOLDER(ac_prefs->folder),
    456 					ac_prefs->account_name);
    457 			folderview_set_all();
    458 			folder_prefs_save_config_recursive(FOLDER(ac_prefs->folder));
    459 			new_prefix = folder_get_identifier(FOLDER(ac_prefs->folder));
    460 
    461 			account_rename_path(old_prefix, new_prefix);
    462 			prefs_actions_rename_path(old_prefix, new_prefix);
    463 
    464 			g_free(old_prefix);
    465 			g_free(new_prefix);
    466 		}
    467 
    468 		account_write_config_all();
    469 
    470 		account_flush_state();
    471 	}
    472 }
    473 
    474 static void account_set_as_default(PrefsAccount *ac_prefs)
    475 {
    476 	PrefsAccount *ap;
    477 	GList *cur;
    478 
    479 	for (cur = account_list; cur != NULL; cur = cur->next) {
    480 		ap = (PrefsAccount *)cur->data;
    481 		if (ap->is_default)
    482 			ap->is_default = FALSE;
    483 	}
    484 
    485 	ac_prefs->is_default = TRUE;
    486 }
    487 
    488 PrefsAccount *account_get_default(void)
    489 {
    490 	PrefsAccount *ap;
    491 	GList *cur;
    492 
    493 	for (cur = account_list; cur != NULL; cur = cur->next) {
    494 		ap = (PrefsAccount *)cur->data;
    495 		if (ap->is_default)
    496 			return ap;
    497 	}
    498 
    499 	return NULL;
    500 }
    501 
    502 void account_set_missing_folder(void)
    503 {
    504 	PrefsAccount *ap;
    505 	GList *cur;
    506 
    507 	for (cur = account_list; cur != NULL; cur = cur->next) {
    508 		ap = (PrefsAccount *)cur->data;
    509 		if ((ap->protocol == A_IMAP4) && !ap->folder) {
    510 			Folder *folder = folder_new(folder_get_class_from_string("imap"), ap->account_name, ap->recv_server);
    511 			if (folder == NULL)
    512 				return;
    513 			folder->account = ap;
    514 			ap->folder = folder;
    515 			folder_add(folder);
    516 			folder->klass->create_tree(folder);
    517 			folder_write_list();
    518 		}
    519 	}
    520 }
    521 
    522 #define CHECK_CHANGE_FOLDER(folder) {						\
    523 	if (folder && !strncmp(folder, old_id, strlen(old_id))) {		\
    524 		if (strlen(folder) == strlen(old_id)) {				\
    525 			g_free(folder);						\
    526 			folder = g_strdup(new_id);				\
    527 		} else if (strlen(folder) > strlen(old_id)			\
    528 		  && folder[strlen(old_id)] == G_DIR_SEPARATOR) {		\
    529 			gchar *new_path = g_strdup_printf("%s%s",		\
    530 					new_id, (folder + strlen(old_id)));	\
    531 			g_free(folder);						\
    532 			folder = new_path;					\
    533 		} 								\
    534 	}									\
    535 }
    536 
    537 void account_rename_path(const gchar *old_id, const gchar *new_id)
    538 {
    539 	GList *cur = account_list;
    540 	for (; cur != NULL; cur = g_list_next(cur)) {
    541 		PrefsAccount *ap = (PrefsAccount *)cur->data;
    542 		CHECK_CHANGE_FOLDER(ap->inbox);
    543 		CHECK_CHANGE_FOLDER(ap->local_inbox);
    544 		CHECK_CHANGE_FOLDER(ap->queue_folder);
    545 		CHECK_CHANGE_FOLDER(ap->sent_folder);
    546 		CHECK_CHANGE_FOLDER(ap->draft_folder);
    547 		CHECK_CHANGE_FOLDER(ap->trash_folder);
    548 	}
    549 }
    550 
    551 FolderItem *account_get_special_folder(PrefsAccount *ac_prefs,
    552 				       SpecialFolderItemType type)
    553 {
    554 	FolderItem *item = NULL;
    555 
    556 	cm_return_val_if_fail(ac_prefs != NULL, NULL);
    557 
    558 	switch (type) {
    559 	case F_INBOX:
    560 		if (ac_prefs->folder)
    561 			item = FOLDER(ac_prefs->folder)->inbox;
    562 		if (!item)
    563 			item = folder_get_default_inbox();
    564 		break;
    565 	case F_OUTBOX:
    566 		if (ac_prefs->set_sent_folder && ac_prefs->sent_folder) {
    567 			item = folder_find_item_from_identifier
    568 				(ac_prefs->sent_folder);
    569 		}
    570 		if (!item) {
    571 			if (ac_prefs->folder)
    572 				item = FOLDER(ac_prefs->folder)->outbox;
    573 			if (!item)
    574 				item = folder_get_default_outbox_for_class(F_MH);
    575 			if (!item)
    576 				item = folder_get_default_outbox();
    577 		}
    578 		break;
    579 	case F_DRAFT:
    580 		if (ac_prefs->set_draft_folder && ac_prefs->draft_folder) {
    581 			item = folder_find_item_from_identifier
    582 				(ac_prefs->draft_folder);
    583 		}
    584 		if (!item) {
    585 			if (ac_prefs->folder)
    586 				item = FOLDER(ac_prefs->folder)->draft;
    587 			if (!item)
    588 				item = folder_get_default_draft_for_class(F_MH);
    589 			if (!item)
    590 				item = folder_get_default_draft();
    591 		}
    592 		break;
    593 	case F_QUEUE:
    594 		if (ac_prefs->set_queue_folder && ac_prefs->queue_folder) {
    595 			item = folder_find_item_from_identifier
    596 				(ac_prefs->queue_folder);
    597 		}
    598 		if (!item) {
    599 			if (ac_prefs->folder)
    600 				item = FOLDER(ac_prefs->folder)->queue;
    601 			if (!item)
    602 				item = folder_get_default_queue_for_class(F_MH);
    603 			if (!item)
    604 				item = folder_get_default_queue();
    605 		}
    606 		break;
    607 	case F_TRASH:
    608 		if (ac_prefs->set_trash_folder && ac_prefs->trash_folder) {
    609 			item = folder_find_item_from_identifier
    610 				(ac_prefs->trash_folder);
    611 		}
    612 		if (!item) {
    613 			if (ac_prefs->folder)
    614 				item = FOLDER(ac_prefs->folder)->trash;
    615 			if (!item)
    616 				item = folder_get_default_trash_for_class(F_MH);
    617 			if (!item)
    618 				item = folder_get_default_trash();
    619 		}
    620 		break;
    621 	default:
    622 		break;
    623 	}
    624 
    625 	return item;
    626 }
    627 
    628 void account_destroy(PrefsAccount *ac_prefs)
    629 {
    630 	cm_return_if_fail(ac_prefs != NULL);
    631 
    632 	folder_unref_account_all(ac_prefs);
    633 
    634 	account_list = g_list_remove(account_list, ac_prefs);
    635 
    636 	if (cur_account == ac_prefs) cur_account = NULL;
    637 	if (!cur_account && account_list) {
    638 		cur_account = account_get_default();
    639 		if (!cur_account) {
    640 			ac_prefs = (PrefsAccount *)account_list->data;
    641 			account_set_as_default(ac_prefs);
    642 			cur_account = ac_prefs;
    643 		}
    644 	}
    645 }
    646 
    647 /*!
    648  *\brief	Save Gtk object size to prefs dataset
    649  */
    650 static void account_size_allocate_cb(GtkWidget *widget,
    651 					 GtkAllocation *allocation)
    652 {
    653 	cm_return_if_fail(allocation != NULL);
    654 
    655 	gtk_window_get_size(GTK_WINDOW(widget),
    656 		&prefs_common.accountswin_width, &prefs_common.accountswin_height);
    657 }
    658 
    659 static void account_edit_create(void)
    660 {
    661 	GtkWidget *window;
    662 	GtkWidget *vbox;
    663 	GtkWidget *label;
    664 	GtkWidget *hbox;
    665 	GtkWidget *scrolledwin;
    666 	GtkWidget *list_view;
    667 
    668 	GtkWidget *vbox2;
    669 	GtkWidget *add_btn;
    670 	GtkWidget *edit_btn;
    671 	GtkWidget *del_btn;
    672 	GtkWidget *up_btn;
    673 	GtkWidget *down_btn;
    674 
    675 	GtkWidget *default_btn;
    676 
    677 	GtkWidget *confirm_area;
    678 	GtkWidget *help_btn;
    679 	GtkWidget *close_btn;
    680 
    681 	static GdkGeometry geometry;
    682 
    683 	debug_print("Creating account edit window...\n");
    684 
    685 	window = gtkut_window_new(GTK_WINDOW_TOPLEVEL, "account");
    686 	gtk_container_set_border_width (GTK_CONTAINER (window), 8);
    687 	gtk_window_set_title (GTK_WINDOW (window), _("Edit accounts"));
    688 	g_signal_connect (G_OBJECT (window), "delete_event",
    689 			  G_CALLBACK (account_delete_event), NULL);
    690 	MANAGE_WINDOW_SIGNALS_CONNECT (window);
    691 	gtk_widget_realize(window);
    692 
    693 	vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 10);
    694 	gtk_widget_show (vbox);
    695 	gtk_container_add (GTK_CONTAINER (window), vbox);
    696 
    697 	hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
    698 	gtk_widget_show (hbox);
    699 	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
    700 
    701 	label = gtk_label_new
    702 		(_("Using 'Get Mail' will retrieve messages from your Accounts "
    703 		   "in the order given, the checkbox indicates which accounts "
    704 		   "will be included. Bold text indicates the default account."));
    705 	gtk_widget_show (label);
    706 
    707 	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 4);
    708 	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
    709 	gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
    710 
    711 	hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
    712 	gtk_widget_show (hbox);
    713 	gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
    714 	gtk_container_set_border_width (GTK_CONTAINER (hbox), 2);
    715 
    716 	scrolledwin = gtk_scrolled_window_new (NULL, NULL);
    717 	gtk_widget_show (scrolledwin);
    718 	gtk_box_pack_start (GTK_BOX (hbox), scrolledwin, TRUE, TRUE, 0);
    719 	gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwin),
    720 					GTK_POLICY_AUTOMATIC,
    721 					GTK_POLICY_AUTOMATIC);
    722 
    723 	list_view = account_list_view_create();
    724 	gtk_widget_show(list_view);
    725 	gtk_container_add(GTK_CONTAINER(scrolledwin), list_view);
    726 
    727 	vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
    728 	gtk_widget_show (vbox2);
    729 	gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 0);
    730 
    731 	add_btn = gtk_button_new_with_mnemonic(_("_New"));
    732 	gtk_widget_show (add_btn);
    733 	gtk_box_pack_start (GTK_BOX (vbox2), add_btn, FALSE, FALSE, 4);
    734 	g_signal_connect (G_OBJECT(add_btn), "clicked",
    735 			  G_CALLBACK (account_add), NULL);
    736 	CLAWS_SET_TIP(add_btn,
    737 			_("Create a new account"));
    738 
    739 	edit_btn = gtk_button_new_with_mnemonic(_("_Edit"));
    740 	gtk_widget_show (edit_btn);
    741 	gtk_box_pack_start (GTK_BOX (vbox2), edit_btn, FALSE, FALSE, 4);
    742 	g_signal_connect (G_OBJECT(edit_btn), "clicked",
    743 			  G_CALLBACK (account_edit_prefs), NULL);
    744 	CLAWS_SET_TIP(edit_btn,
    745 			_("Edit preferences for the selected account"));
    746 
    747 	del_btn = gtkut_stock_button("edit-delete", _("D_elete"));
    748 	gtk_widget_show (del_btn);
    749 	gtk_box_pack_start (GTK_BOX (vbox2), del_btn, FALSE, FALSE, 4);
    750 	g_signal_connect (G_OBJECT(del_btn), "clicked",
    751 			  G_CALLBACK (account_delete), NULL);
    752 	CLAWS_SET_TIP(del_btn,
    753 			_("Delete the selected account from the list"));
    754 
    755 	down_btn = gtkut_stock_button("go-down", _("_Down"));
    756 	gtk_widget_show (down_btn);
    757 	gtk_box_pack_end (GTK_BOX (vbox2), down_btn, FALSE, FALSE, 4);
    758 	g_signal_connect (G_OBJECT(down_btn), "clicked",
    759 			  G_CALLBACK (account_down), NULL);
    760 	CLAWS_SET_TIP(down_btn,
    761 			_("Move the selected account down"));
    762 
    763 	up_btn = gtkut_stock_button("go-up", _("_Up"));
    764 	gtk_widget_show (up_btn);
    765 	gtk_box_pack_end (GTK_BOX (vbox2), up_btn, FALSE, FALSE, 4);
    766 	g_signal_connect (G_OBJECT(up_btn), "clicked",
    767 			  G_CALLBACK (account_up), NULL);
    768 	CLAWS_SET_TIP(up_btn,
    769 			_("Move the selected account up"));
    770 
    771 	hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 8);
    772 	gtk_widget_show (hbox);
    773 	gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
    774 
    775 	default_btn = gtk_button_new_with_mnemonic
    776 		(_(" _Set as default account "));
    777 	gtk_widget_show (default_btn);
    778 	gtk_box_pack_start (GTK_BOX (hbox), default_btn, FALSE, FALSE, 0);
    779 	g_signal_connect (G_OBJECT(default_btn), "clicked",
    780 			  G_CALLBACK (account_set_default), NULL);
    781 
    782 	gtkut_stock_button_set_create_with_help(&confirm_area, &help_btn,
    783 			&close_btn, "window-close", _("_Close"),
    784 			NULL, NULL, NULL, NULL, NULL, NULL);
    785 	gtk_widget_show(confirm_area);
    786 
    787 	gtk_box_pack_end (GTK_BOX (hbox), confirm_area, FALSE, FALSE, 0);
    788 	gtk_widget_grab_default (close_btn);
    789 
    790 	g_signal_connect (G_OBJECT (close_btn), "clicked",
    791 			  G_CALLBACK (account_edit_close),
    792 			  NULL);
    793 	g_signal_connect(G_OBJECT(help_btn), "clicked",
    794 			G_CALLBACK(manual_open_with_anchor_cb),
    795 			MANUAL_ANCHOR_ACCOUNTPREFS);
    796 
    797 
    798 	g_signal_connect(G_OBJECT(window), "size_allocate",
    799 			 G_CALLBACK(account_size_allocate_cb), NULL);
    800 
    801 	if (!geometry.min_height) {
    802 		geometry.min_width = 500;
    803 		geometry.min_height = 380;
    804 	}
    805 
    806 	gtk_window_set_geometry_hints(GTK_WINDOW(window), NULL, &geometry,
    807 				      GDK_HINT_MIN_SIZE);
    808 	gtk_window_set_default_size(GTK_WINDOW(window), prefs_common.accountswin_width,
    809 				    prefs_common.accountswin_height);
    810 
    811 	edit_account.window    = window;
    812 	edit_account.list_view = list_view;
    813 	edit_account.close_btn = close_btn;
    814 }
    815 
    816 static void account_edit_prefs(GtkWidget *widget, gpointer data)
    817 {
    818 	PrefsAccount *ac_prefs;
    819 
    820 	ac_prefs = account_list_view_get_selected_account(edit_account.list_view);
    821 
    822 	if (ac_prefs) {
    823 		account_open(ac_prefs, TRUE);
    824 		account_list_view_set();
    825 	}
    826 }
    827 
    828 static gboolean account_delete_references_func(GNode *node, gpointer data)
    829 {
    830 	FolderItem *item;
    831 	gint account;
    832 
    833 	cm_return_val_if_fail(node->data != NULL, FALSE);
    834 
    835 	item = FOLDER_ITEM(node->data);
    836 	account = GPOINTER_TO_INT(data);
    837 
    838 	if(!item->prefs) /* && item->prefs->stype == F_NORMAL */
    839 		return FALSE;
    840 	if(item->prefs->default_account != account)
    841 		return FALSE;
    842 
    843 	item->prefs->enable_default_account = FALSE;
    844 	item->prefs->default_account = 0;
    845 	folder_item_prefs_save_config(item);
    846 
    847 	return FALSE;
    848 }
    849 
    850 void account_empty_cache(const char *server)
    851 {
    852 	char *cache_dir = prefs_account_cache_dir(server, NULL);
    853 	if (is_dir_exist(cache_dir) && remove_dir_recursive(cache_dir) < 0) {
    854 		g_warning("can't remove directory '%s'", cache_dir);
    855 	}
    856 	g_free(cache_dir);
    857 }
    858 
    859 static void account_delete(GtkWidget *widget, gpointer data)
    860 {
    861 	PrefsAccount *ac_prefs;
    862 	GList *list;
    863 	Folder *folder;
    864 
    865  	ac_prefs = account_list_view_get_selected_account(edit_account.list_view);
    866  	if (ac_prefs == NULL)
    867  		return;
    868 
    869 	char msg[BUFSIZ];
    870 	char *name = ac_prefs->account_name;
    871 	if (!name)
    872 		strlcpy(msg, "Do you really want to delete this account?", sizeof(msg));
    873 	else
    874 		snprintf(msg, sizeof(msg), "Do you really want to delete the account '%s'?", name);
    875 	if (alertpanel_full("Delete account", msg,
    876 		 	    NULL, "_Cancel", "edit-delete-symbolic", "_Delete",
    877 			    NULL, NULL, ALERTFOCUS_FIRST, FALSE,
    878 			    NULL, ALERT_WARNING) != G_ALERTALTERNATE)
    879 		return;
    880 	account_list_dirty = TRUE;
    881 
    882 	if (ac_prefs->folder) {
    883 		FolderItem *item;
    884 
    885 		item = mainwindow_get_mainwindow()->summaryview->folder_item;
    886 		if (item && item->folder == FOLDER(ac_prefs->folder))
    887 			summary_clear_all(mainwindow_get_mainwindow()->summaryview);
    888 		folder_destroy(FOLDER(ac_prefs->folder));
    889 		folderview_set_all();
    890 	}
    891 
    892 	account_destroy(ac_prefs);
    893 	account_list_view_set();
    894 
    895 	debug_print("Removing deleted account references for all the folders...\n");
    896 	list = folder_get_list();
    897 	for (; list != NULL; list = list->next) {
    898 		folder = FOLDER(list->data);
    899 		if (folder->node)  /* && folder->type == F_? */
    900 			g_node_traverse(folder->node, G_PRE_ORDER,
    901 				G_TRAVERSE_ALL, -1,
    902 				account_delete_references_func,
    903 				GINT_TO_POINTER(ac_prefs->account_id));
    904 	}
    905 
    906 	gchar *uid = g_strdup_printf("%d", ac_prefs->account_id);
    907 	passwd_store_delete_block(PWS_ACCOUNT, uid);
    908 	g_free(uid);
    909 
    910 	if (ac_prefs->protocol == A_IMAP4)
    911 		account_empty_cache(ac_prefs->recv_server);
    912 
    913 	folder_write_list();
    914 }
    915 
    916 static void account_up(GtkWidget *widget, gpointer data)
    917 {
    918 	GtkTreePath *sel = account_list_view_get_selected_account_path
    919 				(edit_account.list_view),
    920 		    *up;
    921 	GtkTreeIter isel, iup;
    922 	GtkTreeModel *model = gtk_tree_view_get_model
    923 				(GTK_TREE_VIEW(edit_account.list_view));
    924 
    925 	if (!sel)
    926 		return;
    927 	account_list_dirty = TRUE;
    928 
    929 	up = gtk_tree_path_copy(sel);
    930 	if (!up) {
    931 		gtk_tree_path_free(sel);
    932 		return;
    933 	}
    934 
    935 	if (!gtk_tree_path_prev(up)) {
    936 		gtk_tree_path_free(up);
    937 		gtk_tree_path_free(sel);
    938 		return;
    939 	}
    940 
    941 	if (!gtk_tree_model_get_iter(model, &isel, sel)
    942 	||  !gtk_tree_model_get_iter(model, &iup,  up)) {
    943 		gtk_tree_path_free(up);
    944 		gtk_tree_path_free(sel);
    945 		return;
    946 	}
    947 
    948 	gtk_list_store_swap(GTK_LIST_STORE(model), &isel, &iup);
    949 
    950 	account_list_set();
    951 
    952 	gtk_tree_path_free(up);
    953 	gtk_tree_path_free(sel);
    954 }
    955 
    956 static void account_down(GtkWidget *widget, gpointer data)
    957 {
    958 	GtkTreePath *sel = account_list_view_get_selected_account_path
    959 				(edit_account.list_view),
    960 		    *dn;
    961 	GtkTreeIter isel, idn;
    962 	GtkTreeModel *model = gtk_tree_view_get_model
    963 				(GTK_TREE_VIEW(edit_account.list_view));
    964 
    965 	if (!sel)
    966 		return;
    967 	account_list_dirty = TRUE;
    968 
    969 	dn = gtk_tree_path_copy(sel);
    970 	if (!dn) {
    971 		gtk_tree_path_free(sel);
    972 		return;
    973 	}
    974 
    975 	/* XXX no check possible??? however, if down but at bottom, then
    976 	 * nothing seems to happen much anyway, so the following seems to
    977 	 * be okay */
    978 	gtk_tree_path_next(dn);
    979 
    980 	if (!gtk_tree_model_get_iter(model, &isel, sel)
    981 	||  !gtk_tree_model_get_iter(model, &idn,  dn)) {
    982 		gtk_tree_path_free(dn);
    983 		gtk_tree_path_free(sel);
    984 		return;
    985 	}
    986 
    987 	gtk_list_store_swap(GTK_LIST_STORE(model), &isel, &idn);
    988 
    989 	account_list_set();
    990 
    991 	gtk_tree_path_free(dn);
    992 	gtk_tree_path_free(sel);
    993 }
    994 
    995 static void account_set_default(GtkWidget *widget, gpointer data)
    996 {
    997 	PrefsAccount *ac_prefs;
    998 
    999 	if (NULL == (ac_prefs = account_list_view_get_selected_account
   1000 					(edit_account.list_view)))
   1001 		return;
   1002 
   1003 	/* we need to change the store variables by resetting everything
   1004 	 * and setting the new default one */
   1005 	account_list_view_set_default_by_id(edit_account.list_view,
   1006 					    ac_prefs->account_id);
   1007 
   1008 	account_set_as_default(ac_prefs);
   1009 	account_list_view_set();
   1010 
   1011 	cur_account = ac_prefs;
   1012 	account_flush_state();
   1013 }
   1014 
   1015 static void account_edit_close(GtkWidget *widget, gpointer data)
   1016 {
   1017 	account_list_set();
   1018 	account_write_config_all();
   1019 
   1020 	if (!cur_account && account_list) {
   1021 		PrefsAccount *ac_prefs = (PrefsAccount *)account_list->data;
   1022 		account_set_as_default(ac_prefs);
   1023 		cur_account = ac_prefs;
   1024 	}
   1025 
   1026 	if (account_list_dirty)
   1027 		account_flush_state();
   1028 
   1029 	gtk_widget_hide(edit_account.window);
   1030 	gtk_window_set_modal(GTK_WINDOW(edit_account.window), FALSE);
   1031 	inc_unlock();
   1032 }
   1033 
   1034 static gint account_delete_event(GtkWidget *widget, GdkEventAny *event,
   1035 				 gpointer data)
   1036 {
   1037 	account_edit_close(NULL, NULL);
   1038 	return TRUE;
   1039 }
   1040 
   1041 static gboolean account_search_func_cb (GtkTreeModel *model, gint column, const gchar *key,
   1042 						GtkTreeIter *iter, gpointer search_data)
   1043 {
   1044 	gboolean retval;
   1045 	PrefsAccount *ac;
   1046 
   1047 	gtk_tree_model_get (model, iter, ACCOUNT_DATA, &ac, -1);
   1048 
   1049 	if (!ac->name || !key) return FALSE;
   1050 
   1051 	retval = (strncmp (key, ac->account_name, strlen(key)) != 0);
   1052 
   1053 	debug_print("selecting row\n");
   1054 	account_list_view_select_account(edit_account.list_view, ac->account_id);
   1055 
   1056 	return retval;
   1057 }
   1058 
   1059 static void account_list_view_set(void)
   1060 {
   1061 	GList *cur;
   1062 	gint prev_sel_account;
   1063 	GtkListStore *store;
   1064 
   1065 	store = GTK_LIST_STORE(gtk_tree_view_get_model
   1066 		(GTK_TREE_VIEW(edit_account.list_view)));
   1067 
   1068 	prev_sel_account = account_list_view_get_selected_account_id
   1069 		(edit_account.list_view);
   1070 
   1071 	gtk_list_store_clear(store);
   1072 
   1073 	for (cur = account_list; cur != NULL; cur = cur->next) {
   1074 		account_list_store_insert_account_item(store, (PrefsAccount *)cur->data);
   1075 		if ((PrefsAccount *)cur->data == cur_account)
   1076 			account_list_view_select_account
   1077 				(edit_account.list_view,
   1078 				 cur_account->account_id);
   1079 	}
   1080 
   1081 	if (prev_sel_account >= 0)
   1082 		account_list_view_select_account(edit_account.list_view,
   1083 						 prev_sel_account);
   1084 }
   1085 
   1086 /* set account list from CList */
   1087 static void account_list_set(void)
   1088 {
   1089 	/* want to make sure we iterate *IN ORDER*, so therefore using
   1090 	 * gtk_tree_model_XXXX_nth_child() */
   1091 	gint row, n_rows;
   1092 	PrefsAccount *ac_prefs;
   1093 	GtkTreeModel *model = gtk_tree_view_get_model
   1094 				(GTK_TREE_VIEW(edit_account.list_view));
   1095 
   1096 	while (account_list)
   1097 		account_list = g_list_remove(account_list, account_list->data);
   1098 
   1099 	n_rows = gtk_tree_model_iter_n_children(model, NULL);
   1100 
   1101 	for (row = 0; row < n_rows; row++) {
   1102 		GtkTreeIter iter;
   1103 
   1104 		if (!gtk_tree_model_iter_nth_child(model, &iter, NULL, row)) {
   1105 			g_warning("%s(%d) - no iter found???", __FILE__, __LINE__);
   1106 			continue;
   1107 		}
   1108 
   1109 		ac_prefs = NULL;
   1110 		gtk_tree_model_get(model, &iter,
   1111 				   ACCOUNT_DATA, &ac_prefs,
   1112 				   -1);
   1113 		if (ac_prefs)
   1114 			account_list = g_list_append(account_list, ac_prefs);
   1115 	}
   1116 }
   1117 
   1118 /*!
   1119  *\brief	finds the PrefsAccounts which should be used to answer a mail
   1120  *
   1121  *\param	msginfo The message to be answered
   1122  *\param	reply_autosel Indicates whether reply account autoselection is on
   1123  *
   1124  *\return	PrefsAccount * the correct account, NULL if not found
   1125  */
   1126 PrefsAccount *account_get_reply_account(MsgInfo *msginfo, gboolean reply_autosel)
   1127 {
   1128 	PrefsAccount *account = NULL;
   1129 	/* select the account set in folderitem's property (if enabled) */
   1130 	if (msginfo->folder->prefs && msginfo->folder->prefs->enable_default_account)
   1131 		account = account_find_from_id(msginfo->folder->prefs->default_account);
   1132 	else if (folder_has_parent_of_type(msginfo->folder, F_QUEUE) ||
   1133 		 folder_has_parent_of_type(msginfo->folder, F_OUTBOX) ||
   1134 		 folder_has_parent_of_type(msginfo->folder, F_DRAFT)) {
   1135 			gchar *from = NULL;
   1136 			if (!procheader_get_header_from_msginfo
   1137 				(msginfo, &from, "From:")) {
   1138 				gchar *buf = from + strlen("From:");
   1139 		        	extract_address(buf);
   1140 		        	account = account_find_from_address(buf);
   1141 		        g_free(from);
   1142 			}
   1143 	}
   1144 	/* select account by to: and cc: header if enabled */
   1145 	if (reply_autosel) {
   1146 		gchar * field = NULL;
   1147 		int fieldno = 0;
   1148 		for (field = msginfo->to; fieldno++ < 2; field = msginfo->cc) {
   1149 			if (!account && field) {
   1150 				gchar *f = g_strdup(field);
   1151 				if (f) {
   1152 					gchar *cur = f;
   1153 					gchar *next = NULL;
   1154 					gchar *to = NULL;
   1155 					do {
   1156 						next = strchr_with_skip_quote(cur, '"', ',');
   1157 						if (next)
   1158 							(*next) = 0;
   1159 						Xstrdup_a(to, cur, return NULL);
   1160 						extract_address(to);
   1161 						account = account_find_from_address(to);
   1162 						if (next)
   1163 							cur = next + 1;
   1164 						else
   1165 							break;
   1166 					} while (!account);
   1167 					g_free(f);
   1168 				}
   1169 			}
   1170 		}
   1171 		if (!account) {
   1172 			gchar *deliveredto = NULL;
   1173 			if (!procheader_get_header_from_msginfo
   1174 				(msginfo, &deliveredto, "Delivered-To:")) {
   1175 				gchar *buf = deliveredto + strlen("Delivered-To:");
   1176 		        	extract_address(buf);
   1177 		        	account = account_find_from_address(buf);
   1178 		        g_free(deliveredto);
   1179 			}
   1180 		}
   1181 	}
   1182 
   1183 	/* select the account for the whole folder (IMAP / NNTP) */
   1184 	if (!account)
   1185 		/* FIXME: this is not right, because folder may be nested. we should
   1186 		 * ascend the tree until we find a parent with proper account
   1187 		 * information */
   1188 		account = msginfo->folder->folder->account;
   1189 
   1190 	/* select current account */
   1191 	if (!account) account = cur_account;
   1192 
   1193 	return account;
   1194 }
   1195 
   1196 /*!
   1197  *\brief	Create data store
   1198  */
   1199 static GtkListStore* account_create_data_store(void)
   1200 {
   1201 	return gtk_list_store_new(N_ACCOUNT_COLUMNS,
   1202 				 G_TYPE_INT,		/* ACCOUNT_IS_DEFAULT */
   1203 				 G_TYPE_BOOLEAN,	/* ACCOUNT_ENABLE_GET_ALL */
   1204 				 G_TYPE_STRING,		/* ACCOUNT_NAME */
   1205 				 G_TYPE_STRING,		/* ACCOUNT_PROTOCOL */
   1206 				 G_TYPE_STRING,		/* ACCOUNT_SERVER */
   1207 				 G_TYPE_POINTER,	/* ACCOUNT_DATA */
   1208 				 -1);
   1209 }
   1210 
   1211 /*!
   1212  *\brief	Insert an account item in the list.
   1213  *
   1214  *\return	GtkTreeRowReference * A tree row reference, which is guaranteed to
   1215  *		stable whatever operations are performed on the list.
   1216  */
   1217 static void account_list_store_insert_account_item(GtkListStore *list_store,
   1218 						  PrefsAccount *ac_prefs)
   1219 {
   1220 	GtkTreeIter iter;
   1221 	gboolean is_get_all = (ac_prefs->protocol == A_POP3 ||
   1222 			ac_prefs->protocol == A_IMAP4 ||
   1223 			ac_prefs->protocol == A_LOCAL) &&
   1224 		ac_prefs->recv_at_getall;
   1225 	gchar *protocol, *server;
   1226 
   1227 	protocol = ac_prefs->protocol == A_POP3 ?
   1228 		  (ac_prefs->ssl_pop == SSL_TUNNEL ?
   1229 		   "POP (TLS)" :
   1230 		   ac_prefs->ssl_pop == SSL_STARTTLS ?
   1231 		   "POP (STARTTLS)" : "POP") :
   1232 		   ac_prefs->protocol == A_IMAP4 ?
   1233 		  (ac_prefs->ssl_imap == SSL_TUNNEL ?
   1234 		   "IMAP (TLS)" :
   1235 		   ac_prefs->ssl_imap == SSL_STARTTLS ?
   1236 		   "IMAP (STARTTLS)" : "IMAP") :
   1237 		   ac_prefs->protocol == A_LOCAL ? "Local" :
   1238 		   ac_prefs->protocol == A_NONE ?  "SMTP" : "-";
   1239 
   1240 	server= ac_prefs->protocol == A_LOCAL ?  "-" :
   1241 		   ac_prefs->protocol == A_NONE ? ac_prefs->smtp_server :
   1242 		   ac_prefs->recv_server;
   1243 
   1244 	gtk_list_store_append(list_store, &iter);
   1245 	gtk_list_store_set(list_store, &iter,
   1246 			   ACCOUNT_IS_DEFAULT,     ac_prefs->is_default ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL,
   1247 			   ACCOUNT_ENABLE_GET_ALL, is_get_all,
   1248 			   ACCOUNT_NAME,	   ac_prefs->account_name,
   1249 			   ACCOUNT_PROTOCOL,	   protocol,
   1250 			   ACCOUNT_SERVER,	   server,
   1251 			   ACCOUNT_DATA,	   ac_prefs,
   1252 			   -1);
   1253 }
   1254 
   1255 /*!
   1256  *\brief	Create and set up account list view, including tasks like
   1257  *		creating the data store (\ref account_create_data_store()),
   1258  *		and setting up the account list's individual columns (\ref
   1259  *		account_create_list_view_columns()).
   1260  *
   1261  *\return	GtkWidget * The created list view widget.
   1262  */
   1263 static GtkWidget *account_list_view_create(void)
   1264 {
   1265 	GtkTreeView *list_view;
   1266 	GtkTreeSelection *selector;
   1267 	GtkListStore *store = account_create_data_store();
   1268 
   1269 	list_view = GTK_TREE_VIEW(gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)));
   1270 	g_object_unref(G_OBJECT(store));
   1271 	gtk_tree_view_set_reorderable(list_view, TRUE);
   1272 
   1273 	selector = gtk_tree_view_get_selection(list_view);
   1274 	gtk_tree_selection_set_mode(selector, GTK_SELECTION_BROWSE);
   1275 
   1276 	/* create the columns */
   1277 	account_create_list_view_columns(GTK_WIDGET(list_view));
   1278 
   1279 	/* set a double click listener */
   1280 	g_signal_connect(G_OBJECT(list_view), "row_activated",
   1281 	                 G_CALLBACK(account_double_clicked),
   1282 			 list_view);
   1283 
   1284 	gtk_tree_view_set_reorderable(list_view, TRUE);
   1285 	return GTK_WIDGET(list_view);
   1286 }
   1287 
   1288 static void account_create_list_view_columns(GtkWidget *list_view)
   1289 {
   1290 	GtkTreeViewColumn *column;
   1291 	GtkCellRenderer *renderer;
   1292 
   1293 	renderer = gtk_cell_renderer_toggle_new();
   1294 	g_object_set(renderer,
   1295 		     "radio", FALSE,
   1296 		     "activatable", TRUE,
   1297 		      NULL);
   1298 	column = gtk_tree_view_column_new_with_attributes
   1299 		(C_("Accounts List Get Column Name", "G"), renderer,
   1300 		 "active", ACCOUNT_ENABLE_GET_ALL,
   1301 		 NULL);
   1302 	gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);
   1303 	gtk_tree_view_column_set_alignment (column, 0.5);
   1304 	CLAWS_SET_TIP(gtk_tree_view_column_get_widget(column),
   1305 			_("'Get Mail' retrieves mail from the checked accounts"));
   1306 	g_signal_connect(G_OBJECT(renderer), "toggled",
   1307 			 G_CALLBACK(account_get_all_toggled),
   1308 			 list_view);
   1309 
   1310 	renderer = gtk_cell_renderer_text_new();
   1311 	column = gtk_tree_view_column_new_with_attributes
   1312 		(_("Name"), renderer,
   1313 		 "text", ACCOUNT_NAME,
   1314 		 "weight", ACCOUNT_IS_DEFAULT,
   1315 		 NULL);
   1316 	gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);
   1317 
   1318 	renderer = gtk_cell_renderer_text_new();
   1319 	column = gtk_tree_view_column_new_with_attributes
   1320 		(_("Protocol"), renderer,
   1321 		 "text", ACCOUNT_PROTOCOL,
   1322 		 "weight", ACCOUNT_IS_DEFAULT,
   1323 		 NULL);
   1324 	gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);
   1325 
   1326 	renderer = gtk_cell_renderer_text_new();
   1327 	column = gtk_tree_view_column_new_with_attributes
   1328 		(_("Server"), renderer,
   1329 		 "text", ACCOUNT_SERVER,
   1330 		 "weight", ACCOUNT_IS_DEFAULT,
   1331 		 NULL);
   1332 	gtk_tree_view_set_search_column(GTK_TREE_VIEW(list_view), ACCOUNT_NAME);
   1333 	gtk_tree_view_set_search_equal_func(GTK_TREE_VIEW(list_view), account_search_func_cb , NULL, NULL);
   1334 	gtk_tree_view_append_column(GTK_TREE_VIEW(list_view), column);
   1335 }
   1336 
   1337 /*!
   1338  *\brief	Get currently selected account (by its unique ID)
   1339  */
   1340 static gint account_list_view_get_selected_account_id(GtkWidget *list_view)
   1341 {
   1342 	PrefsAccount *res = NULL;
   1343 
   1344 	res = (PrefsAccount *)gtkut_tree_view_get_selected_pointer(
   1345 			GTK_TREE_VIEW(list_view), ACCOUNT_DATA,
   1346 			NULL, NULL, NULL);
   1347 
   1348 	return (res != NULL ? res->account_id : -1);
   1349 }
   1350 
   1351 /*!
   1352  *\brief	Get the tree path of the currently selected account
   1353  */
   1354 static GtkTreePath *account_list_view_get_selected_account_path(GtkWidget *list_view)
   1355 {
   1356 	GtkTreeSelection *selector;
   1357 	GtkTreeModel *model;
   1358 	GtkTreeIter iter;
   1359 
   1360 	selector = gtk_tree_view_get_selection(GTK_TREE_VIEW(list_view));
   1361 
   1362 	if (!gtk_tree_selection_get_selected(selector, &model, &iter))
   1363 		return NULL;
   1364 
   1365 	return gtk_tree_model_get_path(gtk_tree_view_get_model
   1366 		(GTK_TREE_VIEW(list_view)), &iter);
   1367 }
   1368 
   1369 /*!
   1370  *\brief	Get the account data of the currently selected account
   1371  */
   1372 static PrefsAccount *account_list_view_get_selected_account(GtkWidget *list_view)
   1373 {
   1374 	PrefsAccount *res =
   1375 		(PrefsAccount *)gtkut_tree_view_get_selected_pointer(
   1376 			GTK_TREE_VIEW(list_view), ACCOUNT_DATA,
   1377 			NULL, NULL, NULL);
   1378 
   1379 	return res;
   1380 }
   1381 
   1382 /*!
   1383  *\brief	Select a row by the account it represents
   1384  *
   1385  *\return	gboolean TRUE if found and selected, FALSE if not.
   1386  */
   1387 static gboolean account_list_view_select_account(GtkWidget *list_view, gint account_id)
   1388 {
   1389 	FindAccountInStore fis;
   1390 	GtkTreeModel *model;
   1391 
   1392 	fis.account_id = account_id;
   1393 	fis.path = NULL;
   1394 
   1395 	model = gtk_tree_view_get_model(GTK_TREE_VIEW(list_view));
   1396 
   1397 	gtk_tree_model_foreach(model, (GtkTreeModelForeachFunc) find_account_in_store,
   1398 			       &fis);
   1399 
   1400 	if (fis.path) {
   1401 		GtkTreeSelection *selection;
   1402 		GtkTreePath* path;
   1403 
   1404 		selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(list_view));
   1405 		gtk_tree_selection_select_iter(selection, &fis.iter);
   1406 		path = gtk_tree_model_get_path(model, &fis.iter);
   1407 		/* XXX returned path may not be valid??? create new one to be sure */
   1408 		gtk_tree_view_set_cursor(GTK_TREE_VIEW(list_view), path, NULL, FALSE);
   1409 		gtk_tree_path_free(path);
   1410 	}
   1411 
   1412 	return fis.path != NULL;
   1413 }
   1414 
   1415 /*!
   1416  *\brief	Set a new default account by its ID. (There is only one
   1417  *		default account.)
   1418  */
   1419 static void account_list_view_set_default_by_id(GtkWidget *list_view,
   1420 						gint account_id)
   1421 {
   1422 	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(list_view));
   1423 
   1424 	gtk_tree_model_foreach
   1425 		(model, (GtkTreeModelForeachFunc) set_new_default_account,
   1426 		 &account_id);
   1427 }
   1428 
   1429 static gboolean set_new_default_account(GtkTreeModel *model,
   1430 					GtkTreePath  *path,
   1431 					GtkTreeIter  *iter,
   1432 					gint	     *account_id)
   1433 {
   1434 	PrefsAccount *account = NULL;
   1435 	PangoWeight weight;
   1436 
   1437 	gtk_tree_model_get(model, iter,
   1438 			   ACCOUNT_DATA, &account,
   1439 			   -1);
   1440 
   1441 	if (*account_id == account->account_id)
   1442 		weight = PANGO_WEIGHT_NORMAL;
   1443 	else
   1444 		weight = PANGO_WEIGHT_BOLD;
   1445 
   1446 	gtk_list_store_set(GTK_LIST_STORE(model), iter,
   1447 			   ACCOUNT_IS_DEFAULT, weight, -1);
   1448 
   1449 	return FALSE;
   1450 }
   1451 
   1452 static gboolean find_account_in_store(GtkTreeModel *model,
   1453 				      GtkTreePath  *path,
   1454 				      GtkTreeIter  *iter,
   1455 				      FindAccountInStore *data)
   1456 {
   1457 	PrefsAccount *account = NULL;
   1458 	gtk_tree_model_get(model, iter, ACCOUNT_DATA, &account, -1);
   1459 
   1460 	if (data->account_id == account->account_id) {
   1461 		data->path = path; /* signal we found it */
   1462 		data->iter = *iter;
   1463 		return TRUE;
   1464 	}
   1465 
   1466 	return FALSE;
   1467 }
   1468 
   1469 /*!
   1470  *\brief	Triggered when "get all" column is activated or de-activated
   1471  */
   1472 static void account_get_all_toggled(GtkCellRendererToggle *widget,
   1473 				    gchar *path,
   1474 				    GtkWidget *list_view)
   1475 {
   1476 	GtkTreeIter iter;
   1477 	GtkTreeModel *model = gtk_tree_view_get_model(GTK_TREE_VIEW(list_view));
   1478 	PrefsAccount *ac = NULL;
   1479 	gboolean get_all;
   1480 
   1481 	if (!gtk_tree_model_get_iter_from_string(model, &iter, path))
   1482 		return;
   1483 
   1484 	gtk_tree_model_get(model, &iter,
   1485 			   ACCOUNT_DATA, &ac,
   1486 			   ACCOUNT_ENABLE_GET_ALL, &get_all,
   1487 			   -1);
   1488 
   1489 	/* check if the account has a selectable get all checkbox anyway... */
   1490 	if (!(ac->protocol == A_POP3  ||
   1491 	      ac->protocol == A_IMAP4 ||
   1492 	      ac->protocol == A_LOCAL))
   1493 		return;
   1494 
   1495 	/* set value in store */
   1496 	gtk_list_store_set(GTK_LIST_STORE(model), &iter,
   1497 			   ACCOUNT_ENABLE_GET_ALL, !get_all,
   1498 			   -1);
   1499 
   1500 	/* set value in account */
   1501 	ac->recv_at_getall ^= TRUE;
   1502 }
   1503 
   1504 static void account_double_clicked(GtkTreeView		*list_view,
   1505 				   GtkTreePath		*path,
   1506 				   GtkTreeViewColumn	*column,
   1507 				   gpointer		 data)
   1508 {
   1509 	account_edit_prefs(NULL, NULL);
   1510 }
   1511 
   1512 PrefsAccount *account_get_cur_account (void)
   1513 {
   1514 	return cur_account;
   1515 }
   1516 
   1517 gboolean password_get(const gchar *user,
   1518 		    const gchar *server,
   1519 		    const gchar *protocol,
   1520 		    guint16 port,
   1521 		    gchar **password)
   1522 {
   1523 	PasswordRequest req;
   1524 
   1525 	/* all have to be set */
   1526 	cm_return_val_if_fail(user != NULL, FALSE);
   1527 	cm_return_val_if_fail(server != NULL, FALSE);
   1528 	cm_return_val_if_fail(protocol != NULL, FALSE);
   1529 	cm_return_val_if_fail(port != 0, FALSE);
   1530 
   1531 	req.user = user;
   1532 	req.server = server;
   1533 	req.protocol = protocol;
   1534 	req.port = port;
   1535 
   1536 	if (hooks_invoke(PASSWORD_GET_HOOKLIST, &req)) {
   1537 		*password = req.password;
   1538 		return TRUE;
   1539 	}
   1540 	return FALSE;
   1541 }
   1542