diff --git a/src/callbacks.c b/src/callbacks.c index ca72b65..20eb44c 100644 --- a/src/callbacks.c +++ b/src/callbacks.c @@ -1,19 +1,17 @@ /* $Id$ */ -static char const _copyright[] = -"Copyright (c) 2010 Pierre Pronchery "; +/* Copyright (c) 2010 Pierre Pronchery */ /* This file is part of DeforaOS Desktop Mailer */ -static char const _license[] = -"This program is free software: you can redistribute it and/or modify\n" -"it under the terms of the GNU General Public License as published by\n" -"the Free Software Foundation, version 3 of the License.\n" -"\n" -"This program is distributed in the hope that it will be useful,\n" -"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" -"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" -"GNU General Public License for more details.\n" -"\n" -"You should have received a copy of the GNU General Public License\n" -"along with this program. If not, see .\n"; +/* This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ /* TODO: * - check that the messages font button is initialized correctly */ @@ -25,45 +23,27 @@ static char const _license[] = #include #include #include -#include #include "compose.h" #include "mailer.h" #include "callbacks.h" -/* constants */ -static char const * _authors[] = -{ - "Pierre Pronchery ", - NULL -}; - -static const char * _title[3] = -{ - "New account", "Account settings", "Account confirmation" -}; - - -/* prototypes */ -/* private */ -static void _on_about(GtkWidget * window); - - /* functions */ /* public */ /* callbacks */ /* window */ -gboolean on_closex(GtkWidget * widget, GdkEvent * event, gpointer data) +gboolean on_closex(gpointer data) { - gtk_widget_hide(widget); - /* FIXME may be composing */ + Mailer * mailer; + + /* FIXME may be composing or viewing messages */ gtk_main_quit(); return FALSE; } /* file menu */ -void on_file_new_mail(GtkWidget * widget, gpointer data) +void on_file_new_mail(gpointer data) { Mailer * mailer = data; @@ -71,25 +51,25 @@ void on_file_new_mail(GtkWidget * widget, gpointer data) } -void on_file_send_receive(GtkWidget * widget, gpointer data) +void on_file_send_receive(gpointer data) { /* FIXME implement */ } -void on_file_print(GtkWidget * widget, gpointer data) +void on_file_print(gpointer data) { /* FIXME implement */ } -void on_file_print_preview(GtkWidget * widget, gpointer data) +void on_file_print_preview(gpointer data) { /* FIXME implement */ } -void on_file_quit(GtkWidget * widget, gpointer data) +void on_file_quit(gpointer data) { /* FIXME may be composing */ gtk_main_quit(); @@ -97,231 +77,56 @@ void on_file_quit(GtkWidget * widget, gpointer data) /* message menu */ -void on_message_reply(GtkWidget * widget, gpointer data) +void on_message_reply(gpointer data) { - on_reply(widget, data); + on_reply(data); } -void on_message_reply_to_all(GtkWidget * widget, gpointer data) +void on_message_reply_to_all(gpointer data) { - on_reply_to_all(widget, data); + on_reply_to_all(data); } -void on_message_forward(GtkWidget * widget, gpointer data) +void on_message_forward(gpointer data) { - on_forward(widget, data); + on_forward(data); } -void on_message_delete(GtkWidget * widget, gpointer data) +void on_message_delete(gpointer data) { - on_delete(widget, data); + on_delete(data); } -void on_message_view_source(GtkWidget * widget, gpointer data) +void on_message_view_source(gpointer data) { /* FIXME implement */ } /* edit menu */ -typedef enum _AccountColumn -{ - AC_DATA = 0, - AC_ACTIVE, - AC_ENABLED, - AC_TITLE, - AC_TYPE -} AccountColumn; -#define AC_LAST AC_TYPE -#define AC_COUNT (AC_LAST + 1) -static void _preferences_set(Mailer * mailer); -static gboolean _on_preferences_closex(GtkWidget * widget, GdkEvent * event, - gpointer data); -static void _on_preferences_account_toggle(GtkCellRendererToggle * renderer, - char * path, gpointer data); - -void on_edit_preferences(GtkWidget * widget, gpointer data) +void on_edit_preferences(gpointer data) { Mailer * mailer = data; - GtkWidget * notebook; - GtkWidget * vbox; - GtkWidget * hbox; - GtkWidget * vbox2; - GtkWidget * vbox3; - GtkSizeGroup * group; - GtkListStore * store; - size_t i; - Account * ac; - GtkTreeIter iter; - GtkCellRenderer * renderer; - if(mailer->pr_window != NULL) - { - gtk_widget_show(mailer->pr_window); - return; - } - mailer->pr_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_default_size(GTK_WINDOW(mailer->pr_window), 300, 200); - gtk_container_set_border_width(GTK_CONTAINER(mailer->pr_window), 4); - gtk_window_set_title(GTK_WINDOW(mailer->pr_window), - "Mailer preferences"); - gtk_window_set_transient_for(GTK_WINDOW(mailer->pr_window), GTK_WINDOW( - mailer->window)); - g_signal_connect(G_OBJECT(mailer->pr_window), "delete-event", - G_CALLBACK(_on_preferences_closex), NULL); - vbox = gtk_vbox_new(FALSE, 4); - notebook = gtk_notebook_new(); - /* accounts */ - vbox2 = gtk_vbox_new(FALSE, 4); - gtk_container_set_border_width(GTK_CONTAINER(vbox2), 4); - hbox = gtk_hbox_new(FALSE, 4); - widget = gtk_scrolled_window_new(NULL, NULL); - gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(widget), - GTK_SHADOW_IN); - gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget), - GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - store = gtk_list_store_new(AC_COUNT, G_TYPE_POINTER, G_TYPE_BOOLEAN, - G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING); - for(i = 0; i < mailer->account_cnt; i++) - { - ac = mailer->account[i]; - gtk_list_store_insert_with_values(store, &iter, -1, - AC_DATA, ac, AC_ACTIVE, TRUE, - AC_ENABLED, ac->enabled, AC_TITLE, ac->title, - AC_TYPE, ac->plugin->type, -1); - } - mailer->pr_accounts = gtk_tree_view_new_with_model(GTK_TREE_MODEL( - store)); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(mailer->pr_accounts), - TRUE); - renderer = gtk_cell_renderer_toggle_new(); - g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK( - _on_preferences_account_toggle), store); - gtk_tree_view_append_column(GTK_TREE_VIEW(mailer->pr_accounts), - gtk_tree_view_column_new_with_attributes("Enabled", - renderer, "active", AC_ENABLED, NULL)); - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_append_column(GTK_TREE_VIEW(mailer->pr_accounts), - gtk_tree_view_column_new_with_attributes("Name", - renderer, "text", AC_TITLE, NULL)); - renderer = gtk_cell_renderer_text_new(); - gtk_tree_view_append_column(GTK_TREE_VIEW(mailer->pr_accounts), - gtk_tree_view_column_new_with_attributes("Type", - renderer, "text", AC_TYPE, NULL)); - gtk_container_add(GTK_CONTAINER(widget), mailer->pr_accounts); - gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); - vbox3 = gtk_vbox_new(FALSE, 4); - widget = gtk_button_new_from_stock(GTK_STOCK_NEW); - g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK( - on_account_new), mailer); - gtk_box_pack_start(GTK_BOX(vbox3), widget, FALSE, TRUE, 0); -#if GTK_CHECK_VERSION(2, 6, 0) - widget = gtk_button_new_from_stock(GTK_STOCK_EDIT); -#else - widget = gtk_button_new_with_mnemonic("_Edit"); -#endif - g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK( - on_account_edit), mailer); - gtk_box_pack_start(GTK_BOX(vbox3), widget, FALSE, TRUE, 0); - widget = gtk_button_new_from_stock(GTK_STOCK_DELETE); - g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK( - on_account_delete), mailer); - gtk_box_pack_start(GTK_BOX(vbox3), widget, FALSE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(hbox), vbox3, FALSE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(vbox2), hbox, TRUE, TRUE, 0); - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, gtk_label_new( - "Accounts")); - /* display */ - vbox2 = gtk_vbox_new(FALSE, 4); - gtk_container_set_border_width(GTK_CONTAINER(vbox2), 4); - group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); - /* default font */ - hbox = gtk_hbox_new(FALSE, 4); - widget = gtk_label_new("Messages font:"); - gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0); - mailer->pr_messages_font = gtk_font_button_new(); - widget = mailer->pr_messages_font; - gtk_size_group_add_widget(group, widget); - gtk_font_button_set_use_font(GTK_FONT_BUTTON(widget), TRUE); - gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0); - gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, gtk_label_new( - "Display")); - gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); - /* dialog */ - hbox = gtk_hbox_new(FALSE, 4); - group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); - widget = gtk_button_new_from_stock(GTK_STOCK_OK); - gtk_size_group_add_widget(group, widget); - g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK( - on_preferences_ok), mailer); - gtk_box_pack_end(GTK_BOX(hbox), widget, FALSE, TRUE, 0); - widget = gtk_button_new_from_stock(GTK_STOCK_CANCEL); - gtk_size_group_add_widget(group, widget); - g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK( - on_preferences_cancel), mailer); - gtk_box_pack_end(GTK_BOX(hbox), widget, FALSE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - gtk_container_add(GTK_CONTAINER(mailer->pr_window), vbox); - _preferences_set(mailer); - gtk_widget_show_all(mailer->pr_window); -} - -static void _preferences_set(Mailer * mailer) -{ - char const * p; - - if((p = mailer_get_config(mailer, "messages_font")) == NULL) - p = MAILER_MESSAGES_FONT; - gtk_font_button_set_font_name(GTK_FONT_BUTTON(mailer->pr_messages_font), - p); -} - -static gboolean _on_preferences_closex(GtkWidget * widget, GdkEvent * event, - gpointer data) -{ - gtk_widget_hide(widget); - return TRUE; -} - -static void _on_preferences_account_toggle(GtkCellRendererToggle * renderer, - char * path, gpointer data) -{ - GtkListStore * store = data; - GtkTreeIter iter; - - gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(store), &iter, path); - gtk_list_store_set(store, &iter, AC_ENABLED, - !gtk_cell_renderer_toggle_get_active(renderer), -1); + mailer_show_preferences(mailer, TRUE); } /* help menu */ -static gboolean _on_about_closex(GtkWidget * widget, GdkEvent * event, - gpointer data); - -void on_help_about(GtkWidget * widget, gpointer data) +void on_help_about(gpointer data) { Mailer * mailer = data; - _on_about(mailer->window); -} - -static gboolean _on_about_closex(GtkWidget * widget, GdkEvent * event, - gpointer data) -{ - gtk_widget_hide(widget); - return TRUE; + mailer_show_about(mailer, TRUE); } /* toolbar */ -void on_new_mail(GtkWidget * widget, gpointer data) +void on_new_mail(gpointer data) { Mailer * mailer = data; @@ -329,13 +134,13 @@ void on_new_mail(GtkWidget * widget, gpointer data) } -void on_stop(GtkWidget * widget, gpointer data) +void on_stop(gpointer data) { /* FIXME implement */ } -void on_reply(GtkWidget * widget, gpointer data) +void on_reply(gpointer data) { Mailer * mailer = data; @@ -344,7 +149,7 @@ void on_reply(GtkWidget * widget, gpointer data) } -void on_reply_to_all(GtkWidget * widget, gpointer data) +void on_reply_to_all(gpointer data) { Mailer * mailer = data; @@ -353,7 +158,7 @@ void on_reply_to_all(GtkWidget * widget, gpointer data) } -void on_forward(GtkWidget * widget, gpointer data) +void on_forward(gpointer data) { Mailer * mailer = data; @@ -362,906 +167,31 @@ void on_forward(GtkWidget * widget, gpointer data) } -void on_delete(GtkWidget * widget, gpointer data) +void on_delete(gpointer data) { /* FIXME implement */ } -void on_print(GtkWidget * widget, gpointer data) +void on_print(gpointer data) { /* FIXME implement */ } -/* folder view */ -void on_folder_change(GtkTreeSelection * selection, gpointer data) -{ - Mailer * mailer = data; - GtkTreeModel * model; - GtkTreeIter iter; - GtkListStore * store; - GtkTreePath * path; - -#ifdef DEBUG - fprintf(stderr, "DEBUG: %s()\n", __func__); -#endif - if(!gtk_tree_selection_get_selected(selection, &model, &iter)) - { - mailer->account_cur = NULL; - mailer->folder_cur = NULL; - gtk_tree_view_set_model(GTK_TREE_VIEW(mailer->view_headers), - NULL); - return; - } - /* get current folder */ - gtk_tree_model_get(model, &iter, MF_COL_FOLDER, &mailer->folder_cur, - -1); - /* get current account */ - path = gtk_tree_model_get_path(model, &iter); - while(gtk_tree_path_get_depth(path) > 1 && gtk_tree_path_up(path)); - gtk_tree_model_get_iter(model, &iter, path); - gtk_tree_model_get(model, &iter, MF_COL_ACCOUNT, &mailer->account_cur, - -1); - gtk_tree_path_free(path); - /* display headers */ -#ifdef DEBUG - fprintf(stderr, "DEBUG: %s() account_get_store()\n", __func__); -#endif - store = account_get_store(mailer->account_cur, mailer->folder_cur); - gtk_tree_view_set_model(GTK_TREE_VIEW(mailer->view_headers), - GTK_TREE_MODEL(store)); -} - - -/* header view */ -/* on_header_change */ -void on_header_change(GtkTreeSelection * selection, gpointer data) -{ - Mailer * mailer = data; - GtkTreeModel * model; - GList * sel; - GtkTreeIter iter; - char * p; - AccountMessage * message; - -#ifdef DEBUG - fprintf(stderr, "DEBUG: %s()\n", __func__); -#endif - sel = gtk_tree_selection_get_selected_rows(selection, &model); - if(sel == NULL || sel->next != NULL) /* empty or multiple */ - { - gtk_widget_hide(mailer->hdr_vbox); - gtk_text_view_set_buffer(GTK_TEXT_VIEW(mailer->view_body), - mailer->view_buffer); - } - else - { - gtk_tree_model_get_iter(model, &iter, sel->data); - gtk_tree_model_get(model, &iter, MH_COL_MESSAGE, &message, -1); - gtk_tree_model_get(model, &iter, MH_COL_SUBJECT, &p, -1); - gtk_label_set_text(GTK_LABEL(mailer->hdr_subject), p); - gtk_tree_model_get(model, &iter, MH_COL_FROM, &p, -1); - gtk_label_set_text(GTK_LABEL(mailer->hdr_from), p); - gtk_tree_model_get(model, &iter, MH_COL_TO, &p, -1); - gtk_label_set_text(GTK_LABEL(mailer->hdr_to), p); - gtk_tree_model_get(model, &iter, MH_COL_DATE, &p, -1); - gtk_label_set_text(GTK_LABEL(mailer->hdr_date), p); - gtk_widget_show(mailer->hdr_vbox); - account_select(mailer->account_cur, mailer->folder_cur, - message); - gtk_text_view_set_buffer(GTK_TEXT_VIEW(mailer->view_body), - mailer->account_cur->buffer); - } - g_list_foreach(sel, (GFunc)gtk_tree_path_free, NULL); - g_list_free(sel); -} - - -/* preferences window */ -/* on_preferences_ok */ -static int _preferences_ok_accounts(Mailer * mailer); -static int _preferences_ok_display(Mailer * mailer); -static int _preferences_ok_save(Mailer * mailer); - -void on_preferences_ok(GtkWidget * widget, gpointer data) -{ - Mailer * mailer = data; - - gtk_widget_hide(mailer->pr_window); - if(_preferences_ok_accounts(mailer) != 0 - || _preferences_ok_display(mailer) != 0 - || _preferences_ok_save(mailer) != 0) - mailer_error(mailer, "An error occured while saving" - " preferences", 0); -} - -static int _preferences_ok_accounts(Mailer * mailer) -{ - GtkTreeModel * model; - GtkTreeIter iter; - GtkTreeModel * view_model; - gboolean loop; - Account * account; - gboolean active; - gboolean enabled; - char * title; - size_t title_len; - char * accounts = NULL; - size_t accounts_len = 0; - char * p; - - model = gtk_tree_view_get_model(GTK_TREE_VIEW(mailer->pr_accounts)); - view_model = gtk_tree_view_get_model(GTK_TREE_VIEW( - mailer->view_folders)); - for(loop = gtk_tree_model_get_iter_first(model, &iter); loop == TRUE; - loop = gtk_tree_model_iter_next(model, &iter)) - { - gtk_tree_model_get(model, &iter, AC_DATA, &account, - AC_ACTIVE, &active, AC_ENABLED, &enabled, - AC_TITLE, &title, -1); - title_len = strlen(title); - if(account_config_save(account, mailer->config) != 0) - return 1; - if((p = realloc(accounts, accounts_len + title_len + 2)) - == NULL) - { - free(accounts); - return 1; - } - accounts = p; - sprintf(&accounts[accounts_len], "%s%s", accounts_len ? "," - : "", title); - accounts_len += title_len + (accounts_len ? 1 : 0); - if(active) - { - if(enabled) - continue; -#if 0 /* FIXME API+behaviour change here */ - if(mailer_account_disable(mailer, account) == 0) - gtk_list_store_set(GTK_LIST_STORE(model), &iter, - AC_ACTIVE, FALSE, -1); -#endif - } - else if(enabled && mailer_account_add(mailer, account) == 0) - gtk_list_store_set(GTK_LIST_STORE(model), &iter, - AC_ACTIVE, TRUE, -1); - } -#ifdef DEBUG - fprintf(stderr, "DEBUG: saved accounts \"%s\"\n", accounts); -#endif - config_set(mailer->config, "", "accounts", accounts); - free(accounts); - return 0; -} - -static int _preferences_ok_display(Mailer * mailer) -{ - char const * p; - - p = gtk_font_button_get_font_name(GTK_FONT_BUTTON( - mailer->pr_messages_font)); - config_set(mailer->config, "", "messages_font", p); - return 0; -} - -static int _preferences_ok_save(Mailer * mailer) -{ - int ret; - char * p; - - if((p = mailer_get_config_filename(mailer)) == NULL) - return 1; - ret = config_save(mailer->config, p); - free(p); - return ret; -} - - -void on_preferences_cancel(GtkWidget * widget, gpointer data) -{ - Mailer * mailer = data; - - gtk_widget_hide(mailer->pr_window); - _preferences_set(mailer); -} - - -/* accounts */ -/* on_account_new */ -/* types */ -typedef struct _AccountData -{ - Mailer * mailer; - char * title; - AccountIdentity identity; - unsigned int available; - Account * account; - GtkWidget * assistant; - GtkWidget * settings; - GtkWidget * confirm; -} AccountData; - -/* functions */ -static GtkWidget * _assistant_account_select(AccountData * ad); -static GtkWidget * _assistant_account_config(AccountConfig * config); - -#if !GTK_CHECK_VERSION(2, 10, 0) -# include "gtkassistant.c" -#endif -static void _on_assistant_cancel(GtkWidget * widget, gpointer data); -static void _on_assistant_close(GtkWidget * widget, gpointer data); -static void _on_assistant_apply(GtkWidget * widget, gpointer data); -static void _on_assistant_prepare(GtkWidget * widget, GtkWidget * page, - gpointer data); -static void _on_entry_changed(GtkWidget * widget, gpointer data); -static void _on_account_type_changed(GtkWidget * widget, gpointer data); - -void on_account_new(GtkWidget * widget, gpointer data) -{ - Mailer * mailer = data; - AccountData * ad; - GtkAssistant * assistant; - GtkWidget * page; - - if(mailer->available_cnt == 0) - { - mailer_error(mailer, "No account plug-in available", 0); - return; - } - if((ad = malloc(sizeof(*ad))) == NULL) - { - mailer_error(mailer, strerror(errno), 0); - return; - } - ad->mailer = mailer; - ad->title = strdup(""); - memset(&(ad->identity), 0, sizeof(ad->identity)); - ad->available = 0; - ad->account = NULL; - ad->assistant = gtk_assistant_new(); - assistant = GTK_ASSISTANT(ad->assistant); - g_signal_connect(G_OBJECT(ad->assistant), "cancel", G_CALLBACK( - _on_assistant_cancel), ad); - g_signal_connect(G_OBJECT(ad->assistant), "close", G_CALLBACK( - _on_assistant_close), ad); - g_signal_connect(G_OBJECT(ad->assistant), "apply", G_CALLBACK( - _on_assistant_apply), ad); - g_signal_connect(G_OBJECT(ad->assistant), "prepare", G_CALLBACK( - _on_assistant_prepare), ad); - /* plug-in selection */ - page = _assistant_account_select(ad); - gtk_assistant_append_page(assistant, page); - gtk_assistant_set_page_title(assistant, page, _title[0]); - gtk_assistant_set_page_type(assistant, page, GTK_ASSISTANT_PAGE_INTRO); - gtk_assistant_set_page_complete(assistant, page, FALSE); - /* plug-in preferences */ - page = gtk_vbox_new(FALSE, 0); - ad->settings = page; - gtk_widget_show(page); - gtk_assistant_append_page(assistant, page); - gtk_assistant_set_page_title(assistant, page, _title[1]); - gtk_assistant_set_page_type(assistant, page, - GTK_ASSISTANT_PAGE_CONTENT); - gtk_assistant_set_page_complete(assistant, page, TRUE); - /* confirmation page */ - page = gtk_vbox_new(FALSE, 0); - ad->confirm = page; - gtk_widget_show(page); - gtk_assistant_append_page(assistant, page); - gtk_assistant_set_page_title(assistant, page, _title[2]); - gtk_assistant_set_page_type(assistant, page, - GTK_ASSISTANT_PAGE_CONFIRM); - gtk_assistant_set_page_complete(assistant, page, TRUE); - gtk_widget_show(ad->assistant); -} - - -static void _on_assistant_cancel(GtkWidget * widget, gpointer data) -{ - _on_assistant_close(widget, data); -} - -static void _on_assistant_close(GtkWidget * widget, gpointer data) -{ - AccountData * ad = data; - - if(ad->account != NULL) - account_delete(ad->account); - free(ad); - gtk_widget_destroy(widget); -} - -static void _on_assistant_apply(GtkWidget * widget, gpointer data) -{ - AccountData * ad = data; - GtkTreeModel * model; - GtkTreeIter iter; - - model = gtk_tree_view_get_model(GTK_TREE_VIEW(ad->mailer->pr_accounts)); - gtk_list_store_append(GTK_LIST_STORE(model), &iter); -#ifdef DEBUG - fprintf(stderr, "%s%p%s%s%s%s\n", "AC_DATA ", ad->account, - ", AC_ACTIVE FALSE, AC_ENABLED TRUE, AC_TITLE ", - ad->account->title, ", AC_TYPE ", - ad->account->plugin->type); -#endif - gtk_list_store_set(GTK_LIST_STORE(model), &iter, - AC_DATA, ad->account, AC_ACTIVE, FALSE, - AC_ENABLED, TRUE, AC_TITLE, ad->account->title, - AC_TYPE, ad->account->plugin->type, -1); - ad->account = NULL; - /* _on_assistant_close is then automatically called */ -} - -/* on_assistant_prepare */ -static GtkWidget * _account_display(Account * account); - -static void _on_assistant_prepare(GtkWidget * widget, GtkWidget * page, - gpointer data) -{ - static int old = 0; - AccountData * ad = data; - unsigned int i; - Account * ac; - - i = gtk_assistant_get_current_page(GTK_ASSISTANT(widget)); - gtk_window_set_title(GTK_WINDOW(widget), _title[i]); - if(i == 1) - { - /* XXX something is wrong with gtk_container_remove */ - gtk_container_remove(GTK_CONTAINER(page), ad->settings); - if(old == 0) - { - if(ad->account != NULL) - account_delete(ad->account); - ac = &(ad->mailer->available[ad->available]); - ad->account = account_new(ac->name, ad->title); - } - if(ad->account == NULL) - { - mailer_error(ad->mailer, "Could not load plug-in", 0); - gtk_assistant_set_current_page(GTK_ASSISTANT(widget), - 0); - ad->settings = _assistant_account_select(ad); - } - else - ad->settings = _assistant_account_config( - ad->account->plugin->config); - gtk_container_add(GTK_CONTAINER(page), ad->settings); - gtk_widget_show_all(ad->settings); - } - else if(i == 2) - { - gtk_container_remove(GTK_CONTAINER(page), ad->confirm); - ad->confirm = _account_display(ad->account); - gtk_container_add(GTK_CONTAINER(page), ad->confirm); - } - old = i; -} - -/* _assistant_account_select */ -static void _on_account_name_changed(GtkWidget * widget, gpointer data); -static void _account_add_label(GtkWidget * box, PangoFontDescription * desc, - GtkSizeGroup * group, char const * text); - -static GtkWidget * _assistant_account_select(AccountData * ad) -{ - GtkWidget * vbox; - GtkWidget * hbox; - GtkSizeGroup * group; - PangoFontDescription * desc; - GtkWidget * widget; - unsigned int i; - - vbox = gtk_vbox_new(FALSE, 4); - gtk_container_set_border_width(GTK_CONTAINER(vbox), 4); - group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); - hbox = gtk_hbox_new(FALSE, 4); - desc = pango_font_description_new(); - pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD); - _account_add_label(hbox, desc, group, "Account name"); - widget = gtk_entry_new(); - g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK( - _on_account_name_changed), ad); - gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - hbox = gtk_hbox_new(FALSE, 4); - _account_add_label(hbox, desc, group, "Your name"); - widget = gtk_entry_new(); - g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK( - _on_entry_changed), &(ad->identity.from)); - gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - hbox = gtk_hbox_new(FALSE, 4); - _account_add_label(hbox, desc, group, "e-mail address"); - widget = gtk_entry_new(); - g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK( - _on_entry_changed), &(ad->identity.email)); - gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - hbox = gtk_hbox_new(FALSE, 4); - _account_add_label(hbox, desc, group, "Type of account"); - widget = gtk_combo_box_new_text(); - /* XXX this works because there is no plug-in list reload - * would it be implemented this will need validation later */ - for(i = 0; i < ad->mailer->available_cnt; i++) - gtk_combo_box_append_text(GTK_COMBO_BOX(widget), - ad->mailer->available[i].title); - gtk_combo_box_set_active(GTK_COMBO_BOX(widget), 0); - g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK( - _on_account_type_changed), ad); - gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); - pango_font_description_free(desc); - gtk_widget_show_all(vbox); - return vbox; -} - -static void _on_account_name_changed(GtkWidget * widget, gpointer data) -{ - AccountData * ad = data; - int current; - GtkWidget * page; - - _on_entry_changed(widget, &ad->title); - current = gtk_assistant_get_current_page(GTK_ASSISTANT(ad->assistant)); - page = gtk_assistant_get_nth_page(GTK_ASSISTANT(ad->assistant), - current); - gtk_assistant_set_page_complete(GTK_ASSISTANT(ad->assistant), page, - strlen(ad->title) ? TRUE : FALSE); -} - -static void _account_add_label(GtkWidget * box, PangoFontDescription * desc, - GtkSizeGroup * group, char const * text) -{ - static char buf[80]; /* XXX hard-coded size */ - GtkWidget * label; - - snprintf(buf, sizeof(buf), "%s:", text); - label = gtk_label_new(buf); - if(desc != NULL) - gtk_widget_modify_font(label, desc); - if(group != NULL) - gtk_size_group_add_widget(group, label); - gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); - gtk_box_pack_start(GTK_BOX(box), label, FALSE, TRUE, 0); -} - -/* _assistant_account_config */ -static GtkWidget * _update_string(AccountConfig * config, - PangoFontDescription * desc, GtkSizeGroup * group); -static GtkWidget * _update_password(AccountConfig * config, - PangoFontDescription * desc, GtkSizeGroup * group); -static GtkWidget * _update_file(AccountConfig * config, - PangoFontDescription * desc, GtkSizeGroup * group); -static GtkWidget * _update_uint16(AccountConfig * config, - PangoFontDescription * desc, GtkSizeGroup * group); -static GtkWidget * _update_boolean(AccountConfig * config); - -static GtkWidget * _assistant_account_config(AccountConfig * config) -{ - GtkWidget * vbox; - GtkSizeGroup * group; - PangoFontDescription * desc; - GtkWidget * widget; - size_t i; - - vbox = gtk_vbox_new(FALSE, 4); - gtk_container_set_border_width(GTK_CONTAINER(vbox), 4); - group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); - desc = pango_font_description_new(); - pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD); - for(i = 0; config[i].name != NULL; i++) - { - switch(config[i].type) - { - case ACT_NONE: - continue; - case ACT_STRING: - widget = _update_string(&config[i], desc, - group); - break; - case ACT_PASSWORD: - widget = _update_password(&config[i], desc, - group); - break; - case ACT_FILE: - widget = _update_file(&config[i], desc, group); - break; - case ACT_UINT16: - widget = _update_uint16(&config[i], desc, - group); - break; - case ACT_BOOLEAN: - widget = _update_boolean(&config[i]); - break; - default: /* should not happen */ - continue; - } - gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0); - } - pango_font_description_free(desc); - return vbox; -} - -static GtkWidget * _update_string(AccountConfig * config, - PangoFontDescription * desc, GtkSizeGroup * group) -{ - GtkWidget * hbox; - GtkWidget * widget; - - hbox = gtk_hbox_new(FALSE, 0); - _account_add_label(hbox, desc, group, config->title); - widget = gtk_entry_new(); - if(config->value != NULL) - gtk_entry_set_text(GTK_ENTRY(widget), config->value); - g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK( - _on_entry_changed), &config->value); - gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); - return hbox; -} - -static GtkWidget * _update_password(AccountConfig * config, - PangoFontDescription * desc, GtkSizeGroup * group) -{ - GtkWidget * hbox; - GtkWidget * widget; - - hbox = gtk_hbox_new(FALSE, 0); - _account_add_label(hbox, desc, group, config->title); - widget = gtk_entry_new(); - gtk_entry_set_visibility(GTK_ENTRY(widget), FALSE); - if(config->value != NULL) - gtk_entry_set_text(GTK_ENTRY(widget), config->value); - g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK( - _on_entry_changed), &config->value); - gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); - return hbox; -} - -static void _on_file_activated(GtkWidget * widget, gpointer data); - -static GtkWidget * _update_file(AccountConfig * config, - PangoFontDescription * desc, GtkSizeGroup * group) -{ - GtkWidget * hbox; - GtkWidget * widget; - - hbox = gtk_hbox_new(FALSE, 0); - _account_add_label(hbox, desc, group, config->title); - widget = gtk_file_chooser_button_new("Choose file", - GTK_FILE_CHOOSER_ACTION_OPEN); - gtk_file_chooser_button_set_title(GTK_FILE_CHOOSER_BUTTON(widget), - config->title); - g_signal_connect(G_OBJECT(widget), "file-set", G_CALLBACK( - _on_file_activated), &config->value); - gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); - return hbox; -} - -static void _on_file_activated(GtkWidget * widget, gpointer data) -{ - char * filename; - char ** value = data; - char * p; - - filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget)); -#ifdef DEBUG - fprintf(stderr, "DEBUG: %s(%s)\n", __func__, filename); -#endif - if((p = realloc(*value, strlen(filename) + 1)) == NULL) - { - mailer_error(NULL, strerror(errno), 0); - return; - } - *value = p; - strcpy(p, filename); -} - -static void _on_uint16_changed(GtkWidget * widget, gpointer data); - -static GtkWidget * _update_uint16(AccountConfig * config, - PangoFontDescription * desc, GtkSizeGroup * group) -{ - GtkWidget * hbox; - GtkWidget * widget; - uint16_t u16 = (intptr_t)(config->value); - gdouble value = u16; - - hbox = gtk_hbox_new(FALSE, 0); - _account_add_label(hbox, desc, group, config->title); - widget = gtk_spin_button_new_with_range(0, 65535, 1); - gtk_spin_button_set_digits(GTK_SPIN_BUTTON(widget), 0); - gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), value); - g_signal_connect(G_OBJECT(widget), "value-changed", G_CALLBACK( - _on_uint16_changed), &config->value); - gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); - return hbox; -} - -static void _on_uint16_changed(GtkWidget * widget, gpointer data) -{ - int * value = data; - - *value = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget)); -#ifdef DEBUG - fprintf(stderr, "DEBUG: new value is %d\n", *value); -#endif -} - -static void _on_boolean_toggled(GtkWidget * widget, gpointer data); -static GtkWidget * _update_boolean(AccountConfig * config) -{ - GtkWidget * widget; - - widget = gtk_check_button_new_with_label(config->title); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), - config->value != NULL); - g_signal_connect(G_OBJECT(widget), "toggled", G_CALLBACK( - _on_boolean_toggled), &config->value); - return widget; -} - -static void _on_boolean_toggled(GtkWidget * widget, gpointer data) -{ - int * value = data; - - *value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); -} - -static GtkWidget * _display_string(AccountConfig * config, - PangoFontDescription * desc, GtkSizeGroup * group); -static GtkWidget * _display_password(AccountConfig * config, - PangoFontDescription * desc, GtkSizeGroup * group); -static GtkWidget * _display_file(AccountConfig * config, - PangoFontDescription * desc, GtkSizeGroup * group); -static GtkWidget * _display_uint16(AccountConfig * config, - PangoFontDescription * desc, GtkSizeGroup * group); -static GtkWidget * _display_boolean(AccountConfig * config, - PangoFontDescription * desc, GtkSizeGroup * group); -static GtkWidget * _account_display(Account * account) -{ - AccountConfig * config = account->plugin->config; - AccountConfig p; - GtkWidget * vbox; - GtkSizeGroup * group; - PangoFontDescription * desc; - GtkWidget * widget; - unsigned int i; - - vbox = gtk_vbox_new(FALSE, 4); - gtk_container_set_border_width(GTK_CONTAINER(vbox), 4); - group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); - p.name = NULL; - p.title = "Account name"; - p.value = account->title; - desc = pango_font_description_new(); - pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD); - widget = _display_string(&p, desc, group); - gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0); - for(i = 0; config[i].name != NULL; i++) - { - switch(config[i].type) - { - case ACT_NONE: - continue; - case ACT_STRING: - widget = _display_string(&config[i], desc, - group); - break; - case ACT_PASSWORD: - widget = _display_password(&config[i], desc, - group); - break; - case ACT_FILE: - widget = _display_file(&config[i], desc, group); - break; - case ACT_UINT16: - widget = _display_uint16(&config[i], desc, - group); - break; - case ACT_BOOLEAN: - widget = _display_boolean(&config[i], desc, - group); - break; - default: /* should not happen */ - assert(0); - continue; - } - gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0); - } - pango_font_description_free(desc); - gtk_widget_show_all(vbox); - return vbox; -} - -static GtkWidget * _display_string(AccountConfig * config, - PangoFontDescription * desc, GtkSizeGroup * group) -{ - GtkWidget * hbox; - GtkWidget * widget; - - hbox = gtk_hbox_new(FALSE, 0); - _account_add_label(hbox, desc, group, config->title); - widget = gtk_label_new(config->value); - gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); - return hbox; -} - -static GtkWidget * _display_file(AccountConfig * config, - PangoFontDescription * desc, GtkSizeGroup * group) -{ - return _display_string(config, desc, group); -} - -static GtkWidget * _display_password(AccountConfig * config, - PangoFontDescription * desc, GtkSizeGroup * group) -{ - GtkWidget * hbox; - GtkWidget * widget; - - hbox = gtk_hbox_new(FALSE, 0); - _account_add_label(hbox, desc, group, config->title); - widget = gtk_label_new("hidden"); - desc = pango_font_description_new(); - pango_font_description_set_style(desc, PANGO_STYLE_ITALIC); - gtk_widget_modify_font(widget, desc); - gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); - return hbox; -} - -static GtkWidget * _display_uint16(AccountConfig * config, - PangoFontDescription * desc, GtkSizeGroup * group) -{ - GtkWidget * hbox; - GtkWidget * widget; - char buf[6]; - uint16_t u16 = (intptr_t)config->value; - - hbox = gtk_hbox_new(FALSE, 0); - _account_add_label(hbox, desc, group, config->title); - snprintf(buf, sizeof(buf), "%hu", u16); - widget = gtk_label_new(buf); - gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); - return hbox; -} - -static GtkWidget * _display_boolean(AccountConfig * config, - PangoFontDescription * desc, GtkSizeGroup * group) -{ - GtkWidget * hbox; - GtkWidget * widget; - - hbox = gtk_hbox_new(FALSE, 0); - _account_add_label(hbox, desc, group, config->title); - widget = gtk_label_new(config->value != 0 ? "Yes" : "No"); - gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.5); - gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); - return hbox; -} - -static void _on_entry_changed(GtkWidget * widget, gpointer data) -{ - const char * text; - char ** value = data; - char * p; - - text = gtk_entry_get_text(GTK_ENTRY(widget)); - if((p = realloc(*value, strlen(text) + 1)) == NULL) - { - mailer_error(NULL, strerror(errno), 0); - return; - } - *value = p; - strcpy(p, text); -} - -static void _on_account_type_changed(GtkWidget * widget, gpointer data) -{ - AccountData * ad = data; - - ad->available = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); -#ifdef DEBUG - fprintf(stderr, "%s%u%s", "Account type ", ad->available, " active\n"); -#endif -} - - -/* on_account_edit */ -static void _account_edit(Mailer * mailer, Account * account); - -void on_account_edit(GtkWidget * widget, gpointer data) -{ - Mailer * mailer = data; - GtkTreeSelection * selection; - GtkTreeModel * model; - GtkTreeIter iter; - Account * account; - - selection = gtk_tree_view_get_selection(GTK_TREE_VIEW( - mailer->pr_accounts)); - if(!gtk_tree_selection_get_selected(selection, &model, &iter)) - return; - gtk_tree_model_get(model, &iter, AC_DATA, &account, -1); - _account_edit(mailer, account); -} - -static void _account_edit(Mailer * mailer, Account * account) -{ - GtkWidget * window; - char buf[80]; - GtkWidget * vbox; - GtkWidget * widget; - GtkWidget * hbox; - GtkSizeGroup * group; - - window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - snprintf(buf, sizeof(buf), "%s%s", "Edit account: ", account_get_title( - account)); - gtk_window_set_title(GTK_WINDOW(window), buf); - gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW( - mailer->window)); - gtk_window_set_modal(GTK_WINDOW(window), TRUE); - /* FIXME this affects the account directly (eg cancel does not) */ - widget = _assistant_account_config(account->plugin->config); - vbox = gtk_vbox_new(FALSE, 4); - gtk_box_pack_start(GTK_BOX(vbox), widget, TRUE, TRUE, 0); - hbox = gtk_hbox_new(FALSE, 0); - widget = gtk_hseparator_new(); - gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 4); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0); - hbox = gtk_hbox_new(FALSE, 0); - group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); - widget = gtk_button_new_from_stock(GTK_STOCK_OK); - gtk_size_group_add_widget(group, widget); - /* FIXME implement properly */ - g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK( - gtk_widget_destroy), window); - gtk_box_pack_end(GTK_BOX(hbox), widget, FALSE, TRUE, 4); - widget = gtk_button_new_from_stock(GTK_STOCK_CANCEL); - gtk_size_group_add_widget(group, widget); - g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK( - gtk_widget_destroy), window); - gtk_box_pack_end(GTK_BOX(hbox), widget, FALSE, TRUE, 0); - gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 4); - gtk_container_add(GTK_CONTAINER(window), vbox); - gtk_widget_show_all(window); -} - - -void on_account_delete(GtkWidget * widget, gpointer data) -{ - Mailer * mailer = data; - GtkTreePath * path; - GtkTreeModel * model; - GtkTreeIter iter; - - gtk_tree_view_get_cursor(GTK_TREE_VIEW(mailer->pr_accounts), &path, - NULL); - if(path == NULL) - return; - model = gtk_tree_view_get_model(GTK_TREE_VIEW(mailer->pr_accounts)); - gtk_tree_model_get_iter(model, &iter, path); - gtk_tree_path_free(path); - gtk_list_store_remove(GTK_LIST_STORE(model), &iter); - /* FIXME non-interface code (flag account as deleted and on ok apply) */ -} - - /* compose window */ -gboolean on_compose_closex(GtkWidget * widget, GdkEvent * event, gpointer data) +gboolean on_compose_closex(gpointer data) { - Compose * c = data; + Compose * compose = data; - compose_delete(c); + if(compose_save(compose) != 0) + return TRUE; + compose_delete(compose); return TRUE; } -void on_compose_save(GtkWidget * widget, gpointer data) +void on_compose_save(gpointer data) { Compose * c = data; @@ -1269,7 +199,7 @@ void on_compose_save(GtkWidget * widget, gpointer data) } -void on_compose_send(GtkWidget * widget, gpointer data) +void on_compose_send(gpointer data) { Compose * c = data; @@ -1277,22 +207,24 @@ void on_compose_send(GtkWidget * widget, gpointer data) } -void on_compose_attach(GtkWidget * widget, gpointer data) +void on_compose_attach(gpointer data) { /* FIXME implement */ } /* compose file menu */ -void on_compose_file_new(GtkWidget * widget, gpointer data) +void on_compose_file_new(gpointer data) { - Compose * c = data; + Compose * compose = data; + Mailer * mailer; - compose_new(c->mailer); + mailer = compose_get_mailer(compose); + compose_new(mailer); } -void on_compose_file_send(GtkWidget * widget, gpointer data) +void on_compose_file_send(gpointer data) { Compose * c = data; @@ -1300,19 +232,19 @@ void on_compose_file_send(GtkWidget * widget, gpointer data) } -void on_compose_file_save(GtkWidget * widget, gpointer data) +void on_compose_file_save(gpointer data) { /* FIXME implement */ } -void on_compose_file_save_as(GtkWidget * widget, gpointer data) +void on_compose_file_save_as(gpointer data) { /* FIXME implement */ } -void on_compose_file_close(GtkWidget * widget, gpointer data) +void on_compose_file_close(gpointer data) { Compose * c = data; @@ -1321,31 +253,31 @@ void on_compose_file_close(GtkWidget * widget, gpointer data) /* compose_edit_menu */ -void on_compose_edit_undo(GtkWidget * widget, gpointer data) +void on_compose_edit_undo(gpointer data) { /* FIXME implement */ } -void on_compose_edit_redo(GtkWidget * widget, gpointer data) +void on_compose_edit_redo(gpointer data) { /* FIXME implement */ } -void on_compose_edit_cut(GtkWidget * widget, gpointer data) +void on_compose_edit_cut(gpointer data) { /* FIXME implement */ } -void on_compose_edit_copy(GtkWidget * widget, gpointer data) +void on_compose_edit_copy(gpointer data) { /* FIXME implement */ } -void on_compose_edit_paste(GtkWidget * widget, gpointer data) +void on_compose_edit_paste(gpointer data) { /* FIXME implement */ } @@ -1353,118 +285,46 @@ void on_compose_edit_paste(GtkWidget * widget, gpointer data) /* compose view menu */ /* on_compose_view_cc */ -void on_compose_view_cc(GtkWidget * widget, gpointer data) +void on_compose_view_cc(gpointer data) { - Compose * c = data; + Compose * compose = data; - gtk_widget_show(c->tb_cc); + compose_toggle_show_cc(compose); } /* on_compose_view_bcc */ -void on_compose_view_bcc(GtkWidget * widget, gpointer data) +void on_compose_view_bcc(gpointer data) { - Compose * c = data; + Compose * compose = data; - gtk_widget_show(c->tb_bcc); + compose_toggle_show_bcc(compose); } /* on_compose_help_about */ -void on_compose_help_about(GtkWidget * widget, gpointer data) +void on_compose_help_about(gpointer data) { - Compose * c = data; + Compose * compose = data; - _on_about(c->window); + compose_show_about(compose, TRUE); } /* send mail */ -gboolean on_send_closex(GtkWidget * widget, GdkEvent * event, gpointer data) +gboolean on_send_closex(gpointer data) { - Compose * c = data; + Compose * compose = data; - on_send_cancel(widget, c); + on_send_cancel(compose); return FALSE; } /* on_send_cancel */ -void on_send_cancel(GtkWidget * widget, gpointer data) +void on_send_cancel(gpointer data) { - Compose * c = data; + Compose * compose = data; - g_io_channel_shutdown(c->channel, TRUE, NULL); - gtk_widget_destroy(c->snd_window); - free(c->buf); -} - - -/* on_send_write */ -gboolean on_send_write(GIOChannel * source, GIOCondition condition, - gpointer data) -{ - Compose * c = data; - gsize i; - - if((i = (c->buf_len - c->buf_pos) % 512) == 0) - i = 512; - if(g_io_channel_write_chars(source, &c->buf[c->buf_pos], i, &i, NULL) - != G_IO_STATUS_NORMAL) - { - mailer_error(c->mailer, strerror(errno), FALSE); - on_send_cancel(c->snd_window, c); - return FALSE; - } - c->buf_pos+=i; - gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(c->snd_progress), - c->buf_pos / c->buf_len); - if(c->buf_pos >= c->buf_len) - { - on_send_cancel(c->snd_window, c); - compose_delete(c); - return FALSE; - } - return TRUE; -} - - -/* private */ -/* on_about */ -static void _on_about(GtkWidget * window) -{ - GtkWidget * dialog; - -#if GTK_CHECK_VERSION(2, 6, 0) - gsize cnt = 65536; - gchar * buf; - - if((buf = malloc(sizeof(*buf) * cnt)) == NULL) - { - mailer_error(NULL, "malloc", 0); - return; - } - dialog = gtk_about_dialog_new(); - gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(window)); - gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(dialog), PACKAGE); - gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), VERSION); - gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(dialog), _authors); - gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog), _copyright); - gtk_about_dialog_set_logo_icon_name(GTK_ABOUT_DIALOG(dialog), - "stock_mail"); - if(g_file_get_contents("/usr/share/common-licenses/GPL-2", &buf, &cnt, - NULL) == TRUE) - gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(dialog), buf); - else - gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(dialog), - _license); - free(buf); - g_signal_connect(G_OBJECT(dialog), "delete_event", G_CALLBACK( - _on_about_closex), NULL); - g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK( - gtk_widget_destroy), NULL); - gtk_widget_show(dialog); -#else /* !GTK_CHECK_VERSION(2, 6, 0) */ - /* FIXME implement */ -#endif /* !GTK_CHECK_VERSION(2, 6, 0) */ + compose_send_cancel(compose); } diff --git a/src/callbacks.h b/src/callbacks.h index 9622cc6..33853c6 100644 --- a/src/callbacks.h +++ b/src/callbacks.h @@ -22,36 +22,36 @@ /* mailer window */ -gboolean on_closex(GtkWidget * widget, GdkEvent * event, gpointer data); +gboolean on_closex(gpointer data); /* file menu */ -void on_file_new_mail(GtkWidget * widget, gpointer data); -void on_file_send_receive(GtkWidget * widget, gpointer data); -void on_file_print(GtkWidget * widget, gpointer data); -void on_file_print_preview(GtkWidget * widget, gpointer data); -void on_file_quit(GtkWidget * widget, gpointer data); +void on_file_new_mail(gpointer data); +void on_file_send_receive(gpointer data); +void on_file_print(gpointer data); +void on_file_print_preview(gpointer data); +void on_file_quit(gpointer data); /* edit menu */ -void on_edit_preferences(GtkWidget * widget, gpointer data); +void on_edit_preferences(gpointer data); /* message menu */ -void on_message_reply(GtkWidget * widget, gpointer data); -void on_message_reply_to_all(GtkWidget * widget, gpointer data); -void on_message_forward(GtkWidget * widget, gpointer data); -void on_message_delete(GtkWidget * widget, gpointer data); -void on_message_view_source(GtkWidget * widget, gpointer data); +void on_message_reply(gpointer data); +void on_message_reply_to_all(gpointer data); +void on_message_forward(gpointer data); +void on_message_delete(gpointer data); +void on_message_view_source(gpointer data); /* help menu */ -void on_help_about(GtkWidget * widget, gpointer data); +void on_help_about(gpointer data); /* toolbar */ -void on_new_mail(GtkWidget * widget, gpointer data); -void on_stop(GtkWidget * widget, gpointer data); -void on_reply(GtkWidget * widget, gpointer data); -void on_reply_to_all(GtkWidget * widget, gpointer data); -void on_forward(GtkWidget * widget, gpointer data); -void on_delete(GtkWidget * widget, gpointer data); -void on_print(GtkWidget * widget, gpointer data); +void on_new_mail(gpointer data); +void on_stop(gpointer data); +void on_reply(gpointer data); +void on_reply_to_all(gpointer data); +void on_forward(gpointer data); +void on_delete(gpointer data); +void on_print(gpointer data); /* folder view */ void on_folder_change(GtkTreeSelection * selection, gpointer data); @@ -59,47 +59,37 @@ void on_folder_change(GtkTreeSelection * selection, gpointer data); /* header view */ void on_header_change(GtkTreeSelection * selection, gpointer data); -/* preferences window */ -void on_preferences_ok(GtkWidget * widget, gpointer data); -void on_preferences_cancel(GtkWidget * widget, gpointer data); - - -/* accounts */ -void on_account_new(GtkWidget * widget, gpointer data); -void on_account_edit(GtkWidget * widget, gpointer data); -void on_account_delete(GtkWidget * widget, gpointer data); - /* compose window */ -gboolean on_compose_closex(GtkWidget * widget, GdkEvent * event, gpointer data); -void on_compose_save(GtkWidget * widget, gpointer data); -void on_compose_send(GtkWidget * widget, gpointer data); -void on_compose_attach(GtkWidget * widget, gpointer data); +gboolean on_compose_closex(gpointer data); +void on_compose_save(gpointer data); +void on_compose_send(gpointer data); +void on_compose_attach(gpointer data); /* file menu */ -void on_compose_file_new(GtkWidget * widget, gpointer data); -void on_compose_file_save(GtkWidget * widget, gpointer data); -void on_compose_file_save_as(GtkWidget * widget, gpointer data); -void on_compose_file_send(GtkWidget * widget, gpointer data); -void on_compose_file_close(GtkWidget * widget, gpointer data); +void on_compose_file_new(gpointer data); +void on_compose_file_save(gpointer data); +void on_compose_file_save_as(gpointer data); +void on_compose_file_send(gpointer data); +void on_compose_file_close(gpointer data); /* edit menu */ -void on_compose_edit_undo(GtkWidget * widget, gpointer data); -void on_compose_edit_redo(GtkWidget * widget, gpointer data); -void on_compose_edit_cut(GtkWidget * widget, gpointer data); -void on_compose_edit_copy(GtkWidget * widget, gpointer data); -void on_compose_edit_paste(GtkWidget * widget, gpointer data); +void on_compose_edit_undo(gpointer data); +void on_compose_edit_redo(gpointer data); +void on_compose_edit_cut(gpointer data); +void on_compose_edit_copy(gpointer data); +void on_compose_edit_paste(gpointer data); /* view menu */ -void on_compose_view_cc(GtkWidget * widget, gpointer data); -void on_compose_view_bcc(GtkWidget * widget, gpointer data); +void on_compose_view_cc(gpointer data); +void on_compose_view_bcc(gpointer data); /* help menu */ -void on_compose_help_about(GtkWidget * widget, gpointer data); +void on_compose_help_about(gpointer data); /* send mail */ -gboolean on_send_closex(GtkWidget * widget, GdkEvent * event, gpointer data); -void on_send_cancel(GtkWidget * widget, gpointer data); +gboolean on_send_closex(gpointer data); +void on_send_cancel(gpointer data); gboolean on_send_write(GIOChannel * source, GIOCondition condition, gpointer data); diff --git a/src/common.c b/src/common.c index e501941..aa00d27 100644 --- a/src/common.c +++ b/src/common.c @@ -62,8 +62,9 @@ GtkWidget * common_new_menubar(GtkWindow * window, struct _menubar * mb, image); } if(p->callback != NULL) - g_signal_connect(G_OBJECT(menuitem), "activate", - G_CALLBACK(p->callback), data); + g_signal_connect_swapped(G_OBJECT(menuitem), + "activate", G_CALLBACK( + p->callback), data); else gtk_widget_set_sensitive(menuitem, FALSE); if(p->accel != 0) @@ -101,7 +102,8 @@ GtkWidget * common_new_toolbar(struct _toolbar * tb, gpointer data) widget = gtk_image_new_from_icon_name(tb[i].stock, GTK_ICON_SIZE_LARGE_TOOLBAR); toolitem = gtk_tool_button_new(widget, tb[i].name); - g_signal_connect(toolitem, "clicked", tb[i].callback, data); + g_signal_connect_swapped(toolitem, "clicked", tb[i].callback, + data); gtk_toolbar_insert(GTK_TOOLBAR(toolbar), toolitem, -1); } return toolbar; diff --git a/src/compose.c b/src/compose.c index ed6a49c..fefe569 100644 --- a/src/compose.c +++ b/src/compose.c @@ -28,7 +28,39 @@ #include "compose.h" +/* Compose */ /* private */ +/* types */ +struct _Compose +{ + Mailer * mailer; + + /* sending mail */ + pid_t pid; + int fd; + char * buf; + size_t buf_len; + size_t buf_pos; + GIOChannel * channel; + GtkWidget * snd_window; + GtkWidget * snd_progress; + + /* widgets */ + GtkWidget * window; + GtkWidget * from; + GtkWidget * to; + GtkWidget * tb_cc; + GtkWidget * cc; + GtkWidget * tb_bcc; + GtkWidget * bcc; + GtkWidget * subject; + GtkWidget * view; + GtkWidget * statusbar; + gint statusbar_id; + GtkWidget * ab_window; +}; + + /* constants */ #define SENDMAIL "/usr/sbin/sendmail" @@ -118,8 +150,8 @@ Compose * compose_new(Mailer * mailer) compose->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_title(GTK_WINDOW(compose->window), "Mailer - Compose"); gtk_window_set_default_size(GTK_WINDOW(compose->window), 512, 384); - g_signal_connect(G_OBJECT(compose->window), "delete_event", G_CALLBACK( - on_compose_closex), compose); + g_signal_connect_swapped(G_OBJECT(compose->window), "delete-event", + G_CALLBACK(on_compose_closex), compose); vbox = gtk_vbox_new(FALSE, 0); /* menubar */ widget = common_new_menubar(GTK_WINDOW(compose->window), @@ -207,6 +239,7 @@ Compose * compose_new(Mailer * mailer) compose->statusbar_id = 0; gtk_box_pack_start(GTK_BOX(vbox), compose->statusbar, FALSE, TRUE, 0); gtk_container_add(GTK_CONTAINER(compose->window), vbox); + compose->ab_window = NULL; gtk_widget_show_all(vbox); gtk_widget_hide(compose->tb_cc); gtk_widget_hide(compose->tb_bcc); @@ -271,9 +304,10 @@ Mailer * compose_get_mailer(Compose * compose) /* useful */ /* compose_save */ -void compose_save(Compose * compose) +int compose_save(Compose * compose) { /* FIXME implement */ + return -1; } @@ -282,6 +316,8 @@ static char * _send_headers(Compose * compose); static char * _send_body(GtkWidget * view); static int _send_mail(Compose * compose, char * msg, size_t msg_len); static int _mail_child(int fd[2]); +static gboolean _on_send_write(GIOChannel * source, GIOCondition condition, + gpointer data); void compose_send(Compose * compose) { @@ -330,7 +366,7 @@ static int _send_mail(Compose * compose, char * msg, size_t msg_len) gtk_window_set_resizable(GTK_WINDOW(compose->snd_window), FALSE); gtk_window_set_transient_for(GTK_WINDOW(compose->snd_window), GTK_WINDOW(compose->window)); - g_signal_connect(G_OBJECT(compose->snd_window), "delete_event", + g_signal_connect_swapped(G_OBJECT(compose->snd_window), "delete-event", G_CALLBACK(on_send_closex), compose); hbox = gtk_hbox_new(FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), gtk_label_new("Progression: "), @@ -340,7 +376,7 @@ static int _send_mail(Compose * compose, char * msg, size_t msg_len) 0.0); gtk_box_pack_start(GTK_BOX(hbox), compose->snd_progress, TRUE, TRUE, 0); widget = gtk_button_new_from_stock(GTK_STOCK_CANCEL); - g_signal_connect(G_OBJECT(widget), "clicked", G_CALLBACK( + g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK( on_send_cancel), compose); gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0); gtk_container_set_border_width(GTK_CONTAINER(compose->snd_window), 4); @@ -351,7 +387,7 @@ static int _send_mail(Compose * compose, char * msg, size_t msg_len) compose->buf_len = msg_len; compose->buf_pos = 0; compose->channel = g_io_channel_unix_new(fd[1]); - g_io_add_watch(compose->channel, G_IO_OUT, on_send_write, compose); + g_io_add_watch(compose->channel, G_IO_OUT, _on_send_write, compose); return 0; } @@ -439,3 +475,73 @@ static char * _send_body(GtkWidget * view) return gtk_text_buffer_get_text(GTK_TEXT_BUFFER(tbuf), &start, &end, FALSE); } + +static gboolean _on_send_write(GIOChannel * source, GIOCondition condition, + gpointer data) +{ + Compose * c = data; + gsize i; + + if(condition != G_IO_OUT) + return FALSE; + if((i = (c->buf_len - c->buf_pos) % 512) == 0) + i = 512; + if(g_io_channel_write_chars(source, &c->buf[c->buf_pos], i, &i, NULL) + != G_IO_STATUS_NORMAL) + { + mailer_error(c->mailer, strerror(errno), FALSE); + on_send_cancel(c); + return FALSE; + } + c->buf_pos+=i; + gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(c->snd_progress), + c->buf_pos / c->buf_len); + if(c->buf_pos >= c->buf_len) + { + on_send_cancel(c); + compose_delete(c); + return FALSE; + } + return TRUE; +} + + +/* compose_send_cancel */ +void compose_send_cancel(Compose * compose) +{ + /* FIXME verify that a send operation is in progress */ + g_io_channel_shutdown(compose->channel, TRUE, NULL); + gtk_widget_destroy(compose->snd_window); + free(compose->buf); +} + + +/* compose_show_about */ +void compose_show_about(Compose * compose, gboolean show) +{ + if(compose->ab_window != NULL) + { + if(show) + gtk_widget_show(compose->ab_window); + else + gtk_widget_hide(compose->ab_window); + return; + } + /* FIXME implement */ +} + + +/* compose_toggle_show_bcc */ +void compose_toggle_show_bcc(Compose * compose) +{ + /* FIXME implement correctly */ + gtk_widget_show(compose->tb_bcc); +} + + +/* compose_toggle_show_cc */ +void compose_toggle_show_cc(Compose * compose) +{ + /* FIXME implement correctly */ + gtk_widget_show(compose->tb_cc); +} diff --git a/src/compose.h b/src/compose.h index 628bf36..49e02bf 100644 --- a/src/compose.h +++ b/src/compose.h @@ -23,43 +23,23 @@ /* types */ -typedef struct _Compose -{ - Mailer * mailer; - - /* sending mail */ - pid_t pid; - int fd; - char * buf; - size_t buf_len; - size_t buf_pos; - GIOChannel * channel; - GtkWidget * snd_window; - GtkWidget * snd_progress; - - /* widgets */ - GtkWidget * window; - GtkWidget * from; - GtkWidget * to; - GtkWidget * tb_cc; - GtkWidget * cc; - GtkWidget * tb_bcc; - GtkWidget * bcc; - GtkWidget * subject; - GtkWidget * view; - GtkWidget * statusbar; - gint statusbar_id; -} Compose; +typedef struct _Compose Compose; /* methods */ Compose * compose_new(Mailer * mailer); void compose_delete(Compose * compose); /* accessors */ -Mailer * compose_get_mailer(Compose * compose); /* XXX ugly */ +Mailer * compose_get_mailer(Compose * compose); /* useful */ -void compose_save(Compose * compose); +int compose_save(Compose * compose); void compose_send(Compose * compose); +void compose_send_cancel(Compose * compose); + +void compose_show_about(Compose * compose, gboolean show); + +void compose_toggle_show_bcc(Compose * compose); +void compose_toggle_show_cc(Compose * compose); #endif /* !MAILER_COMPOSE_H */ diff --git a/src/mailer.c b/src/mailer.c index 77887f7..53305a4 100644 --- a/src/mailer.c +++ b/src/mailer.c @@ -1,17 +1,19 @@ /* $Id$ */ -/* Copyright (c) 2010 Pierre Pronchery */ +static char const _copyright[] = +"Copyright (c) 2010 Pierre Pronchery "; /* This file is part of DeforaOS Desktop Mailer */ -/* This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, version 3 of the License. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . */ +static char const _license[] = +"This program is free software: you can redistribute it and/or modify\n" +"it under the terms of the GNU General Public License as published by\n" +"the Free Software Foundation, version 3 of the License.\n" +"\n" +"This program is distributed in the hope that it will be useful,\n" +"but WITHOUT ANY WARRANTY; without even the implied warranty of\n" +"MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n" +"GNU General Public License for more details.\n" +"\n" +"You should have received a copy of the GNU General Public License\n" +"along with this program. If not, see .\n"; @@ -19,6 +21,7 @@ #include #include #include +#include #include #include #include "callbacks.h" @@ -26,8 +29,57 @@ #include "mailer.h" +/* Mailer */ +/* private */ +/* types */ +struct _Mailer +{ + Account * available; /* XXX consider using another data type */ + unsigned int available_cnt; + + Account ** account; + unsigned int account_cnt; + Account * account_cur; + AccountFolder * folder_cur; + + /* configuration */ + Config * config; + + /* widgets */ + GtkWidget * window; + GtkWidget * view_folders; + GtkWidget * view_headers; + GtkWidget * hdr_vbox; + GtkWidget * hdr_subject; + GtkWidget * hdr_from; + GtkWidget * hdr_to; + GtkWidget * hdr_date; + GtkTextBuffer * view_buffer; + GtkWidget * view_body; + GtkWidget * statusbar; + gint statusbar_id; + /* about */ + GtkWidget * ab_window; + /* preferences */ + GtkWidget * pr_window; + GtkWidget * pr_accounts; + GtkWidget * pr_messages_font; +}; + + /* constants */ -struct _menu _menu_file[] = +static char const * _authors[] = +{ + "Pierre Pronchery ", + NULL +}; + +static const char * _title[3] = +{ + "New account", "Account settings", "Account confirmation" +}; + +static struct _menu _menu_file[] = { { "_New mail", G_CALLBACK(on_file_new_mail), "stock_mail-compose", GDK_N }, @@ -43,7 +95,7 @@ struct _menu _menu_file[] = { NULL, NULL, NULL, 0 } }; -struct _menu _menu_edit[] = +static struct _menu _menu_edit[] = { { "_Preferences", G_CALLBACK(on_edit_preferences), GTK_STOCK_PREFERENCES, 0 }, @@ -104,6 +156,7 @@ static struct _toolbar _mailer_toolbar[] = /* private */ /* prototypes */ static int _mailer_config_load_account(Mailer * mailer, char const * name); +static char * _mailer_get_config_filename(Mailer * mailer); /* functions */ @@ -130,8 +183,12 @@ static int _mailer_config_load_account(Mailer * mailer, char const * name) /* mailer_new */ static int _new_plugins(Mailer * mailer); static GtkWidget * _new_folders_view(Mailer * mailer); +static void _on_folders_changed(GtkTreeSelection * selection, gpointer data); static GtkWidget * _new_headers_view(Mailer * mailer); static GtkWidget * _new_headers(Mailer * mailer); +static void _headers_view_column_text(GtkTreeView * view, char const * title, + int id); +static void _on_headers_changed(GtkTreeSelection * selection, gpointer data); static void _new_config_load(Mailer * mailer); Mailer * mailer_new(void) @@ -160,8 +217,8 @@ Mailer * mailer_new(void) gtk_window_set_icon_name(GTK_WINDOW(mailer->window), "stock_mail"); #endif gtk_window_set_title(GTK_WINDOW(mailer->window), "Mailer"); - g_signal_connect(G_OBJECT(mailer->window), "delete-event", G_CALLBACK( - on_closex), NULL); + g_signal_connect_swapped(G_OBJECT(mailer->window), "delete-event", + G_CALLBACK(on_closex), mailer); vbox = gtk_vbox_new(FALSE, 0); /* menubar */ widget = common_new_menubar(GTK_WINDOW(mailer->window), _mailer_menubar, @@ -207,11 +264,13 @@ Mailer * mailer_new(void) gtk_container_add(GTK_CONTAINER(mailer->window), vbox); /* load configuration */ _new_config_load(mailer); + /* widgets */ + mailer->ab_window = NULL; + mailer->pr_window = NULL; /* show window */ gtk_widget_show_all(vbox); gtk_widget_hide(mailer->hdr_vbox); gtk_widget_show(mailer->window); - mailer->pr_window = NULL; return mailer; } @@ -320,12 +379,47 @@ static GtkWidget * _new_folders_view(Mailer * mailer) "Folders", renderer, "text", MF_COL_NAME, NULL); treesel = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)); g_signal_connect(G_OBJECT(treesel), "changed", G_CALLBACK( - on_folder_change), mailer); + _on_folders_changed), mailer); return widget; } -static void _headers_view_column_text(GtkTreeView * view, char const * title, - int id); +static void _on_folders_changed(GtkTreeSelection * selection, gpointer data) +{ + Mailer * mailer = data; + GtkTreeModel * model; + GtkTreeIter iter; + GtkListStore * store; + GtkTreePath * path; + +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s()\n", __func__); +#endif + if(!gtk_tree_selection_get_selected(selection, &model, &iter)) + { + mailer->account_cur = NULL; + mailer->folder_cur = NULL; + gtk_tree_view_set_model(GTK_TREE_VIEW(mailer->view_headers), + NULL); + return; + } + /* get current folder */ + gtk_tree_model_get(model, &iter, MF_COL_FOLDER, &mailer->folder_cur, + -1); + /* get current account */ + path = gtk_tree_model_get_path(model, &iter); + while(gtk_tree_path_get_depth(path) > 1 && gtk_tree_path_up(path)); + gtk_tree_model_get_iter(model, &iter, path); + gtk_tree_model_get(model, &iter, MF_COL_ACCOUNT, &mailer->account_cur, + -1); + gtk_tree_path_free(path); + /* display headers */ +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s() account_get_store()\n", __func__); +#endif + store = account_get_store(mailer->account_cur, mailer->folder_cur); + gtk_tree_view_set_model(GTK_TREE_VIEW(mailer->view_headers), + GTK_TREE_MODEL(store)); +} static GtkWidget * _new_headers_view(Mailer * mailer) { @@ -341,10 +435,51 @@ static GtkWidget * _new_headers_view(Mailer * mailer) treesel = gtk_tree_view_get_selection(treeview); gtk_tree_selection_set_mode(treesel, GTK_SELECTION_MULTIPLE); g_signal_connect(G_OBJECT(treesel), "changed", G_CALLBACK( - on_header_change), mailer); + _on_headers_changed), mailer); return widget; } +static void _on_headers_changed(GtkTreeSelection * selection, gpointer data) +{ + Mailer * mailer = data; + GtkTreeModel * model; + GList * sel; + GtkTreeIter iter; + char * p; + AccountMessage * message; + +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s()\n", __func__); +#endif + sel = gtk_tree_selection_get_selected_rows(selection, &model); + if(sel == NULL || sel->next != NULL) /* empty or multiple */ + { + gtk_widget_hide(mailer->hdr_vbox); + gtk_text_view_set_buffer(GTK_TEXT_VIEW(mailer->view_body), + mailer->view_buffer); + } + else + { + gtk_tree_model_get_iter(model, &iter, sel->data); + gtk_tree_model_get(model, &iter, MH_COL_MESSAGE, &message, -1); + gtk_tree_model_get(model, &iter, MH_COL_SUBJECT, &p, -1); + gtk_label_set_text(GTK_LABEL(mailer->hdr_subject), p); + gtk_tree_model_get(model, &iter, MH_COL_FROM, &p, -1); + gtk_label_set_text(GTK_LABEL(mailer->hdr_from), p); + gtk_tree_model_get(model, &iter, MH_COL_TO, &p, -1); + gtk_label_set_text(GTK_LABEL(mailer->hdr_to), p); + gtk_tree_model_get(model, &iter, MH_COL_DATE, &p, -1); + gtk_label_set_text(GTK_LABEL(mailer->hdr_date), p); + gtk_widget_show(mailer->hdr_vbox); + account_select(mailer->account_cur, mailer->folder_cur, + message); + gtk_text_view_set_buffer(GTK_TEXT_VIEW(mailer->view_body), + mailer->account_cur->buffer); + } + g_list_foreach(sel, (GFunc)gtk_tree_path_free, NULL); + g_list_free(sel); +} + static void _headers_view_column_text(GtkTreeView * view, char const * title, int id) /* FIXME ellipsize text */ @@ -411,32 +546,39 @@ static GtkWidget * _new_headers(Mailer * mailer) static void _new_config_load(Mailer * mailer) { char * filename; - char const * accounts; + char const * value; + PangoFontDescription * font; char * p; char * q; if((mailer->config = config_new()) == NULL) return; - if((filename = mailer_get_config_filename(mailer)) == NULL) + if((filename = _mailer_get_config_filename(mailer)) == NULL) return; config_load(mailer->config, filename); free(filename); - if((accounts = config_get(mailer->config, "", "accounts")) == NULL - || accounts[0] == '\0') + if((value = config_get(mailer->config, NULL, "messages_font")) != NULL) + { + font = pango_font_description_from_string(value); + gtk_widget_modify_font(mailer->view_body, font); + pango_font_description_free(font); + } + if((value = config_get(mailer->config, "", "accounts")) == NULL + || value[0] == '\0') return; - if((p = strdup(accounts)) == NULL) + if((p = strdup(value)) == NULL) return; - accounts = p; + value = p; for(q = p; *q != '\0'; q++) { if(*q != ',') continue; *q = '\0'; - _mailer_config_load_account(mailer, accounts); - accounts = q + 1; + _mailer_config_load_account(mailer, value); + value = q + 1; } - if(accounts[0] != '\0') - _mailer_config_load_account(mailer, accounts); + if(value[0] != '\0') + _mailer_config_load_account(mailer, value); free(p); } @@ -467,23 +609,6 @@ char const * mailer_get_config(Mailer * mailer, char const * variable) } -/* mailer_get_config_filename */ -char * mailer_get_config_filename(Mailer * mailer) - /* FIXME consider replacing with mailer_save_config() */ -{ - char const * homedir; - char * filename; - - if((homedir = getenv("HOME")) == NULL) - return NULL; - if((filename = malloc(strlen(homedir) + sizeof(MAILER_CONFIG_FILE) + 1)) - == NULL) - return NULL; - sprintf(filename, "%s/%s", homedir, MAILER_CONFIG_FILE); - return filename; -} - - /* useful */ /* mailer_error */ int mailer_error(Mailer * mailer, char const * message, int ret) @@ -566,3 +691,1057 @@ int mailer_account_enable(Mailer * mailer, Account * account) return 0; } #endif + + +/* mailer_show_about */ +static gboolean _on_about_closex(gpointer data); + +void mailer_show_about(Mailer * mailer, gboolean show) +{ + GtkWidget * dialog; + +#if GTK_CHECK_VERSION(2, 6, 0) + gsize cnt = 65536; + gchar * buf; + + if(mailer->ab_window != NULL) + { + if(show) + gtk_widget_show(mailer->ab_window); + else + gtk_widget_hide(mailer->ab_window); + return; + } + if((buf = malloc(sizeof(*buf) * cnt)) == NULL) + { + mailer_error(NULL, "malloc", 0); + return; + } + dialog = gtk_about_dialog_new(); + mailer->ab_window = dialog; + gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW( + mailer->window)); + gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(dialog), PACKAGE); + gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), VERSION); + gtk_about_dialog_set_authors(GTK_ABOUT_DIALOG(dialog), _authors); + gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog), _copyright); + gtk_about_dialog_set_logo_icon_name(GTK_ABOUT_DIALOG(dialog), + "stock_mail"); + if(g_file_get_contents("/usr/share/common-licenses/GPL-2", &buf, &cnt, + NULL) == TRUE) + gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(dialog), buf); + else + gtk_about_dialog_set_license(GTK_ABOUT_DIALOG(dialog), + _license); + free(buf); + g_signal_connect_swapped(G_OBJECT(dialog), "delete-event", G_CALLBACK( + _on_about_closex), mailer); + g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK( + gtk_widget_hide), NULL); + gtk_widget_show(dialog); +#else /* !GTK_CHECK_VERSION(2, 6, 0) */ + /* FIXME implement */ +#endif /* !GTK_CHECK_VERSION(2, 6, 0) */ +} + +static gboolean _on_about_closex(gpointer data) +{ + Mailer * mailer = data; + + gtk_widget_hide(mailer->ab_window); + return TRUE; +} + + +/* mailer_show_preferences */ +typedef enum _AccountColumn +{ + AC_DATA = 0, + AC_ACTIVE, + AC_ENABLED, + AC_TITLE, + AC_TYPE +} AccountColumn; +#define AC_LAST AC_TYPE +#define AC_COUNT (AC_LAST + 1) +static void _preferences_set(Mailer * mailer); +static gboolean _on_preferences_closex(gpointer data); +static void _on_preferences_account_delete(gpointer data); +static void _on_preferences_account_edit(gpointer data); +static void _on_preferences_account_new(gpointer data); +static void _on_preferences_account_toggle(GtkCellRendererToggle * renderer, + char * path, gpointer data); +static void _on_preferences_cancel(gpointer data); +static void _on_preferences_ok(gpointer data); +static int _preferences_ok_accounts(Mailer * mailer); +static int _preferences_ok_display(Mailer * mailer); +static int _preferences_ok_save(Mailer * mailer); + +void mailer_show_preferences(Mailer * mailer, gboolean show) +{ + GtkWidget * notebook; + GtkWidget * vbox; + GtkWidget * hbox; + GtkWidget * vbox2; + GtkWidget * vbox3; + GtkWidget * widget; + GtkSizeGroup * group; + GtkListStore * store; + size_t i; + Account * ac; + GtkTreeIter iter; + GtkCellRenderer * renderer; + + if(mailer->pr_window != NULL) + { + if(show) + gtk_widget_show(mailer->pr_window); + else + gtk_widget_hide(mailer->pr_window); + return; + } + mailer->pr_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_default_size(GTK_WINDOW(mailer->pr_window), 300, 200); + gtk_container_set_border_width(GTK_CONTAINER(mailer->pr_window), 4); + gtk_window_set_title(GTK_WINDOW(mailer->pr_window), + "Mailer preferences"); + gtk_window_set_transient_for(GTK_WINDOW(mailer->pr_window), GTK_WINDOW( + mailer->window)); + g_signal_connect_swapped(G_OBJECT(mailer->pr_window), "delete-event", + G_CALLBACK(_on_preferences_closex), mailer); + vbox = gtk_vbox_new(FALSE, 4); + notebook = gtk_notebook_new(); + /* accounts */ + vbox2 = gtk_vbox_new(FALSE, 4); + gtk_container_set_border_width(GTK_CONTAINER(vbox2), 4); + hbox = gtk_hbox_new(FALSE, 4); + widget = gtk_scrolled_window_new(NULL, NULL); + gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(widget), + GTK_SHADOW_IN); + gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(widget), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + store = gtk_list_store_new(AC_COUNT, G_TYPE_POINTER, G_TYPE_BOOLEAN, + G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_STRING); + for(i = 0; i < mailer->account_cnt; i++) + { + ac = mailer->account[i]; + gtk_list_store_insert_with_values(store, &iter, -1, + AC_DATA, ac, AC_ACTIVE, TRUE, + AC_ENABLED, ac->enabled, AC_TITLE, ac->title, + AC_TYPE, ac->plugin->type, -1); + } + mailer->pr_accounts = gtk_tree_view_new_with_model(GTK_TREE_MODEL( + store)); + gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(mailer->pr_accounts), + TRUE); + renderer = gtk_cell_renderer_toggle_new(); + g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK( + _on_preferences_account_toggle), store); + gtk_tree_view_append_column(GTK_TREE_VIEW(mailer->pr_accounts), + gtk_tree_view_column_new_with_attributes("Enabled", + renderer, "active", AC_ENABLED, NULL)); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_append_column(GTK_TREE_VIEW(mailer->pr_accounts), + gtk_tree_view_column_new_with_attributes("Name", + renderer, "text", AC_TITLE, NULL)); + renderer = gtk_cell_renderer_text_new(); + gtk_tree_view_append_column(GTK_TREE_VIEW(mailer->pr_accounts), + gtk_tree_view_column_new_with_attributes("Type", + renderer, "text", AC_TYPE, NULL)); + gtk_container_add(GTK_CONTAINER(widget), mailer->pr_accounts); + gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); + vbox3 = gtk_vbox_new(FALSE, 4); + widget = gtk_button_new_from_stock(GTK_STOCK_NEW); + g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK( + _on_preferences_account_new), mailer); + gtk_box_pack_start(GTK_BOX(vbox3), widget, FALSE, TRUE, 0); +#if GTK_CHECK_VERSION(2, 6, 0) + widget = gtk_button_new_from_stock(GTK_STOCK_EDIT); +#else + widget = gtk_button_new_with_mnemonic("_Edit"); +#endif + g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK( + _on_preferences_account_edit), mailer); + gtk_box_pack_start(GTK_BOX(vbox3), widget, FALSE, TRUE, 0); + widget = gtk_button_new_from_stock(GTK_STOCK_DELETE); + g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK( + _on_preferences_account_delete), mailer); + gtk_box_pack_start(GTK_BOX(vbox3), widget, FALSE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(hbox), vbox3, FALSE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vbox2), hbox, TRUE, TRUE, 0); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, gtk_label_new( + "Accounts")); + /* display */ + vbox2 = gtk_vbox_new(FALSE, 4); + gtk_container_set_border_width(GTK_CONTAINER(vbox2), 4); + group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); + /* default font */ + hbox = gtk_hbox_new(FALSE, 4); + widget = gtk_label_new("Messages font:"); + gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.5); + gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 0); + mailer->pr_messages_font = gtk_font_button_new(); + widget = mailer->pr_messages_font; + gtk_size_group_add_widget(group, widget); + gtk_font_button_set_use_font(GTK_FONT_BUTTON(widget), TRUE); + gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vbox2), hbox, FALSE, FALSE, 0); + gtk_notebook_append_page(GTK_NOTEBOOK(notebook), vbox2, gtk_label_new( + "Display")); + gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); + /* dialog */ + hbox = gtk_hbox_new(FALSE, 4); + group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); + widget = gtk_button_new_from_stock(GTK_STOCK_OK); + gtk_size_group_add_widget(group, widget); + g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK( + _on_preferences_ok), mailer); + gtk_box_pack_end(GTK_BOX(hbox), widget, FALSE, TRUE, 0); + widget = gtk_button_new_from_stock(GTK_STOCK_CANCEL); + gtk_size_group_add_widget(group, widget); + g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK( + _on_preferences_cancel), mailer); + gtk_box_pack_end(GTK_BOX(hbox), widget, FALSE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + gtk_container_add(GTK_CONTAINER(mailer->pr_window), vbox); + _preferences_set(mailer); + gtk_widget_show_all(vbox); + if(show) + gtk_widget_show(mailer->pr_window); + else + gtk_widget_hide(mailer->pr_window); +} + +static void _preferences_set(Mailer * mailer) +{ + char const * p; + + if((p = mailer_get_config(mailer, "messages_font")) == NULL) + p = MAILER_MESSAGES_FONT; + gtk_font_button_set_font_name(GTK_FONT_BUTTON(mailer->pr_messages_font), + p); +} + +static gboolean _on_preferences_closex(gpointer data) +{ + Mailer * mailer = data; + + gtk_widget_hide(mailer->pr_window); + return TRUE; +} + + +/* _on_preferences_account_new */ +/* types */ +typedef struct _AccountData +{ + Mailer * mailer; + char * title; + AccountIdentity identity; + unsigned int available; + Account * account; + GtkWidget * assistant; + GtkWidget * settings; + GtkWidget * confirm; +} AccountData; + +/* functions */ +static GtkWidget * _assistant_account_select(AccountData * ad); +static GtkWidget * _assistant_account_config(AccountConfig * config); + +#if !GTK_CHECK_VERSION(2, 10, 0) +# include "gtkassistant.c" +#endif +static void _on_assistant_cancel(GtkWidget * widget, gpointer data); +static void _on_assistant_close(GtkWidget * widget, gpointer data); +static void _on_assistant_apply(GtkWidget * widget, gpointer data); +static void _on_assistant_prepare(GtkWidget * widget, GtkWidget * page, + gpointer data); +static void _on_entry_changed(GtkWidget * widget, gpointer data); +static void _on_account_type_changed(GtkWidget * widget, gpointer data); + +static void _on_preferences_account_new(gpointer data) +{ + Mailer * mailer = data; + AccountData * ad; + GtkAssistant * assistant; + GtkWidget * page; + + if(mailer->available_cnt == 0) + { + mailer_error(mailer, "No account plug-in available", 0); + return; + } + if((ad = malloc(sizeof(*ad))) == NULL) + { + mailer_error(mailer, strerror(errno), 0); + return; + } + ad->mailer = mailer; + ad->title = strdup(""); + memset(&(ad->identity), 0, sizeof(ad->identity)); + ad->available = 0; + ad->account = NULL; + ad->assistant = gtk_assistant_new(); + assistant = GTK_ASSISTANT(ad->assistant); + g_signal_connect(G_OBJECT(ad->assistant), "cancel", G_CALLBACK( + _on_assistant_cancel), ad); + g_signal_connect(G_OBJECT(ad->assistant), "close", G_CALLBACK( + _on_assistant_close), ad); + g_signal_connect(G_OBJECT(ad->assistant), "apply", G_CALLBACK( + _on_assistant_apply), ad); + g_signal_connect(G_OBJECT(ad->assistant), "prepare", G_CALLBACK( + _on_assistant_prepare), ad); + /* plug-in selection */ + page = _assistant_account_select(ad); + gtk_assistant_append_page(assistant, page); + gtk_assistant_set_page_title(assistant, page, _title[0]); + gtk_assistant_set_page_type(assistant, page, GTK_ASSISTANT_PAGE_INTRO); + gtk_assistant_set_page_complete(assistant, page, FALSE); + /* plug-in preferences */ + page = gtk_vbox_new(FALSE, 0); + ad->settings = page; + gtk_widget_show(page); + gtk_assistant_append_page(assistant, page); + gtk_assistant_set_page_title(assistant, page, _title[1]); + gtk_assistant_set_page_type(assistant, page, + GTK_ASSISTANT_PAGE_CONTENT); + gtk_assistant_set_page_complete(assistant, page, TRUE); + /* confirmation page */ + page = gtk_vbox_new(FALSE, 0); + ad->confirm = page; + gtk_widget_show(page); + gtk_assistant_append_page(assistant, page); + gtk_assistant_set_page_title(assistant, page, _title[2]); + gtk_assistant_set_page_type(assistant, page, + GTK_ASSISTANT_PAGE_CONFIRM); + gtk_assistant_set_page_complete(assistant, page, TRUE); + gtk_widget_show(ad->assistant); +} + +static void _on_assistant_cancel(GtkWidget * widget, gpointer data) +{ + _on_assistant_close(widget, data); +} + +static void _on_assistant_close(GtkWidget * widget, gpointer data) +{ + AccountData * ad = data; + + if(ad->account != NULL) + account_delete(ad->account); + free(ad); + gtk_widget_destroy(widget); +} + +static void _on_assistant_apply(GtkWidget * widget, gpointer data) +{ + AccountData * ad = data; + GtkTreeModel * model; + GtkTreeIter iter; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(ad->mailer->pr_accounts)); + gtk_list_store_append(GTK_LIST_STORE(model), &iter); +#ifdef DEBUG + fprintf(stderr, "%s%p%s%s%s%s\n", "AC_DATA ", ad->account, + ", AC_ACTIVE FALSE, AC_ENABLED TRUE, AC_TITLE ", + ad->account->title, ", AC_TYPE ", + ad->account->plugin->type); +#endif +#if 0 /* FIXME move to mailer.c */ + gtk_list_store_set(GTK_LIST_STORE(model), &iter, + AC_DATA, ad->account, AC_ACTIVE, FALSE, + AC_ENABLED, TRUE, AC_TITLE, ad->account->title, + AC_TYPE, ad->account->plugin->type, -1); +#endif + ad->account = NULL; + /* _on_assistant_close is then automatically called */ +} + +/* on_assistant_prepare */ +static GtkWidget * _account_display(Account * account); + +static void _on_assistant_prepare(GtkWidget * widget, GtkWidget * page, + gpointer data) +{ + static int old = 0; + AccountData * ad = data; + unsigned int i; + Account * ac; + + i = gtk_assistant_get_current_page(GTK_ASSISTANT(widget)); + gtk_window_set_title(GTK_WINDOW(widget), _title[i]); + if(i == 1) + { + /* XXX something is wrong with gtk_container_remove */ + gtk_container_remove(GTK_CONTAINER(page), ad->settings); + if(old == 0) + { + if(ad->account != NULL) + account_delete(ad->account); + ac = &(ad->mailer->available[ad->available]); + ad->account = account_new(ac->name, ad->title); + } + if(ad->account == NULL) + { + mailer_error(ad->mailer, "Could not load plug-in", 0); + gtk_assistant_set_current_page(GTK_ASSISTANT(widget), + 0); + ad->settings = _assistant_account_select(ad); + } + else + ad->settings = _assistant_account_config( + ad->account->plugin->config); + gtk_container_add(GTK_CONTAINER(page), ad->settings); + gtk_widget_show_all(ad->settings); + } + else if(i == 2) + { + gtk_container_remove(GTK_CONTAINER(page), ad->confirm); + ad->confirm = _account_display(ad->account); + gtk_container_add(GTK_CONTAINER(page), ad->confirm); + } + old = i; +} + +/* _assistant_account_select */ +static void _on_account_name_changed(GtkWidget * widget, gpointer data); +static void _account_add_label(GtkWidget * box, PangoFontDescription * desc, + GtkSizeGroup * group, char const * text); + +static GtkWidget * _assistant_account_select(AccountData * ad) +{ + GtkWidget * vbox; + GtkWidget * hbox; + GtkSizeGroup * group; + PangoFontDescription * desc; + GtkWidget * widget; + unsigned int i; + + vbox = gtk_vbox_new(FALSE, 4); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 4); + group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); + hbox = gtk_hbox_new(FALSE, 4); + desc = pango_font_description_new(); + pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD); + _account_add_label(hbox, desc, group, "Account name"); + widget = gtk_entry_new(); + g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK( + _on_account_name_changed), ad); + gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + hbox = gtk_hbox_new(FALSE, 4); + _account_add_label(hbox, desc, group, "Your name"); + widget = gtk_entry_new(); + g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK( + _on_entry_changed), &(ad->identity.from)); + gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + hbox = gtk_hbox_new(FALSE, 4); + _account_add_label(hbox, desc, group, "e-mail address"); + widget = gtk_entry_new(); + g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK( + _on_entry_changed), &(ad->identity.email)); + gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + hbox = gtk_hbox_new(FALSE, 4); + _account_add_label(hbox, desc, group, "Type of account"); + widget = gtk_combo_box_new_text(); + /* XXX this works because there is no plug-in list reload + * would it be implemented this will need validation later */ + for(i = 0; i < ad->mailer->available_cnt; i++) + gtk_combo_box_append_text(GTK_COMBO_BOX(widget), + ad->mailer->available[i].title); + gtk_combo_box_set_active(GTK_COMBO_BOX(widget), 0); + g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK( + _on_account_type_changed), ad); + gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); + pango_font_description_free(desc); + gtk_widget_show_all(vbox); + return vbox; +} + +static void _on_account_name_changed(GtkWidget * widget, gpointer data) +{ + AccountData * ad = data; + int current; + GtkWidget * page; + + _on_entry_changed(widget, &ad->title); + current = gtk_assistant_get_current_page(GTK_ASSISTANT(ad->assistant)); + page = gtk_assistant_get_nth_page(GTK_ASSISTANT(ad->assistant), + current); + gtk_assistant_set_page_complete(GTK_ASSISTANT(ad->assistant), page, + strlen(ad->title) ? TRUE : FALSE); +} + +static void _account_add_label(GtkWidget * box, PangoFontDescription * desc, + GtkSizeGroup * group, char const * text) +{ + static char buf[80]; /* XXX hard-coded size */ + GtkWidget * label; + + snprintf(buf, sizeof(buf), "%s:", text); + label = gtk_label_new(buf); + if(desc != NULL) + gtk_widget_modify_font(label, desc); + if(group != NULL) + gtk_size_group_add_widget(group, label); + gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5); + gtk_box_pack_start(GTK_BOX(box), label, FALSE, TRUE, 0); +} + +/* _assistant_account_config */ +static GtkWidget * _update_string(AccountConfig * config, + PangoFontDescription * desc, GtkSizeGroup * group); +static GtkWidget * _update_password(AccountConfig * config, + PangoFontDescription * desc, GtkSizeGroup * group); +static GtkWidget * _update_file(AccountConfig * config, + PangoFontDescription * desc, GtkSizeGroup * group); +static GtkWidget * _update_uint16(AccountConfig * config, + PangoFontDescription * desc, GtkSizeGroup * group); +static GtkWidget * _update_boolean(AccountConfig * config); + +static GtkWidget * _assistant_account_config(AccountConfig * config) +{ + GtkWidget * vbox; + GtkSizeGroup * group; + PangoFontDescription * desc; + GtkWidget * widget; + size_t i; + + vbox = gtk_vbox_new(FALSE, 4); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 4); + group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); + desc = pango_font_description_new(); + pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD); + for(i = 0; config[i].name != NULL; i++) + { + switch(config[i].type) + { + case ACT_NONE: + continue; + case ACT_STRING: + widget = _update_string(&config[i], desc, + group); + break; + case ACT_PASSWORD: + widget = _update_password(&config[i], desc, + group); + break; + case ACT_FILE: + widget = _update_file(&config[i], desc, group); + break; + case ACT_UINT16: + widget = _update_uint16(&config[i], desc, + group); + break; + case ACT_BOOLEAN: + widget = _update_boolean(&config[i]); + break; + default: /* should not happen */ + continue; + } + gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0); + } + pango_font_description_free(desc); + return vbox; +} + +static GtkWidget * _update_string(AccountConfig * config, + PangoFontDescription * desc, GtkSizeGroup * group) +{ + GtkWidget * hbox; + GtkWidget * widget; + + hbox = gtk_hbox_new(FALSE, 0); + _account_add_label(hbox, desc, group, config->title); + widget = gtk_entry_new(); + if(config->value != NULL) + gtk_entry_set_text(GTK_ENTRY(widget), config->value); + g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK( + _on_entry_changed), &config->value); + gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); + return hbox; +} + +static GtkWidget * _update_password(AccountConfig * config, + PangoFontDescription * desc, GtkSizeGroup * group) +{ + GtkWidget * hbox; + GtkWidget * widget; + + hbox = gtk_hbox_new(FALSE, 0); + _account_add_label(hbox, desc, group, config->title); + widget = gtk_entry_new(); + gtk_entry_set_visibility(GTK_ENTRY(widget), FALSE); + if(config->value != NULL) + gtk_entry_set_text(GTK_ENTRY(widget), config->value); + g_signal_connect(G_OBJECT(widget), "changed", G_CALLBACK( + _on_entry_changed), &config->value); + gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); + return hbox; +} + +static void _on_file_activated(GtkWidget * widget, gpointer data); + +static GtkWidget * _update_file(AccountConfig * config, + PangoFontDescription * desc, GtkSizeGroup * group) +{ + GtkWidget * hbox; + GtkWidget * widget; + + hbox = gtk_hbox_new(FALSE, 0); + _account_add_label(hbox, desc, group, config->title); + widget = gtk_file_chooser_button_new("Choose file", + GTK_FILE_CHOOSER_ACTION_OPEN); + if(config->value != NULL) + gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(widget), + config->value); + gtk_file_chooser_button_set_title(GTK_FILE_CHOOSER_BUTTON(widget), + config->title); + g_signal_connect(G_OBJECT(widget), "file-set", G_CALLBACK( + _on_file_activated), &config->value); + gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); + return hbox; +} + +static void _on_file_activated(GtkWidget * widget, gpointer data) +{ + char * filename; + char ** value = data; + char * p; + + filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget)); +#ifdef DEBUG + fprintf(stderr, "DEBUG: %s(%s)\n", __func__, filename); +#endif + if((p = realloc(*value, strlen(filename) + 1)) == NULL) + { + mailer_error(NULL, strerror(errno), 0); + return; + } + *value = p; + strcpy(p, filename); +} + +static void _on_uint16_changed(GtkWidget * widget, gpointer data); + +static GtkWidget * _update_uint16(AccountConfig * config, + PangoFontDescription * desc, GtkSizeGroup * group) +{ + GtkWidget * hbox; + GtkWidget * widget; + uint16_t u16 = (intptr_t)(config->value); + gdouble value = u16; + + hbox = gtk_hbox_new(FALSE, 0); + _account_add_label(hbox, desc, group, config->title); + widget = gtk_spin_button_new_with_range(0, 65535, 1); + gtk_spin_button_set_digits(GTK_SPIN_BUTTON(widget), 0); + gtk_spin_button_set_value(GTK_SPIN_BUTTON(widget), value); + g_signal_connect(G_OBJECT(widget), "value-changed", G_CALLBACK( + _on_uint16_changed), &config->value); + gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); + return hbox; +} + +static void _on_uint16_changed(GtkWidget * widget, gpointer data) +{ + int * value = data; + + *value = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget)); +#ifdef DEBUG + fprintf(stderr, "DEBUG: new value is %d\n", *value); +#endif +} + +static void _on_boolean_toggled(GtkWidget * widget, gpointer data); +static GtkWidget * _update_boolean(AccountConfig * config) +{ + GtkWidget * widget; + + widget = gtk_check_button_new_with_label(config->title); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget), + config->value != NULL); + g_signal_connect(G_OBJECT(widget), "toggled", G_CALLBACK( + _on_boolean_toggled), &config->value); + return widget; +} + +static void _on_boolean_toggled(GtkWidget * widget, gpointer data) +{ + int * value = data; + + *value = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)); +} + +static GtkWidget * _display_string(AccountConfig * config, + PangoFontDescription * desc, GtkSizeGroup * group); +static GtkWidget * _display_password(AccountConfig * config, + PangoFontDescription * desc, GtkSizeGroup * group); +static GtkWidget * _display_file(AccountConfig * config, + PangoFontDescription * desc, GtkSizeGroup * group); +static GtkWidget * _display_uint16(AccountConfig * config, + PangoFontDescription * desc, GtkSizeGroup * group); +static GtkWidget * _display_boolean(AccountConfig * config, + PangoFontDescription * desc, GtkSizeGroup * group); +static GtkWidget * _account_display(Account * account) +{ + AccountConfig * config = account->plugin->config; + AccountConfig p; + GtkWidget * vbox; + GtkSizeGroup * group; + PangoFontDescription * desc; + GtkWidget * widget; + unsigned int i; + + vbox = gtk_vbox_new(FALSE, 4); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 4); + group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); + p.name = NULL; + p.title = "Account name"; + p.value = account->title; + desc = pango_font_description_new(); + pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD); + widget = _display_string(&p, desc, group); + gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0); + for(i = 0; config[i].name != NULL; i++) + { + switch(config[i].type) + { + case ACT_NONE: + continue; + case ACT_STRING: + widget = _display_string(&config[i], desc, + group); + break; + case ACT_PASSWORD: + widget = _display_password(&config[i], desc, + group); + break; + case ACT_FILE: + widget = _display_file(&config[i], desc, group); + break; + case ACT_UINT16: + widget = _display_uint16(&config[i], desc, + group); + break; + case ACT_BOOLEAN: + widget = _display_boolean(&config[i], desc, + group); + break; + default: /* should not happen */ + assert(0); + continue; + } + gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, TRUE, 0); + } + pango_font_description_free(desc); + gtk_widget_show_all(vbox); + return vbox; +} + +static GtkWidget * _display_string(AccountConfig * config, + PangoFontDescription * desc, GtkSizeGroup * group) +{ + GtkWidget * hbox; + GtkWidget * widget; + + hbox = gtk_hbox_new(FALSE, 0); + _account_add_label(hbox, desc, group, config->title); + widget = gtk_label_new(config->value); + gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); + return hbox; +} + +static GtkWidget * _display_file(AccountConfig * config, + PangoFontDescription * desc, GtkSizeGroup * group) +{ + return _display_string(config, desc, group); +} + +static GtkWidget * _display_password(AccountConfig * config, + PangoFontDescription * desc, GtkSizeGroup * group) +{ + GtkWidget * hbox; + GtkWidget * widget; + + hbox = gtk_hbox_new(FALSE, 0); + _account_add_label(hbox, desc, group, config->title); + widget = gtk_label_new("hidden"); + desc = pango_font_description_new(); + pango_font_description_set_style(desc, PANGO_STYLE_ITALIC); + gtk_widget_modify_font(widget, desc); + gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.5); + gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); + return hbox; +} + +static GtkWidget * _display_uint16(AccountConfig * config, + PangoFontDescription * desc, GtkSizeGroup * group) +{ + GtkWidget * hbox; + GtkWidget * widget; + char buf[6]; + uint16_t u16 = (intptr_t)config->value; + + hbox = gtk_hbox_new(FALSE, 0); + _account_add_label(hbox, desc, group, config->title); + snprintf(buf, sizeof(buf), "%hu", u16); + widget = gtk_label_new(buf); + gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.5); + gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); + return hbox; +} + +static GtkWidget * _display_boolean(AccountConfig * config, + PangoFontDescription * desc, GtkSizeGroup * group) +{ + GtkWidget * hbox; + GtkWidget * widget; + + hbox = gtk_hbox_new(FALSE, 0); + _account_add_label(hbox, desc, group, config->title); + widget = gtk_label_new(config->value != 0 ? "Yes" : "No"); + gtk_misc_set_alignment(GTK_MISC(widget), 0.0, 0.5); + gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 0); + return hbox; +} + +static void _on_entry_changed(GtkWidget * widget, gpointer data) +{ + const char * text; + char ** value = data; + char * p; + + text = gtk_entry_get_text(GTK_ENTRY(widget)); + if((p = realloc(*value, strlen(text) + 1)) == NULL) + { + mailer_error(NULL, strerror(errno), 0); + return; + } + *value = p; + strcpy(p, text); +} + +static void _on_account_type_changed(GtkWidget * widget, gpointer data) +{ + AccountData * ad = data; + + ad->available = gtk_combo_box_get_active(GTK_COMBO_BOX(widget)); +#ifdef DEBUG + fprintf(stderr, "%s%u%s", "Account type ", ad->available, " active\n"); +#endif +} + +static void _on_preferences_account_toggle(GtkCellRendererToggle * renderer, + char * path, gpointer data) +{ + GtkListStore * store = data; + GtkTreeIter iter; + + gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(store), &iter, path); + gtk_list_store_set(store, &iter, AC_ENABLED, + !gtk_cell_renderer_toggle_get_active(renderer), -1); +} + +/* _on_preferences_account_edit */ +static void _account_edit(Mailer * mailer, Account * account); + +static void _on_preferences_account_edit(gpointer data) +{ + Mailer * mailer = data; + GtkTreeSelection * selection; + GtkTreeModel * model; + GtkTreeIter iter; + Account * account; + + selection = gtk_tree_view_get_selection(GTK_TREE_VIEW( + mailer->pr_accounts)); + if(!gtk_tree_selection_get_selected(selection, &model, &iter)) + return; + gtk_tree_model_get(model, &iter, AC_DATA, &account, -1); + _account_edit(mailer, account); +} + +static void _account_edit(Mailer * mailer, Account * account) +{ + GtkWidget * window; + char buf[80]; + GtkWidget * vbox; + GtkWidget * widget; + GtkWidget * hbox; + GtkSizeGroup * group; + + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + snprintf(buf, sizeof(buf), "%s%s", "Edit account: ", account_get_title( + account)); + gtk_window_set_title(GTK_WINDOW(window), buf); + gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW( + mailer->window)); + gtk_window_set_modal(GTK_WINDOW(window), TRUE); + /* FIXME this affects the account directly (eg cancel does not) */ + widget = _assistant_account_config(account->plugin->config); + vbox = gtk_vbox_new(FALSE, 4); + gtk_box_pack_start(GTK_BOX(vbox), widget, TRUE, TRUE, 0); + hbox = gtk_hbox_new(FALSE, 0); + widget = gtk_hseparator_new(); + gtk_box_pack_start(GTK_BOX(hbox), widget, TRUE, TRUE, 4); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0); + hbox = gtk_hbox_new(FALSE, 0); + group = gtk_size_group_new(GTK_SIZE_GROUP_HORIZONTAL); + widget = gtk_button_new_from_stock(GTK_STOCK_OK); + gtk_size_group_add_widget(group, widget); + /* FIXME implement properly */ + g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK( + gtk_widget_destroy), window); + gtk_box_pack_end(GTK_BOX(hbox), widget, FALSE, TRUE, 4); + widget = gtk_button_new_from_stock(GTK_STOCK_CANCEL); + gtk_size_group_add_widget(group, widget); + g_signal_connect_swapped(G_OBJECT(widget), "clicked", G_CALLBACK( + gtk_widget_destroy), window); + gtk_box_pack_end(GTK_BOX(hbox), widget, FALSE, TRUE, 0); + gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 4); + gtk_container_add(GTK_CONTAINER(window), vbox); + gtk_widget_show_all(window); +} + +static void _on_preferences_account_delete(gpointer data) +{ + Mailer * mailer = data; + GtkTreePath * path; + GtkTreeModel * model; + GtkTreeIter iter; + + gtk_tree_view_get_cursor(GTK_TREE_VIEW(mailer->pr_accounts), &path, + NULL); + if(path == NULL) + return; + model = gtk_tree_view_get_model(GTK_TREE_VIEW(mailer->pr_accounts)); + gtk_tree_model_get_iter(model, &iter, path); + gtk_tree_path_free(path); + gtk_list_store_remove(GTK_LIST_STORE(model), &iter); + /* FIXME non-interface code (flag account as deleted and on ok apply) */ +} + +static void _on_preferences_cancel(gpointer data) +{ + Mailer * mailer = data; + + gtk_widget_hide(mailer->pr_window); + _preferences_set(mailer); +} + +static void _on_preferences_ok(gpointer data) +{ + Mailer * mailer = data; + + mailer_show_preferences(mailer, FALSE); + if(_preferences_ok_accounts(mailer) != 0 + || _preferences_ok_display(mailer) != 0 + || _preferences_ok_save(mailer) != 0) + mailer_error(mailer, "An error occured while saving" + " preferences", 0); +} + +static int _preferences_ok_accounts(Mailer * mailer) +{ + GtkTreeModel * model; + GtkTreeIter iter; + GtkTreeModel * view_model; + gboolean loop; + Account * account; + gboolean active; + gboolean enabled; + char * title; + size_t title_len; + char * accounts = NULL; + size_t accounts_len = 0; + char * p; + + model = gtk_tree_view_get_model(GTK_TREE_VIEW(mailer->pr_accounts)); + view_model = gtk_tree_view_get_model(GTK_TREE_VIEW( + mailer->view_folders)); + for(loop = gtk_tree_model_get_iter_first(model, &iter); loop == TRUE; + loop = gtk_tree_model_iter_next(model, &iter)) + { + gtk_tree_model_get(model, &iter, AC_DATA, &account, + AC_ACTIVE, &active, AC_ENABLED, &enabled, + AC_TITLE, &title, -1); + title_len = strlen(title); + if(account_config_save(account, mailer->config) != 0) + return 1; + if((p = realloc(accounts, accounts_len + title_len + 2)) + == NULL) + { + free(accounts); + return 1; + } + accounts = p; + sprintf(&accounts[accounts_len], "%s%s", accounts_len ? "," + : "", title); + accounts_len += title_len + (accounts_len ? 1 : 0); + if(active) + { + if(enabled) + continue; +#if 0 /* FIXME API+behaviour change here */ + if(mailer_account_disable(mailer, account) == 0) + gtk_list_store_set(GTK_LIST_STORE(model), &iter, + AC_ACTIVE, FALSE, -1); +#endif + } + else if(enabled && mailer_account_add(mailer, account) == 0) + gtk_list_store_set(GTK_LIST_STORE(model), &iter, + AC_ACTIVE, TRUE, -1); + } +#ifdef DEBUG + fprintf(stderr, "DEBUG: saved accounts \"%s\"\n", accounts); +#endif + config_set(mailer->config, "", "accounts", accounts); + free(accounts); + return 0; +} + +static int _preferences_ok_display(Mailer * mailer) +{ + char const * p; + + p = gtk_font_button_get_font_name(GTK_FONT_BUTTON( + mailer->pr_messages_font)); + config_set(mailer->config, "", "messages_font", p); + return 0; +} + +static int _preferences_ok_save(Mailer * mailer) +{ + int ret; + char * p; + + if((p = _mailer_get_config_filename(mailer)) == NULL) + return 1; + ret = config_save(mailer->config, p); + free(p); + return ret; +} + + +/* private */ +/* functions */ +/* mailer_get_config_filename */ +static char * _mailer_get_config_filename(Mailer * mailer) + /* FIXME consider replacing with mailer_save_config() */ +{ + char const * homedir; + char * filename; + + if((homedir = getenv("HOME")) == NULL) + return NULL; + if((filename = malloc(strlen(homedir) + sizeof(MAILER_CONFIG_FILE) + 1)) + == NULL) + return NULL; + sprintf(filename, "%s/%s", homedir, MAILER_CONFIG_FILE); + return filename; +} diff --git a/src/mailer.h b/src/mailer.h index 66face3..9fff281 100644 --- a/src/mailer.h +++ b/src/mailer.h @@ -52,37 +52,7 @@ enum # define MH_COL_LAST MH_COL_DATE # define MH_COL_COUNT (MH_COL_LAST + 1) -typedef struct _Mailer -{ - Account * available; /* XXX consider using another data type */ - unsigned int available_cnt; - - Account ** account; - unsigned int account_cnt; - Account * account_cur; - AccountFolder * folder_cur; - - /* configuration */ - Config * config; - - /* widgets */ - GtkWidget * window; - GtkWidget * view_folders; - GtkWidget * view_headers; - GtkWidget * hdr_vbox; - GtkWidget * hdr_subject; - GtkWidget * hdr_from; - GtkWidget * hdr_to; - GtkWidget * hdr_date; - GtkTextBuffer * view_buffer; - GtkWidget * view_body; - GtkWidget * statusbar; - gint statusbar_id; - /* preferences */ - GtkWidget * pr_window; - GtkWidget * pr_accounts; - GtkWidget * pr_messages_font; -} Mailer; +typedef struct _Mailer Mailer; /* functions */ @@ -91,7 +61,6 @@ void mailer_delete(Mailer * mailer); /* accessors */ char const * mailer_get_config(Mailer * mailer, char const * variable); -char * mailer_get_config_filename(Mailer * mailer); /* useful */ int mailer_error(Mailer * mailer, char const * message, int ret); @@ -104,4 +73,7 @@ int mailer_account_enable(Mailer * mailer, Account * account); /* FIXME implement int mailer_account_remove(Mailer * mailer, Account * account); */ -#endif +void mailer_show_about(Mailer * mailer, gboolean show); +void mailer_show_preferences(Mailer * mailer, gboolean show); + +#endif /* !MAILER_MAILER_H */