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