2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 1999-2001 Hiroyuki Yamamoto
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 2 of the License, or
8 * (at your option) any later version.
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.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 #include <gdk/gdkkeysyms.h>
34 #include "mainwindow.h"
35 #include "folderview.h"
39 #include "prefs_account.h"
40 #include "prefs_folder_item.h"
42 #include "manage_window.h"
46 #include "alertpanel.h"
48 #include "pixmaps/mark.xpm"
57 } EditAccountColumnPos;
59 # define N_EDIT_ACCOUNT_COLS 5
61 #define PREFSBUFSIZE 1024
63 PrefsAccount *cur_account;
65 static GList *account_list = NULL;
67 static struct EditAccount {
73 static GdkPixmap *markxpm;
74 static GdkBitmap *markxpmmask;
76 static void account_edit_create (void);
78 static void account_edit_prefs (void);
79 static void account_delete (void);
81 static void account_up (void);
82 static void account_down (void);
84 static void account_set_default (void);
86 static void account_edit_close (void);
87 static gint account_delete_event (GtkWidget *widget,
90 static void account_selected (GtkCList *clist,
95 static void account_key_pressed (GtkWidget *widget,
99 static gint account_clist_set_row (PrefsAccount *ac_prefs,
101 static void account_clist_set (void);
103 static void account_list_set (void);
105 void account_read_config_all(void)
107 GSList *ac_label_list = NULL, *cur;
110 gchar buf[PREFSBUFSIZE];
111 PrefsAccount *ac_prefs;
113 debug_print(_("Reading all config for each account...\n"));
115 rcpath = g_strconcat(get_rc_dir(), G_DIR_SEPARATOR_S, ACCOUNT_RC, NULL);
116 if ((fp = fopen(rcpath, "r")) == NULL) {
117 if (ENOENT != errno) FILE_OP_ERROR(rcpath, "fopen");
123 while (fgets(buf, sizeof(buf), fp) != NULL) {
124 if (!strncmp(buf, "[Account: ", 10)) {
126 memmove(buf, buf + 1, strlen(buf));
127 buf[strlen(buf) - 1] = '\0';
128 debug_print(_("Found label: %s\n"), buf);
129 ac_label_list = g_slist_append(ac_label_list,
135 /* read config data from file */
137 for (cur = ac_label_list; cur != NULL; cur = cur->next) {
138 ac_prefs = g_new0(PrefsAccount, 1);
139 prefs_account_read_config(ac_prefs, (gchar *)cur->data);
140 account_list = g_list_append(account_list, ac_prefs);
141 if (ac_prefs->is_default)
142 cur_account = ac_prefs;
144 /* if default is not set, assume first account as default */
145 if (!cur_account && account_list) {
146 ac_prefs = (PrefsAccount *)account_list->data;
147 account_set_as_default(ac_prefs);
148 cur_account = ac_prefs;
152 main_window_reflect_prefs_all();
154 while (ac_label_list) {
155 g_free(ac_label_list->data);
156 ac_label_list = g_slist_remove(ac_label_list,
157 ac_label_list->data);
161 void account_save_config_all(void)
163 prefs_account_save_config_all(account_list);
166 PrefsAccount *account_find_from_smtp_server(const gchar *address,
167 const gchar *smtp_server)
172 for (cur = account_list; cur != NULL; cur = cur->next) {
173 ac = (PrefsAccount *)cur->data;
174 if (!strcmp2(address, ac->address) &&
175 !strcmp2(smtp_server, ac->smtp_server))
183 * account_find_from_address:
184 * @address: Email address string.
186 * Find a mail (not news) account with the specified email address.
188 * Return value: The found account, or NULL if not found.
190 PrefsAccount *account_find_from_address(const gchar *address)
195 for (cur = account_list; cur != NULL; cur = cur->next) {
196 ac = (PrefsAccount *)cur->data;
197 if (ac->protocol != A_NNTP && strcasestr(address, ac->address))
204 PrefsAccount *account_find_from_id(gint id)
209 for (cur = account_list; cur != NULL; cur = cur->next) {
210 ac = (PrefsAccount *)cur->data;
211 if (id == ac->account_id)
218 void account_set_menu(void)
220 main_window_set_account_menu(account_list);
223 void account_foreach(AccountFunc func, gpointer user_data)
227 for (cur = account_list; cur != NULL; cur = cur->next)
228 if (func((PrefsAccount *)cur->data, user_data) != 0)
232 GList *account_get_list(void)
237 void account_edit_open(void)
241 if (compose_get_compose_list()) {
242 alertpanel_notice(_("Some composing windows are open.\n"
243 "Please close all the composing windows before editing the accounts."));
248 debug_print(_("Opening account edit window...\n"));
250 if (!edit_account.window)
251 account_edit_create();
255 manage_window_set_transient(GTK_WINDOW(edit_account.window));
256 gtk_widget_grab_focus(edit_account.close_btn);
257 gtk_widget_show(edit_account.window);
259 manage_window_focus_in(edit_account.window, NULL, NULL);
262 void account_add(void)
264 PrefsAccount *ac_prefs;
266 ac_prefs = prefs_account_open(NULL);
268 if (!ac_prefs) return;
270 account_list = g_list_append(account_list, ac_prefs);
272 if (ac_prefs->is_default)
273 account_set_as_default(ac_prefs);
277 if (ac_prefs->protocol == A_IMAP4 || ac_prefs->protocol == A_NNTP) {
280 if (ac_prefs->protocol == A_IMAP4) {
281 folder = folder_new(F_IMAP, ac_prefs->account_name,
282 ac_prefs->recv_server);
284 folder = folder_new(F_NEWS, ac_prefs->account_name,
285 ac_prefs->nntp_server);
288 folder->account = ac_prefs;
289 ac_prefs->folder = REMOTE_FOLDER(folder);
291 if (ac_prefs->protocol == A_IMAP4)
292 folder->create_tree(folder);
293 folderview_set_all();
297 void account_set_as_default(PrefsAccount *ac_prefs)
302 for (cur = account_list; cur != NULL; cur = cur->next) {
303 ap = (PrefsAccount *)cur->data;
305 ap->is_default = FALSE;
308 ac_prefs->is_default = TRUE;
311 PrefsAccount *account_get_default(void)
316 for (cur = account_list; cur != NULL; cur = cur->next) {
317 ap = (PrefsAccount *)cur->data;
325 void account_set_missing_folder(void)
330 for (cur = account_list; cur != NULL; cur = cur->next) {
331 ap = (PrefsAccount *)cur->data;
332 if ((ap->protocol == A_IMAP4 || ap->protocol == A_NNTP) &&
336 if (ap->protocol == A_IMAP4) {
337 folder = folder_new(F_IMAP, ap->account_name,
340 folder = folder_new(F_NEWS, ap->account_name,
344 folder->account = ap;
345 ap->folder = REMOTE_FOLDER(folder);
347 if (ap->protocol == A_IMAP4)
348 folder->create_tree(folder);
353 void account_destroy(PrefsAccount *ac_prefs)
355 g_return_if_fail(ac_prefs != NULL);
357 prefs_account_free(ac_prefs);
358 account_list = g_list_remove(account_list, ac_prefs);
360 if (cur_account == ac_prefs) cur_account = NULL;
361 if (!cur_account && account_list) {
362 cur_account = account_get_default();
364 ac_prefs = (PrefsAccount *)account_list->data;
365 account_set_as_default(ac_prefs);
366 cur_account = ac_prefs;
372 static void account_edit_create(void)
378 GtkWidget *scrolledwin;
380 gchar *titles[N_EDIT_ACCOUNT_COLS];
390 GtkWidget *default_btn;
393 GtkWidget *close_btn;
395 debug_print(_("Creating account edit window...\n"));
397 window = gtk_window_new (GTK_WINDOW_DIALOG);
398 gtk_widget_set_usize (window, 500, 320);
399 gtk_container_set_border_width (GTK_CONTAINER (window), 8);
400 gtk_window_set_title (GTK_WINDOW (window), _("Edit accounts"));
401 gtk_window_set_modal (GTK_WINDOW (window), TRUE);
402 gtk_signal_connect (GTK_OBJECT (window), "delete_event",
403 GTK_SIGNAL_FUNC (account_delete_event), NULL);
404 gtk_signal_connect (GTK_OBJECT (window), "key_press_event",
405 GTK_SIGNAL_FUNC (account_key_pressed), NULL);
406 gtk_signal_connect (GTK_OBJECT (window), "focus_in_event",
407 GTK_SIGNAL_FUNC (manage_window_focus_in), NULL);
408 gtk_signal_connect (GTK_OBJECT (window), "focus_out_event",
409 GTK_SIGNAL_FUNC (manage_window_focus_out), NULL);
410 gtk_widget_realize(window);
412 vbox = gtk_vbox_new (FALSE, 10);
413 gtk_widget_show (vbox);
414 gtk_container_add (GTK_CONTAINER (window), vbox);
416 hbox = gtk_hbox_new (FALSE, 0);
417 gtk_widget_show (hbox);
418 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
420 label = gtk_label_new
421 (_("New messages will be checked in this order. Click in the 'G' column\n"
422 "to enable message retrieval by `Get all' for that account."));
423 gtk_widget_show (label);
424 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 4);
425 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
427 hbox = gtk_hbox_new (FALSE, 8);
428 gtk_widget_show (hbox);
429 gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
430 gtk_container_set_border_width (GTK_CONTAINER (hbox), 2);
432 scrolledwin = gtk_scrolled_window_new (NULL, NULL);
433 gtk_widget_show (scrolledwin);
434 gtk_box_pack_start (GTK_BOX (hbox), scrolledwin, TRUE, TRUE, 0);
435 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolledwin),
436 GTK_POLICY_AUTOMATIC,
437 GTK_POLICY_AUTOMATIC);
439 titles[COL_DEFAULT] = "D";
440 titles[COL_GETALL] = "G";
441 titles[COL_NAME] = _("Name");
442 titles[COL_PROTOCOL] = _("Protocol");
443 titles[COL_SERVER] = _("Server");
445 clist = gtk_clist_new_with_titles (N_EDIT_ACCOUNT_COLS, titles);
446 gtk_widget_show (clist);
447 gtk_container_add (GTK_CONTAINER (scrolledwin), clist);
448 gtk_clist_set_column_width (GTK_CLIST(clist), COL_DEFAULT , 10);
449 gtk_clist_set_column_width (GTK_CLIST(clist), COL_GETALL , 10);
450 gtk_clist_set_column_width (GTK_CLIST(clist), COL_NAME , 100);
451 gtk_clist_set_column_width (GTK_CLIST(clist), COL_PROTOCOL, 100);
452 gtk_clist_set_column_width (GTK_CLIST(clist), COL_SERVER , 100);
453 gtk_clist_set_selection_mode (GTK_CLIST(clist), GTK_SELECTION_BROWSE);
455 for (i = 0; i < N_EDIT_ACCOUNT_COLS; i++)
456 GTK_WIDGET_UNSET_FLAGS(GTK_CLIST(clist)->column[i].button,
459 gtk_signal_connect (GTK_OBJECT (clist), "select_row",
460 GTK_SIGNAL_FUNC (account_selected), NULL);
462 vbox2 = gtk_vbox_new (FALSE, 0);
463 gtk_widget_show (vbox2);
464 gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 0);
466 add_btn = gtk_button_new_with_label (_("Add"));
467 gtk_widget_show (add_btn);
468 gtk_box_pack_start (GTK_BOX (vbox2), add_btn, FALSE, FALSE, 4);
469 gtk_signal_connect (GTK_OBJECT(add_btn), "clicked",
470 GTK_SIGNAL_FUNC (account_add), NULL);
472 edit_btn = gtk_button_new_with_label (_("Edit"));
473 gtk_widget_show (edit_btn);
474 gtk_box_pack_start (GTK_BOX (vbox2), edit_btn, FALSE, FALSE, 4);
475 gtk_signal_connect (GTK_OBJECT(edit_btn), "clicked",
476 GTK_SIGNAL_FUNC (account_edit_prefs), NULL);
478 del_btn = gtk_button_new_with_label (_(" Delete "));
479 gtk_widget_show (del_btn);
480 gtk_box_pack_start (GTK_BOX (vbox2), del_btn, FALSE, FALSE, 4);
481 gtk_signal_connect (GTK_OBJECT(del_btn), "clicked",
482 GTK_SIGNAL_FUNC (account_delete), NULL);
484 down_btn = gtk_button_new_with_label (_("Down"));
485 gtk_widget_show (down_btn);
486 gtk_box_pack_end (GTK_BOX (vbox2), down_btn, FALSE, FALSE, 4);
487 gtk_signal_connect (GTK_OBJECT(down_btn), "clicked",
488 GTK_SIGNAL_FUNC (account_down), NULL);
490 up_btn = gtk_button_new_with_label (_("Up"));
491 gtk_widget_show (up_btn);
492 gtk_box_pack_end (GTK_BOX (vbox2), up_btn, FALSE, FALSE, 4);
493 gtk_signal_connect (GTK_OBJECT(up_btn), "clicked",
494 GTK_SIGNAL_FUNC (account_up), NULL);
496 hbox = gtk_hbox_new (FALSE, 8);
497 gtk_widget_show (hbox);
498 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
500 vbox2 = gtk_vbox_new(FALSE, 0);
501 gtk_widget_show (vbox2);
502 gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 0);
504 default_btn = gtk_button_new_with_label (_(" Set as default account "));
505 gtk_widget_show (default_btn);
506 gtk_box_pack_start (GTK_BOX (vbox2), default_btn, TRUE, FALSE, 0);
507 gtk_signal_connect (GTK_OBJECT(default_btn), "clicked",
508 GTK_SIGNAL_FUNC (account_set_default), NULL);
510 gtkut_button_set_create(&hbbox, &close_btn, _("Close"),
511 NULL, NULL, NULL, NULL);
512 gtk_widget_show(hbbox);
513 gtk_box_pack_end (GTK_BOX (hbox), hbbox, FALSE, FALSE, 0);
514 gtk_widget_grab_default (close_btn);
516 gtk_signal_connect (GTK_OBJECT (close_btn), "clicked",
517 GTK_SIGNAL_FUNC (account_edit_close),
520 PIXMAP_CREATE(clist, markxpm, markxpmmask, mark_xpm);
522 edit_account.window = window;
523 edit_account.clist = clist;
524 edit_account.close_btn = close_btn;
527 static void account_edit_prefs(void)
529 GtkCList *clist = GTK_CLIST(edit_account.clist);
530 PrefsAccount *ac_prefs;
532 gboolean prev_default;
535 if (!clist->selection) return;
537 row = GPOINTER_TO_INT(clist->selection->data);
538 ac_prefs = gtk_clist_get_row_data(clist, row);
539 prev_default = ac_prefs->is_default;
540 Xstrdup_a(ac_name, ac_prefs->account_name, return);
542 prefs_account_open(ac_prefs);
544 if (!prev_default && ac_prefs->is_default)
545 account_set_as_default(ac_prefs);
547 if ((ac_prefs->protocol == A_IMAP4 || ac_prefs->protocol == A_NNTP) &&
548 ac_prefs->folder && strcmp(ac_name, ac_prefs->account_name) != 0) {
549 folder_set_name(FOLDER(ac_prefs->folder),
550 ac_prefs->account_name);
551 folderview_update_all();
557 static void account_delete_references_recursive(const GNode *node, const gint account)
561 FolderItem *item = node->data;
562 if (item->prefs) /* && item->prefs->stype == F_NORMAL */
563 if (item->prefs->default_account == account) {
564 item->prefs->enable_default_account = FALSE;
565 item->prefs->default_account = 0;
566 prefs_folder_item_save_config(item);
569 /* its children (vertical dive) */
571 account_delete_references_recursive(node->children, account);
572 /* its brothers (horizontal dive) */
574 account_delete_references_recursive(node->next, account);
577 static void account_delete(void)
579 GtkCList *clist = GTK_CLIST(edit_account.clist);
580 PrefsAccount *ac_prefs;
585 if (!clist->selection) return;
587 if (alertpanel(_("Delete account"),
588 _("Do you really want to delete this account?"),
589 _("Yes"), _("+No"), NULL) != G_ALERTDEFAULT)
592 row = GPOINTER_TO_INT(clist->selection->data);
593 ac_prefs = gtk_clist_get_row_data(clist, row);
594 if (ac_prefs->folder) {
595 folder_destroy(FOLDER(ac_prefs->folder));
596 folderview_update_all();
598 account_destroy(ac_prefs);
601 debug_print(_("Removing deleted account references for all the folders...\n"));
602 list = folder_get_list();
603 for (; list != NULL; list = list->next) {
604 folder = FOLDER(list->data);
605 if (folder->node) /* && folder->type == F_? */
606 account_delete_references_recursive(folder->node, ac_prefs->account_id);
610 static void account_up(void)
612 GtkCList *clist = GTK_CLIST(edit_account.clist);
615 if (!clist->selection) return;
617 row = GPOINTER_TO_INT(clist->selection->data);
619 gtk_clist_row_move(clist, row, row - 1);
624 static void account_down(void)
626 GtkCList *clist = GTK_CLIST(edit_account.clist);
629 if (!clist->selection) return;
631 row = GPOINTER_TO_INT(clist->selection->data);
632 if (row < clist->rows - 1) {
633 gtk_clist_row_move(clist, row, row + 1);
638 static void account_set_default(void)
640 GtkCList *clist = GTK_CLIST(edit_account.clist);
642 PrefsAccount *ac_prefs;
644 if (!clist->selection) return;
646 row = GPOINTER_TO_INT(clist->selection->data);
647 ac_prefs = gtk_clist_get_row_data(clist, row);
648 account_set_as_default(ac_prefs);
651 cur_account = ac_prefs;
653 main_window_reflect_prefs_all();
656 static void account_edit_close(void)
659 account_save_config_all();
661 if (!cur_account && account_list) {
662 PrefsAccount *ac_prefs = (PrefsAccount *)account_list->data;
663 account_set_as_default(ac_prefs);
664 cur_account = ac_prefs;
668 main_window_reflect_prefs_all();
670 gtk_widget_hide(edit_account.window);
675 static gint account_delete_event(GtkWidget *widget, GdkEventAny *event,
678 account_edit_close();
682 static void account_selected(GtkCList *clist, gint row, gint column,
683 GdkEvent *event, gpointer data)
685 if (event && event->type == GDK_2BUTTON_PRESS)
686 account_edit_prefs();
688 if (column == COL_GETALL) {
691 ac = gtk_clist_get_row_data(clist, row);
692 if (ac->protocol == A_POP3 || ac->protocol == A_APOP) {
693 ac->recv_at_getall ^= TRUE;
694 account_clist_set_row(ac, row);
699 static void account_key_pressed(GtkWidget *widget, GdkEventKey *event,
702 if (event && event->keyval == GDK_Escape)
703 account_edit_close();
706 /* set one CList row or add new row */
707 static gint account_clist_set_row(PrefsAccount *ac_prefs, gint row)
709 GtkCList *clist = GTK_CLIST(edit_account.clist);
710 gchar *text[N_EDIT_ACCOUNT_COLS];
712 text[COL_DEFAULT] = ac_prefs->is_default ? "*" : "";
713 text[COL_GETALL] = (ac_prefs->protocol == A_POP3 ||
714 ac_prefs->protocol == A_APOP) &&
715 ac_prefs->recv_at_getall ? "*" : "";
716 text[COL_NAME] = ac_prefs->account_name;
718 text[COL_PROTOCOL] = ac_prefs->protocol == A_POP3 ?
719 (ac_prefs->ssl_pop ? "POP3 (SSL)" : "POP3") :
720 ac_prefs->protocol == A_APOP ?
722 "POP3 (APOP, SSL)" : "POP3 (APOP)") :
723 ac_prefs->protocol == A_IMAP4 ?
724 (ac_prefs->ssl_imap ? "IMAP4 (SSL)" : "IMAP4") :
725 ac_prefs->protocol == A_LOCAL ? "Local" :
726 ac_prefs->protocol == A_NNTP ? "NNTP" : "";
728 text[COL_PROTOCOL] = ac_prefs->protocol == A_POP3 ? "POP3" :
729 ac_prefs->protocol == A_APOP ? "POP3 (APOP)" :
730 ac_prefs->protocol == A_IMAP4 ? "IMAP4" :
731 ac_prefs->protocol == A_LOCAL ? "Local" :
732 ac_prefs->protocol == A_NNTP ? "NNTP" : "";
734 text[COL_SERVER] = ac_prefs->protocol == A_NNTP
735 ? ac_prefs->nntp_server : ac_prefs->recv_server;
738 row = gtk_clist_append(clist, text);
740 gtk_clist_set_text(clist, row, COL_DEFAULT, text[COL_DEFAULT]);
741 gtk_clist_set_text(clist, row, COL_GETALL, text[COL_GETALL]);
742 gtk_clist_set_text(clist, row, COL_NAME, text[COL_NAME]);
743 gtk_clist_set_text(clist, row, COL_PROTOCOL, text[COL_PROTOCOL]);
744 gtk_clist_set_text(clist, row, COL_SERVER, text[COL_SERVER]);
747 if (*text[COL_DEFAULT])
748 gtk_clist_set_pixmap(clist, row, COL_DEFAULT,
749 markxpm, markxpmmask);
750 if (*text[COL_GETALL])
751 gtk_clist_set_pixmap(clist, row, COL_GETALL,
752 markxpm, markxpmmask);
754 gtk_clist_set_row_data(clist, row, ac_prefs);
759 /* set CList from account list */
760 static void account_clist_set(void)
762 GtkCList *clist = GTK_CLIST(edit_account.clist);
766 if (clist->selection)
767 prev_row = GPOINTER_TO_INT(clist->selection->data);
771 gtk_clist_freeze(clist);
772 gtk_clist_clear(clist);
774 for (cur = account_list; cur != NULL; cur = cur->next) {
777 row = account_clist_set_row((PrefsAccount *)cur->data, -1);
778 if ((PrefsAccount *)cur->data == cur_account) {
779 gtk_clist_select_row(clist, row, -1);
780 gtkut_clist_set_focus_row(clist, row);
785 gtk_clist_select_row(clist, prev_row, -1);
786 gtkut_clist_set_focus_row(clist, prev_row);
789 gtk_clist_thaw(clist);
792 /* set account list from CList */
793 static void account_list_set(void)
795 GtkCList *clist = GTK_CLIST(edit_account.clist);
797 PrefsAccount *ac_prefs;
800 account_list = g_list_remove(account_list, account_list->data);
802 for (row = 0; (ac_prefs = gtk_clist_get_row_data(clist, row)) != NULL;
804 account_list = g_list_append(account_list, ac_prefs);