diff options
Diffstat (limited to 'mail')
53 files changed, 5916 insertions, 1576 deletions
diff --git a/mail/ChangeLog b/mail/ChangeLog index 2954cbdaaf..97a64fff60 100644 --- a/mail/ChangeLog +++ b/mail/ChangeLog @@ -411,6 +411,216 @@ * Makefile.am (SUBDIRS): Revert previous error change +2004-09-10 Not Zed <NotZed@Ximian.com> + + * em-*: various doco updates. + + * em-format-quote.c (emfq_builtin_init): instead of removing the + type, just add an override noop. Changed api's. + +2004-09-09 Not Zed <NotZed@Ximian.com> + + * em-format.c (em_format_class_remove_handler): Change this to use + the original structure only, not by type. + + * em-format-hook.c (emfh_enable): implement hook enablation. + +2004-09-07 Not Zed <NotZed@Ximian.com> + + * em-account-editor.c (emae_setup_providers): set the provider + shown selected on the store as well. + + * mail-config.glade: moved the druid 'help text' directly into the + glade file. + + * em-account-editor.c (emae_check_complete): add pre-load for + management page options. + + * em-utils.c (em_utils_configure_account): remove use of + mail-config-druid. + + * em-account-editor.c (emae_remove_childen): removed. + (*): removed service->url, always get it from/set it to the + e-account so it doesn't have side-effects with plugins. + + * mail-dialogs.glade: fix up the names of the various license + dialog fields. + +2004-09-06 Not Zed <NotZed@Ximian.com> + + * em-account-editor.c (emae_receive_options_extra_item): store the + config widgets in the item entry itself. + (emae_auto_detect): wasted a whole lot of time on this crap. + + * em-account-prefs.c (account_able_clicked): removed some redundant logic. + + * mail-send-recv.c (mail_autoreceive_setup): renamed to + mail_autoreceive_init and rewrote all the callbacks. now it + listens to events on the accountlist directly and doesn't need + invoking manually. It also runs relative to the account always, + rather than copying the uri. Removed all callers except the mail + component one. + + * em-account-editor.c (em_account_editor_provider_selector_new): + removed becaus eof below. + (em_account_editor_construct): copy the account to a working + object if supplied, else create a new one. + + * mail-config.glade: make the provider selectors just use + em_account_editor_dropdown new for the dropdown menu. + + * em-account-editor.c (prepare_signatures): removed, merged into + the identity page code. + (sig_fill_menu): removed. + (emae_setup_signatures): new function to setup signatures on a + gtkcombobox. + (clear_menu): removed. + (signature_changed): removed. + (emae_signature_changed): new function for changed. + (signature_removed): removed. + (emae_signature_removed): new function for removed. + (emae_signature_get_iter): helper for finding the right row for + this signature. + (signature_added): removed. + (emae_signature_added): new function for added. + (sig_activate): removed. + (emae_signaturetype_changed): new function to update the account + info immediately. + (sig_add_new_signature): renamed to emae_signature_new. + (select_account_signature): no longer needed, this happens in the + setup. + + * mail-config.glade: changed the signature thing to a custom + widget (gtkcombobox). + + * em-account-editor.c (em_account_editor_construct): updates for + api change, table sections require table items. + (emae_setup_service): handle host:port hostname syntax. + (emae_hostname_changed): and here too. + (emae_commit): fill this out, and implement it. + +2004-09-04 Not Zed <NotZed@Ximian.com> + + * *.c: include gnome i18.h if needed since camel-object.h was + fixed. + + * em-format.c (em_format_class_add_handler): if a handler is + already set for type, link it in. + + * em-format.h: added a link pointer to EMFormatHanlder, so that + overrides can also fallback. remove applications member - not + used anymore. + +2004-09-01 Not Zed <NotZed@Ximian.com> + + * em-popup.h: added some docs. + + * em-popup.c (emp_standard_menu_factory): + * em-folder-tree.c (tree_drag_data_received): popup api changes. + +2004-08-31 Not Zed <NotZed@Ximian.com> + + * em-format-html-display.c (efhd_attachment_button_show): use a + wrapper for the button event since the popup event has changed + signature. + +2004-08-30 Not Zed <NotZed@Ximian.com> + + * em-popup.c (emp_standard_menu_factory): changed args. + (struct _open_in_item): removed, use user data instead. + (*): fix callbacks for new apis. + (emp_popup_open): Removed some dead popup callbacks never invoked. + (em_popup_target_new_attachments): new target type for attachment + bar in composer. + + * em-folder-tree.c (emft_popup*): convert to new e-popup apis. + + * em-folder-view.c: emfv_popup_*: convert to new e-poup callback + signatures. + (EMFV_MAP_CALLBACK): fix for e-popup callback change. + (EMFV_POPUP_AUTO_TYPE): same. + (emfv_popup): dont bother setting item callback data. + (emfv_popup_labels_free): api changes. + (emfv_popup_items_free): new free method. + (EMFVPopupItem): No longer needed. + (emfv_uri_popup_free): api changes. + (emfv_format_popup_event): new api's == simpler code. + + * em-account-editor.c (emae_receive_options_extra_item): add a + hack for the label item, which is only used by connector to + override the hostname and username labels. + +2004-08-24 Not Zed <NotZed@Ximian.com> + + * em-account-editor.c (em_account_editor_construct): create the + window rather than the widget here. + + * mail-config.glade: remove the extra_page from the druid, it is + autogenerated now. renamed the "Receiving options" notebook page + to "Receiving Email" since it isn't hte options page. + + * em-account-editor.c (emae_receive_options_page): no longer + needed, autogenerated. + (emae_receive_options_item): setup the auto-receive time values. + (emae_receive_page): don't setup the auto check time values here. + + * mail-config.glade: Remove the Receiving Mail tab, it is now + completely auto-generated. + +2004-08-17 Not Zed <NotZed@Ximian.com> + + * em-event.[ch]: mail event dispatcher. + + * mail-component.c (mc_startup): hook into events. + + * mail-folder-cache.c (update_1folder): always set the uri field. + (real_flush_updates): emit a folder.changed:new event if we have new + mail. + +2004-08-13 Not Zed <NotZed@Ximian.com> + + * mail-config.glade: replaced ssl selector with custom widget + (gtkcombobox). Giv the preferences, composer toplevel unique + names. + +2004-07-29 Not Zed <NotZed@Ximian.com> + + * mail-config.glade: replaced source and transport selector with + custom widget (gtkcombobox). + + * em-account-editor.[ch]: copy over mail-account-gui.[ch] and + rename stuff. Make a gobject. Move most internals, internal. + +2004-07-28 Not Zed <NotZed@Ximian.com> + + * em-composer-prefs.c (em_composer_prefs_construct): get the + toplevel tab as the root. + (em_composer_prefs_construct): setup plugin metadata for composer + prefs. + + * em-mailer-prefs.c (em_mailer_prefs_construct): setup plugin + metadata for mail preferences. + + * em-config.c (em_config_target_new_prefs): new target for 'prefs' + mode, everything global via gconf. + + * em-mailer-prefs.c (em_mailer_prefs_construct): get the gui from + the preferences_toplevel not the preferences_tab window which we + don't need. + + * mail-config.glade: rename the preferences 'toplevel' to + preferences_toplevel so we can get it unparented. And the + composer toplevel to composer_toplevel. + + * em-folder-properties.c (em_folder_properties_show): remove test + code. + + * em-format.h (struct _EMFormatPURI): add a free function + callback. + + * em-format.c (emf_clear_puri_node): if the free function is set, + call it. + 2004-07-01 Rodney Dawes <dobey@novell.com> * Makefile.am (BUILT_SOURCES): Remove $(error_i18n) diff --git a/mail/Makefile.am b/mail/Makefile.am index 888529cd1e..834ad77d4c 100644 --- a/mail/Makefile.am +++ b/mail/Makefile.am @@ -58,76 +58,86 @@ libevolution_mail_la_SOURCES = \ $(MARSHAL_GENERATED) \ e-searching-tokenizer.c \ e-searching-tokenizer.h \ + em-account-editor.c \ + em-account-editor.h \ em-account-prefs.c \ em-account-prefs.h \ em-composer-prefs.c \ em-composer-prefs.h \ - em-mailer-prefs.c \ - em-mailer-prefs.h \ - em-inline-filter.c \ - em-inline-filter.h \ + em-composer-utils.c \ + em-composer-utils.h \ + em-config.c \ + em-config.h \ + em-event.c \ + em-event.h \ em-filter-context.c \ em-filter-context.h \ em-filter-editor.c \ em-filter-editor.h \ - em-filter-rule.c \ - em-filter-rule.h \ em-filter-folder-element.c \ em-filter-folder-element.h \ - em-filter-source-element.h \ + em-filter-rule.c \ + em-filter-rule.h \ em-filter-source-element.c \ + em-filter-source-element.h \ + em-folder-browser.c \ + em-folder-browser.h \ em-folder-properties.c \ em-folder-properties.h \ - em-folder-selection.c \ - em-folder-selection.h \ em-folder-selection-button.c \ em-folder-selection-button.h \ + em-folder-selection.c \ + em-folder-selection.h \ em-folder-selector.c \ em-folder-selector.h \ - em-folder-tree.c \ - em-folder-tree.h \ em-folder-tree-model.c \ em-folder-tree-model.h \ + em-folder-tree.c \ + em-folder-tree.h \ em-folder-view.c \ em-folder-view.h \ - em-folder-browser.c \ - em-folder-browser.h \ - em-format.c \ - em-format.h \ - em-format-html.c \ - em-format-html.h \ + em-format-hook.c \ + em-format-hook.h \ em-format-html-display.c \ em-format-html-display.h \ em-format-html-print.c \ em-format-html-print.h \ - em-stripsig-filter.c \ - em-stripsig-filter.h \ + em-format-html.c \ + em-format-html.h \ em-format-quote.c \ em-format-quote.h \ + em-format.c \ + em-format.h \ + em-html-stream.c \ + em-html-stream.h \ + em-icon-stream.c \ + em-icon-stream.h \ + em-inline-filter.c \ + em-inline-filter.h \ + em-junk-filter.c \ + em-junk-filter.h \ + em-junk-plugin.c \ + em-junk-plugin.h \ + em-mailer-prefs.c \ + em-mailer-prefs.h \ + em-menu.c \ + em-menu.h \ em-message-browser.c \ em-message-browser.h \ em-migrate.c \ em-migrate.h \ - em-composer-utils.c \ - em-composer-utils.h \ em-popup.c \ em-popup.h \ - em-utils.c \ - em-utils.h \ em-search-context.c \ em-search-context.h \ + em-stripsig-filter.c \ + em-stripsig-filter.h \ em-subscribe-editor.c \ em-subscribe-editor.h \ em-sync-stream.c \ em-sync-stream.h \ - em-icon-stream.c \ - em-icon-stream.h \ - em-junk-filter.c \ - em-junk-filter.h \ - em-junk-plugin.c \ - em-junk-plugin.h \ - em-html-stream.c \ - em-html-stream.h \ + em-utils.c \ + em-utils.h \ em-vfolder-context.c \ em-vfolder-context.h \ em-vfolder-editor.c \ @@ -143,14 +153,14 @@ libevolution_mail_la_SOURCES = \ mail-component-factory.c \ mail-component.c \ mail-component.h \ - mail-config.c \ - mail-config.h \ mail-config-druid.c \ mail-config-druid.h \ - mail-crypto.c \ - mail-crypto.h \ mail-config-factory.c \ mail-config-factory.h \ + mail-config.c \ + mail-config.h \ + mail-crypto.c \ + mail-crypto.h \ mail-folder-cache.c \ mail-folder-cache.h \ mail-mt.c \ diff --git a/mail/em-account-editor.c b/mail/em-account-editor.c new file mode 100644 index 0000000000..080b59d5cc --- /dev/null +++ b/mail/em-account-editor.c @@ -0,0 +1,2439 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: + * Dan Winship <danw@ximian.com> + * Jeffrey Stedfast <fejj@ximian.com> + * Michael Zucchi <notzed@ximian.com> + * + * Copyright 2001 Ximian, Inc. (www.ximian.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +/* + work before merge can occur: + + verify behaviour. + work out what to do with the startup druid. + + also need to work out: + how to remove unecessary items from a service url once + configured (removing settings from other types). + +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <glib.h> + +#include <string.h> +#include <stdarg.h> + +#include <gconf/gconf-client.h> + +#include <glade/glade.h> + +#include <gtk/gtkentry.h> +#include <gtk/gtktogglebutton.h> +#include <gtk/gtktextbuffer.h> +#include <gtk/gtktextview.h> +#include <gtk/gtkcheckbutton.h> +#include <gtk/gtkspinbutton.h> +#include <gtk/gtkmenuitem.h> +#include <gtk/gtknotebook.h> +#include <gtk/gtkhbox.h> +#include <gtk/gtkcellrenderertext.h> +#include <gtk/gtkcelllayout.h> +#include <gtk/gtklabel.h> +#include <gtk/gtkcombobox.h> +#include <gtk/gtktable.h> + +#include <libgnome/gnome-i18n.h> +#include <libgnomeui/gnome-druid.h> +#include <libgnomeui/gnome-druid-page-standard.h> + +#include <e-util/e-account-list.h> +#include <e-util/e-signature-list.h> + +#include <widgets/misc/e-error.h> + +#include "em-config.h" +#include "em-folder-selection-button.h" +#include "em-account-editor.h" +#include "mail-session.h" +#include "mail-send-recv.h" +#include "mail-signature-editor.h" +#include "mail-component.h" +#include "em-utils.h" +#include "em-composer-prefs.h" +#include "mail-config.h" +#include "mail-ops.h" +#include "mail-mt.h" + +#if defined (HAVE_NSS) +#include "smime/gui/e-cert-selector.h" +#endif + +#define d(x) + +/* econfig item for the extra config hings */ +struct _receive_options_item { + EMConfigItem item; + GSList *widgets; + + /* Only CAMEL_PROVIDER_CONF_ENTRYs GtkEntrys are stored here. + The auto-detect camel provider code will probably be removed */ + GHashTable *extra_table; +}; + +typedef struct _EMAccountEditorService { + EMAccountEditor *emae; /* parent pointer, for callbacks */ + + struct _GtkWidget *frame; + struct _GtkWidget *container; + + struct _GtkLabel *description; + struct _GtkEntry *hostname; + struct _GtkEntry *username; + struct _GtkEntry *path; + struct _GtkWidget *ssl_frame; + struct _GtkComboBox *use_ssl; + struct _GtkWidget *ssl_hbox; + struct _GtkWidget *no_ssl; + + struct _GtkWidget *auth_frame; + struct _GtkComboBox *authtype; + struct _GtkWidget *authitem; + struct _GtkToggleButton *remember; + struct _GtkButton *check_supported; + struct _GtkToggleButton *needs_auth; + + GList *authtypes; /* if "Check supported" */ + CamelProvider *provider; + CamelProviderType type; + + int auth_changed_id; +} EMAccountEditorService; + +typedef struct _EMAccountEditorPrivate { + struct _GladeXML *xml; + struct _GladeXML *druidxml; + struct _EMConfig *config; + GList *providers; + + /* signatures */ + struct _GtkComboBox *signatures_dropdown; + guint sig_added_id; + guint sig_removed_id; + guint sig_changed_id; + const char *sig_uid; + + /* incoming mail */ + EMAccountEditorService source; + + /* extra incoming config */ + CamelProvider *extra_provider; + GSList *extra_items; /* this is freed by the econfig automatically */ + + /* outgoing mail */ + EMAccountEditorService transport; + + /* account management */ + struct _GtkToggleButton *default_account; + + /* special folders */ + struct _GtkButton *drafts_folder_button; + struct _GtkButton *sent_folder_button; + struct _GtkButton *restore_folders_button; + + /* Security */ + struct _GtkEntry *pgp_key; + struct _GtkToggleButton *pgp_encrypt_to_self; + struct _GtkToggleButton *pgp_always_sign; + struct _GtkToggleButton *pgp_no_imip_sign; + struct _GtkToggleButton *pgp_always_trust; + + struct _GtkToggleButton *smime_sign_default; + struct _GtkEntry *smime_sign_key; + struct _GtkButton *smime_sign_key_select; + struct _GtkButton *smime_sign_key_clear; + struct _GtkButton *smime_sign_select; + struct _GtkToggleButton *smime_encrypt_default; + struct _GtkToggleButton *smime_encrypt_to_self; + struct _GtkEntry *smime_encrypt_key; + struct _GtkButton *smime_encrypt_key_select; + struct _GtkButton *smime_encrypt_key_clear; + + /* for druid page preparation */ + unsigned int identity_set:1; + unsigned int receive_set:1; + unsigned int management_set:1; +} EMAccountEditorPrivate; + +static GtkWidget *emae_setup_authtype(EMAccountEditor *emae, EMAccountEditorService *service); + +static GtkVBoxClass *emae_parent; + +static void +emae_init(GObject *o) +{ + EMAccountEditor *emae = (EMAccountEditor *)o; + + emae->priv = g_malloc0(sizeof(*emae->priv)); + + emae->priv->source.emae = emae; + emae->priv->transport.emae = emae; +} + +static void +emae_finalise(GObject *o) +{ + EMAccountEditor *emae = (EMAccountEditor *)o; + EMAccountEditorPrivate *p = emae->priv; + + if (p->sig_added_id) { + ESignatureList *signatures = mail_config_get_signatures(); + + g_signal_handler_disconnect(signatures, p->sig_added_id); + g_signal_handler_disconnect(signatures, p->sig_removed_id); + g_signal_handler_disconnect(signatures, p->sig_changed_id); + } + + if (p->xml) + g_object_unref(p->xml); + if (p->druidxml) + g_object_unref(p->druidxml); + + g_list_free(p->source.authtypes); + g_list_free(p->transport.authtypes); + + g_list_free(p->providers); + g_free(p); + + g_object_unref(emae->account); + if (emae->original) + g_object_unref(emae->original); + + ((GObjectClass *)emae_parent)->finalize(o); +} + +static void +emae_class_init(GObjectClass *klass) +{ + klass->finalize = emae_finalise; +} + +GType +em_account_editor_get_type(void) +{ + static GType type = 0; + + if (type == 0) { + static const GTypeInfo info = { + sizeof(EMAccountEditorClass), + NULL, NULL, + (GClassInitFunc)emae_class_init, + NULL, NULL, + sizeof(EMAccountEditor), 0, + (GInstanceInitFunc)emae_init + }; + emae_parent = g_type_class_ref(G_TYPE_OBJECT); + type = g_type_register_static(G_TYPE_OBJECT, "EMAccountEditor", &info, 0); + } + + return type; +} + +/** + * em_account_editor_new: + * @account: + * @type: + * + * Create a new account editor. If @account is NULL then this is to + * create a new account, else @account is copied to a working + * structure and is for editing an existing account. + * + * Return value: + **/ +EMAccountEditor *em_account_editor_new(EAccount *account, em_account_editor_t type) +{ + EMAccountEditor *emae = g_object_new(em_account_editor_get_type(), 0); + + em_account_editor_construct(emae, account, type); + + return emae; +} + +/* ********************************************************************** */ + +static struct { + char *label; + char *value; +} ssl_options[] = { + { N_("Always"), "always" }, + { N_("Whenever Possible"), "when-possible" }, + { N_("Never"), "never" } +}; + +#define num_ssl_options (sizeof (ssl_options) / sizeof (ssl_options[0])) + +static gboolean +is_email (const char *address) +{ + /* This is supposed to check if the address's domain could be + an FQDN but alas, it's not worth the pain and suffering. */ + const char *at; + + at = strchr (address, '@'); + /* make sure we have an '@' and that it's not the first or last char */ + if (!at || at == address || *(at + 1) == '\0') + return FALSE; + + return TRUE; +} + +static CamelURL * +emae_account_url(EMAccountEditor *emae, int urlid) +{ + CamelURL *url = NULL; + const char *uri; + + uri = e_account_get_string(emae->account, urlid); + + if (uri && uri[0]) + url = camel_url_new(uri, NULL); + + if (url == NULL) { + url = camel_url_new("dummy:", NULL); + camel_url_set_protocol(url, NULL); + } + + return url; +} + +/* ********************************************************************** */ +static void +emae_license_state(GtkToggleButton *button, GtkDialog *dialog) +{ + gtk_dialog_set_response_sensitive(dialog, GTK_RESPONSE_ACCEPT, + gtk_toggle_button_get_active(button)); +} + +static gboolean +emae_load_text(GtkTextView *view, const char *filename) +{ + FILE *fd; + char filebuf[1024]; + GtkTextIter iter; + GtkTextBuffer *buffer; + int count; + + g_return_val_if_fail (filename != NULL , FALSE); + + fd = fopen (filename, "r"); + if (fd) { + buffer = gtk_text_buffer_new (NULL); + gtk_text_buffer_get_start_iter (buffer, &iter); + while (!feof (fd) && !ferror (fd)) { + count = fread (filebuf, 1, sizeof (filebuf), fd); + gtk_text_buffer_insert (buffer, &iter, filebuf, count); + } + + gtk_text_view_set_buffer(GTK_TEXT_VIEW (view), GTK_TEXT_BUFFER(buffer)); + fclose (fd); + } + + return fd != NULL; +} + +static gboolean +emae_display_license(EMAccountEditor *emae, CamelProvider *prov) +{ + GladeXML *xml; + GtkWidget *w, *dialog; + char *tmp; + GtkResponseType response = GTK_RESPONSE_NONE; + + xml = glade_xml_new (EVOLUTION_GLADEDIR "/mail-dialogs.glade", "license_dialog", NULL); + dialog = glade_xml_get_widget(xml, "license_dialog"); + gtk_dialog_set_response_sensitive((GtkDialog *)dialog, GTK_RESPONSE_ACCEPT, FALSE); + tmp = g_strdup_printf(_("%s License Agreement"), prov->license); + gtk_window_set_title((GtkWindow *)dialog, tmp); + g_free(tmp); + + g_signal_connect(glade_xml_get_widget(xml, "license_checkbutton"), + "toggled", G_CALLBACK(emae_license_state), dialog); + + tmp = g_strdup_printf(_("\nPlease read carefully the license agreement\n" + "for %s displayed below\n" + "and tick the check box for accepting it\n"), prov->license); + gtk_label_set_text((GtkLabel *)glade_xml_get_widget(xml, "license_top_label"), tmp); + g_free(tmp); + + w = glade_xml_get_widget(xml, "license_textview"); + if (emae_load_text((GtkTextView *)w, prov->license_file)) { + gtk_text_view_set_editable((GtkTextView *)w, FALSE); + response = gtk_dialog_run((GtkDialog *)dialog); + } else { + e_error_run((GtkWindow *)gtk_widget_get_toplevel(emae->editor), + "mail:no-load-license", prov->license_file, NULL); + } + + gtk_widget_destroy(dialog); + g_object_unref(xml); + + return (response == GTK_RESPONSE_ACCEPT); +} + +static gboolean +emae_check_license(EMAccountEditor *emae, CamelProvider *prov) +{ + gboolean accepted = TRUE; + + if (prov->flags & CAMEL_PROVIDER_HAS_LICENSE) { + GConfClient *gconf = mail_config_get_gconf_client(); + GSList *providers_list, *l; + + providers_list = gconf_client_get_list (gconf, "/apps/evolution/mail/licenses", GCONF_VALUE_STRING, NULL); + + for (l = providers_list, accepted = FALSE; l && !accepted; l = g_slist_next(l)) + accepted = (strcmp((char *)l->data, prov->protocol) == 0); + + if (!accepted + && (accepted = emae_display_license(emae, prov)) == TRUE) { + providers_list = g_slist_append(providers_list, g_strdup(prov->protocol)); + gconf_client_set_list(gconf, + "/apps/evolution/mail/licenses", + GCONF_VALUE_STRING, + providers_list, NULL); + } + + g_slist_foreach(providers_list, (GFunc)g_free, NULL); + g_slist_free(providers_list); + } + + return accepted; +} + +static void +default_folders_clicked (GtkButton *button, gpointer user_data) +{ + EMAccountEditor *emae = user_data; + const char *uri; + + uri = mail_component_get_folder_uri(NULL, MAIL_COMPONENT_FOLDER_DRAFTS); + em_folder_selection_button_set_selection((EMFolderSelectionButton *)emae->priv->drafts_folder_button, uri); + + uri = mail_component_get_folder_uri(NULL, MAIL_COMPONENT_FOLDER_SENT); + em_folder_selection_button_set_selection((EMFolderSelectionButton *)emae->priv->sent_folder_button, uri); +} + +/* custom widget factories */ +GtkWidget *em_account_editor_folder_selector_button_new (char *widget_name, char *string1, char *string2, int int1, int int2); + +GtkWidget * +em_account_editor_folder_selector_button_new (char *widget_name, char *string1, char *string2, int int1, int int2) +{ + return (GtkWidget *)em_folder_selection_button_new(_("Select Folder"), NULL); +} + +GtkWidget *em_account_editor_dropdown_new(char *widget_name, char *string1, char *string2, int int1, int int2); + +GtkWidget * +em_account_editor_dropdown_new(char *widget_name, char *string1, char *string2, int int1, int int2) +{ + return (GtkWidget *)gtk_combo_box_new(); +} + +GtkWidget *em_account_editor_ssl_selector_new(char *widget_name, char *string1, char *string2, int int1, int int2); + +GtkWidget * +em_account_editor_ssl_selector_new(char *widget_name, char *string1, char *string2, int int1, int int2) +{ + GtkComboBox *dropdown = (GtkComboBox *)gtk_combo_box_new(); + GtkCellRenderer *cell = gtk_cell_renderer_text_new(); + GtkListStore *store; + int i; + GtkTreeIter iter; + + gtk_widget_show((GtkWidget *)dropdown); + + store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER); + + for (i=0;i<num_ssl_options;i++) { + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, _(ssl_options[i].label), 1, ssl_options[i].value, -1); + } + + gtk_cell_layout_pack_start((GtkCellLayout *)dropdown, cell, TRUE); + gtk_cell_layout_set_attributes((GtkCellLayout *)dropdown, cell, "text", 0, NULL); + + gtk_combo_box_set_model(dropdown, (GtkTreeModel *)store); + + return (GtkWidget *)dropdown; +} + +/* The camel provider auto-detect interface should be deprecated. + But it still needs to be replaced with something of similar functionality. + Just using the normal econfig plugin mechanism should be adequate. */ +static void +emae_auto_detect_free (gpointer key, gpointer value, gpointer user_data) +{ + g_free (key); + g_free (value); +} + +static void +emae_auto_detect(EMAccountEditor *emae) +{ + EMAccountEditorPrivate *gui = emae->priv; + EMAccountEditorService *service = &gui->source; + GHashTable *auto_detected; + GSList *l; + CamelProviderConfEntry *entries; + char *value; + int i; + CamelURL *url; + + if (service->provider == NULL + || (entries = service->provider->extra_conf) == NULL) + return; + + printf("Running auto-detect\n"); + + url = emae_account_url(emae, E_ACCOUNT_SOURCE_URL); + camel_provider_auto_detect(service->provider, url, &auto_detected, NULL); + camel_url_free(url); + if (auto_detected == NULL) { + printf(" no values detected\n"); + return; + } + + for (i = 0; entries[i].type != CAMEL_PROVIDER_CONF_END; i++) { + struct _receive_options_item *item; + GtkWidget *w; + + if (entries[i].name == NULL + || (value = g_hash_table_lookup (auto_detected, entries[i].name)) == NULL) + continue; + + /* only 2 providers use this, and they only do it for 3 entries only */ + g_assert(entries[i].type == CAMEL_PROVIDER_CONF_ENTRY); + + w = NULL; + for (l = emae->priv->extra_items;l;l=g_slist_next(l)) { + item = l->data; + if (item->extra_table && (w = g_hash_table_lookup(item->extra_table, entries[i].name))) + break; + } + + gtk_entry_set_text((GtkEntry *)w, value?value:""); + } + + g_hash_table_foreach(auto_detected, emae_auto_detect_free, NULL); + g_hash_table_destroy(auto_detected); +} + +static gint +provider_compare (const CamelProvider *p1, const CamelProvider *p2) +{ + /* sort providers based on "location" (ie. local or remote) */ + if (p1->flags & CAMEL_PROVIDER_IS_REMOTE) { + if (p2->flags & CAMEL_PROVIDER_IS_REMOTE) + return 0; + return -1; + } else { + if (p2->flags & CAMEL_PROVIDER_IS_REMOTE) + return 1; + return 0; + } +} + +static void +emae_signature_added(ESignatureList *signatures, ESignature *sig, EMAccountEditor *emae) +{ + GtkTreeModel *model; + GtkTreeIter iter; + + model = gtk_combo_box_get_model(emae->priv->signatures_dropdown); + + gtk_list_store_append((GtkListStore *)model, &iter); + gtk_list_store_set((GtkListStore *)model, &iter, 0, sig->autogen?_("Autogenerated"):sig->name, 1, sig->uid, -1); + + gtk_combo_box_set_active(emae->priv->signatures_dropdown, gtk_tree_model_iter_n_children(model, NULL)-1); +} + +static int +emae_signature_get_iter(EMAccountEditor *emae, ESignature *sig, GtkTreeModel **modelp, GtkTreeIter *iter) +{ + GtkTreeModel *model; + int found = 0; + + model = gtk_combo_box_get_model(emae->priv->signatures_dropdown); + *modelp = model; + if (!gtk_tree_model_get_iter_first(model, iter)) + return FALSE; + + do { + char *uid; + + gtk_tree_model_get(model, iter, 1, &uid, -1); + if (uid && !strcmp(uid, sig->uid)) + found = TRUE; + g_free(uid); + } while (!found && gtk_tree_model_iter_next(model, iter)); + + return found; +} + +static void +emae_signature_removed(ESignatureList *signatures, ESignature *sig, EMAccountEditor *emae) +{ + GtkTreeIter iter; + GtkTreeModel *model; + + if (emae_signature_get_iter(emae, sig, &model, &iter)) + gtk_list_store_remove((GtkListStore *)model, &iter); +} + +static void +emae_signature_changed(ESignatureList *signatures, ESignature *sig, EMAccountEditor *emae) +{ + GtkTreeIter iter; + GtkTreeModel *model; + + if (emae_signature_get_iter(emae, sig, &model, &iter)) + gtk_list_store_set((GtkListStore *)model, &iter, 0, sig->autogen?_("Autogenerated"):sig->name, -1); +} + +static void +emae_signaturetype_changed(GtkComboBox *dropdown, EMAccountEditor *emae) +{ + int id = gtk_combo_box_get_active(dropdown); + GtkTreeModel *model; + GtkTreeIter iter; + char *uid = NULL; + + if (id != -1) { + model = gtk_combo_box_get_model(dropdown); + if (gtk_tree_model_iter_nth_child(model, &iter, NULL, id)) + gtk_tree_model_get(model, &iter, 1, &uid, -1); + } + + printf("signaturetype changed: %d uid=%s\n", id, uid?uid:""); + + e_account_set_string(emae->account, E_ACCOUNT_ID_SIGNATURE, uid); + g_free(uid); +} + +static void +emae_signature_new(GtkWidget *w, EMAccountEditor *emae) +{ + /* TODO: why is this in composer prefs? apart from it being somewhere to put it? */ + em_composer_prefs_new_signature((GtkWindow *)gtk_widget_get_toplevel(w), + gconf_client_get_bool(mail_config_get_gconf_client(), + "/apps/evolution/mail/composer/send_html", NULL)); +} + +static GtkWidget * +emae_setup_signatures(EMAccountEditor *emae) +{ + EMAccountEditorPrivate *p = emae->priv; + GtkComboBox *dropdown = (GtkComboBox *)glade_xml_get_widget(p->xml, "signature_dropdown"); + GtkCellRenderer *cell = gtk_cell_renderer_text_new(); + GtkListStore *store; + int i, active=0; + GtkTreeIter iter; + ESignatureList *signatures; + EIterator *it; + const char *current = e_account_get_string(emae->account, E_ACCOUNT_ID_SIGNATURE); + GtkWidget *button; + + emae->priv->signatures_dropdown = dropdown; + gtk_widget_show((GtkWidget *)dropdown); + + store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); + + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, _("None"), 1, NULL, -1); + + signatures = mail_config_get_signatures (); + + p->sig_added_id = g_signal_connect(signatures, "signature-added", G_CALLBACK(emae_signature_added), emae); + p->sig_removed_id = g_signal_connect(signatures, "signature-removed", G_CALLBACK(emae_signature_removed), emae); + p->sig_changed_id = g_signal_connect(signatures, "signature-changed", G_CALLBACK(emae_signature_changed), emae); + + /* we need to count the 'none' entry before using the index */ + i = 1; + it = e_list_get_iterator ((EList *) signatures); + while (e_iterator_is_valid (it)) { + ESignature *sig = (ESignature *)e_iterator_get(it); + + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, sig->autogen?_("Autogenerated"):sig->name, 1, sig->uid, -1); + + printf("check sig '%s' is ours '%s' = %s\n", sig->uid, current, (current && !strcmp(current, sig->uid))?"yep":"no"); + if (current && !strcmp(current, sig->uid)) + active = i; + + e_iterator_next(it); + i++; + } + g_object_unref (it); + + gtk_cell_layout_pack_start((GtkCellLayout *)dropdown, cell, TRUE); + gtk_cell_layout_set_attributes((GtkCellLayout *)dropdown, cell, "text", 0, NULL); + + gtk_combo_box_set_model(dropdown, (GtkTreeModel *)store); + gtk_combo_box_set_active(dropdown, active); + + g_signal_connect(dropdown, "changed", G_CALLBACK(emae_signaturetype_changed), emae); + gtk_widget_set_sensitive((GtkWidget *)dropdown, e_account_writable(emae->account, E_ACCOUNT_ID_SIGNATURE)); + + button = glade_xml_get_widget(p->xml, "sigAddNew"); + g_signal_connect(button, "clicked", G_CALLBACK(emae_signature_new), emae); + gtk_widget_set_sensitive(button, + gconf_client_key_is_writable(mail_config_get_gconf_client(), + "/apps/evolution/mail/signatures", NULL)); + + return (GtkWidget *)dropdown; +} + +static void +emae_account_entry_changed(GtkEntry *entry, EMAccountEditor *emae) +{ + int item = GPOINTER_TO_INT(g_object_get_data((GObject *)entry, "account-item")); + + e_account_set_string(emae->account, item, gtk_entry_get_text(entry)); +} + +static GtkEntry * +emae_account_entry(EMAccountEditor *emae, const char *name, int item) +{ + GtkEntry *entry; + const char *text; + + entry = (GtkEntry *)glade_xml_get_widget(emae->priv->xml, name); + text = e_account_get_string(emae->account, item); + if (text) + gtk_entry_set_text(entry, text); + g_object_set_data((GObject *)entry, "account-item", GINT_TO_POINTER(item)); + g_signal_connect(entry, "changed", G_CALLBACK(emae_account_entry_changed), emae); + gtk_widget_set_sensitive((GtkWidget *)entry, e_account_writable(emae->account, item)); + + return entry; +} + +static void +emae_account_toggle_changed(GtkToggleButton *toggle, EMAccountEditor *emae) +{ + int item = GPOINTER_TO_INT(g_object_get_data((GObject *)toggle, "account-item")); + + e_account_set_bool(emae->account, item, gtk_toggle_button_get_active(toggle)); +} + +static void +emae_account_toggle_widget(EMAccountEditor *emae, GtkToggleButton *toggle, int item) +{ + gtk_toggle_button_set_active(toggle, e_account_get_bool(emae->account, item)); + g_object_set_data((GObject *)toggle, "account-item", GINT_TO_POINTER(item)); + g_signal_connect(toggle, "toggled", G_CALLBACK(emae_account_toggle_changed), emae); + gtk_widget_set_sensitive((GtkWidget *)toggle, e_account_writable(emae->account, item)); +} + +static GtkToggleButton * +emae_account_toggle(EMAccountEditor *emae, const char *name, int item) +{ + GtkToggleButton *toggle; + + toggle = (GtkToggleButton *)glade_xml_get_widget(emae->priv->xml, name); + emae_account_toggle_widget(emae, toggle, item); + + return toggle; +} + +static void +emae_account_spinint_changed(GtkSpinButton *spin, EMAccountEditor *emae) +{ + int item = GPOINTER_TO_INT(g_object_get_data((GObject *)spin, "account-item")); + + e_account_set_int(emae->account, item, gtk_spin_button_get_value(spin)); +} + +static void +emae_account_spinint_widget(EMAccountEditor *emae, GtkSpinButton *spin, int item) +{ + gtk_spin_button_set_value(spin, e_account_get_int(emae->account, item)); + g_object_set_data((GObject *)spin, "account-item", GINT_TO_POINTER(item)); + g_signal_connect(spin, "value_changed", G_CALLBACK(emae_account_spinint_changed), emae); + gtk_widget_set_sensitive((GtkWidget *)spin, e_account_writable(emae->account, item)); +} + +#if 0 +static GtkSpinButton * +emae_account_spinint(EMAccountEditor *emae, const char *name, int item) +{ + GtkSpinButton *spin; + + spin = (GtkSpinButton *)glade_xml_get_widget(emae->priv->xml, name); + emae_account_spinint_widget(emae, spin, item); + + return spin; +} +#endif + +static void +emae_account_folder_changed(EMFolderSelectionButton *folder, EMAccountEditor *emae) +{ + int item = GPOINTER_TO_INT(g_object_get_data((GObject *)folder, "account-item")); + + e_account_set_string(emae->account, item, em_folder_selection_button_get_selection(folder)); +} + +static EMFolderSelectionButton * +emae_account_folder(EMAccountEditor *emae, const char *name, int item, int deffolder) +{ + EMFolderSelectionButton *folder; + const char *uri; + + folder = (EMFolderSelectionButton *)glade_xml_get_widget(emae->priv->xml, name); + uri = e_account_get_string(emae->account, item); + if (uri) { + char *tmp = em_uri_to_camel(uri); + + em_folder_selection_button_set_selection(folder, tmp); + g_free(tmp); + } else { + em_folder_selection_button_set_selection(folder, mail_component_get_folder_uri(NULL, deffolder)); + } + + g_object_set_data((GObject *)folder, "account-item", GINT_TO_POINTER(item)); + g_object_set_data((GObject *)folder, "folder-default", GINT_TO_POINTER(deffolder)); + g_signal_connect(folder, "selected", G_CALLBACK(emae_account_folder_changed), emae); + gtk_widget_show((GtkWidget *)folder); + + gtk_widget_set_sensitive((GtkWidget *)folder, e_account_writable(emae->account, item)); + + return folder; +} + +#if defined (HAVE_NSS) +static void +smime_changed(EMAccountEditor *emae) +{ + EMAccountEditorPrivate *gui = emae->priv; + int act; + const char *tmp; + + tmp = gtk_entry_get_text(gui->smime_sign_key); + act = tmp && tmp[0]; + gtk_widget_set_sensitive((GtkWidget *)gui->smime_sign_key_clear, act); + gtk_widget_set_sensitive((GtkWidget *)gui->smime_sign_default, act); + if (!act) + gtk_toggle_button_set_active(gui->smime_sign_default, FALSE); + + tmp = gtk_entry_get_text(gui->smime_encrypt_key); + act = tmp && tmp[0]; + gtk_widget_set_sensitive((GtkWidget *)gui->smime_encrypt_key_clear, act); + gtk_widget_set_sensitive((GtkWidget *)gui->smime_encrypt_default, act); + gtk_widget_set_sensitive((GtkWidget *)gui->smime_encrypt_to_self, act); + if (!act) { + gtk_toggle_button_set_active(gui->smime_encrypt_default, FALSE); + gtk_toggle_button_set_active(gui->smime_encrypt_to_self, FALSE); + } +} + +static void +smime_sign_key_selected(GtkWidget *dialog, const char *key, EMAccountEditor *emae) +{ + EMAccountEditorPrivate *gui = emae->priv; + + if (key != NULL) { + gtk_entry_set_text(gui->smime_sign_key, key); + smime_changed(emae); + } + + gtk_widget_destroy(dialog); +} + +static void +smime_sign_key_select(GtkWidget *button, EMAccountEditor *emae) +{ + EMAccountEditorPrivate *gui = emae->priv; + GtkWidget *w; + + w = e_cert_selector_new(E_CERT_SELECTOR_SIGNER, gtk_entry_get_text(gui->smime_sign_key)); + gtk_window_set_modal((GtkWindow *)w, TRUE); + gtk_window_set_transient_for((GtkWindow *)w, (GtkWindow *)gtk_widget_get_toplevel((GtkWidget *)emae)); + g_signal_connect(w, "selected", G_CALLBACK(smime_sign_key_selected), emae); + gtk_widget_show(w); +} + +static void +smime_sign_key_clear(GtkWidget *w, EMAccountEditor *emae) +{ + EMAccountEditorPrivate *gui = emae->priv; + + gtk_entry_set_text(gui->smime_sign_key, ""); + smime_changed(emae); +} + +static void +smime_encrypt_key_selected(GtkWidget *dialog, const char *key, EMAccountEditor *emae) +{ + EMAccountEditorPrivate *gui = emae->priv; + + if (key != NULL) { + gtk_entry_set_text(gui->smime_encrypt_key, key); + smime_changed(emae); + } + + gtk_widget_destroy(dialog); +} + +static void +smime_encrypt_key_select(GtkWidget *button, EMAccountEditor *emae) +{ + EMAccountEditorPrivate *gui = emae->priv; + GtkWidget *w; + + w = e_cert_selector_new(E_CERT_SELECTOR_SIGNER, gtk_entry_get_text(gui->smime_encrypt_key)); + gtk_window_set_modal((GtkWindow *)w, TRUE); + gtk_window_set_transient_for((GtkWindow *)w, (GtkWindow *)gtk_widget_get_toplevel((GtkWidget *)emae)); + g_signal_connect(w, "selected", G_CALLBACK(smime_encrypt_key_selected), emae); + gtk_widget_show(w); +} + +static void +smime_encrypt_key_clear(GtkWidget *w, EMAccountEditor *emae) +{ + EMAccountEditorPrivate *gui = emae->priv; + + gtk_entry_set_text(gui->smime_encrypt_key, ""); + smime_changed(emae); +} +#endif + +static void +emae_url_set_hostport(CamelURL *url, const char *txt) +{ + const char *port; + char *host; + + if (txt && (port = strchr(txt, ':'))) { + camel_url_set_port(url, atoi(port+1)); + host = g_alloca(port-txt+1); + memcpy(host, txt, port-txt); + host[port-txt] = 0; + } else { + host = (char *)txt; + } + camel_url_set_host(url, host); +} + +/* This is used to map a funciton which will set on the url a string value. + We need our own function for host:port decoding, as above */ +struct _provider_host_info { + guint32 flag; + void (*setval)(CamelURL *, const char *); + const char *widgets[3]; +}; + +static struct _provider_host_info emae_source_host_info[] = { + { CAMEL_URL_PART_HOST, emae_url_set_hostport, { "source_host", "source_host_label" } }, + { CAMEL_URL_PART_USER, camel_url_set_user, { "source_user", "source_user_label", } }, + { CAMEL_URL_PART_PATH, camel_url_set_path, { "source_path", "source_path_label", "source_path_entry" } }, + { CAMEL_URL_PART_AUTH, NULL, { NULL, "source_auth_frame" } }, + { 0 }, +}; + +static struct _provider_host_info emae_transport_host_info[] = { + { CAMEL_URL_PART_HOST, emae_url_set_hostport, { "transport_host", "transport_host_label" } }, + { CAMEL_URL_PART_USER, camel_url_set_user, { "transport_user", "transport_user_label", } }, + { CAMEL_URL_PART_AUTH, NULL, { NULL, "transport_auth_frame" } }, + { 0 }, +}; + +/* This is used to map each of the two services in a typical account to the widgets that represent each service. + i.e. the receiving (source) service, and the sending (transport) service. + It is used throughout the following code to drive each page */ +static struct _service_info { + int account_uri_key; + int save_passwd_key; + + char *frame; + char *type_dropdown; + + char *container; + char *description; + char *hostname; + char *username; + char *path; + + char *security_frame; + char *ssl_hbox; + char *use_ssl; + char *ssl_disabled; + + char *needs_auth; + char *auth_frame; + + char *authtype; + char *authtype_check; + + char *remember_password; + + struct _provider_host_info *host_info; +} emae_service_info[CAMEL_NUM_PROVIDER_TYPES] = { + { E_ACCOUNT_SOURCE_URL, E_ACCOUNT_SOURCE_SAVE_PASSWD, + "source_frame", "source_type_dropdown", + "source_vbox", "source_description", "source_host", "source_user", "source_path", + "source_security_frame", "source_ssl_hbox", "source_use_ssl", "source_ssl_disabled", + NULL, "source_auth_frame", + "source_auth_dropdown", "source_check_supported", + "source_remember_password", + emae_source_host_info, + }, + { E_ACCOUNT_TRANSPORT_URL, E_ACCOUNT_TRANSPORT_SAVE_PASSWD, + "transport_frame", "transport_type_dropdown", + "transport_vbox", "transport_description", "transport_host", "transport_user", NULL, + "transport_security_frame", "transport_ssl_hbox", "transport_use_ssl", "transport_ssl_disabled", + "transport_needs_auth", "transport_auth_frame", + "transport_auth_dropdown", "transport_check_supported", + "transport_remember_password", + emae_transport_host_info, + }, +}; + +static void +emae_uri_changed(EMAccountEditorService *service, CamelURL *url) +{ + char *uri; + + uri = camel_url_to_string(url, 0); + printf("uri changed: '%s'\n", uri); + e_account_set_string(service->emae->account, emae_service_info[service->type].account_uri_key, uri); + g_free(uri); +} + +static void +emae_service_url_changed(EMAccountEditorService *service, void (*setval)(CamelURL *, const char *), GtkEntry *entry) +{ + CamelURL *url = emae_account_url(service->emae, emae_service_info[service->type].account_uri_key); + + setval(url, gtk_entry_get_text(entry)); + emae_uri_changed(service, url); + camel_url_free(url); +} + +static void +emae_hostname_changed(GtkEntry *entry, EMAccountEditorService *service) +{ + emae_service_url_changed(service, emae_url_set_hostport, entry); +} + +static void +emae_username_changed(GtkEntry *entry, EMAccountEditorService *service) +{ + emae_service_url_changed(service, camel_url_set_user, entry); +} + +static void +emae_path_changed(GtkEntry *entry, EMAccountEditorService *service) +{ + emae_service_url_changed(service, camel_url_set_path, entry); +} + +static void +emae_needs_auth(GtkToggleButton *toggle, EMAccountEditorService *service) +{ + GtkWidget *w; + int need = gtk_toggle_button_get_active(toggle); + + w = glade_xml_get_widget(service->emae->priv->xml, emae_service_info[service->type].auth_frame); + gtk_widget_set_sensitive(w, need); + /* if need ; service_changed? */ +} + +static int +emae_ssl_update(EMAccountEditorService *service, CamelURL *url) +{ + int id = gtk_combo_box_get_active(service->use_ssl); + GtkTreeModel *model; + GtkTreeIter iter; + char *ssl; + + if (id == -1) + return 0; + + model = gtk_combo_box_get_model(service->use_ssl); + if (gtk_tree_model_iter_nth_child(model, &iter, NULL, id)) { + gtk_tree_model_get(model, &iter, 1, &ssl, -1); + if (!strcmp(ssl, "none")) + ssl = NULL; + camel_url_set_param(url, "use_ssl", ssl); + return 1; + } + + return 0; +} + +static void +emae_ssl_changed(GtkComboBox *dropdown, EMAccountEditorService *service) +{ + CamelURL *url = emae_account_url(service->emae, emae_service_info[service->type].account_uri_key); + + if (emae_ssl_update(service, url)) + emae_uri_changed(service, url); + camel_url_free(url); +} + +static void +emae_service_provider_changed(EMAccountEditorService *service) +{ + int i, j; + void (*show)(GtkWidget *); + CamelURL *url = emae_account_url(service->emae, emae_service_info[service->type].account_uri_key); + + if (service->provider) { + int enable; + GtkWidget *dwidget = NULL; + + camel_url_set_protocol(url, service->provider->protocol); + gtk_label_set_text(service->description, service->provider->description); + if (!emae_check_license(service->emae, service->provider)) + gtk_widget_hide(service->frame); + else + gtk_widget_show(service->frame); + + enable = e_account_writable_option(service->emae->account, service->provider->protocol, "auth"); + gtk_widget_set_sensitive((GtkWidget *)service->authtype, enable); + gtk_widget_set_sensitive((GtkWidget *)service->check_supported, enable); + + enable = e_account_writable_option(service->emae->account, service->provider->protocol, "use_ssl"); + gtk_widget_set_sensitive((GtkWidget *)service->use_ssl, enable); + + enable = e_account_writable(service->emae->account, emae_service_info[service->type].save_passwd_key); + gtk_widget_set_sensitive((GtkWidget *)service->remember, enable); + + for (i=0;emae_service_info[service->type].host_info[i].flag;i++) { + const char *name; + GtkWidget *w; + struct _provider_host_info *info = &emae_service_info[service->type].host_info[i]; + + enable = CAMEL_PROVIDER_ALLOWS(service->provider, info->flag); + show = enable?gtk_widget_show:gtk_widget_hide; + + for (j=0; j < sizeof(info->widgets)/sizeof(info->widgets[0]); j++) { + name = info->widgets[j]; + if (name) { + w = glade_xml_get_widget(service->emae->priv->xml, name); + show(w); + if (j == 0) { + if (dwidget == NULL && enable) + dwidget = w; + + if (info->setval) + info->setval(url, enable?gtk_entry_get_text((GtkEntry *)w):NULL); + } + } + } + } + + if (dwidget) + gtk_widget_grab_focus(dwidget); + + if (CAMEL_PROVIDER_ALLOWS(service->provider, CAMEL_URL_PART_AUTH)) { + camel_url_set_authmech(url, NULL); + emae_setup_authtype(service->emae, service); + if (service->needs_auth && !CAMEL_PROVIDER_NEEDS(service->provider, CAMEL_URL_PART_AUTH)) + gtk_widget_show((GtkWidget *)service->needs_auth); + } else { + if (service->needs_auth) + gtk_widget_hide((GtkWidget *)service->needs_auth); + } +#ifdef HAVE_SSL + gtk_widget_hide(service->no_ssl); + if (service->provider->flags & CAMEL_PROVIDER_SUPPORTS_SSL) { + emae_ssl_update(service, url); + show = gtk_widget_show; + } else { + camel_url_set_param(url, "use_ssl", NULL); + show = gtk_widget_hide; + } + show(service->ssl_frame); + show(service->ssl_hbox); +#else + gtk_widget_hide(service->ssl_hbox); + gtk_widget_show(service->no_ssl); + camel_url_set_param(url, "use_ssl", NULL); +#endif + } else { + camel_url_set_protocol(url, NULL); + gtk_label_set_text(service->description, ""); + gtk_widget_hide(service->frame); + gtk_widget_hide(service->auth_frame); + gtk_widget_hide(service->ssl_frame); + } + + /* FIXME: linked services? */ + /* FIXME: permissions setup */ + + emae_uri_changed(service, url); + camel_url_free(url); +} + +static void +emae_provider_changed(GtkComboBox *dropdown, EMAccountEditorService *service) +{ + int id = gtk_combo_box_get_active(dropdown); + GtkTreeModel *model; + GtkTreeIter iter; + + if (id == -1) + return; + + model = gtk_combo_box_get_model(dropdown); + if (!gtk_tree_model_iter_nth_child(model, &iter, NULL, id)) + return; + + gtk_tree_model_get(model, &iter, 1, &service->provider, -1); + + g_list_free(service->authtypes); + service->authtypes = NULL; + + emae_service_provider_changed(service); + + e_config_target_changed((EConfig *)service->emae->priv->config, E_CONFIG_TARGET_CHANGED_REBUILD); +} + +static GtkWidget * +emae_setup_providers(EMAccountEditor *emae, EMAccountEditorService *service) +{ + EMAccountEditorPrivate *gui = emae->priv; + EAccount *account = emae->account; + GtkListStore *store; + GtkTreeIter iter; + GList *l; + GtkCellRenderer *cell = gtk_cell_renderer_text_new(); + GtkComboBox *dropdown; + int active = 0, i; + struct _service_info *info = &emae_service_info[service->type]; + const char *uri = e_account_get_string(account, info->account_uri_key); + char *current = NULL; + + dropdown = (GtkComboBox *)glade_xml_get_widget(gui->xml, info->type_dropdown); + gtk_widget_show((GtkWidget *)dropdown); + + if (uri) { + const char *colon = strchr(uri, ':'); + int len; + + if (colon) { + len = colon-uri; + current = g_alloca(len+1); + memcpy(current, uri, len); + current[len] = 0; + } + } + + store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_POINTER); + + i = 0; + + /* We just special case each type here, its just easier */ + if (service->type == CAMEL_PROVIDER_STORE) { + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, _("None"), 1, NULL, -1); + i++; + } + + for (l=gui->providers; l; l=l->next) { + CamelProvider *provider = l->data; + + if (!((strcmp(provider->domain, "mail") == 0 + || strcmp (provider->domain, "news") == 0) + && provider->object_types[service->type] + && (service->type != CAMEL_PROVIDER_STORE || (provider->flags & CAMEL_PROVIDER_IS_SOURCE) != 0))) + continue; + + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, provider->name, 1, provider, -1); + + /* FIXME: GtkCombo doesn't support sensitiviy, we can hopefully kill this crap anyway */ +#if 0 + if (type == CAMEL_PROVIDER_TRANSPORT + && CAMEL_PROVIDER_IS_STORE_AND_TRANSPORT (provider)) + gtk_widget_set_sensitive (item, FALSE); +#endif + /* find the displayed and set default */ + if (i == 0 || (current && strcmp(provider->protocol, current) == 0)) { + service->provider = provider; + active = i; + + /* we need to set this value on the uri too */ + if (current == NULL) { + CamelURL *url = emae_account_url(emae, info->account_uri_key); + + camel_url_set_protocol(url, provider->protocol); + emae_uri_changed(service, url); + camel_url_free(url); + } + } + i++; + } + + gtk_combo_box_set_model(dropdown, (GtkTreeModel *)store); + gtk_cell_layout_pack_start((GtkCellLayout *)dropdown, cell, TRUE); + gtk_cell_layout_set_attributes((GtkCellLayout *)dropdown, cell, "text", 0, NULL); + + gtk_combo_box_set_active(dropdown, -1); /* needed for gtkcombo bug(?) */ + gtk_combo_box_set_active(dropdown, active); + g_signal_connect(dropdown, "changed", G_CALLBACK(emae_provider_changed), service); + + return (GtkWidget *)dropdown; +} + +static void +emae_authtype_changed(GtkComboBox *dropdown, EMAccountEditorService *service) +{ + int id = gtk_combo_box_get_active(dropdown); + GtkTreeModel *model; + GtkTreeIter iter; + CamelServiceAuthType *authtype; + CamelURL *url; + + if (id == -1) + return; + + url = emae_account_url(service->emae, emae_service_info[service->type].account_uri_key); + model = gtk_combo_box_get_model(dropdown); + if (gtk_tree_model_iter_nth_child(model, &iter, NULL, id)) { + gtk_tree_model_get(model, &iter, 1, &authtype, -1); + if (authtype) + camel_url_set_authmech(url, authtype->authproto); + else + camel_url_set_authmech(url, NULL); + emae_uri_changed(service, url); + } + camel_url_free(url); + + gtk_widget_set_sensitive((GtkWidget *)service->remember, authtype?authtype->need_password:FALSE); +} + +static void emae_check_authtype(GtkWidget *w, EMAccountEditorService *service); + +static GtkWidget * +emae_setup_authtype(EMAccountEditor *emae, EMAccountEditorService *service) +{ + EMAccountEditorPrivate *gui = emae->priv; + EAccount *account = emae->account; + GtkListStore *store; + GtkTreeIter iter; + GtkComboBox *dropdown; + GtkWidget *w; + int active = 0; + int i; + struct _service_info *info = &emae_service_info[service->type]; + const char *uri = e_account_get_string(account, info->account_uri_key); + GList *l, *ll; + CamelURL *url = NULL; + + dropdown = (GtkComboBox *)glade_xml_get_widget(gui->xml, info->authtype); + gtk_widget_show((GtkWidget *)dropdown); + + store = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_POINTER, G_TYPE_BOOLEAN); + + if (uri) + url = camel_url_new(uri, NULL); + + if (service->provider) { + for (i=0, l=service->provider->authtypes; l; l=l->next, i++) { + CamelServiceAuthType *authtype = l->data; + int avail; + + /* if we have some already shown */ + if (service->authtypes) { + for (ll = service->authtypes;ll;ll = g_list_next(ll)) + if (!strcmp(authtype->authproto, ((CamelServiceAuthType *)ll->data)->authproto)) + break; + avail = ll != NULL; + } else { + avail = TRUE; + } + + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, 0, authtype->name, 1, authtype, 2, !avail, -1); + + if (url && url->authmech && !strcmp(url->authmech, authtype->authproto)) + active = i; + } + } + + gtk_combo_box_set_model(dropdown, (GtkTreeModel *)store); + gtk_combo_box_set_active(dropdown, -1); + + if (service->auth_changed_id == 0) { + GtkCellRenderer *cell = gtk_cell_renderer_text_new(); + + gtk_cell_layout_pack_start((GtkCellLayout *)dropdown, cell, TRUE); + gtk_cell_layout_set_attributes((GtkCellLayout *)dropdown, cell, "text", 0, "strikethrough", 2, NULL); + + service->auth_changed_id = g_signal_connect(dropdown, "changed", G_CALLBACK(emae_authtype_changed), service); + w = glade_xml_get_widget(gui->xml, info->authtype_check); + g_signal_connect(w, "clicked", G_CALLBACK(emae_check_authtype), service); + } + + gtk_combo_box_set_active(dropdown, active); + + if (url) + camel_url_free(url); + + return (GtkWidget *)dropdown; +} + +static void emae_check_authtype(GtkWidget *w, EMAccountEditorService *service) +{ + EMAccountEditor *emae = service->emae; + const char *uri; + + if (service->authtypes) { + g_list_free(service->authtypes); + service->authtypes = NULL; + } + + uri = e_account_get_string(emae->account, emae_service_info[service->type].account_uri_key); + if (mail_config_check_service(uri, service->type, &service->authtypes, (GtkWindow *)gtk_widget_get_toplevel((GtkWidget *)emae->editor))) + emae_setup_authtype(emae, service); +} + +static void +emae_setup_service(EMAccountEditor *emae, EMAccountEditorService *service) +{ + EMAccountEditorPrivate *gui = emae->priv; + struct _service_info *info = &emae_service_info[service->type]; + CamelURL *url = emae_account_url(emae, info->account_uri_key); + const char *uri = e_account_get_string(emae->account, info->account_uri_key); + const char *tmp; + int i; + + service->provider = uri?camel_provider_get(uri, NULL):NULL; + + service->frame = glade_xml_get_widget(gui->xml, info->frame); + service->container = glade_xml_get_widget(gui->xml, info->container); + service->description = GTK_LABEL (glade_xml_get_widget (gui->xml, info->description)); + service->hostname = GTK_ENTRY (glade_xml_get_widget (gui->xml, info->hostname)); + service->username = GTK_ENTRY (glade_xml_get_widget (gui->xml, info->username)); + if (info->path) + service->path = GTK_ENTRY (glade_xml_get_widget (gui->xml, info->path)); + + service->ssl_frame = glade_xml_get_widget (gui->xml, info->security_frame); + gtk_widget_hide (service->ssl_frame); + service->ssl_hbox = glade_xml_get_widget (gui->xml, info->ssl_hbox); + service->use_ssl = (GtkComboBox *)glade_xml_get_widget (gui->xml, info->use_ssl); + service->no_ssl = glade_xml_get_widget (gui->xml, info->ssl_disabled); + + /* configure ui for current settings */ + if (url->host) { + if (url->port) { + char *host = g_strdup_printf("%s:%d", url->host, url->port); + + gtk_entry_set_text(service->hostname, host); + g_free(host); + } else + gtk_entry_set_text(service->hostname, url->host); + } + if (url->user) + gtk_entry_set_text(service->username, url->user); + if (service->path && url->path) + gtk_entry_set_text(service->path, url->path); + + tmp = camel_url_get_param(url, "use_ssl"); + if (tmp == NULL) + tmp = "never"; + + for (i=0;i<num_ssl_options;i++) { + if (!strcmp(ssl_options[i].value, tmp)) { + gtk_combo_box_set_active(service->use_ssl, i); + break; + } + } + camel_url_free(url); + + g_signal_connect (service->hostname, "changed", G_CALLBACK (emae_hostname_changed), service); + g_signal_connect (service->username, "changed", G_CALLBACK (emae_username_changed), service); + if (service->path) + g_signal_connect (service->path, "changed", G_CALLBACK (emae_path_changed), service); + + g_signal_connect(service->use_ssl, "changed", G_CALLBACK(emae_ssl_changed), service); + + service->auth_frame = glade_xml_get_widget(gui->xml, info->auth_frame); + service->remember = emae_account_toggle(emae, info->remember_password, info->save_passwd_key); + service->check_supported = (GtkButton *)glade_xml_get_widget(gui->xml, info->authtype_check); + if (info->needs_auth) { + service->needs_auth = (GtkToggleButton *)glade_xml_get_widget (gui->xml, info->needs_auth); + g_signal_connect(service->needs_auth, "toggled", G_CALLBACK(emae_needs_auth), service); + emae_needs_auth(service->needs_auth, service); + } + + emae_setup_providers(emae, service); + service->authtype = (GtkComboBox *)emae_setup_authtype(emae, service); + + if (!e_account_writable (emae->account, info->account_uri_key)) + gtk_widget_set_sensitive(service->container, FALSE); + else + gtk_widget_set_sensitive(service->container, TRUE); + + emae_service_provider_changed(service); +} + +static struct { + char *name; + int item; +} emae_identity_entries[] = { + { "management_name", E_ACCOUNT_NAME }, + { "identity_full_name", E_ACCOUNT_ID_NAME }, + { "identity_address", E_ACCOUNT_ID_ADDRESS }, + { "identity_reply_to", E_ACCOUNT_ID_REPLY_TO }, + { "identity_organization", E_ACCOUNT_ID_ORGANIZATION }, +}; + +static GtkWidget * +emae_identity_page(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data) +{ + EMAccountEditor *emae = data; + EMAccountEditorPrivate *gui = emae->priv; + EAccount *account = emae->account; + int i; + GtkWidget *w; + + if (old) + return old; + + /* Management & Identity fields*/ + for (i=0;i<sizeof(emae_identity_entries)/sizeof(emae_identity_entries[0]);i++) + emae_account_entry(emae, emae_identity_entries[i].name, emae_identity_entries[i].item); + + gui->default_account = GTK_TOGGLE_BUTTON (glade_xml_get_widget (gui->xml, "management_default")); + if (!mail_config_get_default_account () + || (account == mail_config_get_default_account ())) + gtk_toggle_button_set_active (gui->default_account, TRUE); + + if (emae->do_signature) { + emae_setup_signatures(emae); + } else { + /* TODO: this could/should probably be neater */ + gtk_widget_hide(glade_xml_get_widget(gui->xml, "sigLabel")); + gtk_widget_hide(glade_xml_get_widget(gui->xml, "sigOption")); + gtk_widget_hide(glade_xml_get_widget(gui->xml, "sigAddNew")); + } + + w = glade_xml_get_widget(gui->xml, item->label); + if (((EConfig *)gui->config)->type == E_CONFIG_DRUID) { + GtkWidget *page = glade_xml_get_widget(gui->druidxml, "identity_page"); + + /* need to set packing? */ + gtk_widget_reparent(w, ((GnomeDruidPageStandard *)page)->vbox); + + return page; + } + + return w; +} + +static GtkWidget * +emae_receive_page(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data) +{ + EMAccountEditor *emae = data; + EMAccountEditorPrivate *gui = emae->priv; + GtkWidget *w; + + if (old) + return old; + + gui->source.type = CAMEL_PROVIDER_STORE; + emae_setup_service(emae, &gui->source); + + w = glade_xml_get_widget(gui->xml, item->label); + if (((EConfig *)gui->config)->type == E_CONFIG_DRUID) { + GtkWidget *page = glade_xml_get_widget(gui->druidxml, "source_page"); + + /* need to set packing? */ + gtk_widget_reparent(w, ((GnomeDruidPageStandard *)page)->vbox); + + return page; + } + + return w; +} + +static void +emae_option_toggle_changed(GtkToggleButton *toggle, EMAccountEditorService *service) +{ + const char *name = g_object_get_data((GObject *)toggle, "option-name"); + GSList *depl = g_object_get_data((GObject *)toggle, "dependent-list"); + int active = gtk_toggle_button_get_active(toggle); + CamelURL *url = emae_account_url(service->emae, emae_service_info[service->type].account_uri_key); + + for (;depl;depl = g_slist_next(depl)) + gtk_widget_set_sensitive((GtkWidget *)depl->data, active); + + camel_url_set_param(url, name, active?"":NULL); + emae_uri_changed(service, url); + camel_url_free(url); +} + +static GtkWidget * +emae_option_toggle(EMAccountEditorService *service, CamelURL *url, const char *text, const char *name, int def) +{ + GtkWidget *w; + + /* FIXME: how do we get the default value ever? */ + w = g_object_new(gtk_check_button_get_type(), + "label", text, + "active", camel_url_get_param(url, name) != NULL, + NULL); + g_object_set_data((GObject *)w, "option-name", (void *)name); + g_signal_connect(w, "toggled", G_CALLBACK(emae_option_toggle_changed), service); + gtk_widget_show(w); + + printf("adding option toggle '%s'\n", text); + + return w; +} + +static void +emae_option_entry_changed(GtkEntry *entry, EMAccountEditorService *service) +{ + const char *name = g_object_get_data((GObject *)entry, "option-name"); + const char *text = gtk_entry_get_text(entry); + CamelURL *url = emae_account_url(service->emae, emae_service_info[service->type].account_uri_key); + + camel_url_set_param(url, name, text && text[0]?text:NULL); + emae_uri_changed(service, url); + camel_url_free(url); +} + +static GtkWidget * +emae_option_entry(EMAccountEditorService *service, CamelURL *url, const char *name, const char *def) +{ + GtkWidget *w; + const char *val = camel_url_get_param(url, name); + + if (val == NULL) + val = def; + + w = g_object_new(gtk_entry_get_type(), + "text", val, + NULL); + g_object_set_data((GObject *)w, "option-name", (void *)name); + g_signal_connect(w, "changed", G_CALLBACK(emae_option_entry_changed), service); + gtk_widget_show(w); + + return w; +} + +static void +emae_option_checkspin_changed(GtkSpinButton *spin, EMAccountEditorService *service) +{ + const char *name = g_object_get_data((GObject *)spin, "option-name"); + char value[16]; + CamelURL *url = emae_account_url(service->emae, emae_service_info[service->type].account_uri_key); + + sprintf(value, "%d", gtk_spin_button_get_value_as_int(spin)); + camel_url_set_param(url, name, value); + emae_uri_changed(service, url); + camel_url_free(url); +} + +static void +emae_option_checkspin_check_changed(GtkToggleButton *toggle, EMAccountEditorService *service) +{ + const char *name = g_object_get_data((GObject *)toggle, "option-name"); + GtkSpinButton *spin = g_object_get_data((GObject *)toggle, "option-target"); + + if (gtk_toggle_button_get_active(toggle)) { + gtk_widget_set_sensitive((GtkWidget *)spin, TRUE); + emae_option_checkspin_changed(spin, service); + } else { + CamelURL *url = emae_account_url(service->emae, emae_service_info[service->type].account_uri_key); + + camel_url_set_param(url, name, NULL); + gtk_widget_set_sensitive((GtkWidget *)spin, FALSE); + emae_uri_changed(service, url); + camel_url_free(url); + } +} + +/* this is a fugly api */ +static GtkWidget * +emae_option_checkspin(EMAccountEditorService *service, CamelURL *url, const char *name, const char *fmt, const char *info) +{ + GtkWidget *hbox, *check, *spin, *label; + double min, def, max; + char *pre, *post; + const char *val; + char on; + int enable; + + pre = g_alloca(strlen(fmt)+1); + strcpy(pre, fmt); + post = strstr(pre, "%s"); + if (post) { + *post = 0; + post+=2; + } + + if (sscanf(info, "%c:%lf:%lf:%lf", &on, &min, &def, &max) != 4) { + min = 0.0; + def = 0.0; + max = 1.0; + } + + if ((enable = (val = camel_url_get_param(url, name)) != NULL) ) + def = strtod(val, NULL); + else + enable = (on == 'y'); + + hbox = gtk_hbox_new(FALSE, 0); + check = g_object_new(gtk_check_button_get_type(), "label", pre, "active", enable, NULL); + spin = gtk_spin_button_new((GtkAdjustment *)gtk_adjustment_new(def, min, max, 1, 1, 1), 1, 0); + if (post) + label = gtk_label_new(post); + gtk_box_pack_start((GtkBox *)hbox, check, FALSE, TRUE, 0); + gtk_box_pack_start((GtkBox *)hbox, spin, FALSE, TRUE, 0); + if (label) + gtk_box_pack_start((GtkBox *)hbox, label, FALSE, TRUE, 4); + + g_object_set_data((GObject *)spin, "option-name", (void *)name); + g_object_set_data((GObject *)check, "option-name", (void *)name); + g_object_set_data((GObject *)check, "option-target", (void *)spin); + + g_signal_connect(spin, "value_changed", G_CALLBACK(emae_option_checkspin_changed), service); + g_signal_connect(check, "toggled", G_CALLBACK(emae_option_checkspin_check_changed), service); + + gtk_widget_show_all(hbox); + + return hbox; +} + +static GtkWidget * +emae_receive_options_item(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data) +{ + EMAccountEditor *emae = data; + GtkWidget *w, *box; + int row; + + if (emae->priv->source.provider == NULL + || emae->priv->source.provider->extra_conf == NULL) + return NULL; + + if (old) + return old; + + /* We have to add the automatic mail check item with the rest of the receive options */ + row = ((GtkTable *)parent)->nrows; + + box = gtk_hbox_new(FALSE, 4); + w = gtk_check_button_new_with_label(_("Automatically check for _new mail every")); + emae_account_toggle_widget(emae, (GtkToggleButton *)w, E_ACCOUNT_SOURCE_AUTO_CHECK); + gtk_box_pack_start((GtkBox *)box, w, FALSE, FALSE, 0); + + w = gtk_spin_button_new_with_range(1.0, 1440.0, 1.0); + emae_account_spinint_widget(emae, (GtkSpinButton *)w, E_ACCOUNT_SOURCE_AUTO_CHECK_TIME); + gtk_box_pack_start((GtkBox *)box, w, FALSE, TRUE, 0); + + w = gtk_label_new(_("minutes")); + gtk_box_pack_start((GtkBox *)box, w, FALSE, FALSE, 0); + + gtk_widget_show_all(box); + + gtk_table_attach((GtkTable *)parent, box, 0, 2, row, row+1, GTK_EXPAND|GTK_FILL, 0, 0, 0); + + return box; +} + +static GtkWidget * +emae_receive_options_extra_item(EConfig *ec, EConfigItem *eitem, struct _GtkWidget *parent, struct _GtkWidget *old, void *data) +{ + EMAccountEditor *emae = data; + struct _receive_options_item *item = (struct _receive_options_item *)eitem; + GtkWidget *w, *l; + CamelProviderConfEntry *entries; + GtkWidget *depw; + GSList *depl = NULL, *widgets = NULL, *n; + EMAccountEditorService *service = &emae->priv->source; + int row, i; + GHashTable *extra; + CamelURL *url; + + /* Clean up any widgets we had setup before */ + if (item->widgets) { + g_slist_foreach(item->widgets, (GFunc)gtk_widget_destroy, NULL); + g_hash_table_destroy(item->extra_table); + item->widgets = NULL; + item->extra_table = NULL; + } + + if (emae->priv->source.provider == NULL + || emae->priv->source.provider->extra_conf == NULL) + return NULL; + + entries = emae->priv->source.provider->extra_conf; + for (i=0;entries && entries[i].type != CAMEL_PROVIDER_CONF_END;i++) + if (entries[i].type == CAMEL_PROVIDER_CONF_SECTION_START + && entries[i].name + && strcmp(entries[i].name, eitem->user_data) == 0) + goto section; + + return NULL; +section: + printf("Building extra section '%s'\n", eitem->path); + + url = emae_account_url(emae, emae_service_info[service->type].account_uri_key); + item->extra_table = g_hash_table_new(g_str_hash, g_str_equal); + extra = g_hash_table_new(g_str_hash, g_str_equal); + row = ((GtkTable *)parent)->nrows; + + for (;entries[i].type != CAMEL_PROVIDER_CONF_END && entries[i].type != CAMEL_PROVIDER_CONF_SECTION_END;i++) { + if (entries[i].depname) { + depw = g_hash_table_lookup(extra, entries[i].depname); + if (depw) + depl = g_object_steal_data((GObject *)depw, "dependent-list"); + } else + depw = NULL; + + switch (entries[i].type) { + case CAMEL_PROVIDER_CONF_SECTION_START: + case CAMEL_PROVIDER_CONF_SECTION_END: + break; + case CAMEL_PROVIDER_CONF_LABEL: + /* FIXME: This is a hack for exchange connector, labels should be removed from confentry */ + if (!strcmp(entries[i].name, "hostname")) + l = glade_xml_get_widget(emae->priv->xml, "source_host_label"); + else if (!strcmp(entries[i].name, "username")) + l = glade_xml_get_widget(emae->priv->xml,"source_user_label"); + else + l = NULL; + + if (l) { + gtk_label_set_text_with_mnemonic((GtkLabel *)l, entries[i].text); + if (depw) + depl = g_slist_prepend(depl, l); + } + break; + case CAMEL_PROVIDER_CONF_CHECKBOX: + w = emae_option_toggle(service, url, entries[i].text, entries[i].name, atoi(entries[i].value)); + gtk_table_attach((GtkTable *)parent, w, 0, 2, row, row+1, GTK_EXPAND|GTK_FILL, 0, 0, 0); + g_hash_table_insert(extra, entries[i].name, w); + if (depw) + depl = g_slist_prepend(depl, w); + widgets = g_slist_prepend(widgets, w); + row++; + break; + case CAMEL_PROVIDER_CONF_ENTRY: + l = g_object_new(gtk_label_get_type(), "label", entries[i].text, "xalign", 0.0, NULL); + gtk_widget_show(l); + w = emae_option_entry(service, url, entries[i].name, entries[i].value); + gtk_table_attach((GtkTable *)parent, l, 0, 1, row, row+1, GTK_FILL, 0, 0, 0); + gtk_table_attach((GtkTable *)parent, w, 1, 2, row, row+1, GTK_EXPAND|GTK_FILL, 0, 0, 0); + if (depw) { + depl = g_slist_prepend(depl, w); + depl = g_slist_prepend(depl, l); + } + widgets = g_slist_prepend(widgets, w); + widgets = g_slist_prepend(widgets, l); + row++; + /* FIXME: this is another hack for exchange/groupwise connector */ + g_hash_table_insert(item->extra_table, entries[i].name, w); + break; + case CAMEL_PROVIDER_CONF_CHECKSPIN: + w = emae_option_checkspin(service, url, entries[i].name, entries[i].text, entries[i].value); + gtk_table_attach((GtkTable *)parent, w, 0, 2, row, row+1, GTK_EXPAND|GTK_FILL, 0, 0, 0); + if (depw) + depl = g_slist_prepend(depl, w); + widgets = g_slist_prepend(widgets, w); + row++; + break; + default: + break; + } + + if (depw && depl) { + int act = gtk_toggle_button_get_active((GtkToggleButton *)depw); + + g_object_set_data_full((GObject *)depw, "dependent-list", depl, (GDestroyNotify)g_slist_free); + for (n=depl;n;n=g_slist_next(n)) + gtk_widget_set_sensitive((GtkWidget *)n->data, act); + } + } + + camel_url_free(url); + + /* Since EConfig destroys the factory widget when it changes, we + * need to destroy our own ones as well, and add a dummy item + * so it knows this section isn't empty */ + + w = gtk_label_new(""); + gtk_widget_hide(w); + gtk_table_attach((GtkTable *)parent, w, 0, 2, row, row+1, 0, 0, 0, 0); + item->widgets = widgets; + + return w; +} + +static GtkWidget * +emae_send_page(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data) +{ + EMAccountEditor *emae = data; + EMAccountEditorPrivate *gui = emae->priv; + GtkWidget *w; + + if (old) + return old; + + /* Transport */ + gui->transport.type = CAMEL_PROVIDER_TRANSPORT; + emae_setup_service(emae, &gui->transport); + + w = glade_xml_get_widget(gui->xml, item->label); + if (((EConfig *)gui->config)->type == E_CONFIG_DRUID) { + GtkWidget *page = glade_xml_get_widget(gui->druidxml, "transport_page"); + + /* need to set packing? */ + gtk_widget_reparent(w, ((GnomeDruidPageStandard *)page)->vbox); + + return page; + } + + return w; +} + +static GtkWidget * +emae_defaults_page(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data) +{ + EMAccountEditor *emae = data; + EMAccountEditorPrivate *gui = emae->priv; + + if (old) + return old; + + /* Special folders */ + gui->drafts_folder_button = (GtkButton *)emae_account_folder(emae, "drafts_button", E_ACCOUNT_DRAFTS_FOLDER_URI, MAIL_COMPONENT_FOLDER_DRAFTS); + gui->sent_folder_button = (GtkButton *)emae_account_folder(emae, "sent_button", E_ACCOUNT_SENT_FOLDER_URI, MAIL_COMPONENT_FOLDER_SENT); + + /* Special Folders "Reset Defaults" button */ + gui->restore_folders_button = (GtkButton *)glade_xml_get_widget (gui->xml, "default_folders_button"); + g_signal_connect (gui->restore_folders_button, "clicked", G_CALLBACK (default_folders_clicked), emae); + + /* Always Cc/Bcc */ + emae_account_toggle(emae, "always_cc", E_ACCOUNT_CC_ALWAYS); + emae_account_entry(emae, "cc_addrs", E_ACCOUNT_CC_ADDRS); + emae_account_toggle(emae, "always_bcc", E_ACCOUNT_BCC_ALWAYS); + emae_account_entry(emae, "bcc_addrs", E_ACCOUNT_BCC_ADDRS); + + gtk_widget_set_sensitive((GtkWidget *)gui->drafts_folder_button, e_account_writable(emae->account, E_ACCOUNT_DRAFTS_FOLDER_URI)); + gtk_widget_set_sensitive((GtkWidget *)gui->sent_folder_button, e_account_writable(emae->account, E_ACCOUNT_SENT_FOLDER_URI)); + gtk_widget_set_sensitive((GtkWidget *)gui->restore_folders_button, + e_account_writable(emae->account, E_ACCOUNT_SENT_FOLDER_URI) + || e_account_writable(emae->account, E_ACCOUNT_DRAFTS_FOLDER_URI)); + + return glade_xml_get_widget(gui->xml, item->label); +} + +static GtkWidget * +emae_security_page(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data) +{ + EMAccountEditor *emae = data; + EMAccountEditorPrivate *gui = emae->priv; + + if (old) + return old; + + /* Security */ + emae_account_entry(emae, "pgp_key", E_ACCOUNT_PGP_KEY); + emae_account_toggle(emae, "pgp_encrypt_to_self", E_ACCOUNT_PGP_ENCRYPT_TO_SELF); + emae_account_toggle(emae, "pgp_always_sign", E_ACCOUNT_PGP_ALWAYS_SIGN); + emae_account_toggle(emae, "pgp_no_imip_sign", E_ACCOUNT_PGP_NO_IMIP_SIGN); + emae_account_toggle(emae, "pgp_always_trust", E_ACCOUNT_PGP_ALWAYS_TRUST); + +#if defined (HAVE_NSS) + /* TODO: this should handle its entry separately? */ + gui->smime_sign_key = emae_account_entry(emae, "smime_sign_key", E_ACCOUNT_SMIME_SIGN_KEY); + gui->smime_sign_key_select = (GtkButton *)glade_xml_get_widget (gui->xml, "smime_sign_key_select"); + gui->smime_sign_key_clear = (GtkButton *)glade_xml_get_widget (gui->xml, "smime_sign_key_clear"); + g_signal_connect(gui->smime_sign_key_select, "clicked", G_CALLBACK(smime_sign_key_select), emae); + g_signal_connect(gui->smime_sign_key_clear, "clicked", G_CALLBACK(smime_sign_key_clear), emae); + + gui->smime_sign_default = emae_account_toggle(emae, "smime_sign_default", E_ACCOUNT_SMIME_SIGN_DEFAULT); + + gui->smime_encrypt_key = emae_account_entry(emae, "smime_encrypt_key", E_ACCOUNT_SMIME_ENCRYPT_KEY); + gui->smime_encrypt_key_select = (GtkButton *)glade_xml_get_widget (gui->xml, "smime_encrypt_key_select"); + gui->smime_encrypt_key_clear = (GtkButton *)glade_xml_get_widget (gui->xml, "smime_encrypt_key_clear"); + g_signal_connect(gui->smime_encrypt_key_select, "clicked", G_CALLBACK(smime_encrypt_key_select), emae); + g_signal_connect(gui->smime_encrypt_key_clear, "clicked", G_CALLBACK(smime_encrypt_key_clear), emae); + + gui->smime_encrypt_default = emae_account_toggle(emae, "smime_encrypt_default", E_ACCOUNT_SMIME_ENCRYPT_DEFAULT); + gui->smime_encrypt_to_self = emae_account_toggle(emae, "smime_encrypt_to_self", E_ACCOUNT_SMIME_ENCRYPT_TO_SELF); + smime_changed(emae); +#else + { + /* Since we don't have NSS, hide the S/MIME config options */ + GtkWidget *frame; + + frame = glade_xml_get_widget (gui->xml, "smime_vbox"); + gtk_widget_destroy (frame); + } +#endif /* HAVE_NSS */ + + return glade_xml_get_widget(gui->xml, item->label); +} + +static GtkWidget * +emae_widget_glade(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data) +{ + EMAccountEditor *emae = data; + + if (old) + return old; + + printf("getting widget '%s' = %p\n", item->label, glade_xml_get_widget(emae->priv->xml, item->label)); + + return glade_xml_get_widget(emae->priv->xml, item->label); +} + +/* plugin meta-data for "com.novell.evolution.mail.config.accountEditor" */ +static EMConfigItem emae_editor_items[] = { + { E_CONFIG_BOOK, "", "account_editor_notebook", emae_widget_glade }, + { E_CONFIG_PAGE, "00.identity", "vboxIdentityBorder", emae_identity_page }, + { E_CONFIG_SECTION, "00.identity/00.name", "account_vbox", emae_widget_glade }, + /* table not vbox: { E_CONFIG_SECTION, "00.identity/10.required", "identity_required_table", emae_widget_glade }, */ + /* table not vbox: { E_CONFIG_SECTION, "00.identity/20.info", "identity_optional_table", emae_widget_glade }, */ + + { E_CONFIG_PAGE, "10.receive", "vboxSourceBorder", emae_receive_page }, + /* table not vbox: { E_CONFIG_SECTION, "10.receive/00.type", "source_type_table", emcp_widget_glade }, */ + /* table not vbox: { E_CONFIG_SECTION, "10.receive/10.config", "table13", emcp_widget_glade }, */ + { E_CONFIG_SECTION, "10.receive/20.security", "vbox181", emae_widget_glade }, + { E_CONFIG_SECTION, "10.receive/30.auth", "vbox179", emae_widget_glade }, + + /* Most sections for this is auto-generated fromt the camel config */ + { E_CONFIG_PAGE, "20.receive_options", N_("Receiving Options"), }, + { E_CONFIG_SECTION_TABLE, "20.receive_options/10.mailcheck", N_("Checking for New Mail"), }, + { E_CONFIG_ITEM_TABLE, "20.receive_options/10.mailcheck/00.autocheck", NULL, emae_receive_options_item, }, + + { E_CONFIG_PAGE, "30.send", "vboxTransportBorder", emae_send_page }, + /* table not vbox: { E_CONFIG_SECTION, "30.send/00.type", "transport_type_table", emcp_widget_glade }, */ + { E_CONFIG_SECTION, "30.send/10.config", "vbox12", emae_widget_glade }, + { E_CONFIG_SECTION, "30.send/20.security", "vbox183", emae_widget_glade }, + { E_CONFIG_SECTION, "30.send/30.auth", "vbox61", emae_widget_glade }, + + { E_CONFIG_PAGE, "40.defaults", "vboxFoldersBorder", emae_defaults_page }, + { E_CONFIG_SECTION, "40.defaults/00.folders", "vbox184", emae_widget_glade }, + /* table not vbox: { E_CONFIG_SECTION, "40.defaults/10.composing", "table8", emae_widget_glade }, */ + + { E_CONFIG_PAGE, "50.security", "vboxSecurityBorder", emae_security_page }, + /* 1x1 table(!) not vbox: { E_CONFIG_SECTION, "50.security/00.gpg", "table19", emae_widget_glade }, */ + /* table not vbox: { E_CONFIG_SECTION, "50.security/10.smime", "smime_table", emae_widget_glade }, */ + { 0 }, +}; + +static GtkWidget * +emae_management_page(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data) +{ + EMAccountEditor *emae = data; + EMAccountEditorPrivate *gui = emae->priv; + GtkWidget *w; + + if (old) + return old; + + w = glade_xml_get_widget(gui->xml, item->label); + if (((EConfig *)gui->config)->type == E_CONFIG_DRUID) { + GtkWidget *page = glade_xml_get_widget(gui->druidxml, "management_page"); + + /* need to set packing? */ + gtk_widget_reparent(w, ((GnomeDruidPageStandard *)page)->vbox); + + return page; + } + + return w; +} + +static GtkWidget * +emae_widget_druid_glade(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data) +{ + EMAccountEditor *emae = data; + GtkWidget *w; + + if (old) + return old; + + printf("getting widget '%s' = %p\n", item->label, glade_xml_get_widget(emae->priv->druidxml, item->label)); + + w = glade_xml_get_widget(emae->priv->druidxml, item->label); + /* i think the glade file has issues, we need to show all on at least the end page */ + gtk_widget_show_all(w); + + return w; +} + +/* plugin meta-data for "com.novell.evolution.mail.config.accountDruid" */ +static EMConfigItem emae_druid_items[] = { + { E_CONFIG_DRUID, "", "druid", emae_widget_druid_glade }, + { E_CONFIG_PAGE_START, "0.start", "start_page", emae_widget_druid_glade }, + + { E_CONFIG_PAGE, "00.identity", "vboxIdentityBorder", emae_identity_page }, + { E_CONFIG_SECTION, "00.identity/00.name", "account_vbox", emae_widget_glade }, + /* table not vbox: { E_CONFIG_SECTION, "00.identity/10.required", "identity_required_table", emae_widget_glade }, */ + /* table not vbox: { E_CONFIG_SECTION, "00.identity/20.info", "identity_optional_table", emae_widget_glade }, */ + + { E_CONFIG_PAGE, "10.receive", "vboxSourceBorder", emae_receive_page }, + /* table not vbox: { E_CONFIG_SECTION, "10.receive/00.type", "source_type_table", emcp_widget_glade }, */ + /* table not vbox: { E_CONFIG_SECTION, "10.receive/10.config", "table13", emcp_widget_glade }, */ + { E_CONFIG_SECTION, "10.receive/20.security", "vbox181", emae_widget_glade }, + { E_CONFIG_SECTION, "10.receive/30.auth", "vbox179", emae_widget_glade }, + + /* Most sections for this is auto-generated fromt the camel config */ + { E_CONFIG_PAGE, "20.receive_options", N_("Receiving Options"), }, + { E_CONFIG_SECTION_TABLE, "20.receive_options/10.mailcheck", N_("Checking for New Mail"), }, + { E_CONFIG_ITEM_TABLE, "20.receive_options/10.mailcheck/00.autocheck", NULL, emae_receive_options_item, }, + + { E_CONFIG_PAGE, "30.send", "vboxTransportBorder", emae_send_page }, + /* table not vbox: { E_CONFIG_SECTION, "30.send/00.type", "transport_type_table", emcp_widget_glade }, */ + { E_CONFIG_SECTION, "30.send/10.config", "vbox12", emae_widget_glade }, + { E_CONFIG_SECTION, "30.send/20.security", "vbox183", emae_widget_glade }, + { E_CONFIG_SECTION, "30.send/30.auth", "vbox61", emae_widget_glade }, + + { E_CONFIG_PAGE, "40.management", "management_frame", emae_management_page }, + + { E_CONFIG_PAGE_FINISH, "999.end", "finish_page", emae_widget_druid_glade }, + { 0 }, +}; + +static void +emae_free(EConfig *ec, GSList *items, void *data) +{ + g_slist_free(items); +} + +static void +emae_free_auto(EConfig *ec, GSList *items, void *data) +{ + GSList *l, *n; + + for (l=items;l;) { + struct _receive_options_item *item = l->data; + + n = g_slist_next(l); + g_free(item->item.path); + if (item->extra_table) + g_hash_table_destroy(item->extra_table); + g_slist_free(item->widgets); + g_free(item); + g_slist_free_1(l); + l = n; + } +} + +static gboolean +emae_service_complete(EMAccountEditor *emae, EMAccountEditorService *service) +{ + CamelURL *url; + int ok = TRUE; + const char *uri; + + if (service->provider == NULL) + return TRUE; + + uri = e_account_get_string(emae->account, emae_service_info[service->type].account_uri_key); + if (uri == NULL || (url = camel_url_new(uri, NULL)) == NULL) + return FALSE; + + if (CAMEL_PROVIDER_NEEDS(service->provider, CAMEL_URL_PART_HOST) + && (url->host == NULL || url->host[0] == 0)) + ok = FALSE; + + /* We only need the user if the service needs auth as well, i think */ + if (ok + && (service->needs_auth == NULL + || CAMEL_PROVIDER_NEEDS(service->provider, CAMEL_URL_PART_AUTH) + || gtk_toggle_button_get_active(service->needs_auth)) + && CAMEL_PROVIDER_NEEDS(service->provider, CAMEL_URL_PART_USER) + && (url->user == NULL || url->user[0] == 0)) + ok = FALSE; + + if (ok + && CAMEL_PROVIDER_NEEDS(service->provider, CAMEL_URL_PART_PATH) + && (url->path == NULL || url->path[0] == 0)) + ok = FALSE; + + camel_url_free(url); + + return ok; +} + +static gboolean +emae_check_complete(EConfig *ec, const char *pageid, void *data) +{ + EMAccountEditor *emae = data; + int ok = TRUE; + const char *tmp; + EAccount *ea; + + if (pageid == NULL || !strcmp(pageid, "00.identity")) { + /* TODO: check the account name is set, and unique in the account list */ + ok = (tmp = e_account_get_string(emae->account, E_ACCOUNT_ID_NAME)) + && tmp[0] + && (tmp = e_account_get_string(emae->account, E_ACCOUNT_ID_ADDRESS)) + && is_email(tmp) + && ((tmp = e_account_get_string(emae->account, E_ACCOUNT_ID_REPLY_TO)) == NULL + || tmp[0] == 0 + || is_email(tmp)); + if (!ok) + printf("identity incomplete\n"); + } + + if (ok && (pageid == NULL || !strcmp(pageid, "10.receive"))) { + ok = emae_service_complete(emae, &emae->priv->source); + if (!ok) + printf("receive page incomplete\n"); + } + + if (ok && (pageid == NULL || !strcmp(pageid, "30.send"))) { + ok = emae_service_complete(emae, &emae->priv->transport); + if (!ok) + printf("send page incomplete\n"); + } + + if (ok && (pageid == NULL || !strcmp(pageid, "40.management"))) { + ok = (tmp = e_account_get_string(emae->account, E_ACCOUNT_NAME)) + && tmp[0] + && ((ea = mail_config_get_account_by_name(tmp)) == NULL + || ea == emae->original); + if (!ok) + printf("management page incomplete\n"); + } + + /* We use the page-check of various pages to 'prepare' or + pre-load their values, only in the druid */ + if (pageid + && ((EConfig *)emae->priv->config)->type == E_CONFIG_DRUID) { + if (!strcmp(pageid, "00.identity")) { + if (!emae->priv->identity_set) { + char *uname; + + emae->priv->identity_set = 1; + uname = g_locale_to_utf8(g_get_real_name(), -1, NULL, NULL, NULL); + if (uname) { + gtk_entry_set_text((GtkEntry *)glade_xml_get_widget(emae->priv->xml, "management_name"), uname); + g_free(uname); + } + } + } else if (!strcmp(pageid, "10.receive")) { + if (!emae->priv->receive_set) { + char *user, *at; + + emae->priv->receive_set = 1; + tmp = e_account_get_string(emae->account, E_ACCOUNT_ID_ADDRESS); + at = strchr(tmp, '@'); + user = g_alloca(at-tmp+1); + memcpy(user, tmp, at-tmp); + user[at-tmp] = 0; + gtk_entry_set_text(emae->priv->source.username, user); + gtk_entry_set_text(emae->priv->transport.username, user); + } + } else if (!strcmp(pageid, "20.receive_options")) { + if (emae->priv->source.provider + && emae->priv->extra_provider != emae->priv->source.provider) { + emae->priv->extra_provider = emae->priv->source.provider; + emae_auto_detect(emae); + } + } else if (!strcmp(pageid, "40.management")) { + if (!emae->priv->management_set) { + char *template; + unsigned int i = 0, len; + + emae->priv->management_set = 1; + tmp = e_account_get_string(emae->account, E_ACCOUNT_ID_ADDRESS); + len = strlen(tmp); + template = alloca(len + 14); + strcpy(template, tmp); + while (mail_config_get_account_by_name(template)) + sprintf(template + len, " (%d)", i++); + + gtk_entry_set_text((GtkEntry *)glade_xml_get_widget(emae->priv->xml, "management_name"), template); + } + } + } + + return ok; +} + +/* HACK: FIXME: the component should listen to the account object directly */ +static void +add_new_store (char *uri, CamelStore *store, void *user_data) +{ + MailComponent *component = mail_component_peek (); + EAccount *account = user_data; + + if (store == NULL) + return; + + mail_component_add_store (component, store, account->name); +} + +static void +emae_commit(EConfig *ec, GSList *items, void *data) +{ + EMAccountEditor *emae = data; + EAccountList *accounts = mail_config_get_accounts(); + EAccount *account; + + /* the mail-config*acconts* api needs a lot of work */ + + if (emae->original) { + printf("Committing account '%s'\n", e_account_get_string(emae->account, E_ACCOUNT_NAME)); + e_account_import(emae->original, emae->account); + account = emae->original; + e_account_list_change(accounts, account); + } else { + printf("Adding new account '%s'\n", e_account_get_string(emae->account, E_ACCOUNT_NAME)); + e_account_list_add(accounts, emae->account); + account = emae->account; + + /* HACK: this will add the account to the folder tree. + We should just be listening to the account list directly for changed events */ + if (account->enabled + && emae->priv->source.provider + && (emae->priv->source.provider->flags & CAMEL_PROVIDER_IS_STORAGE)) + mail_get_store(e_account_get_string(emae->account, E_ACCOUNT_SOURCE_URL), NULL, add_new_store, account); + } + + if (gtk_toggle_button_get_active(emae->priv->default_account)) + e_account_list_set_default(accounts, account); + + e_account_list_save(accounts); +} + +void +em_account_editor_construct(EMAccountEditor *emae, EAccount *account, em_account_editor_t type) +{ + EMAccountEditorPrivate *gui = emae->priv; + int i, index; + GSList *l; + GList *prov; + EMConfig *ec; + EMConfigTargetAccount *target; + GHashTable *have; + EConfigItem *items; + + emae->type = type; + emae->original = account; + if (emae->original) { + char *xml; + + g_object_ref(emae->original); + xml = e_account_to_xml(emae->original); + emae->account = e_account_new_from_xml(xml); + g_free(xml); + + emae->do_signature = TRUE; + } else { + /* TODO: have a get_default_account thing?? */ + emae->account = e_account_new(); + emae->account->enabled = TRUE; + e_account_set_string(emae->account, E_ACCOUNT_DRAFTS_FOLDER_URI, + mail_component_get_folder_uri(NULL, MAIL_COMPONENT_FOLDER_DRAFTS)); + e_account_set_string(emae->account, E_ACCOUNT_SENT_FOLDER_URI, + mail_component_get_folder_uri(NULL, MAIL_COMPONENT_FOLDER_SENT)); + } + + gui->xml = glade_xml_new(EVOLUTION_GLADEDIR "/mail-config.glade", "account_editor_notebook", NULL); + if (type == EMAE_DRUID) + gui->druidxml = glade_xml_new(EVOLUTION_GLADEDIR "/mail-config.glade", "druid", NULL); + + /* sort the providers, remote first */ + gui->providers = g_list_sort(camel_provider_list(TRUE), (GCompareFunc)provider_compare); + + if (type == EMAE_NOTEBOOK) { + ec = em_config_new(E_CONFIG_BOOK, "com.novell.evolution.mail.config.accountEditor"); + items = emae_editor_items; + } else { + ec = em_config_new(E_CONFIG_DRUID, "com.novell.evolution.mail.config.accountDruid"); + items = emae_druid_items; + } + + emae->config = gui->config = ec; + l = NULL; + for (i=0;items[i].path;i++) + l = g_slist_prepend(l, &items[i]); + e_config_add_items((EConfig *)ec, l, emae_commit, NULL, emae_free, emae); + + /* This is kinda yuck, we're dynamically mapping from the 'old style' extensibility api to the new one */ + l = NULL; + have = g_hash_table_new(g_str_hash, g_str_equal); + index = 20; + for (prov=gui->providers;prov;prov=g_list_next(prov)) { + CamelProviderConfEntry *entries = ((CamelProvider *)prov->data)->extra_conf; + + for (i=0;entries && entries[i].type != CAMEL_PROVIDER_CONF_END;i++) { + struct _receive_options_item *item; + char *name = entries[i].name; + int myindex = index; + + if (entries[i].type != CAMEL_PROVIDER_CONF_SECTION_START + || name == NULL + || g_hash_table_lookup(have, name)) + continue; + + /* override mailcheck since we also insert our own mailcheck item at this index */ + if (name && !strcmp(name, "mailcheck")) + myindex = 10; + + item = g_malloc0(sizeof(*item)); + item->item.type = E_CONFIG_SECTION_TABLE; + item->item.path = g_strdup_printf("20.receive_options/%02d.%s", myindex, name?name:"unnamed"); + item->item.label = entries[i].text; + + l = g_slist_prepend(l, item); + + item = g_malloc0(sizeof(*item)); + item->item.type = E_CONFIG_ITEM_TABLE; + item->item.path = g_strdup_printf("20.receive_options/%02d.%s/80.camelitem", myindex, name?name:"unnamed"); + item->item.factory = emae_receive_options_extra_item; + item->item.user_data = entries[i].name; + + l = g_slist_prepend(l, item); + + index += 10; + g_hash_table_insert(have, entries[i].name, have); + } + } + g_hash_table_destroy(have); + e_config_add_items((EConfig *)ec, l, NULL, NULL, emae_free_auto, emae); + gui->extra_items = l; + + e_config_add_page_check((EConfig *)ec, NULL, emae_check_complete, emae); + + target = em_config_target_new_account(ec, emae->account); + e_config_set_target((EConfig *)ec, (EConfigTarget *)target); + emae->editor = e_config_create_window((EConfig *)ec, NULL, type==EMAE_NOTEBOOK?_("Account Editor"):_("Evolution Account Assistant")); + + /* FIXME: need to hook onto destroy as required */ +} diff --git a/mail/em-account-editor.h b/mail/em-account-editor.h new file mode 100644 index 0000000000..0e84a07b7d --- /dev/null +++ b/mail/em-account-editor.h @@ -0,0 +1,86 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: + * Jeffrey Stedfast <fejj@ximian.com> + * Dan Winship <danw@ximian.com> + * + * Copyright 2001-2003 Ximian, Inc. (www.ximian.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * 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, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ + +#ifndef EM_ACCOUNT_EDITOR_H +#define EM_ACCOUNT_EDITOR_H + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus */ + +#include <gtk/gtkvbox.h> + +struct _EAccount; + +typedef struct _EMAccountEditor EMAccountEditor; +typedef struct _EMAccountEditorClass EMAccountEditorClass; + +typedef enum { + EMAE_NOTEBOOK, + EMAE_DRUID, +} em_account_editor_t; + +struct _EMAccountEditor { + GObject gobject; + + struct _EMAccountEditorPrivate *priv; + + em_account_editor_t type; + struct _GtkWidget *editor; /* gtknotebook or druid, depending on type */ + + struct _EMConfig *config; /* driver object */ + + struct _EAccount *account; /* working account, must instant apply to this */ + struct _EAccount *original; /* original account, not changed unless commit is invoked */ + + int do_signature:1; /* allow editing signature */ +}; + +struct _EMAccountEditorClass { + GObjectClass gobject_class; +}; + +GType em_account_editor_get_type(void); + +void em_account_editor_construct(EMAccountEditor *emae, struct _EAccount *account, em_account_editor_t type); +EMAccountEditor *em_account_editor_new(struct _EAccount *account, em_account_editor_t type); + +gboolean em_account_editor_save (EMAccountEditor *gui); +void em_account_editor_destroy (EMAccountEditor *gui); + +gboolean em_account_editor_identity_complete (EMAccountEditor *gui, struct _GtkWidget **incomplete); +gboolean em_account_editor_source_complete (EMAccountEditor *gui, struct _GtkWidget **incomplete); +gboolean em_account_editor_transport_complete (EMAccountEditor *gui, struct _GtkWidget **incomplete); +gboolean em_account_editor_management_complete (EMAccountEditor *gui, struct _GtkWidget **incomplete); + +void em_account_editor_build_extra_conf (EMAccountEditor *gui, const char *url); + +void em_account_editor_auto_detect_extra_conf (EMAccountEditor *gui); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* EM_ACCOUNT_EDITOR_H */ diff --git a/mail/em-account-prefs.c b/mail/em-account-prefs.c index 348fb5fd83..2966171472 100644 --- a/mail/em-account-prefs.c +++ b/mail/em-account-prefs.c @@ -32,6 +32,8 @@ #include <gtk/gtkcellrenderertoggle.h> #include <gtk/gtkcellrenderertext.h> +#include <libgnome/gnome-i18n.h> + #include "mail-component.h" #include "mail-config.h" #include "mail-config-druid.h" @@ -44,6 +46,8 @@ #include "em-account-prefs.h" +#include "em-account-editor.h" + static void em_account_prefs_class_init (EMAccountPrefsClass *class); static void em_account_prefs_init (EMAccountPrefs *prefs); static void em_account_prefs_finalise (GObject *obj); @@ -132,13 +136,17 @@ account_add_finished (EMAccountPrefs *prefs, GObject *deadbeef) g_object_unref (prefs); } +#include "em-config.h" + static void account_add_clicked (GtkButton *button, gpointer user_data) { EMAccountPrefs *prefs = (EMAccountPrefs *) user_data; - GtkWidget *parent; if (prefs->druid == NULL) { +#if 0 + GtkWidget *parent; + prefs->druid = (GtkWidget *) mail_config_druid_new (); parent = gtk_widget_get_toplevel ((GtkWidget *) prefs); @@ -150,6 +158,12 @@ account_add_clicked (GtkButton *button, gpointer user_data) gtk_widget_show (prefs->druid); g_object_ref (prefs); +#else + EMAccountEditor *emae; + + emae = em_account_editor_new(NULL, EMAE_DRUID); + gtk_widget_show(emae->editor); +#endif } else { gdk_window_raise (prefs->druid->window); } @@ -182,8 +196,9 @@ account_edit_clicked (GtkButton *button, gpointer user_data) gtk_tree_model_get (model, &iter, 3, &account, -1); if (account) { +#if 0 GtkWidget *parent; - + parent = gtk_widget_get_toplevel ((GtkWidget *) prefs); parent = GTK_WIDGET_TOPLEVEL (parent) ? parent : NULL; @@ -192,6 +207,15 @@ account_edit_clicked (GtkButton *button, gpointer user_data) g_object_weak_ref ((GObject *) prefs->editor, (GWeakNotify) account_edit_finished, prefs); gtk_widget_show (prefs->editor); g_object_ref (prefs); +#endif + /* test foo */ + { + EMAccountEditor *emae; + + emae = em_account_editor_new(account, EMAE_NOTEBOOK); + gtk_widget_show(emae->editor); + } + } } else { gdk_window_raise (prefs->editor->window); @@ -231,8 +255,6 @@ account_delete_clicked (GtkButton *button, gpointer user_data) mail_config_write (); - mail_autoreceive_setup (); - gtk_list_store_remove ((GtkListStore *) model, &iter); len = e_list_length ((EList *) accounts); @@ -270,12 +292,30 @@ account_default_clicked (GtkButton *button, gpointer user_data) } static void -account_able_clicked (GtkButton *button, gpointer user_data) +account_able_changed(EAccount *account) { MailComponent *component = mail_component_peek (); + + /* FIXME: do this directly by listening to the mail accounts changed events in the relevant components */ + + if (account->source->url) { + if (account->enabled) + mail_component_load_store_by_uri (component, + account->source->url, + account->name); + else + mail_component_remove_store_by_uri (component, account->source->url); + } + + mail_config_write (); +} + +static void +account_able_clicked (GtkButton *button, gpointer user_data) +{ EMAccountPrefs *prefs = user_data; GtkTreeSelection *selection; - EAccount *account = NULL; + EAccount *account; GtkTreeModel *model; GtkTreeIter iter; @@ -286,23 +326,10 @@ account_able_clicked (GtkButton *button, gpointer user_data) gtk_list_store_set ((GtkListStore *) model, &iter, 0, account->enabled, -1); gtk_button_set_label (prefs->mail_able, account->enabled ? _("Disable") : _("Enable")); - } - - if (account) { - /* if the account got disabled, remove it from the - folder-tree, otherwise add it to the folder-tree */ - if (account->source->url) { - if (account->enabled) - mail_component_load_store_by_uri (component, - account->source->url, - account->name); - else - mail_component_remove_store_by_uri (component, account->source->url); - } - - mail_autoreceive_setup (); - - mail_config_write (); + + /* let the rest of the application know it changed */ + e_account_list_change(mail_config_get_accounts(), account); + account_able_changed(account); } } @@ -327,25 +354,13 @@ account_able_toggled (GtkCellRendererToggle *renderer, char *arg1, gpointer user if (gtk_tree_selection_iter_is_selected (selection, &iter)) gtk_button_set_label (prefs->mail_able, account->enabled ? _("Disable") : _("Enable")); + + /* let the rest of the application know it changed */ + e_account_list_change(mail_config_get_accounts(), account); + account_able_changed(account); } gtk_tree_path_free (path); - - if (account) { - MailComponent *component = mail_component_peek (); - - /* if the account got disabled, remove it from the - folder-tree, otherwise add it to the folder-tree */ - if (account->source->url) { - if (account->enabled) - mail_component_load_store_by_uri (component, account->source->url, account->name); - else - mail_component_remove_store_by_uri (component, account->source->url); - } - - mail_autoreceive_setup (); - mail_config_write (); - } } static void diff --git a/mail/em-composer-prefs.c b/mail/em-composer-prefs.c index 053d14cae6..f361d20e74 100644 --- a/mail/em-composer-prefs.c +++ b/mail/em-composer-prefs.c @@ -66,6 +66,7 @@ #include "mail-config.h" #include "mail-signature-editor.h" +#include "em-config.h" #define d(x) @@ -840,6 +841,36 @@ toggle_button_init (EMComposerPrefs *prefs, GtkToggleButton *toggle, int not, co gtk_widget_set_sensitive ((GtkWidget *) toggle, FALSE); } +static GtkWidget * +emcp_widget_glade(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data) +{ + EMComposerPrefs *prefs = data; + + return glade_xml_get_widget(prefs->gui, item->label); +} + +/* plugin meta-data */ +static EMConfigItem emcp_items[] = { + { E_CONFIG_BOOK, "", "composer_toplevel", emcp_widget_glade }, + { E_CONFIG_PAGE, "00.general", "vboxGeneral", emcp_widget_glade }, + { E_CONFIG_SECTION, "00.general/00.behavior", "vboxBehavior", emcp_widget_glade }, + { E_CONFIG_SECTION, "00.general/10.alerts", "vboxAlerts", emcp_widget_glade }, + { E_CONFIG_PAGE, "10.signatures", "vboxSignatures", emcp_widget_glade }, + /* signature/signatures and signature/preview parts not usable */ + + { E_CONFIG_PAGE, "20.spellcheck", "vboxSpellChecking", emcp_widget_glade }, + { E_CONFIG_SECTION, "20.spellcheck/00.languages", "vbox178", emcp_widget_glade }, + { E_CONFIG_SECTION, "20.spellcheck/00.options", "vboxOptions", emcp_widget_glade }, +}; + +static void +emcp_free(EConfig *ec, GSList *items, void *data) +{ + /* the prefs data is freed automagically */ + + g_slist_free(items); +} + static void em_composer_prefs_construct (EMComposerPrefs *prefs) { @@ -850,22 +881,23 @@ em_composer_prefs_construct (EMComposerPrefs *prefs) GtkTreeSelection *selection; int style; char *buf; + EMConfig *ec; + EMConfigTargetPrefs *target; + GSList *l; + int i; prefs->gconf = mail_config_get_gconf_client (); - gui = glade_xml_new (EVOLUTION_GLADEDIR "/mail-config.glade", "composer_tab", NULL); + gui = glade_xml_new (EVOLUTION_GLADEDIR "/mail-config.glade", "composer_toplevel", NULL); prefs->gui = gui; prefs->sig_script_gui = glade_xml_new (EVOLUTION_GLADEDIR "/mail-config.glade", "vbox_add_script_signature", NULL); - - /* get our toplevel widget */ - toplevel = glade_xml_get_widget (gui, "toplevel"); - - /* reparent */ - gtk_widget_ref (toplevel); - gtk_container_remove (GTK_CONTAINER (toplevel->parent), toplevel); - gtk_container_add (GTK_CONTAINER (prefs), toplevel); - gtk_widget_unref (toplevel); - + + ec = em_config_new(E_CONFIG_BOOK, "com.novell.evolution.mail.composerPrefs"); + l = NULL; + for (i=0;i<sizeof(emcp_items)/sizeof(emcp_items[0]);i++) + l = g_slist_prepend(l, &emcp_items[i]); + e_config_add_items((EConfig *)ec, l, NULL, NULL, emcp_free, prefs); + /* General tab */ /* Default Behavior */ @@ -988,8 +1020,13 @@ em_composer_prefs_construct (EMComposerPrefs *prefs) g_signal_connect (prefs->sig_preview, "url_requested", G_CALLBACK (url_requested), NULL); gtk_widget_show (GTK_WIDGET (prefs->sig_preview)); gtk_container_add (GTK_CONTAINER (widget), GTK_WIDGET (prefs->sig_preview)); -} + /* get our toplevel widget */ + target = em_config_target_new_prefs(ec, prefs->gconf); + e_config_set_target((EConfig *)ec, (EConfigTarget *)target); + toplevel = e_config_create_widget((EConfig *)ec); + gtk_container_add (GTK_CONTAINER (prefs), toplevel); +} GtkWidget * em_composer_prefs_new (void) diff --git a/mail/em-composer-utils.c b/mail/em-composer-utils.c index 025b490472..b6b0474b3f 100644 --- a/mail/em-composer-utils.c +++ b/mail/em-composer-utils.c @@ -28,6 +28,7 @@ #include <gtk/gtkdialog.h> #include <gal/util/e-util.h> +#include <libgnome/gnome-i18n.h> #include "mail-mt.h" #include "mail-ops.h" diff --git a/mail/em-config.c b/mail/em-config.c new file mode 100644 index 0000000000..be8d4c95d4 --- /dev/null +++ b/mail/em-config.c @@ -0,0 +1,321 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: Michael Zucchi <notzed@ximian.com> + * + * Copyright 2004 Novell, Inc. (www.novell.com) + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> +#include <stdlib.h> + +#include <glib.h> + +#include <gtk/gtkmenu.h> +#include <gtk/gtkmenuitem.h> +#include <gtk/gtkimagemenuitem.h> +#include <gtk/gtkcheckmenuitem.h> +#include <gtk/gtkradiomenuitem.h> +#include <gtk/gtkseparatormenuitem.h> +#include <gtk/gtklabel.h> +#include <gtk/gtkimage.h> + +#include <libgnome/gnome-url.h> +#include <libgnomevfs/gnome-vfs-mime.h> + +#include "em-config.h" +#include "e-util/e-msgport.h" +#include <e-util/e-icon-factory.h> +#include "em-utils.h" +#include "em-composer-utils.h" + +#include <camel/camel-store.h> +#include <camel/camel-folder.h> +#include <camel/camel-mime-message.h> +#include <camel/camel-string-utils.h> +#include <camel/camel-mime-utils.h> +#include <camel/camel-mime-part.h> +#include <camel/camel-url.h> + +#include <camel/camel-vee-folder.h> +#include <camel/camel-vtrash-folder.h> + +#include <gconf/gconf.h> +#include <gconf/gconf-client.h> + +#include <gal/util/e-util.h> + +static GObjectClass *emp_parent; + +struct _EMConfigPrivate { + gint account_changed_id; +}; + +static void +emp_init(GObject *o) +{ + EMConfig *emp = (EMConfig *)o; + + emp->priv = g_malloc0(sizeof(*emp->priv)); +} + +static void +emp_finalise(GObject *o) +{ + struct _EMConfigPrivate *p = ((EMConfig *)o)->priv; + + /* Note we can't be unreffed if a target exists, so the target + * will need to be freed first which will clean up any + * listeners */ + + g_free(p); + + ((GObjectClass *)emp_parent)->finalize(o); +} + +static void +emp_target_free(EConfig *ep, EConfigTarget *t) +{ + if (ep->target == t) { + switch (t->type) { + case EM_CONFIG_TARGET_FOLDER: { + /*EMConfigTargetFolder *s = (EMConfigTargetFolder *)t;*/ + break; } + case EM_CONFIG_TARGET_PREFS: { + /*EMConfigTargetPrefs *s = (EMConfigTargetPrefs *)t;*/ + break; } + case EM_CONFIG_TARGET_ACCOUNT: { + EMConfigTargetAccount *s = (EMConfigTargetAccount *)t; + + if (((EMConfig *)ep)->priv->account_changed_id) { + g_signal_handler_disconnect(s->account, ((EMConfig *)ep)->priv->account_changed_id); + ((EMConfig *)ep)->priv->account_changed_id = 0; + } + break; } + } + } + + switch (t->type) { + case EM_CONFIG_TARGET_FOLDER: { + EMConfigTargetFolder *s = (EMConfigTargetFolder *)t; + + g_free(s->uri); + camel_object_unref(s->folder); + break; } + case EM_CONFIG_TARGET_PREFS: { + EMConfigTargetPrefs *s = (EMConfigTargetPrefs *)t; + + if (s->gconf) + g_object_unref(s->gconf); + break; } + case EM_CONFIG_TARGET_ACCOUNT: { + EMConfigTargetAccount *s = (EMConfigTargetAccount *)t; + + g_object_unref(s->account); + break; } + } + + ((EConfigClass *)emp_parent)->target_free(ep, t); +} + +static void +emp_account_changed(struct _EAccount *ea, int id, EMConfig *emc) +{ + e_config_target_changed((EConfig *)emc, E_CONFIG_TARGET_CHANGED_STATE); +} + +static void +emp_set_target(EConfig *ep, EConfigTarget *t) +{ + ((EConfigClass *)emp_parent)->set_target(ep, t); + + if (t) { + switch (t->type) { + case EM_CONFIG_TARGET_FOLDER: { + /*EMConfigTargetFolder *s = (EMConfigTargetFolder *)t;*/ + break; } + case EM_CONFIG_TARGET_PREFS: { + /*EMConfigTargetPrefs *s = (EMConfigTargetPrefs *)t;*/ + break; } + case EM_CONFIG_TARGET_ACCOUNT: { + EMConfigTargetAccount *s = (EMConfigTargetAccount *)t; + + ((EMConfig *)ep)->priv->account_changed_id = g_signal_connect(s->account, "changed", G_CALLBACK(emp_account_changed), ep); + break; } + } + } +} + +static void +emp_class_init(GObjectClass *klass) +{ + klass->finalize = emp_finalise; + ((EConfigClass *)klass)->set_target = emp_set_target; + ((EConfigClass *)klass)->target_free = emp_target_free; +} + +GType +em_config_get_type(void) +{ + static GType type = 0; + + if (type == 0) { + static const GTypeInfo info = { + sizeof(EMConfigClass), + NULL, NULL, + (GClassInitFunc)emp_class_init, + NULL, NULL, + sizeof(EMConfig), 0, + (GInstanceInitFunc)emp_init + }; + emp_parent = g_type_class_ref(e_config_get_type()); + type = g_type_register_static(e_config_get_type(), "EMConfig", &info, 0); + } + + return type; +} + +EMConfig *em_config_new(int type, const char *menuid) +{ + EMConfig *emp = g_object_new(em_config_get_type(), 0); + + e_config_construct(&emp->config, type, menuid); + + return emp; +} + +EMConfigTargetFolder * +em_config_target_new_folder(EMConfig *emp, struct _CamelFolder *folder, const char *uri) +{ + EMConfigTargetFolder *t = e_config_target_new(&emp->config, EM_CONFIG_TARGET_FOLDER, sizeof(*t)); + + t->uri = g_strdup(uri); + t->folder = folder; + camel_object_ref(folder); + + return t; +} + +EMConfigTargetPrefs * +em_config_target_new_prefs(EMConfig *emp, struct _GConfClient *gconf) +{ + EMConfigTargetPrefs *t = e_config_target_new(&emp->config, EM_CONFIG_TARGET_PREFS, sizeof(*t)); + + t->gconf = gconf; + if (gconf) + g_object_ref(gconf); + + return t; +} + +EMConfigTargetAccount * +em_config_target_new_account(EMConfig *emp, struct _EAccount *account) +{ + EMConfigTargetAccount *t = e_config_target_new(&emp->config, EM_CONFIG_TARGET_ACCOUNT, sizeof(*t)); + + t->account = account; + g_object_ref(account); + + return t; +} + + +/* ********************************************************************** */ + +/* Popup menu plugin handler */ + +/* +<e-plugin + class="com.ximian.mail.plugin.popup:1.0" + id="com.ximian.mail.plugin.popup.item:1.0" + type="shlib" + location="/opt/gnome2/lib/camel/1.0/libcamelimap.so" + name="imap" + description="IMAP4 and IMAP4v1 mail store"> + <hook class="com.ximian.mail.popupMenu:1.0" + handler="HandlePopup"> + <menu id="any" target="select"> + <item + type="item|toggle|radio|image|submenu|bar" + active + path="foo/bar" + label="label" + icon="foo" + mask="select_one" + activate="emp_view_emacs"/> + </menu> + </extension> + +*/ + +static void *emph_parent_class; +#define emph ((EMConfigHook *)eph) + +static const EConfigHookTargetMask emph_no_masks[] = { + { 0 } +}; + +static const EConfigHookTargetMap emph_targets[] = { + { "folder", EM_CONFIG_TARGET_FOLDER, emph_no_masks }, + { "prefs", EM_CONFIG_TARGET_PREFS, emph_no_masks }, + { "account", EM_CONFIG_TARGET_ACCOUNT, emph_no_masks }, + { 0 } +}; + +static void +emph_finalise(GObject *o) +{ + /*EPluginHook *eph = (EPluginHook *)o;*/ + + ((GObjectClass *)emph_parent_class)->finalize(o); +} + +static void +emph_class_init(EPluginHookClass *klass) +{ + int i; + + ((GObjectClass *)klass)->finalize = emph_finalise; + ((EPluginHookClass *)klass)->id = "com.novell.evolution.mail.config:1.0"; + + for (i=0;emph_targets[i].type;i++) + e_config_hook_class_add_target_map((EConfigHookClass *)klass, &emph_targets[i]); + + ((EConfigHookClass *)klass)->config_class = g_type_class_ref(em_config_get_type()); +} + +GType +em_config_hook_get_type(void) +{ + static GType type = 0; + + if (!type) { + static const GTypeInfo info = { + sizeof(EMConfigHookClass), NULL, NULL, (GClassInitFunc) emph_class_init, NULL, NULL, + sizeof(EMConfigHook), 0, (GInstanceInitFunc) NULL, + }; + + emph_parent_class = g_type_class_ref(e_config_hook_get_type()); + type = g_type_register_static(e_config_hook_get_type(), "EMConfigHook", &info, 0); + } + + return type; +} diff --git a/mail/em-config.h b/mail/em-config.h new file mode 100644 index 0000000000..ff5b06a209 --- /dev/null +++ b/mail/em-config.h @@ -0,0 +1,114 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Authors: Michel Zucchi <notzed@ximian.com> + * + * Copyright 2004 Novell, Inc. (www.novell.com) + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __EM_CONFIG_H__ +#define __EM_CONFIG_H__ + +#include <glib-object.h> + +#include "e-util/e-config.h" + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus */ + +struct _GConfClient; + +typedef struct _EMConfig EMConfig; +typedef struct _EMConfigClass EMConfigClass; + +/* Current target description */ +/* Types of popup tagets */ +enum _em_config_target_t { + EM_CONFIG_TARGET_FOLDER, + EM_CONFIG_TARGET_PREFS, + EM_CONFIG_TARGET_ACCOUNT, +}; + +typedef struct _EMConfigTargetFolder EMConfigTargetFolder; +typedef struct _EMConfigTargetPrefs EMConfigTargetPrefs; +typedef struct _EMConfigTargetAccount EMConfigTargetAccount; + +struct _EMConfigTargetFolder { + EConfigTarget target; + + struct _CamelFolder *folder; + char *uri; +}; + +struct _EMConfigTargetPrefs { + EConfigTarget target; + + /* preferences are global from gconf */ + struct _GConfClient *gconf; +}; + +struct _EMConfigTargetAccount { + EConfigTarget target; + + struct _EAccount *account; + /* Need also: working account, not just real account, so changes can be propagated around + And some mechamism for controlling the gui if we're running inside a druid, e.g. enabling 'next' */ +}; + +typedef struct _EConfigItem EMConfigItem; + +/* The object */ +struct _EMConfig { + EConfig config; + + struct _EMConfigPrivate *priv; +}; + +struct _EMConfigClass { + EConfigClass config_class; +}; + +GType em_config_get_type(void); + +EMConfig *em_config_new(int type, const char *menuid); + +EMConfigTargetFolder *em_config_target_new_folder(EMConfig *emp, struct _CamelFolder *folder, const char *uri); +EMConfigTargetPrefs *em_config_target_new_prefs(EMConfig *emp, struct _GConfClient *gconf); +EMConfigTargetAccount *em_config_target_new_account(EMConfig *emp, struct _EAccount *account); + +/* ********************************************************************** */ + +typedef struct _EMConfigHook EMConfigHook; +typedef struct _EMConfigHookClass EMConfigHookClass; + +struct _EMConfigHook { + EConfigHook hook; +}; + +struct _EMConfigHookClass { + EConfigHookClass hook_class; +}; + +GType em_config_hook_get_type(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EM_CONFIG_H__ */ diff --git a/mail/em-event.c b/mail/em-event.c new file mode 100644 index 0000000000..450d198d4c --- /dev/null +++ b/mail/em-event.c @@ -0,0 +1,185 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: Michael Zucchi <notzed@ximian.com> + * + * Copyright 2004 Ximian, Inc. (www.ximian.com) + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> +#include <stdlib.h> + +#include <glib.h> + +#include "em-event.h" +#include "e-util/e-msgport.h" +#include <e-util/e-icon-factory.h> + +#include <camel/camel-store.h> +#include <camel/camel-folder.h> +#include <camel/camel-mime-message.h> +#include <camel/camel-string-utils.h> +#include <camel/camel-mime-utils.h> +#include <camel/camel-mime-part.h> +#include <camel/camel-url.h> + +#include <camel/camel-vee-folder.h> +#include <camel/camel-vtrash-folder.h> + +static GObjectClass *eme_parent; +static EMEvent *em_event; + +static void +eme_init(GObject *o) +{ + /*EMEvent *eme = (EMEvent *)o; */ +} + +static void +eme_finalise(GObject *o) +{ + ((GObjectClass *)eme_parent)->finalize(o); +} + +static void +eme_target_free(EEvent *ep, EEventTarget *t) +{ + switch (t->type) { + case EM_EVENT_TARGET_FOLDER: { + EMEventTargetFolder *s = (EMEventTargetFolder *)t; + + g_free(s->uri); + break; } + } + + ((EEventClass *)eme_parent)->target_free(ep, t); +} + +static void +eme_class_init(GObjectClass *klass) +{ + klass->finalize = eme_finalise; + ((EEventClass *)klass)->target_free = eme_target_free; +} + +GType +em_event_get_type(void) +{ + static GType type = 0; + + if (type == 0) { + static const GTypeInfo info = { + sizeof(EMEventClass), + NULL, NULL, + (GClassInitFunc)eme_class_init, + NULL, NULL, + sizeof(EMEvent), 0, + (GInstanceInitFunc)eme_init + }; + eme_parent = g_type_class_ref(e_event_get_type()); + type = g_type_register_static(e_event_get_type(), "EMEvent", &info, 0); + } + + return type; +} + +/** + * em_event_peek: + * @void: + * + * Get the singular instance of the mail event handler. + * + * Return value: + **/ +EMEvent *em_event_peek(void) +{ + if (em_event == NULL) { + em_event = g_object_new(em_event_get_type(), 0); + e_event_construct(&em_event->popup, "com.ximian.evolution.mail.events"); + } + + return em_event; +} + +EMEventTargetFolder * +em_event_target_new_folder (EMEvent *eme, const char *uri, guint32 flags) +{ + EMEventTargetFolder *t = e_event_target_new(&eme->popup, EM_EVENT_TARGET_FOLDER, sizeof(*t)); + + t->uri = g_strdup(uri); + t->target.mask = ~flags; + + return t; +} + +/* ********************************************************************** */ + +static void *emeh_parent_class; +#define emeh ((EMEventHook *)eph) + +static const EEventHookTargetMask emeh_folder_masks[] = { + { "newmail", EM_EVENT_FOLDER_NEWMAIL }, + { 0 } +}; +static const EEventHookTargetMap emeh_targets[] = { + { "folder", EM_EVENT_TARGET_FOLDER, emeh_folder_masks }, + { 0 } +}; + +static void +emeh_finalise(GObject *o) +{ + /*EPluginHook *eph = (EPluginHook *)o;*/ + + ((GObjectClass *)emeh_parent_class)->finalize(o); +} + +static void +emeh_class_init(EPluginHookClass *klass) +{ + int i; + + ((GObjectClass *)klass)->finalize = emeh_finalise; + ((EPluginHookClass *)klass)->id = "com.ximian.evolution.mail.events:1.0"; + + for (i=0;emeh_targets[i].type;i++) + e_event_hook_class_add_target_map((EEventHookClass *)klass, &emeh_targets[i]); + + ((EEventHookClass *)klass)->event = (EEvent *)em_event_peek(); +} + +GType +em_event_hook_get_type(void) +{ + static GType type = 0; + + if (!type) { + static const GTypeInfo info = { + sizeof(EMEventHookClass), NULL, NULL, (GClassInitFunc) emeh_class_init, NULL, NULL, + sizeof(EMEventHook), 0, (GInstanceInitFunc) NULL, + }; + + emeh_parent_class = g_type_class_ref(e_event_hook_get_type()); + type = g_type_register_static(e_event_hook_get_type(), "EMEventHook", &info, 0); + } + + return type; +} diff --git a/mail/em-event.h b/mail/em-event.h new file mode 100644 index 0000000000..05c62d9f50 --- /dev/null +++ b/mail/em-event.h @@ -0,0 +1,94 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Authors: Michel Zucchi <notzed@ximian.com> + * + * Copyright 2003 Ximian, Inc. (www.ximian.com) + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __EM_EVENT_H__ +#define __EM_EVENT_H__ + +#include <glib-object.h> + +#include "e-util/e-event.h" + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus */ + +typedef struct _EMEvent EMEvent; +typedef struct _EMEventClass EMEventClass; + +/* Current target description */ +/* Types of popup tagets */ +enum _em_event_target_t { + EM_EVENT_TARGET_FOLDER, +}; + +/* Flags that describe TARGET_FOLDER */ +enum { + EM_EVENT_FOLDER_NEWMAIL = 1<< 0, +}; + +typedef struct _EMEventTargetFolder EMEventTargetFolder; + +struct _EMEventTargetFolder { + EEventTarget target; + char *uri; +}; + +typedef struct _EEventItem EMEventItem; + +/* The object */ +struct _EMEvent { + EEvent popup; + + struct _EMEventPrivate *priv; +}; + +struct _EMEventClass { + EEventClass popup_class; +}; + +GType em_event_get_type(void); + +EMEvent *em_event_peek(void); + +EMEventTargetFolder *em_event_target_new_folder(EMEvent *emp, const char *uri, guint32 flags); + +/* ********************************************************************** */ + +typedef struct _EMEventHook EMEventHook; +typedef struct _EMEventHookClass EMEventHookClass; + +struct _EMEventHook { + EEventHook hook; +}; + +struct _EMEventHookClass { + EEventHookClass hook_class; +}; + +GType em_event_hook_get_type(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EM_EVENT_H__ */ diff --git a/mail/em-folder-browser.c b/mail/em-folder-browser.c index e9c14ea600..40633d5d36 100644 --- a/mail/em-folder-browser.c +++ b/mail/em-folder-browser.c @@ -74,6 +74,7 @@ #include "em-folder-browser.h" #include "em-folder-properties.h" #include "em-subscribe-editor.h" +#include "em-menu.h" #include "message-list.h" #include "mail-component.h" @@ -100,6 +101,8 @@ struct _EMFolderBrowserPrivate { guint list_built_id; /* hook onto list-built for delayed 'select first unread' stuff */ char *select_uid; + + EMMenu *menu; /* toplevel menu manager */ }; static void emfb_activate(EMFolderView *emfv, BonoboUIComponent *uic, int state); @@ -284,6 +287,8 @@ GtkWidget *em_folder_browser_new(void) { EMFolderBrowser *emfb = g_object_new(em_folder_browser_get_type(), 0); + ((EMFolderView *)emfb)->menu = em_menu_new("com.novell.evolution.mail.browser"); + return (GtkWidget *)emfb; } diff --git a/mail/em-folder-properties.c b/mail/em-folder-properties.c index 885abcceef..9c32e30a87 100644 --- a/mail/em-folder-properties.c +++ b/mail/em-folder-properties.c @@ -39,8 +39,10 @@ #include <gtk/gtkvbox.h> #include <camel/camel-folder.h> +#include <libgnome/gnome-i18n.h> #include "em-folder-properties.h" +#include "em-config.h" #include "mail-ops.h" #include "mail-mt.h" @@ -50,19 +52,32 @@ struct _prop_data { void *object; CamelArgV *argv; GtkWidget **widgets; + + GSList *properties; + char *name; + int total; + int unread; + EMConfig *config; }; static void emfp_dialog_response (GtkWidget *dialog, int response, struct _prop_data *prop_data) { + if (response == GTK_RESPONSE_OK) + e_config_commit((EConfig *)prop_data->config); + else + e_config_abort((EConfig *)prop_data->config); + + gtk_widget_destroy (dialog); +} + +static void +emfp_commit(EConfig *ec, GSList *items, void *data) +{ + struct _prop_data *prop_data = data; CamelArgV *argv = prop_data->argv; int i; - if (response != GTK_RESPONSE_OK) { - gtk_widget_destroy (dialog); - return; - } - for (i = 0; i < argv->argc; i++) { CamelArg *arg = &argv->argv[i]; @@ -81,136 +96,75 @@ emfp_dialog_response (GtkWidget *dialog, int response, struct _prop_data *prop_d } camel_object_setv (prop_data->object, NULL, argv); - gtk_widget_destroy (dialog); } static void -emfp_dialog_free (void *data) +emfp_free(EConfig *ec, GSList *items, void *data) { struct _prop_data *prop_data = data; int i; + g_slist_free(items); + for (i = 0; i < prop_data->argv->argc; i++) { if ((prop_data->argv->argv[i].tag & CAMEL_ARG_TYPE) == CAMEL_ARG_STR) g_free (prop_data->argv->argv[i].ca_str); } + + camel_object_free (prop_data->object, CAMEL_FOLDER_PROPERTIES, prop_data->properties); + camel_object_free (prop_data->object, CAMEL_FOLDER_NAME, prop_data->name); camel_object_unref (prop_data->object); g_free (prop_data->argv); + g_free (prop_data); } -static void -emfp_dialog_got_folder (char *uri, CamelFolder *folder, void *data) +static GtkWidget * +emfp_get_folder_item(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data) { - GtkWidget *dialog, *w, *table, *label, *vbox, *hbox; - struct _prop_data *prop_data; - CamelArgGetV *arggetv; - CamelArgV *argv; - GSList *list, *l; - gint32 count, i; - char *name, *title; char countstr[16]; - int row = 0, total=0, unread=0; - - if (folder == NULL) - return; - - camel_object_get (folder, NULL, CAMEL_FOLDER_PROPERTIES, &list, CAMEL_FOLDER_NAME, &name, - CAMEL_FOLDER_TOTAL, &total, CAMEL_FOLDER_UNREAD, &unread, NULL); - - dialog = gtk_dialog_new_with_buttons (_("Folder Properties"), NULL, - GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_OK, GTK_RESPONSE_OK, - NULL); - gtk_window_set_default_size ((GtkWindow *) dialog, 192, 160); - gtk_widget_ensure_style (dialog); - gtk_container_set_border_width ((GtkContainer *) ((GtkDialog *) dialog)->vbox, 0); - gtk_container_set_border_width ((GtkContainer *) ((GtkDialog *) dialog)->vbox, 12); - - vbox = gtk_vbox_new (FALSE, 12); - gtk_container_set_border_width ((GtkContainer *) vbox, 12); - gtk_box_pack_start ((GtkBox *) ((GtkDialog *) dialog)->vbox, vbox, TRUE, TRUE, 0); - gtk_widget_show (vbox); - - title = g_strdup_printf ("<b>%s</b>", name); - label = gtk_label_new (title); - gtk_label_set_use_markup ((GtkLabel *) label, TRUE); - gtk_misc_set_alignment ((GtkMisc *) label, 0.0, 0.5); - gtk_box_pack_start ((GtkBox *) vbox, label, FALSE, FALSE, 0); - gtk_widget_show (label); - g_free (title); - - hbox = gtk_hbox_new (FALSE, 12); - gtk_box_pack_start ((GtkBox *) vbox, hbox, FALSE, FALSE, 0); - gtk_widget_show (hbox); + GtkWidget *w, *table, *label; + struct _prop_data *prop_data = data; + int row = 0, i; + GSList *l; - label = gtk_label_new (""); - gtk_box_pack_start ((GtkBox *) hbox, label, FALSE, FALSE, 0); - gtk_widget_show (label); + if (old) + return old; - /* TODO: maybe we want some basic properties here, like message counts/approximate size/etc */ - table = gtk_table_new (g_slist_length (list) + 2, 2, FALSE); + table = gtk_table_new (g_slist_length (prop_data->properties) + 2, 2, FALSE); gtk_table_set_row_spacings ((GtkTable *) table, 6); gtk_table_set_col_spacings ((GtkTable *) table, 12); gtk_widget_show (table); - gtk_box_pack_start ((GtkBox *) hbox, table, TRUE, TRUE, 0); + gtk_box_pack_start ((GtkBox *) parent, table, TRUE, TRUE, 0); /* TODO: can this be done in a loop? */ - label = gtk_label_new (ngettext ("Total message:", "Total messages:", total)); + label = gtk_label_new (ngettext ("Total message:", "Total messages:", prop_data->total)); gtk_widget_show (label); gtk_misc_set_alignment ((GtkMisc *) label, 0.0, 0.5); gtk_table_attach ((GtkTable *) table, label, 0, 1, row, row+1, GTK_FILL, 0, 0, 0); - sprintf(countstr, "%d", total); + sprintf(countstr, "%d", prop_data->total); label = gtk_label_new (countstr); gtk_widget_show (label); gtk_misc_set_alignment ((GtkMisc *) label, 1.0, 0.5); gtk_table_attach ((GtkTable *) table, label, 1, 2, row, row+1, GTK_FILL | GTK_EXPAND, 0, 0, 0); row++; - label = gtk_label_new (ngettext ("Unread message:", "Unread messages:", unread)); + label = gtk_label_new (ngettext ("Unread message:", "Unread messages:", prop_data->unread)); gtk_widget_show (label); gtk_misc_set_alignment ((GtkMisc *) label, 0.0, 0.5); gtk_table_attach ((GtkTable *) table, label, 0, 1, row, row+1, GTK_FILL, 0, 0, 0); - sprintf(countstr, "%d", unread); + sprintf(countstr, "%d", prop_data->unread); label = gtk_label_new (countstr); gtk_widget_show (label); gtk_misc_set_alignment ((GtkMisc *) label, 1.0, 0.5); gtk_table_attach ((GtkTable *) table, label, 1, 2, row, row+1, GTK_FILL | GTK_EXPAND, 0, 0, 0); row++; - /* build an arggetv/argv to retrieve/store the results */ - count = g_slist_length (list); - arggetv = g_malloc0 (sizeof (*arggetv) + (count - CAMEL_ARGV_MAX) * sizeof (arggetv->argv[0])); - arggetv->argc = count; - argv = g_malloc0 (sizeof (*argv) + (count - CAMEL_ARGV_MAX) * sizeof (argv->argv[0])); - argv->argc = count; - - i = 0; - l = list; - while (l) { - CamelProperty *prop = l->data; - - argv->argv[i].tag = prop->tag; - arggetv->argv[i].tag = prop->tag; - arggetv->argv[i].ca_ptr = &argv->argv[i].ca_ptr; - - l = l->next; - i++; - } - - camel_object_getv (folder, NULL, arggetv); - g_free (arggetv); - - prop_data = g_malloc0 (sizeof (*prop_data)); - prop_data->widgets = g_malloc0 (sizeof (prop_data->widgets[0]) * count); - prop_data->argv = argv; - /* setup the ui with the values retrieved */ - l = list; + l = prop_data->properties; i = 0; while (l) { CamelProperty *prop = l->data; @@ -218,7 +172,7 @@ emfp_dialog_got_folder (char *uri, CamelFolder *folder, void *data) switch (prop->tag & CAMEL_ARG_TYPE) { case CAMEL_ARG_BOO: w = gtk_check_button_new_with_label (prop->description); - gtk_toggle_button_set_active ((GtkToggleButton *) w, argv->argv[i].ca_int != 0); + gtk_toggle_button_set_active ((GtkToggleButton *) w, prop_data->argv->argv[i].ca_int != 0); gtk_widget_show (w); gtk_table_attach ((GtkTable *) table, w, 0, 2, row, row + 1, GTK_FILL | GTK_EXPAND, 0, 0, 0); prop_data->widgets[i] = w; @@ -231,10 +185,10 @@ emfp_dialog_got_folder (char *uri, CamelFolder *folder, void *data) w = gtk_entry_new (); gtk_widget_show (w); - if (argv->argv[i].ca_str) { - gtk_entry_set_text ((GtkEntry *) w, argv->argv[i].ca_str); - camel_object_free (folder, argv->argv[i].tag, argv->argv[i].ca_str); - argv->argv[i].ca_str = NULL; + if (prop_data->argv->argv[i].ca_str) { + gtk_entry_set_text ((GtkEntry *) w, prop_data->argv->argv[i].ca_str); + camel_object_free (prop_data->object, prop_data->argv->argv[i].tag, prop_data->argv->argv[i].ca_str); + prop_data->argv->argv[i].ca_str = NULL; } gtk_table_attach ((GtkTable *) table, w, 1, 2, row, row + 1, GTK_FILL | GTK_EXPAND, 0, 0, 0); prop_data->widgets[i] = w; @@ -247,17 +201,95 @@ emfp_dialog_got_folder (char *uri, CamelFolder *folder, void *data) row++; l = l->next; } - + + return table; +} + +#define EMFP_FOLDER_SECTION (2) + +static EMConfigItem emfp_items[] = { + { E_CONFIG_BOOK, "", NULL }, + { E_CONFIG_PAGE, "00.general", N_("General") }, + { E_CONFIG_SECTION, "00.general/00.folder", NULL /* set by code */ }, + { E_CONFIG_ITEM, "00.general/00.folder/00.info", NULL, emfp_get_folder_item }, +}; + +static void +emfp_dialog_got_folder (char *uri, CamelFolder *folder, void *data) +{ + GtkWidget *dialog, *w; + struct _prop_data *prop_data; + GSList *l; + gint32 count, i; + EMConfig *ec; + EMConfigTargetFolder *target; + CamelArgGetV *arggetv; + CamelArgV *argv; + + if (folder == NULL) + return; + + prop_data = g_malloc0 (sizeof (*prop_data)); prop_data->object = folder; camel_object_ref (folder); + + camel_object_get (folder, NULL, CAMEL_FOLDER_PROPERTIES, &prop_data->properties, CAMEL_FOLDER_NAME, &prop_data->name, + CAMEL_FOLDER_TOTAL, &prop_data->total, CAMEL_FOLDER_UNREAD, &prop_data->unread, NULL); + + emfp_items[EMFP_FOLDER_SECTION].label = prop_data->name; + + count = g_slist_length (prop_data->properties); + + prop_data->widgets = g_malloc0 (sizeof (prop_data->widgets[0]) * count); + + /* build an arggetv/argv to retrieve/store the results */ + argv = g_malloc0 (sizeof (*argv) + (count - CAMEL_ARGV_MAX) * sizeof (argv->argv[0])); + argv->argc = count; + arggetv = g_malloc0 (sizeof (*arggetv) + (count - CAMEL_ARGV_MAX) * sizeof (arggetv->argv[0])); + arggetv->argc = count; - camel_object_free (folder, CAMEL_FOLDER_PROPERTIES, list); - camel_object_free (folder, CAMEL_FOLDER_NAME, name); + i = 0; + l = prop_data->properties; + while (l) { + CamelProperty *prop = l->data; + + argv->argv[i].tag = prop->tag; + arggetv->argv[i].tag = prop->tag; + arggetv->argv[i].ca_ptr = &argv->argv[i].ca_ptr; + + l = l->next; + i++; + } + camel_object_getv (prop_data->object, NULL, arggetv); + g_free (arggetv); + prop_data->argv = argv; + + dialog = gtk_dialog_new_with_buttons (_("Folder Properties"), NULL, + GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR, + GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, + GTK_STOCK_OK, GTK_RESPONSE_OK, + NULL); + gtk_window_set_default_size ((GtkWindow *) dialog, 192, 160); + gtk_widget_ensure_style (dialog); + gtk_container_set_border_width ((GtkContainer *) ((GtkDialog *) dialog)->vbox, 12); + + ec = em_config_new(E_CONFIG_BOOK, "com.novell.evolution.mail.folderConfig"); + prop_data->config = ec; + l = NULL; + for (i=0;i<sizeof(emfp_items)/sizeof(emfp_items[0]);i++) + l = g_slist_prepend(l, &emfp_items[i]); + e_config_add_items((EConfig *)ec, l, emfp_commit, NULL, emfp_free, prop_data); + + target = em_config_target_new_folder(ec, folder, uri); + e_config_set_target((EConfig *)ec, (EConfigTarget *)target); + w = e_config_create_widget((EConfig *)ec); + + gtk_box_pack_start ((GtkBox *) ((GtkDialog *) dialog)->vbox, w, TRUE, TRUE, 0); + /* we do 'apply on ok' ... since instant apply may apply some very long running tasks */ g_signal_connect (dialog, "response", G_CALLBACK (emfp_dialog_response), prop_data); - g_object_set_data_full ((GObject *) dialog, "e-prop-data", prop_data, emfp_dialog_free); gtk_widget_show (dialog); } diff --git a/mail/em-folder-selection-button.c b/mail/em-folder-selection-button.c index 9124918301..b727891781 100644 --- a/mail/em-folder-selection-button.c +++ b/mail/em-folder-selection-button.c @@ -31,6 +31,7 @@ #include <gtk/gtkhbox.h> #include <gal/util/e-util.h> +#include <libgnome/gnome-i18n.h> #include "mail-component.h" #include "em-folder-tree.h" diff --git a/mail/em-folder-tree-model.c b/mail/em-folder-tree-model.c index 6947dc5ef4..4f1a8dda67 100644 --- a/mail/em-folder-tree-model.c +++ b/mail/em-folder-tree-model.c @@ -20,7 +20,6 @@ * */ - #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -38,6 +37,7 @@ #include <e-util/e-mktemp.h> #include <gal/util/e-xml-utils.h> +#include <libgnome/gnome-i18n.h> #include <camel/camel-file-utils.h> @@ -427,7 +427,7 @@ em_folder_tree_model_set_folder_info (EMFolderTreeModel *model, GtkTreeIter *ite gboolean load = FALSE; struct _CamelFolder *folder; gboolean emitted = FALSE; - + if (!fully_loaded) load = fi->child == NULL && !(fi->flags & (CAMEL_FOLDER_NOCHILDREN | CAMEL_FOLDER_NOINFERIORS)); diff --git a/mail/em-folder-tree.c b/mail/em-folder-tree.c index 5d8005ed40..5c8c384af8 100644 --- a/mail/em-folder-tree.c +++ b/mail/em-folder-tree.c @@ -37,6 +37,7 @@ #include <gtk/gtk.h> #include <gdk-pixbuf/gdk-pixbuf.h> +#include <libgnome/gnome-i18n.h> #include <camel/camel-session.h> #include <camel/camel-store.h> @@ -987,36 +988,48 @@ tree_drag_data_action(struct _DragDataReceivedAsync *m) } static void -emft_drop_popup_copy(GtkWidget *item, struct _DragDataReceivedAsync *m) +emft_drop_popup_copy(EPopup *ep, EPopupItem *item, void *data) { + struct _DragDataReceivedAsync *m = data; + m->action = GDK_ACTION_COPY; tree_drag_data_action(m); } static void -emft_drop_popup_move(GtkWidget *item, struct _DragDataReceivedAsync *m) +emft_drop_popup_move(EPopup *ep, EPopupItem *item, void *data) { + struct _DragDataReceivedAsync *m = data; + m->action = GDK_ACTION_MOVE; tree_drag_data_action(m); } static void -emft_drop_popup_cancel(GtkWidget *item, struct _DragDataReceivedAsync *m) +emft_drop_popup_cancel(EPopup *ep, EPopupItem *item, void *data) { + struct _DragDataReceivedAsync *m = data; + m->aborted = TRUE; mail_msg_free(&m->msg); } -static EMPopupItem emft_drop_popup_menu[] = { - { EM_POPUP_ITEM, "00.emc.00", N_("_Copy to Folder"), G_CALLBACK (emft_drop_popup_copy), NULL, NULL, 1 }, - { EM_POPUP_ITEM, "00.emc.01", N_("_Move to Folder"), G_CALLBACK (emft_drop_popup_move), NULL, NULL, 1 }, - { EM_POPUP_ITEM, "00.emc.02", N_("_Copy"), G_CALLBACK (emft_drop_popup_copy), NULL, "stock_folder-copy", 2 }, - { EM_POPUP_ITEM, "00.emc.03", N_("_Move"), G_CALLBACK (emft_drop_popup_move), NULL, "stock_folder-move", 2 }, - { EM_POPUP_BAR, "10.emc" }, - { EM_POPUP_ITEM, "99.emc.00", N_("Cancel _Drag"), G_CALLBACK (emft_drop_popup_cancel), NULL, "stock_cancel", 0 }, +static EPopupItem emft_drop_popup_menu[] = { + { E_POPUP_ITEM, "00.emc.00", N_("_Copy to Folder"), emft_drop_popup_copy, NULL, NULL, 1 }, + { E_POPUP_ITEM, "00.emc.01", N_("_Move to Folder"), emft_drop_popup_move, NULL, NULL, 1 }, + { E_POPUP_ITEM, "00.emc.02", N_("_Copy"), emft_drop_popup_copy, NULL, "stock_folder-copy", 2 }, + { E_POPUP_ITEM, "00.emc.03", N_("_Move"), emft_drop_popup_move, NULL, "stock_folder-move", 2 }, + { E_POPUP_BAR, "10.emc" }, + { E_POPUP_ITEM, "99.emc.00", N_("Cancel _Drag"), emft_drop_popup_cancel, NULL, "stock_cancel", 0 }, }; static void +emft_drop_popup_free(EPopup *ep, GSList *items, void *data) +{ + g_slist_free(items); +} + +static void tree_drag_data_received(GtkWidget *widget, GdkDragContext *context, int x, int y, GtkSelectionData *selection, guint info, guint time, EMFolderTree *emft) { struct _EMFolderTreePrivate *priv = emft->priv; @@ -1082,15 +1095,13 @@ tree_drag_data_received(GtkWidget *widget, GdkDragContext *context, int x, int y mask = ~2; for (i=0;i<sizeof(emft_drop_popup_menu)/sizeof(emft_drop_popup_menu[0]);i++) { - EMPopupItem *item = &emft_drop_popup_menu[i]; + EPopupItem *item = &emft_drop_popup_menu[i]; - if ((item->mask & mask) == 0) { - item->activate_data = m; + if ((item->visible & mask) == 0) menus = g_slist_append(menus, item); - } } - em_popup_add_items(emp, menus, (GDestroyNotify)g_slist_free); - menu = em_popup_create_menu_once(emp, NULL, mask, mask); + e_popup_add_items((EPopup *)emp, menus, emft_drop_popup_free, m); + menu = e_popup_create_menu_once((EPopup *)emp, NULL, mask, mask); gtk_menu_popup(menu, NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time()); } else { tree_drag_data_action(m); @@ -2192,8 +2203,9 @@ fail: } static void -emft_popup_copy (GtkWidget *item, EMFolderTree *emft) +emft_popup_copy(EPopup *ep, EPopupItem *item, void *data) { + EMFolderTree *emft = data; struct _copy_folder_data *cfd; cfd = g_malloc (sizeof (*cfd)); @@ -2205,8 +2217,9 @@ emft_popup_copy (GtkWidget *item, EMFolderTree *emft) } static void -emft_popup_move (GtkWidget *item, EMFolderTree *emft) +emft_popup_move(EPopup *ep, EPopupItem *item, void *data) { + EMFolderTree *emft = data; struct _copy_folder_data *cfd; cfd = g_malloc (sizeof (*cfd)); @@ -2419,8 +2432,10 @@ emft_popup_new_folder_response (EMFolderSelector *emfs, int response, EMFolderTr } static void -emft_popup_new_folder (GtkWidget *item, EMFolderTree *emft) +emft_popup_new_folder (EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderTree *emft = data; + EMFolderTree *folder_tree; GtkWidget *dialog; char *uri; @@ -2545,8 +2560,9 @@ emft_popup_delete_response (GtkWidget *dialog, int response, EMFolderTree *emft) } static void -emft_popup_delete_folder (GtkWidget *item, EMFolderTree *emft) +emft_popup_delete_folder (EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderTree *emft = data; struct _EMFolderTreePrivate *priv = emft->priv; GtkTreeSelection *selection; CamelStore *local, *store; @@ -2580,8 +2596,9 @@ emft_popup_delete_folder (GtkWidget *item, EMFolderTree *emft) } static void -emft_popup_rename_folder (GtkWidget *item, EMFolderTree *emft) +emft_popup_rename_folder (EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderTree *emft = data; struct _EMFolderTreePrivate *priv = emft->priv; char *prompt, *full_name, *name, *new_name, *uri; GtkTreeSelection *selection; @@ -2676,8 +2693,9 @@ emft_popup_rename_folder (GtkWidget *item, EMFolderTree *emft) static void -emft_popup_properties (GtkWidget *item, EMFolderTree *emft) +emft_popup_properties (EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderTree *emft = data; struct _EMFolderTreePrivate *priv = emft->priv; GtkTreeSelection *selection; GtkTreeModel *model; @@ -2693,33 +2711,39 @@ emft_popup_properties (GtkWidget *item, EMFolderTree *emft) g_free (uri); } -static EMPopupItem emft_popup_menu[] = { +static EPopupItem emft_popup_menu[] = { #if 0 - { EM_POPUP_ITEM, "00.emc.00", N_("_View"), G_CALLBACK (emft_popup_view), NULL, NULL, EM_POPUP_FOLDER_SELECT }, - { EM_POPUP_ITEM, "00.emc.01", N_("Open in _New Window"), G_CALLBACK (emft_popup_open_new), NULL, NULL, EM_POPUP_FOLDER_SELECT }, + { E_POPUP_ITEM, "00.emc.00", N_("_View"), emft_popup_view, NULL, NULL, EM_POPUP_FOLDER_SELECT }, + { E_POPUP_ITEM, "00.emc.01", N_("Open in _New Window"), emft_popup_open_new, NULL, NULL, EM_POPUP_FOLDER_SELECT }, - { EM_POPUP_BAR, "10.emc" }, + { E_POPUP_BAR, "10.emc" }, #endif - { EM_POPUP_ITEM, "10.emc.00", N_("_Copy..."), G_CALLBACK (emft_popup_copy), NULL, "stock_folder-copy", EM_POPUP_FOLDER_FOLDER|EM_POPUP_FOLDER_SELECT }, - { EM_POPUP_ITEM, "10.emc.01", N_("_Move..."), G_CALLBACK (emft_popup_move), NULL, "stock_folder-move", EM_POPUP_FOLDER_FOLDER|EM_POPUP_FOLDER_DELETE }, + { E_POPUP_ITEM, "10.emc.00", N_("_Copy..."), emft_popup_copy, NULL, "stock_folder-copy", EM_POPUP_FOLDER_FOLDER|EM_POPUP_FOLDER_SELECT }, + { E_POPUP_ITEM, "10.emc.01", N_("_Move..."), emft_popup_move, NULL, "stock_folder-move", EM_POPUP_FOLDER_FOLDER|EM_POPUP_FOLDER_DELETE }, - { EM_POPUP_BAR, "20.emc" }, + { E_POPUP_BAR, "20.emc" }, /* FIXME: need to disable for nochildren folders */ - { EM_POPUP_ITEM, "20.emc.00", N_("_New Folder..."), G_CALLBACK (emft_popup_new_folder), NULL, "stock_folder", EM_POPUP_FOLDER_INFERIORS }, + { E_POPUP_ITEM, "20.emc.00", N_("_New Folder..."), emft_popup_new_folder, NULL, "stock_folder", EM_POPUP_FOLDER_INFERIORS }, /* FIXME: need to disable for undeletable folders */ - { EM_POPUP_ITEM, "20.emc.01", N_("_Delete"), G_CALLBACK (emft_popup_delete_folder), NULL, "stock_delete", EM_POPUP_FOLDER_FOLDER|EM_POPUP_FOLDER_DELETE }, - { EM_POPUP_ITEM, "20.emc.01", N_("_Rename..."), G_CALLBACK (emft_popup_rename_folder), NULL, NULL, EM_POPUP_FOLDER_FOLDER|EM_POPUP_FOLDER_DELETE }, + { E_POPUP_ITEM, "20.emc.01", N_("_Delete"), emft_popup_delete_folder, NULL, "stock_delete", EM_POPUP_FOLDER_FOLDER|EM_POPUP_FOLDER_DELETE }, + { E_POPUP_ITEM, "20.emc.01", N_("_Rename..."), emft_popup_rename_folder, NULL, NULL, EM_POPUP_FOLDER_FOLDER|EM_POPUP_FOLDER_DELETE }, - { EM_POPUP_BAR, "80.emc" }, - { EM_POPUP_ITEM, "80.emc.00", N_("_Properties"), G_CALLBACK (emft_popup_properties), NULL, "stock_folder-properties", EM_POPUP_FOLDER_FOLDER|EM_POPUP_FOLDER_SELECT } + { E_POPUP_BAR, "80.emc" }, + { E_POPUP_ITEM, "80.emc.00", N_("_Properties"), emft_popup_properties, NULL, "stock_folder-properties", EM_POPUP_FOLDER_FOLDER|EM_POPUP_FOLDER_SELECT } }; +static void +emft_popup_free(EPopup *ep, GSList *items, void *data) +{ + g_slist_free(items); +} + static gboolean emft_tree_button_press (GtkTreeView *treeview, GdkEventButton *event, EMFolderTree *emft) { GtkTreeSelection *selection; CamelStore *local, *store; - EMPopupTarget *target; + EMPopupTargetFolder *target; GtkTreePath *tree_path; GtkTreeModel *model; GtkTreeIter iter; @@ -2789,18 +2813,14 @@ emft_tree_button_press (GtkTreeView *treeview, GdkEventButton *event, EMFolderTr emp = em_popup_new ("com.ximian.mail.storageset.popup.select"); /* FIXME: pass valid fi->flags here */ - target = em_popup_target_new_folder (uri, info_flags, flags); + target = em_popup_target_new_folder (emp, uri, info_flags, flags); - for (i = 0; i < sizeof (emft_popup_menu) / sizeof (emft_popup_menu[0]); i++) { - EMPopupItem *item = &emft_popup_menu[i]; - - item->activate_data = emft; - menus = g_slist_prepend (menus, item); - } + for (i = 0; i < sizeof (emft_popup_menu) / sizeof (emft_popup_menu[0]); i++) + menus = g_slist_prepend (menus, &emft_popup_menu[i]); - em_popup_add_items (emp, menus, (GDestroyNotify) g_slist_free); + e_popup_add_items ((EPopup *)emp, menus, emft_popup_free, emft); - menu = em_popup_create_menu_once (emp, target, 0, target->mask); + menu = e_popup_create_menu_once ((EPopup *)emp, (EPopupTarget *)target, 0, target->target.mask); if (event == NULL || event->type == GDK_KEY_PRESS) { /* FIXME: menu pos function */ diff --git a/mail/em-folder-view.c b/mail/em-folder-view.c index 00f918ed80..ef9007a683 100644 --- a/mail/em-folder-view.c +++ b/mail/em-folder-view.c @@ -77,6 +77,7 @@ #include "em-utils.h" #include "em-composer-utils.h" #include "em-marshal.h" +#include "em-menu.h" #include <gtkhtml/gtkhtml.h> #include <gtkhtml/htmlobject.h> @@ -590,22 +591,17 @@ emfv_selection_clear_event(GtkWidget *widget, GdkEventSelection *event, EMFolder /* Popup menu In many cases these are the functions called by the bonobo callbacks too */ -struct _emfv_label_item { - EMPopupItem item; - - EMFolderView *emfv; - const char *label; -}; - static void -emfv_popup_open(GtkWidget *w, EMFolderView *emfv) +emfv_popup_open(EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderView *emfv = data; em_folder_view_open_selected(emfv); } static void -emfv_popup_edit (GtkWidget *w, EMFolderView *emfv) +emfv_popup_edit (EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderView *emfv = data; GPtrArray *uids; if (!em_utils_check_user_can_send_mail((GtkWidget *)emfv)) @@ -616,8 +612,9 @@ emfv_popup_edit (GtkWidget *w, EMFolderView *emfv) } static void -emfv_popup_saveas(GtkWidget *w, EMFolderView *emfv) +emfv_popup_saveas(EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderView *emfv = data; GPtrArray *uids; uids = message_list_get_selected(emfv->list); @@ -625,32 +622,37 @@ emfv_popup_saveas(GtkWidget *w, EMFolderView *emfv) } static void -emfv_popup_print(GtkWidget *w, EMFolderView *emfv) +emfv_popup_print(EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderView *emfv = data; em_folder_view_print(emfv, FALSE); } static void -emfv_popup_reply_sender(GtkWidget *w, EMFolderView *emfv) +emfv_popup_reply_sender(EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderView *emfv = data; emfv_message_reply(emfv, REPLY_MODE_SENDER); } static void -emfv_popup_reply_list(GtkWidget *w, EMFolderView *emfv) +emfv_popup_reply_list(EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderView *emfv = data; emfv_message_reply(emfv, REPLY_MODE_LIST); } static void -emfv_popup_reply_all(GtkWidget *w, EMFolderView *emfv) +emfv_popup_reply_all(EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderView *emfv = data; emfv_message_reply(emfv, REPLY_MODE_ALL); } static void -emfv_popup_forward(GtkWidget *w, EMFolderView *emfv) +emfv_popup_forward(EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderView *emfv = data; GPtrArray *uids; if (!em_utils_check_user_can_send_mail((GtkWidget *)emfv)) @@ -661,16 +663,18 @@ emfv_popup_forward(GtkWidget *w, EMFolderView *emfv) } static void -emfv_popup_flag_followup(GtkWidget *w, EMFolderView *emfv) +emfv_popup_flag_followup(EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderView *emfv = data; GPtrArray *uids = message_list_get_selected(emfv->list); em_utils_flag_for_followup((GtkWidget *)emfv, emfv->folder, uids); } static void -emfv_popup_flag_completed(GtkWidget *w, EMFolderView *emfv) +emfv_popup_flag_completed(EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderView *emfv = data; GPtrArray *uids; uids = message_list_get_selected(emfv->list); @@ -678,22 +682,25 @@ emfv_popup_flag_completed(GtkWidget *w, EMFolderView *emfv) } static void -emfv_popup_flag_clear(GtkWidget *w, EMFolderView *emfv) +emfv_popup_flag_clear(EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderView *emfv = data; GPtrArray *uids = message_list_get_selected(emfv->list); em_utils_flag_for_followup_clear((GtkWidget *)emfv, emfv->folder, uids); } static void -emfv_popup_mark_read(GtkWidget *w, EMFolderView *emfv) +emfv_popup_mark_read(EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderView *emfv = data; em_folder_view_mark_selected(emfv, CAMEL_MESSAGE_SEEN, CAMEL_MESSAGE_SEEN); } static void -emfv_popup_mark_unread(GtkWidget *w, EMFolderView *emfv) +emfv_popup_mark_unread(EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderView *emfv = data; em_folder_view_mark_selected(emfv, CAMEL_MESSAGE_SEEN|CAMEL_MESSAGE_DELETED, 0); if (emfv->priv->seen_id) { @@ -703,20 +710,23 @@ emfv_popup_mark_unread(GtkWidget *w, EMFolderView *emfv) } static void -emfv_popup_mark_important(GtkWidget *w, EMFolderView *emfv) +emfv_popup_mark_important(EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderView *emfv = data; em_folder_view_mark_selected(emfv, CAMEL_MESSAGE_FLAGGED|CAMEL_MESSAGE_DELETED, CAMEL_MESSAGE_FLAGGED); } static void -emfv_popup_mark_unimportant(GtkWidget *w, EMFolderView *emfv) +emfv_popup_mark_unimportant(EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderView *emfv = data; em_folder_view_mark_selected(emfv, CAMEL_MESSAGE_FLAGGED, 0); } static void -emfv_popup_mark_junk (GtkWidget *w, EMFolderView *emfv) +emfv_popup_mark_junk (EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderView *emfv = data; GPtrArray *uids; uids = message_list_get_selected(emfv->list); @@ -730,8 +740,9 @@ emfv_popup_mark_junk (GtkWidget *w, EMFolderView *emfv) } static void -emfv_popup_mark_nojunk (GtkWidget *w, EMFolderView *emfv) +emfv_popup_mark_nojunk (EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderView *emfv = data; GPtrArray *uids; uids = message_list_get_selected(emfv->list); @@ -745,8 +756,9 @@ emfv_popup_mark_nojunk (GtkWidget *w, EMFolderView *emfv) } static void -emfv_popup_delete(GtkWidget *w, EMFolderView *emfv) +emfv_popup_delete(EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderView *emfv = data; GPtrArray *uids; uids = message_list_get_selected(emfv->list); @@ -760,8 +772,9 @@ emfv_popup_delete(GtkWidget *w, EMFolderView *emfv) } static void -emfv_popup_undelete(GtkWidget *w, EMFolderView *emfv) +emfv_popup_undelete(EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderView *emfv = data; em_folder_view_mark_selected(emfv, CAMEL_MESSAGE_DELETED, 0); } @@ -790,8 +803,9 @@ emfv_popup_move_cb(const char *uri, void *data) } static void -emfv_popup_move(GtkWidget *w, EMFolderView *emfv) +emfv_popup_move(EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderView *emfv = data; struct _move_data *d; d = g_malloc(sizeof(*d)); @@ -804,8 +818,9 @@ emfv_popup_move(GtkWidget *w, EMFolderView *emfv) } static void -emfv_popup_copy(GtkWidget *w, EMFolderView *emfv) +emfv_popup_copy(EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderView *emfv = data; struct _move_data *d; d = g_malloc(sizeof(*d)); @@ -830,20 +845,24 @@ emfv_set_label(EMFolderView *emfv, const char *label) } static void -emfv_popup_label_clear(GtkWidget *w, EMFolderView *emfv) +emfv_popup_label_clear(EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderView *emfv = data; emfv_set_label(emfv, NULL); } static void -emfv_popup_label_set(GtkWidget *w, struct _emfv_label_item *item) +emfv_popup_label_set(EPopup *ep, EPopupItem *pitem, void *data) { - emfv_set_label(item->emfv, item->label); + EMFolderView *emfv = data; + + emfv_set_label(emfv, pitem->user_data); } static void -emfv_popup_add_sender(GtkWidget *w, EMFolderView *emfv) +emfv_popup_add_sender(EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderView *emfv = data; GPtrArray *uids = message_list_get_selected(emfv->list); CamelMessageInfo *info; const char *addr; @@ -858,16 +877,18 @@ emfv_popup_add_sender(GtkWidget *w, EMFolderView *emfv) } static void -emfv_popup_apply_filters(GtkWidget *w, EMFolderView *emfv) +emfv_popup_apply_filters(EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderView *emfv = data; GPtrArray *uids = message_list_get_selected(emfv->list); mail_filter_on_demand(emfv->folder, uids); } static void -emfv_popup_filter_junk(GtkWidget *w, EMFolderView *emfv) +emfv_popup_filter_junk(EPopup *ep, EPopupItem *pitem, void *data) { + EMFolderView *emfv = data; GPtrArray *uids = message_list_get_selected(emfv->list); mail_filter_junk(emfv->folder, uids); @@ -878,8 +899,9 @@ emfv_popup_filter_junk(GtkWidget *w, EMFolderView *emfv) #define EMFV_POPUP_AUTO_TYPE(autotype, name, type) \ static void \ -name(GtkWidget *w, EMFolderView *emfv) \ +name(EPopup *ep, EPopupItem *item, void *data) \ { \ + EMFolderView *emfv = data; \ autotype(emfv, type); \ } @@ -895,83 +917,87 @@ EMFV_POPUP_AUTO_TYPE(filter_type_current, emfv_popup_filter_mlist, AUTO_MLIST) /* TODO: Move some of these to be 'standard' menu's */ -static EMPopupItem emfv_popup_menu[] = { - { EM_POPUP_ITEM, "00.emfv.00", N_("_Open"), G_CALLBACK(emfv_popup_open), NULL, NULL, 0 }, - { EM_POPUP_ITEM, "00.emfv.01", N_("_Edit as New Message..."), G_CALLBACK(emfv_popup_edit), NULL, NULL, EM_POPUP_SELECT_EDIT }, - { EM_POPUP_ITEM, "00.emfv.02", N_("_Save As..."), G_CALLBACK(emfv_popup_saveas), NULL, "stock_save-as", 0 }, - { EM_POPUP_ITEM, "00.emfv.03", N_("_Print"), G_CALLBACK(emfv_popup_print), NULL, "stock_print", 0 }, - - { EM_POPUP_BAR, "10.emfv" }, - { EM_POPUP_ITEM, "10.emfv.00", N_("_Reply to Sender"), G_CALLBACK(emfv_popup_reply_sender), NULL, "stock_mail-reply", EM_POPUP_SELECT_ONE }, - { EM_POPUP_ITEM, "10.emfv.01", N_("Reply to _List"), G_CALLBACK(emfv_popup_reply_list), NULL, NULL, EM_POPUP_SELECT_ONE|EM_POPUP_SELECT_MAILING_LIST }, - { EM_POPUP_ITEM, "10.emfv.02", N_("Reply to _All"), G_CALLBACK(emfv_popup_reply_all), NULL, "stock_mail-reply-to-all", EM_POPUP_SELECT_ONE }, - { EM_POPUP_ITEM, "10.emfv.03", N_("_Forward"), G_CALLBACK(emfv_popup_forward), NULL, "stock_mail-forward", EM_POPUP_SELECT_MANY }, - - { EM_POPUP_BAR, "20.emfv", NULL, NULL, NULL, NULL, EM_POPUP_SELECT_FLAG_FOLLOWUP|EM_POPUP_SELECT_FLAG_COMPLETED|EM_POPUP_SELECT_FLAG_CLEAR }, - { EM_POPUP_ITEM, "20.emfv.00", N_("Follo_w Up..."), G_CALLBACK(emfv_popup_flag_followup), NULL, "stock_mail-flag-for-followup", EM_POPUP_SELECT_FLAG_FOLLOWUP }, - { EM_POPUP_ITEM, "20.emfv.01", N_("Fla_g Completed"), G_CALLBACK(emfv_popup_flag_completed), NULL, NULL, EM_POPUP_SELECT_FLAG_COMPLETED }, - { EM_POPUP_ITEM, "20.emfv.02", N_("Cl_ear Flag"), G_CALLBACK(emfv_popup_flag_clear), NULL, NULL, EM_POPUP_SELECT_FLAG_CLEAR }, - - { EM_POPUP_BAR, "30.emfv" }, - { EM_POPUP_ITEM, "30.emfv.00", N_("Mar_k as Read"), G_CALLBACK(emfv_popup_mark_read), NULL, "stock_mail-open", EM_POPUP_SELECT_MARK_READ }, - { EM_POPUP_ITEM, "30.emfv.01", N_("Mark as _Unread"), G_CALLBACK(emfv_popup_mark_unread), NULL, "stock_mail-unread", EM_POPUP_SELECT_MARK_UNREAD }, - { EM_POPUP_ITEM, "30.emfv.02", N_("Mark as _Important"), G_CALLBACK(emfv_popup_mark_important), NULL, "stock_mail-priority-high", EM_POPUP_SELECT_MARK_IMPORTANT }, - { EM_POPUP_ITEM, "30.emfv.03", N_("_Mark as Unimportant"), G_CALLBACK(emfv_popup_mark_unimportant), NULL, NULL, EM_POPUP_SELECT_MARK_UNIMPORTANT }, - { EM_POPUP_ITEM, "30.emfv.04", N_("Mark as _Junk"), G_CALLBACK(emfv_popup_mark_junk), NULL, "stock_spam", EM_POPUP_SELECT_MARK_JUNK }, - { EM_POPUP_ITEM, "30.emfv.05", N_("Mark as _Not Junk"), G_CALLBACK(emfv_popup_mark_nojunk), NULL, "stock_not-spam", EM_POPUP_SELECT_MARK_NOJUNK }, - - { EM_POPUP_BAR, "40.emfv" }, - { EM_POPUP_ITEM, "40.emfv.00", N_("_Delete"), G_CALLBACK(emfv_popup_delete), NULL, "stock_delete", EM_POPUP_SELECT_DELETE }, - { EM_POPUP_ITEM, "40.emfv.01", N_("U_ndelete"), G_CALLBACK(emfv_popup_undelete), NULL, "stock_undelete", EM_POPUP_SELECT_UNDELETE }, - - { EM_POPUP_BAR, "50.emfv" }, - { EM_POPUP_ITEM, "50.emfv.00", N_("Mo_ve to Folder..."), G_CALLBACK(emfv_popup_move) }, - { EM_POPUP_ITEM, "50.emfv.01", N_("_Copy to Folder..."), G_CALLBACK(emfv_popup_copy) }, - - { EM_POPUP_BAR, "60.label" }, - { EM_POPUP_SUBMENU, "60.label.00", N_("Label") }, - { EM_POPUP_IMAGE, "60.label.00/00.label", N_("None"), G_CALLBACK(emfv_popup_label_clear) }, - { EM_POPUP_BAR, "60.label.00/00.label.00" }, - - { EM_POPUP_BAR, "70.emfv", NULL, NULL, NULL, NULL, EM_POPUP_SELECT_ADD_SENDER }, - { EM_POPUP_ITEM, "70.emfv.00", N_("Add Sender to Address_book"), G_CALLBACK(emfv_popup_add_sender), NULL, NULL, EM_POPUP_SELECT_ADD_SENDER }, - - { EM_POPUP_BAR, "80.emfv" }, - { EM_POPUP_ITEM, "80.emfv.00", N_("Appl_y Filters"), G_CALLBACK(emfv_popup_apply_filters), NULL, "stock_mail-filters-apply" }, - { EM_POPUP_ITEM, "80.emfv.01", N_("F_ilter Junk"), G_CALLBACK(emfv_popup_filter_junk), NULL, "stock_spam" }, - - { EM_POPUP_BAR, "90.filter", NULL, NULL, NULL, NULL, EM_POPUP_SELECT_ONE }, - { EM_POPUP_SUBMENU, "90.filter.00", N_("Crea_te Rule From Message"), NULL, NULL, NULL, EM_POPUP_SELECT_ONE }, - { EM_POPUP_ITEM, "90.filter.00/00.00", N_("VFolder on _Subject"), G_CALLBACK(emfv_popup_vfolder_subject), NULL, NULL, EM_POPUP_SELECT_ONE }, - { EM_POPUP_ITEM, "90.filter.00/00.01", N_("VFolder on Se_nder"), G_CALLBACK(emfv_popup_vfolder_sender), NULL, NULL, EM_POPUP_SELECT_ONE }, - { EM_POPUP_ITEM, "90.filter.00/00.02", N_("VFolder on _Recipients"), G_CALLBACK(emfv_popup_vfolder_recipients), NULL, NULL, EM_POPUP_SELECT_ONE }, - { EM_POPUP_ITEM, "90.filter.00/00.03", N_("VFolder on Mailing _List"), - G_CALLBACK(emfv_popup_vfolder_mlist), NULL, NULL, EM_POPUP_SELECT_ONE|EM_POPUP_SELECT_MAILING_LIST }, - - { EM_POPUP_BAR, "90.filter.00/10", NULL, NULL, NULL, NULL, EM_POPUP_SELECT_ONE }, - { EM_POPUP_ITEM, "90.filter.00/10.00", N_("Filter on Sub_ject"), G_CALLBACK(emfv_popup_filter_subject), NULL, NULL, EM_POPUP_SELECT_ONE }, - { EM_POPUP_ITEM, "90.filter.00/10.01", N_("Filter on Sen_der"), G_CALLBACK(emfv_popup_filter_sender), NULL, NULL, EM_POPUP_SELECT_ONE }, - { EM_POPUP_ITEM, "90.filter.00/10.02", N_("Filter on Re_cipients"), G_CALLBACK(emfv_popup_filter_recipients), NULL, NULL, EM_POPUP_SELECT_ONE }, - { EM_POPUP_ITEM, "90.filter.00/10.03", N_("Filter on _Mailing List"), - G_CALLBACK(emfv_popup_filter_mlist), NULL, NULL, EM_POPUP_SELECT_ONE|EM_POPUP_SELECT_MAILING_LIST }, +static EPopupItem emfv_popup_menu[] = { + { E_POPUP_ITEM, "00.emfv.00", N_("_Open"), emfv_popup_open, NULL, NULL, 0 }, + { E_POPUP_ITEM, "00.emfv.01", N_("_Edit as New Message..."), emfv_popup_edit, NULL, NULL, EM_POPUP_SELECT_EDIT }, + { E_POPUP_ITEM, "00.emfv.02", N_("_Save As..."), emfv_popup_saveas, NULL, "stock_save-as", 0 }, + { E_POPUP_ITEM, "00.emfv.03", N_("_Print"), emfv_popup_print, NULL, "stock_print", 0 }, + + { E_POPUP_BAR, "10.emfv" }, + { E_POPUP_ITEM, "10.emfv.00", N_("_Reply to Sender"), emfv_popup_reply_sender, NULL, "stock_mail-reply", EM_POPUP_SELECT_ONE }, + { E_POPUP_ITEM, "10.emfv.01", N_("Reply to _List"), emfv_popup_reply_list, NULL, NULL, EM_POPUP_SELECT_ONE|EM_POPUP_SELECT_MAILING_LIST }, + { E_POPUP_ITEM, "10.emfv.02", N_("Reply to _All"), emfv_popup_reply_all, NULL, "stock_mail-reply-to-all", EM_POPUP_SELECT_ONE }, + { E_POPUP_ITEM, "10.emfv.03", N_("_Forward"), emfv_popup_forward, NULL, "stock_mail-forward", EM_POPUP_SELECT_MANY }, + + { E_POPUP_BAR, "20.emfv", NULL, NULL, NULL, NULL, EM_POPUP_SELECT_FLAG_FOLLOWUP|EM_POPUP_SELECT_FLAG_COMPLETED|EM_POPUP_SELECT_FLAG_CLEAR }, + { E_POPUP_ITEM, "20.emfv.00", N_("Follo_w Up..."), emfv_popup_flag_followup, NULL, "stock_mail-flag-for-followup", EM_POPUP_SELECT_FLAG_FOLLOWUP }, + { E_POPUP_ITEM, "20.emfv.01", N_("Fla_g Completed"), emfv_popup_flag_completed, NULL, NULL, EM_POPUP_SELECT_FLAG_COMPLETED }, + { E_POPUP_ITEM, "20.emfv.02", N_("Cl_ear Flag"), emfv_popup_flag_clear, NULL, NULL, EM_POPUP_SELECT_FLAG_CLEAR }, + + { E_POPUP_BAR, "30.emfv" }, + { E_POPUP_ITEM, "30.emfv.00", N_("Mar_k as Read"), emfv_popup_mark_read, NULL, "stock_mail-open", EM_POPUP_SELECT_MARK_READ }, + { E_POPUP_ITEM, "30.emfv.01", N_("Mark as _Unread"), emfv_popup_mark_unread, NULL, "stock_mail-unread", EM_POPUP_SELECT_MARK_UNREAD }, + { E_POPUP_ITEM, "30.emfv.02", N_("Mark as _Important"), emfv_popup_mark_important, NULL, "stock_mail-priority-high", EM_POPUP_SELECT_MARK_IMPORTANT }, + { E_POPUP_ITEM, "30.emfv.03", N_("_Mark as Unimportant"), emfv_popup_mark_unimportant, NULL, NULL, EM_POPUP_SELECT_MARK_UNIMPORTANT }, + { E_POPUP_ITEM, "30.emfv.04", N_("Mark as _Junk"), emfv_popup_mark_junk, NULL, "stock_spam", EM_POPUP_SELECT_MARK_JUNK }, + { E_POPUP_ITEM, "30.emfv.05", N_("Mark as _Not Junk"), emfv_popup_mark_nojunk, NULL, "stock_not-spam", EM_POPUP_SELECT_MARK_NOJUNK }, + + { E_POPUP_BAR, "40.emfv" }, + { E_POPUP_ITEM, "40.emfv.00", N_("_Delete"), emfv_popup_delete, NULL, "stock_delete", EM_POPUP_SELECT_DELETE }, + { E_POPUP_ITEM, "40.emfv.01", N_("U_ndelete"), emfv_popup_undelete, NULL, "stock_undelete", EM_POPUP_SELECT_UNDELETE }, + + { E_POPUP_BAR, "50.emfv" }, + { E_POPUP_ITEM, "50.emfv.00", N_("Mo_ve to Folder..."), emfv_popup_move }, + { E_POPUP_ITEM, "50.emfv.01", N_("_Copy to Folder..."), emfv_popup_copy }, + + { E_POPUP_BAR, "60.label" }, + { E_POPUP_SUBMENU, "60.label.00", N_("Label") }, + { E_POPUP_IMAGE, "60.label.00/00.label", N_("None"), emfv_popup_label_clear }, + { E_POPUP_BAR, "60.label.00/00.label.00" }, + + { E_POPUP_BAR, "70.emfv", NULL, NULL, NULL, NULL, EM_POPUP_SELECT_ADD_SENDER }, + { E_POPUP_ITEM, "70.emfv.00", N_("Add Sender to Address_book"), emfv_popup_add_sender, NULL, NULL, EM_POPUP_SELECT_ADD_SENDER }, + + { E_POPUP_BAR, "80.emfv" }, + { E_POPUP_ITEM, "80.emfv.00", N_("Appl_y Filters"), emfv_popup_apply_filters, NULL, "stock_mail-filters-apply" }, + { E_POPUP_ITEM, "80.emfv.01", N_("F_ilter Junk"), emfv_popup_filter_junk, NULL, "stock_spam" }, + + { E_POPUP_BAR, "90.filter", NULL, NULL, NULL, NULL, EM_POPUP_SELECT_ONE }, + { E_POPUP_SUBMENU, "90.filter.00", N_("Crea_te Rule From Message"), NULL, NULL, NULL, EM_POPUP_SELECT_ONE }, + { E_POPUP_ITEM, "90.filter.00/00.00", N_("VFolder on _Subject"), emfv_popup_vfolder_subject, NULL, NULL, EM_POPUP_SELECT_ONE }, + { E_POPUP_ITEM, "90.filter.00/00.01", N_("VFolder on Se_nder"), emfv_popup_vfolder_sender, NULL, NULL, EM_POPUP_SELECT_ONE }, + { E_POPUP_ITEM, "90.filter.00/00.02", N_("VFolder on _Recipients"), emfv_popup_vfolder_recipients, NULL, NULL, EM_POPUP_SELECT_ONE }, + { E_POPUP_ITEM, "90.filter.00/00.03", N_("VFolder on Mailing _List"), + emfv_popup_vfolder_mlist, NULL, NULL, EM_POPUP_SELECT_ONE|EM_POPUP_SELECT_MAILING_LIST }, + + { E_POPUP_BAR, "90.filter.00/10", NULL, NULL, NULL, NULL, EM_POPUP_SELECT_ONE }, + { E_POPUP_ITEM, "90.filter.00/10.00", N_("Filter on Sub_ject"), emfv_popup_filter_subject, NULL, NULL, EM_POPUP_SELECT_ONE }, + { E_POPUP_ITEM, "90.filter.00/10.01", N_("Filter on Sen_der"), emfv_popup_filter_sender, NULL, NULL, EM_POPUP_SELECT_ONE }, + { E_POPUP_ITEM, "90.filter.00/10.02", N_("Filter on Re_cipients"), emfv_popup_filter_recipients, NULL, NULL, EM_POPUP_SELECT_ONE }, + { E_POPUP_ITEM, "90.filter.00/10.03", N_("Filter on _Mailing List"), + emfv_popup_filter_mlist, NULL, NULL, EM_POPUP_SELECT_ONE|EM_POPUP_SELECT_MAILING_LIST }, }; static void -emfv_popup_labels_free(void *data) +emfv_popup_labels_free(EPopup *ep, GSList *l, void *data) { - GSList *l = data; - while (l) { GSList *n = l->next; - struct _emfv_label_item *item = l->data; + EPopupItem *item = l->data; - g_free(item->item.path); + g_free(item->path); g_free(item); g_slist_free_1(l); l = n; } } + +static void +emfv_popup_items_free(EPopup *ep, GSList *items, void *data) +{ + g_slist_free(items); +} static void emfv_popup(EMFolderView *emfv, GdkEvent *event) @@ -979,37 +1005,31 @@ emfv_popup(EMFolderView *emfv, GdkEvent *event) GSList *menus = NULL, *l, *label_list = NULL; GtkMenu *menu; EMPopup *emp; - EMPopupTarget *target; + EMPopupTargetSelect *target; int i; emp = em_popup_new("com.ximian.mail.folderview.popup.select"); - target = em_folder_view_get_popup_target(emfv); + target = em_folder_view_get_popup_target(emfv, emp); - for (i=0;i<sizeof(emfv_popup_menu)/sizeof(emfv_popup_menu[0]);i++) { - EMPopupItem *item = &emfv_popup_menu[i]; + for (i=0;i<sizeof(emfv_popup_menu)/sizeof(emfv_popup_menu[0]);i++) + menus = g_slist_prepend(menus, &emfv_popup_menu[i]); - item->activate_data = emfv; - menus = g_slist_prepend(menus, item); - } - - em_popup_add_items(emp, menus, (GDestroyNotify)g_slist_free); + e_popup_add_items((EPopup *)emp, menus, emfv_popup_items_free, emfv); i = 1; for (l = mail_config_get_labels(); l; l = l->next) { - struct _emfv_label_item *item; + EPopupItem *item; MailConfigLabel *label = l->data; GdkPixmap *pixmap; GdkColor colour; GdkGC *gc; item = g_malloc0(sizeof(*item)); - item->item.type = EM_POPUP_IMAGE; - item->item.path = g_strdup_printf("60.label.00/00.label.%02d", i++); - item->item.label = label->name; - item->item.activate = G_CALLBACK(emfv_popup_label_set); - item->item.activate_data = item; - item->emfv = emfv; - item->label = label->tag; + item->type = E_POPUP_IMAGE; + item->path = g_strdup_printf("60.label.00/00.label.%02d", i++); + item->label = label->name; + item->activate = emfv_popup_label_set; + item->user_data = label->tag; gdk_color_parse(label->colour, &colour); gdk_color_alloc(gdk_colormap_get_system(), &colour); @@ -1020,15 +1040,15 @@ emfv_popup(EMFolderView *emfv, GdkEvent *event) gdk_draw_rectangle(pixmap, gc, TRUE, 0, 0, 16, 16); gdk_gc_unref(gc); - item->item.image = gtk_image_new_from_pixmap(pixmap, NULL); - gtk_widget_show(item->item.image); + item->image = gtk_image_new_from_pixmap(pixmap, NULL); + gtk_widget_show(item->image); label_list = g_slist_prepend(label_list, item); } - em_popup_add_items(emp, label_list, emfv_popup_labels_free); + e_popup_add_items((EPopup *)emp, label_list, emfv_popup_labels_free, emfv); - menu = em_popup_create_menu_once(emp, target, target->mask, target->mask); + menu = e_popup_create_menu_once((EPopup *)emp, (EPopupTarget *)target, target->target.mask, target->target.mask); if (event == NULL || event->type == GDK_KEY_PRESS) { /* FIXME: menu pos function */ @@ -1047,7 +1067,7 @@ emfv_popup(EMFolderView *emfv, GdkEvent *event) static void \ from(BonoboUIComponent *uid, void *data, const char *path) \ { \ - to(NULL, (EMFolderView *)data); \ + to(NULL, NULL, data); \ } EMFV_MAP_CALLBACK(emfv_add_sender_addressbook, emfv_popup_add_sender) @@ -1619,15 +1639,31 @@ emfv_enable_menus(EMFolderView *emfv) guint32 disable_mask; GString *name; GSList *l; - EMPopupTarget *t; if (emfv->uic == NULL) return; + { + if (emfv->menu) { + if (emfv->folder) { + EMMenuTargetSelect *t; + + t = em_menu_target_new_select(emfv->menu, emfv->folder, emfv->folder_uri, message_list_get_selected(emfv->list)); + e_menu_update_target((EMenu *)emfv->menu, t); + } else { + e_menu_update_target((EMenu *)emfv->menu, NULL); + } + } + } + if (emfv->folder) { - t = em_folder_view_get_popup_target(emfv); - disable_mask = t->mask; - em_popup_target_free(t); + EMPopup *emp = em_popup_new("dummy"); + EMPopupTargetSelect *t; + + t = em_folder_view_get_popup_target(emfv, emp); + disable_mask = t->target.mask; + e_popup_target_free((EPopup *)emp, t); + g_object_unref(emp); } else { disable_mask = ~0; } @@ -1720,6 +1756,9 @@ emfv_activate(EMFolderView *emfv, BonoboUIComponent *uic, int act) { struct _EMFolderViewPrivate *p = emfv->priv; + if (emfv->menu) + e_menu_activate((EMenu *)emfv->menu, uic, act); + if (act) { em_format_mode_t style; gboolean state; @@ -1856,29 +1895,29 @@ int em_folder_view_print(EMFolderView *emfv, int preview) return 0; } -EMPopupTarget * -em_folder_view_get_popup_target(EMFolderView *emfv) +EMPopupTargetSelect * +em_folder_view_get_popup_target(EMFolderView *emfv, EMPopup *emp) { - EMPopupTarget *t; + EMPopupTargetSelect *t; - t = em_popup_target_new_select(emfv->folder, emfv->folder_uri, message_list_get_selected(emfv->list)); - t->widget = (GtkWidget *)emfv; + t = em_popup_target_new_select(emp, emfv->folder, emfv->folder_uri, message_list_get_selected(emfv->list)); + t->target.widget = (GtkWidget *)emfv; if (emfv->list->threaded) - t->mask &= ~EM_FOLDER_VIEW_SELECT_THREADED; + t->target.mask &= ~EM_FOLDER_VIEW_SELECT_THREADED; if (message_list_hidden(emfv->list) != 0) - t->mask &= ~EM_FOLDER_VIEW_SELECT_HIDDEN; + t->target.mask &= ~EM_FOLDER_VIEW_SELECT_HIDDEN; if (message_list_can_select(emfv->list, MESSAGE_LIST_SELECT_NEXT, 0, 0)) - t->mask &= ~EM_FOLDER_VIEW_SELECT_NEXT_MSG; + t->target.mask &= ~EM_FOLDER_VIEW_SELECT_NEXT_MSG; if (message_list_can_select(emfv->list, MESSAGE_LIST_SELECT_PREVIOUS, 0, 0)) - t->mask &= ~EM_FOLDER_VIEW_SELECT_PREV_MSG; + t->target.mask &= ~EM_FOLDER_VIEW_SELECT_PREV_MSG; /* See bug #54770 */ if (!emfv->hide_deleted) - t->mask &= ~EM_POPUP_SELECT_DELETE; + t->target.mask &= ~EM_POPUP_SELECT_DELETE; return t; } @@ -2092,38 +2131,32 @@ emfv_format_link_clicked(EMFormatHTMLDisplay *efhd, const char *uri, EMFolderVie } } -struct _EMFVPopupItem { - EMPopupItem item; - - EMFolderView *emfv; - char *uri; -}; - static void -emp_uri_popup_link_copy(GtkWidget *w, struct _EMFVPopupItem *item) +emp_uri_popup_link_copy(EPopup *ep, EPopupItem *pitem, void *data) { - struct _EMFolderViewPrivate *p = item->emfv->priv; + EMFolderView *emfv = data; + struct _EMFolderViewPrivate *p = emfv->priv; g_free(p->selection_uri); - p->selection_uri = g_strdup(item->uri); + p->selection_uri = g_strdup(pitem->user_data); gtk_selection_owner_set(p->invisible, GDK_SELECTION_PRIMARY, gtk_get_current_event_time()); gtk_selection_owner_set(p->invisible, GDK_SELECTION_CLIPBOARD, gtk_get_current_event_time()); } -static struct _EMFVPopupItem emfv_uri_popups[] = { - { { EM_POPUP_ITEM, "00.uri.01", N_("_Copy Link Location"), G_CALLBACK(emp_uri_popup_link_copy), NULL, NULL, EM_POPUP_URI_NOT_MAILTO }, }, +static EPopupItem emfv_uri_popups[] = { + { E_POPUP_ITEM, "00.uri.01", N_("_Copy Link Location"), emp_uri_popup_link_copy, NULL, NULL, EM_POPUP_URI_NOT_MAILTO }, }; static void -emfv_uri_popup_free(GSList *list) +emfv_uri_popup_free(EPopup *ep, GSList *list, void *data) { while (list) { GSList *n = list->next; - struct _EMFVPopupItem *item = list->data; + struct _EPopupItem *item = list->data; - g_free(item->uri); - g_object_unref(item->emfv); + g_free(item->user_data); + item->user_data = NULL; g_slist_free_1(list); list = n; @@ -2134,7 +2167,7 @@ static int emfv_format_popup_event(EMFormatHTMLDisplay *efhd, GdkEventButton *event, const char *uri, CamelMimePart *part, EMFolderView *emfv) { EMPopup *emp; - EMPopupTarget *target; + EPopupTarget *target; GtkMenu *menu; if (uri == NULL && part == NULL) { @@ -2153,24 +2186,23 @@ emfv_format_popup_event(EMFormatHTMLDisplay *efhd, GdkEventButton *event, const emp = em_popup_new("com.ximian.mail.folderview.popup.uri"); if (part) - target = em_popup_target_new_part(part, NULL); + target = (EPopupTarget *)em_popup_target_new_part(emp, part, NULL); else { GSList *menus = NULL; int i; + EMPopupTargetURI *t; - target = em_popup_target_new_uri(uri); + t = em_popup_target_new_uri(emp, uri); + target = (EPopupTarget *)t; for (i=0;i<sizeof(emfv_uri_popups)/sizeof(emfv_uri_popups[0]);i++) { - emfv_uri_popups[i].item.activate_data = &emfv_uri_popups[i]; - emfv_uri_popups[i].emfv = emfv; - g_object_ref(emfv); - emfv_uri_popups[i].uri = g_strdup(target->data.uri); + emfv_uri_popups[i].user_data = g_strdup(t->uri); menus = g_slist_prepend(menus, &emfv_uri_popups[i]); } - em_popup_add_items(emp, menus, (GDestroyNotify)emfv_uri_popup_free); + e_popup_add_items((EPopup *)emp, menus, emfv_uri_popup_free, emfv); } - menu = em_popup_create_menu_once(emp, target, target->mask, target->mask); + menu = e_popup_create_menu_once((EPopup *)emp, target, target->mask, target->mask); gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event->button, event->time); return TRUE; diff --git a/mail/em-folder-view.h b/mail/em-folder-view.h index 3cf9586bb4..a6ece9fcb1 100644 --- a/mail/em-folder-view.h +++ b/mail/em-folder-view.h @@ -75,6 +75,9 @@ struct _EMFolderView { GSList *ui_files; /* const char * list, TODO: should this be on class? */ const char *ui_app_name; + /* used to manage some menus, particularly plugins */ + struct _EMMenu *menu; + /* for proxying jobs to main or other threads */ struct _MailAsyncEvent *async; @@ -119,7 +122,7 @@ GtkWidget *em_folder_view_new(void); #define em_folder_view_set_folder_uri(emfv, uri) EM_FOLDER_VIEW_GET_CLASS (emfv)->set_folder_uri((emfv), (uri)) #define em_folder_view_set_message(emfv, uid, nomarkseen) EM_FOLDER_VIEW_GET_CLASS (emfv)->set_message((emfv), (uid), (nomarkseen)) -struct _EMPopupTarget *em_folder_view_get_popup_target(EMFolderView *emfv); +EMPopupTargetSelect *em_folder_view_get_popup_target(EMFolderView *emfv, EMPopup *emp); int em_folder_view_mark_selected(EMFolderView *emfv, guint32 mask, guint32 set); int em_folder_view_open_selected(EMFolderView *emfv); diff --git a/mail/em-format-hook.c b/mail/em-format-hook.c new file mode 100644 index 0000000000..c62e75bb67 --- /dev/null +++ b/mail/em-format-hook.c @@ -0,0 +1,270 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: Michael Zucchi <notzed@ximian.com> + * + * Copyright 2004 Ximian, Inc. (www.ximian.com) + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> +#include <stdlib.h> + +#include <glib.h> + +#include "em-format-hook.h" + +#include <e-util/e-icon-factory.h> + +#include <libgnome/gnome-i18n.h> + + +/* class name -> klass map for EMFormat and subclasses */ +static GHashTable *emfh_types; + +/* ********************************************************************** */ + +/* Mail formatter handler plugin */ + +/* + <hook class="com.novell.evolution.mail.format:1.0"> + <group id="EMFormatHTML"> + <item flags="inline,inline_disposition" + mime_type="text/vcard" + format="format_vcard"/> + </group> + </hook> + +*/ + +static void *emfh_parent_class; +#define emfh ((EMFormatHook *)eph) + +static const EPluginHookTargetKey emfh_flag_map[] = { + { "inline", EM_FORMAT_HANDLER_INLINE }, + { "inline_disposition", EM_FORMAT_HANDLER_INLINE_DISPOSITION }, + { 0 } +}; + +static void +emfh_format_format(EMFormat *md, struct _CamelStream *stream, struct _CamelMimePart *part, const EMFormatHandler *info) +{ + struct _EMFormatHookItem *item = (EMFormatHookItem *)info; + EMFormatHookTarget target = { + md, stream, part, item + }; + + e_plugin_invoke(item->hook->hook.plugin, item->format, &target); +} + +static void +emfh_free_item(struct _EMFormatHookItem *item) +{ + /* FIXME: remove from formatter class */ + + g_free(item->handler.mime_type); + g_free(item->format); + g_free(item); +} + +static void +emfh_free_group(struct _EMFormatHookGroup *group) +{ + g_slist_foreach(group->items, (GFunc)emfh_free_item, NULL); + g_slist_free(group->items); + + g_free(group->id); + g_free(group); +} + +static struct _EMFormatHookItem * +emfh_construct_item(EPluginHook *eph, EMFormatHookGroup *group, xmlNodePtr root) +{ + struct _EMFormatHookItem *item; + + printf(" loading group item\n"); + item = g_malloc0(sizeof(*item)); + + item->handler.mime_type = e_plugin_xml_prop(root, "mime_type"); + item->handler.flags = e_plugin_hook_mask(root, emfh_flag_map, "flags"); + item->format = e_plugin_xml_prop(root, "format"); + + item->handler.handler = emfh_format_format; + item->hook = emfh; + + if (item->handler.mime_type == NULL || item->format == NULL) + goto error; + + printf(" type='%s' format='%s'\n", item->handler.mime_type, item->format); + + return item; +error: + printf("error!\n"); + emfh_free_item(item); + return NULL; +} + +static struct _EMFormatHookGroup * +emfh_construct_group(EPluginHook *eph, xmlNodePtr root) +{ + struct _EMFormatHookGroup *group; + xmlNodePtr node; + + printf(" loading group\n"); + group = g_malloc0(sizeof(*group)); + + group->id = e_plugin_xml_prop(root, "id"); + if (group->id == NULL) + goto error; + + node = root->children; + while (node) { + if (0 == strcmp(node->name, "item")) { + struct _EMFormatHookItem *item; + + item = emfh_construct_item(eph, group, node); + if (item) + group->items = g_slist_append(group->items, item); + } + node = node->next; + } + + return group; +error: + emfh_free_group(group); + return NULL; +} + +static int +emfh_construct(EPluginHook *eph, EPlugin *ep, xmlNodePtr root) +{ + xmlNodePtr node; + + printf("loading format hook\n"); + + if (((EPluginHookClass *)emfh_parent_class)->construct(eph, ep, root) == -1) + return -1; + + node = root->children; + while (node) { + if (strcmp(node->name, "group") == 0) { + struct _EMFormatHookGroup *group; + + group = emfh_construct_group(eph, node); + if (group) { + EMFormatClass *klass; + + if (emfh_types + && (klass = g_hash_table_lookup(emfh_types, group->id))) { + GSList *l = group->items; + + for (;l;l=g_slist_next(l)) { + EMFormatHookItem *item = l->data; + /* TODO: only add handlers if enabled? */ + em_format_class_add_handler(klass, &item->handler); + } + } + /* We don't actually need to keep this around once its set on the class */ + emfh->groups = g_slist_append(emfh->groups, group); + } + } + node = node->next; + } + + eph->plugin = ep; + + return 0; +} + +static void +emfh_enable(EPluginHook *eph, int state) +{ + GSList *g, *l; + EMFormatClass *klass; + + g = emfh->groups; + if (emfh_types == NULL) + return; + + for (;g;g=g_slist_next(g)) { + struct _EMFormatHookGroup *group = g->data; + + klass = g_hash_table_lookup(emfh_types, group->id); + for (l=group->items;l;g=g_slist_next(l)) { + EMFormatHookItem *item = l->data; + + if (state) + em_format_class_add_handler(klass, &item->handler); + else + em_format_class_remove_handler(klass, &item->handler); + } + } +} + +static void +emfh_finalise(GObject *o) +{ + EPluginHook *eph = (EPluginHook *)o; + + g_slist_foreach(emfh->groups, (GFunc)emfh_free_group, NULL); + g_slist_free(emfh->groups); + + ((GObjectClass *)emfh_parent_class)->finalize(o); +} + +static void +emfh_class_init(EPluginHookClass *klass) +{ + ((GObjectClass *)klass)->finalize = emfh_finalise; + klass->construct = emfh_construct; + klass->enable = emfh_enable; + klass->id = "com.novell.evolution.mail.format:1.0"; +} + +GType +em_format_hook_get_type(void) +{ + static GType type = 0; + + if (!type) { + static const GTypeInfo info = { + sizeof(EMFormatHookClass), NULL, NULL, (GClassInitFunc) emfh_class_init, NULL, NULL, + sizeof(EMFormatHook), 0, (GInstanceInitFunc) NULL, + }; + + emfh_parent_class = g_type_class_ref(e_plugin_hook_get_type()); + type = g_type_register_static(e_plugin_hook_get_type(), "EMFormatHook", &info, 0); + } + + return type; +} + +void em_format_hook_register_type(GType type) +{ + EMFormatClass *klass; + + if (emfh_types == NULL) + emfh_types = g_hash_table_new(g_str_hash, g_str_equal); + + printf("registering formatter type '%s'\n", g_type_name(type)); + + klass = g_type_class_ref(type); + g_hash_table_insert(emfh_types, (void *)g_type_name(type), klass); +} diff --git a/mail/em-format-hook.h b/mail/em-format-hook.h new file mode 100644 index 0000000000..20010604f5 --- /dev/null +++ b/mail/em-format-hook.h @@ -0,0 +1,97 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Authors: Michel Zucchi <notzed@ximian.com> + * + * Copyright 2003 Ximian, Inc. (www.ximian.com) + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __EM_FORMAT_HOOK_H__ +#define __EM_FORMAT_HOOK_H__ + +#include <glib-object.h> +#include "e-util/e-msgport.h" +#include "e-util/e-plugin.h" + +#include "em-format.h" + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus */ + +typedef struct _EMFormatHookItem EMFormatHookItem; +typedef struct _EMFormatHookGroup EMFormatHookGroup; +typedef struct _EMFormatHook EMFormatHook; +typedef struct _EMFormatHookClass EMFormatHookClass; + +typedef struct _EMFormatHookTarget EMFormatHookTarget; + +typedef void (*EMFormatHookFunc)(struct _EPlugin *plugin, EMFormatHookTarget *data); + +struct _EMFormatHookTarget { + struct _EMFormat *format; + struct _CamelStream *stream; + struct _CamelMimePart *part; + struct _EMFormatHookItem *item; +}; + +struct _EMFormatHookItem { + EMFormatHandler handler; + + struct _EMFormatHook *hook; /* parent pointer */ + char *format; /* format handler */ +}; + +struct _EMFormatHookGroup { + struct _EMFormatHook *hook; /* parent pointer */ + char *id; /* target formatter id */ + GSList *items; /* items to consider */ +}; + +/** + * struct _EMFormatHook - Mail formatter hook. + * + * @hook: + * @groups: + * + * The Mail formatter hook links all of the plugin formatter hooks + * into the relevent formatter classes. + **/ +struct _EMFormatHook { + EPluginHook hook; + + GSList *groups; +}; + +struct _EMFormatHookClass { + EPluginHookClass hook_class; + + /* which class to add matching items to */ + GHashTable *format_classes; +}; + +GType em_format_hook_get_type(void); + +/* register a type as a possible formatter hook point */ +void em_format_hook_register_type(GType type); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EM_FORMAT_HOOK_H__ */ diff --git a/mail/em-format-html-display.c b/mail/em-format-html-display.c index 96e65e2d5c..e73c4af6f2 100644 --- a/mail/em-format-html-display.c +++ b/mail/em-format-html-display.c @@ -52,12 +52,7 @@ #include <glade/glade.h> #include <libgnomevfs/gnome-vfs-mime-handlers.h> - -#if 0 -#include <libgnomevfs/gnome-vfs-utils.h> -#include <libgnomevfs/gnome-vfs-mime-utils.h> -#include <libgnomevfs/gnome-vfs-mime.h> -#endif +#include <libgnome/gnome-i18n.h> #include <bonobo/bonobo-control-frame.h> #include <bonobo/bonobo-stream-memory.h> @@ -1043,21 +1038,35 @@ static void efhd_format_source(EMFormat *emf, CamelStream *stream, CamelMimePart /* if it hasn't been processed yet, format the attachment */ static void -efhd_attachment_show(GtkWidget *w, struct _attach_puri *info) +efhd_attachment_show(EPopup *ep, EPopupItem *item, void *data) { + struct _attach_puri *info = data; + d(printf("show attachment button called\n")); info->shown = ~info->shown; em_format_set_inline(info->puri.format, info->puri.part_id, info->shown); } -static EMPopupItem efhd_menu_items[] = { - { EM_POPUP_BAR, "05.display", }, - { EM_POPUP_ITEM, "05.display.00", N_("_View Inline"), G_CALLBACK(efhd_attachment_show) }, - { EM_POPUP_ITEM, "05.display.00", N_("_Hide"), G_CALLBACK(efhd_attachment_show) }, +static void +efhd_attachment_button_show(GtkWidget *w, void *data) +{ + efhd_attachment_show(NULL, NULL, data); +} + +static EPopupItem efhd_menu_items[] = { + { E_POPUP_BAR, "05.display", }, + { E_POPUP_ITEM, "05.display.00", N_("_View Inline"), efhd_attachment_show }, + { E_POPUP_ITEM, "05.display.00", N_("_Hide"), efhd_attachment_show }, }; static void +efhd_menu_items_free(EPopup *ep, GSList *items, void *data) +{ + g_slist_free(items); +} + +static void efhd_popup_place_widget(GtkMenu *menu, int *x, int *y, gboolean *push_in, gpointer user_data) { GtkWidget *w = user_data; @@ -1073,8 +1082,8 @@ efhd_attachment_popup(GtkWidget *w, GdkEventButton *event, struct _attach_puri * GtkMenu *menu; GSList *menus = NULL; EMPopup *emp; - EMPopupTarget *target; - EMPopupItem *item; + EMPopupTargetPart *target; + EPopupItem *item; d(printf("attachment popup, button %d\n", event->button)); @@ -1084,22 +1093,20 @@ efhd_attachment_popup(GtkWidget *w, GdkEventButton *event, struct _attach_puri * } emp = em_popup_new("com.ximian.mail.formathtmldisplay.popup.part"); - target = em_popup_target_new_part(info->puri.part, info->handle?info->handle->mime_type:NULL); - target->widget = w; + target = em_popup_target_new_part(emp, info->puri.part, info->handle?info->handle->mime_type:NULL); + target->target.widget = w; /* add our local menus */ if (info->handle) { /* show/hide menus, only if we have an inline handler */ - efhd_menu_items[0].activate_data = info; menus = g_slist_prepend(menus, &efhd_menu_items[0]); item = &efhd_menu_items[info->shown?2:1]; - item->activate_data = info; menus = g_slist_prepend(menus, item); } - em_popup_add_items(emp, menus, (GDestroyNotify)g_slist_free); + e_popup_add_items((EPopup *)emp, menus, efhd_menu_items_free, info); - menu = em_popup_create_menu_once(emp, target, target->mask, target->mask); + menu = e_popup_create_menu_once((EPopup *)emp, (EPopupTarget *)target, target->target.mask, target->target.mask); if (event) gtk_menu_popup(menu, NULL, NULL, NULL, NULL, event->button, event->time); else @@ -1217,7 +1224,7 @@ efhd_attachment_button(EMFormatHTML *efh, GtkHTMLEmbedded *eb, EMFormatHTMLPObje button = gtk_button_new(); if (info->handle) - g_signal_connect(button, "clicked", G_CALLBACK(efhd_attachment_show), info); + g_signal_connect(button, "clicked", G_CALLBACK(efhd_attachment_button_show), info); else { gtk_widget_set_sensitive(button, FALSE); GTK_WIDGET_UNSET_FLAGS(button, GTK_CAN_FOCUS); diff --git a/mail/em-format-html.c b/mail/em-format-html.c index 60baac02d5..6d72ce3f1e 100644 --- a/mail/em-format-html.c +++ b/mail/em-format-html.c @@ -41,9 +41,7 @@ #include <gtkhtml/gtkhtml-stream.h> #include <gtkhtml/htmlengine.h> -#include <libgnomevfs/gnome-vfs-utils.h> -#include <libgnomevfs/gnome-vfs-mime-utils.h> -#include <libgnomevfs/gnome-vfs-mime-handlers.h> +#include <libgnome/gnome-i18n.h> #include <camel/camel-mime-message.h> #include <camel/camel-stream.h> diff --git a/mail/em-format-html.h b/mail/em-format-html.h index 8ad399315a..ae6747dfdc 100644 --- a/mail/em-format-html.h +++ b/mail/em-format-html.h @@ -49,8 +49,32 @@ struct _CamelStream; typedef struct _EMFormatHTMLJob EMFormatHTMLJob; +/** + * struct _EMFormatHTMLJob - A formatting job. + * + * @next: Double linked list header. + * @prev: Double linked list header. + * @format: Set by allocation function. + * @stream: Free for use by caller. + * @puri_level: Set by allocation function. + * @base: Set by allocation function, used to save state. + * @callback: This callback will always be invoked, only once, even if the user + * cancelled the display. So the callback should free any extra data + * it allocated every time it is called. + * @u: Union data, free for caller to use. + * + * This object is used to queue a long-running-task which cannot be + * processed in the primary thread. When its turn comes, the job will + * be de-queued and the @callback invoked to perform its processing, + * restoring various state to match the original state. This is used + * for image loading and other internal tasks. + * + * This object is struct-subclassable. Only em_format_html_job_new() + * may be used to allocate these. + **/ struct _EMFormatHTMLJob { - struct _EMFormatHTMLJob *next, *prev; + struct _EMFormatHTMLJob *next; + struct _EMFormatHTMLJob *prev; EMFormatHTML *format; struct _CamelStream *stream; @@ -75,8 +99,27 @@ typedef struct _EMFormatHTMLPObject EMFormatHTMLPObject; typedef gboolean (*EMFormatHTMLPObjectFunc)(EMFormatHTML *md, struct _GtkHTMLEmbedded *eb, EMFormatHTMLPObject *pobject); +/** + * struct _EMFormatHTMLPObject - Pending object. + * + * @next: Double linked list header. + * @prev: Double linked list header. + * @free: Invoked when the object is no longer needed. + * @format: The parent formatter. + * @classid: The assigned class id as passed to add_pobject(). + * @func: Callback function. + * @part: The part as passed to add_pobject(). + * + * This structure is used to track OBJECT tags which have been + * inserted into the HTML stream. When GtkHTML requests them the + * @func will be invoked to create the embedded widget. + * + * This object is struct-subclassable. Only + * em_format_html_add_pobject() may be used to allocate these. + **/ struct _EMFormatHTMLPObject { - struct _EMFormatHTMLPObject *next, *prev; + struct _EMFormatHTMLPObject *next; + struct _EMFormatHTMLPObject *prev; void (*free)(struct _EMFormatHTMLPObject *); struct _EMFormatHTML *format; @@ -93,6 +136,33 @@ struct _EMFormatHTMLPObject { #define EM_FORMAT_HTML_VPAD "<table cellspacing=0 cellpadding=3><tr><td><a name=\"padding\"></a></td></tr></table>\n" +/** + * struct _EMFormatHTML - HTML formatter object. + * + * @format: + * @priv: + * @html: + * @pending_object_list: + * @headers: + * @text_html_flags: + * @body_colour: + * @text_colour: + * @frame_colour: + * @content_colour: + * @citation_colour: + * @load_http:2: + * @load_http_now:1: + * @mark_citations:1: + * @simple_headers:1: + * @hide_headers:1: + * @show_rupert:1: + * + * Most of these fields are private or read-only. + * + * The base HTML formatter object. This object drives HTML generation + * into a GtkHTML parser. It also handles text to HTML conversion, + * multipart/related objects and inline images. + **/ struct _EMFormatHTML { EMFormat format; diff --git a/mail/em-format-quote.c b/mail/em-format-quote.c index 59f75181f9..88dcfdc7c8 100644 --- a/mail/em-format-quote.c +++ b/mail/em-format-quote.c @@ -35,6 +35,7 @@ #include <camel/camel-url.h> #include <gal/util/e-iconv.h> +#include <libgnome/gnome-i18n.h> #include "em-stripsig-filter.h" #include "em-format-quote.h" @@ -493,10 +494,11 @@ emfq_text_html(EMFormat *emf, CamelStream *stream, CamelMimePart *part, EMFormat em_format_format_text(emf, stream, camel_medium_get_content_object((CamelMedium *)part)); } -static const char *type_remove_table[] = { - "message/external-body", - "multipart/appledouble", -}; +static void +emfq_ignore(EMFormat *emf, CamelStream *stream, CamelMimePart *part, EMFormatHandler *info) +{ + /* NOOP */ +} static EMFormatHandler type_builtin_table[] = { { "text/plain",(EMFormatFunc)emfq_text_plain }, @@ -504,6 +506,8 @@ static EMFormatHandler type_builtin_table[] = { { "text/richtext",(EMFormatFunc)emfq_text_enriched }, { "text/html",(EMFormatFunc)emfq_text_html }, /* { "multipart/related",(EMFormatFunc)emfq_multipart_related },*/ + { "message/external-body", (EMFormatFunc)emfq_ignore }, + { "multipart/appledouble", (EMFormatFunc)emfq_ignore }, }; static void @@ -511,9 +515,6 @@ emfq_builtin_init(EMFormatQuoteClass *efhc) { int i; - for (i = 0; i < sizeof(type_remove_table) / sizeof(type_remove_table[0]); i++) - em_format_class_remove_handler((EMFormatClass *) efhc, type_remove_table[i]); - for (i=0;i<sizeof(type_builtin_table)/sizeof(type_builtin_table[0]);i++) em_format_class_add_handler((EMFormatClass *)efhc, &type_builtin_table[i]); } diff --git a/mail/em-format.c b/mail/em-format.c index c34d66c5a2..39b039e2b6 100644 --- a/mail/em-format.c +++ b/mail/em-format.c @@ -31,6 +31,7 @@ #include <libgnomevfs/gnome-vfs-mime.h> #include <libgnomevfs/gnome-vfs-mime-utils.h> #include <libgnomevfs/gnome-vfs-mime-handlers.h> +#include <libgnome/gnome-i18n.h> #include <e-util/e-msgport.h> #include <camel/camel-url.h> @@ -201,8 +202,10 @@ em_format_get_type(void) * @emfc: EMFormatClass * @info: Callback information. * - * Add a mime type handler to this class. This is only used by implementing - * classes. + * Add a mime type handler to this class. This is only used by + * implementing classes. The @info.old pointer will automatically be + * setup to point to the old hanlder if one was already set. This can + * be used for overrides a fallback. * * When a mime type described by @info is encountered, the callback will * be invoked. Note that @info may be extended by sub-classes if @@ -213,26 +216,36 @@ em_format_get_type(void) void em_format_class_add_handler(EMFormatClass *emfc, EMFormatHandler *info) { + printf("adding format handler to '%s' '%s'\n", g_type_name_from_class((GTypeClass *)emfc), info->mime_type); + info->old = g_hash_table_lookup(emfc->type_handlers, info->mime_type); g_hash_table_insert(emfc->type_handlers, info->mime_type, info); - /* FIXME: do we care? This is really gui stuff */ - /* - if (info->applications == NULL) - info->applications = gnome_vfs_mime_get_short_list_applications(info->mime_type);*/ } - /** * em_format_class_remove_handler: - * @emfc: EMFormatClass - * @mime_type: mime-type of handler to remove - * - * Remove a mime type handler from this class. This is only used by - * implementing classes. + * @emfc: + * @info: + * + * Remove a handler. @info must be a value which was previously + * added. **/ void -em_format_class_remove_handler (EMFormatClass *emfc, const char *mime_type) +em_format_class_remove_handler(EMFormatClass *emfc, EMFormatHandler *info) { - g_hash_table_remove (emfc->type_handlers, mime_type); + EMFormatHandler *current; + + /* TODO: thread issues? */ + + current = g_hash_table_lookup(emfc->type_handlers, info->mime_type); + if (current == info) { + current = info->old; + g_hash_table_insert(emfc->type_handlers, current->mime_type, current); + } else { + while (current && current->old != info) + current = current->old; + g_return_if_fail(current != NULL); + current->old = info->old; + } } /** @@ -312,6 +325,8 @@ em_format_add_puri(EMFormat *emf, size_t size, const char *cid, CamelMimePart *p EMFormatPURI *puri; const char *tmp; + printf("adding puri for part: %s\n", emf->part_id->str); + g_assert(size >= sizeof(*puri)); puri = g_malloc0(size); @@ -425,13 +440,13 @@ em_format_find_visible_puri(EMFormat *emf, const char *uri) EMFormatPURI *pw; struct _EMFormatPURITree *ptree; - d(printf("checking for visible uri '%s'\n", uri)); + (printf("checking for visible uri '%s'\n", uri)); ptree = emf->pending_uri_level; while (ptree) { pw = (EMFormatPURI *)ptree->uri_list.head; while (pw->next) { - d(printf(" pw->uri = '%s' pw->cid = '%s\n", pw->uri?pw->uri:"", pw->cid)); + (printf(" pw->uri = '%s' pw->cid = '%s\n", pw->uri?pw->uri:"", pw->cid)); if ((pw->uri && !strcmp(pw->uri, uri)) || !strcmp(pw->cid, uri)) return pw; pw = pw->next; @@ -468,6 +483,8 @@ emf_clear_puri_node(struct _EMFormatPURITree *node) pw = (EMFormatPURI *)node->uri_list.head; pn = pw->next; while (pn) { + if (pw->free) + pw->free(pw); g_free(pw->uri); g_free(pw->cid); g_free(pw->part_id); diff --git a/mail/em-format.h b/mail/em-format.h index 8cbdc69a1a..ac12853fd2 100644 --- a/mail/em-format.h +++ b/mail/em-format.h @@ -53,25 +53,70 @@ typedef enum _em_format_mode_t { EM_FORMAT_SOURCE, } em_format_mode_t; -/* can be subclassed/extended ... */ +/** + * struct _EMFormatHandler - MIME type handler. + * + * @mime_type: Type this handler handles. + * @handler: The handler callback. + * @flags: Handling flags, see enum _em_format_handler_t. + * @old: The last handler set on this type. Allows overrides to + * fallback to previous implementation. + * + **/ struct _EMFormatHandler { char *mime_type; EMFormatFunc handler; guint32 flags; - GList *applications; /* gnome vfs short-list of applications, do we care? */ + + struct _EMFormatHandler *old; +}; + +/** + * enum _em_format_handler_t - Format handler flags. + * + * @EM_FORMAT_HANDLER_INLINE: This type should be shown expanded + * inline by default. + * @EM_FORMAT_HANDLER_INLINE_DISPOSITION: This type should always be + * shown inline, despite what the Content-Disposition suggests. + * + **/ +enum _em_format_handler_t { + EM_FORMAT_HANDLER_INLINE = 1<<0, + EM_FORMAT_HANDLER_INLINE_DISPOSITION = 1<<1, }; -/* inline by default */ -#define EM_FORMAT_HANDLER_INLINE (1<<0) -/* inline by default, and override content-disposition always */ -#define EM_FORMAT_HANDLER_INLINE_DISPOSITION (1<<1) typedef struct _EMFormatPURI EMFormatPURI; typedef void (*EMFormatPURIFunc)(EMFormat *md, struct _CamelStream *stream, EMFormatPURI *puri); +/** + * struct _EMFormatPURI - Pending URI object. + * + * @next: Double-linked list header. + * @prev: Double-linked list header. + * @free: May be set by allocator and will be called when no longer needed. + * @format: + * @uri: Calculated URI of the part, if the part has one in its + * Content-Location field. + * @cid: The RFC2046 Content-Id of the part. If none is present, a unique value + * is calculated from @part_id. + * @part_id: A unique identifier for each part. + * @func: Callback for when the URI is requested. The callback writes + * its data to the supplied stream. + * @part: + * @use_count: + * + * This is used for multipart/related, and other formatters which may + * need to include a reference to out-of-band data in the content + * stream. + * + * This object may be subclassed as a struct. + **/ struct _EMFormatPURI { - struct _EMFormatPURI *next, *prev; + struct _EMFormatPURI *next; + struct _EMFormatPURI *prev; + void (*free)(struct _EMFormatPURI *p); /* optional callback for freeing user-fields */ struct _EMFormat *format; char *uri; /* will be the location of the part, may be empty */ @@ -84,9 +129,23 @@ struct _EMFormatPURI { unsigned int use_count; /* used by multipart/related to see if it was accessed */ }; -/* used to stack pending uri's for visibility (multipart/related) */ +/** + * struct _EMFormatPURITree - Pending URI visibility tree. + * + * @next: Double-linked list header. + * @prev: Double-linked list header. + * @parent: Parent in tree. + * @uri_list: List of EMFormatPURI objects at this level. + * @children: Child nodes of EMFormatPURITree. + * + * This structure is used internally to form a visibility tree of + * parts in the current formatting stream. This is to implement the + * part resolution rules for RFC2387 to implement multipart/related. + **/ struct _EMFormatPURITree { - struct _EMFormatPURITree *next, *prev, *parent; + struct _EMFormatPURITree *next; + struct _EMFormatPURITree *prev; + struct _EMFormatPURITree *parent; EDList uri_list; EDList children; @@ -102,6 +161,34 @@ struct _EMFormatHeader { #define EM_FORMAT_HEADER_BOLD (1<<0) #define EM_FORMAT_HEADER_LAST (1<<4) /* reserve 4 slots */ +/** + * struct _EMFormat - Mail formatter object. + * + * @parent: + * @priv: + * @message: + * @folder: + * @uid: + * @part_id: + * @header_list: + * @session: + * @base url: + * @snoop_mime_type: + * @valid: + * @valid_parent: + * @inline_table: + * @pending_uri_table: + * @pending_uri_tree: + * @pending_uri_level: + * @mode: + * @charset: + * @default_charset: + * + * Most fields are private or read-only. + * + * This is the base MIME formatter class. It provides no formatting + * itself, but drives most of the basic types, including multipart / * types. + **/ struct _EMFormat { GObject parent; @@ -200,7 +287,7 @@ char *em_format_describe_part(struct _CamelMimePart *part, const char *mimetype) GType em_format_get_type(void); void em_format_class_add_handler(EMFormatClass *emfc, EMFormatHandler *info); -void em_format_class_remove_handler (EMFormatClass *emfc, const char *mime_type); +void em_format_class_remove_handler(EMFormatClass *emfc, EMFormatHandler *info); #define em_format_find_handler(emf, type) ((EMFormatClass *)G_OBJECT_GET_CLASS(emf))->find_handler((emf), (type)) const EMFormatHandler *em_format_fallback_handler(EMFormat *emf, const char *mime_type); diff --git a/mail/em-junk-filter.c b/mail/em-junk-filter.c index 3c9627af66..efc1cfdc3a 100644 --- a/mail/em-junk-filter.c +++ b/mail/em-junk-filter.c @@ -37,6 +37,7 @@ #include <camel/camel-file-utils.h> #include <camel/camel-data-wrapper.h> #include <camel/camel-stream-fs.h> +#include <camel/camel-i18n.h> #include "mail-session.h" #include "em-junk-filter.h" diff --git a/mail/em-mailer-prefs.c b/mail/em-mailer-prefs.c index 0232ff6707..c619aeba97 100644 --- a/mail/em-mailer-prefs.c +++ b/mail/em-mailer-prefs.c @@ -55,6 +55,7 @@ #include <gtk/gtkmenuitem.h> #include "mail-config.h" +#include "em-config.h" static void em_mailer_prefs_class_init (EMMailerPrefsClass *class); static void em_mailer_prefs_init (EMMailerPrefs *dialog); @@ -660,6 +661,42 @@ notify_sound_changed (GtkWidget *widget, EMMailerPrefs *prefs) gconf_client_set_string (prefs->gconf, "/apps/evolution/mail/notify/sound", filename, NULL); } +static GtkWidget * +emmp_widget_glade(EConfig *ec, EConfigItem *item, struct _GtkWidget *parent, struct _GtkWidget *old, void *data) +{ + EMMailerPrefs *prefs = data; + + return glade_xml_get_widget(prefs->gui, item->label); +} + +/* plugin meta-data */ +static EMConfigItem emmp_items[] = { + { E_CONFIG_BOOK, "", "preferences_toplevel", emmp_widget_glade }, + { E_CONFIG_PAGE, "00.general", "vboxGeneral", emmp_widget_glade }, + { E_CONFIG_SECTION, "00.general/00.fonts", "vboxMessageFonts", emmp_widget_glade }, + { E_CONFIG_SECTION, "00.general/10.display", "vboxMessageDisplay", emmp_widget_glade }, + { E_CONFIG_SECTION, "00.general/20.delete", "vboxDeletingMail", emmp_widget_glade }, + { E_CONFIG_SECTION, "00.general/30.newmail", "vboxNewMailNotify", emmp_widget_glade }, + { E_CONFIG_PAGE, "10.html", "vboxHtmlMail", emmp_widget_glade }, + { E_CONFIG_SECTION, "10.html/00.general", "vbox173", emmp_widget_glade }, + { E_CONFIG_SECTION, "10.html/10.images", "vbox190", emmp_widget_glade }, + { E_CONFIG_PAGE, "20.labels", "frameColours", emmp_widget_glade }, + /* this is a table, so we can't use it { E_CONFIG_SECTION, "20.labels/00.labels", "tableColours", emmp_widget_glade }, */ + { E_CONFIG_PAGE, "30.headers", "vboxHeaderTab", emmp_widget_glade }, + /* no subvbox for section { E_CONFIG_PAGE, "30.headers/00.headers", "vbox199", emmp_widget_glade }, */ + { E_CONFIG_PAGE, "40.junk", "vbox161", emmp_widget_glade }, + /* no subvbox for section { E_CONFIG_SECTION, "40.junk/00.general", xxx, emmp_widget_glade } */ + { E_CONFIG_SECTION, "40.junk/10.options", "vbox204", emmp_widget_glade }, +}; + +static void +emmp_free(EConfig *ec, GSList *items, void *data) +{ + /* the prefs data is freed automagically */ + + g_slist_free(items); +} + static void em_mailer_prefs_construct (EMMailerPrefs *prefs) { @@ -673,19 +710,19 @@ em_mailer_prefs_construct (EMMailerPrefs *prefs) GladeXML *gui; gboolean locked; int val, i; - - gui = glade_xml_new (EVOLUTION_GLADEDIR "/mail-config.glade", "preferences_tab", NULL); + EMConfig *ec; + EMConfigTargetPrefs *target; + GSList *l; + + gui = glade_xml_new (EVOLUTION_GLADEDIR "/mail-config.glade", "preferences_toplevel", NULL); prefs->gui = gui; - - /* get our toplevel widget */ - toplevel = glade_xml_get_widget (gui, "toplevel"); - - /* reparent */ - gtk_widget_ref (toplevel); - gtk_container_remove (GTK_CONTAINER (toplevel->parent), toplevel); - gtk_container_add (GTK_CONTAINER (prefs), toplevel); - gtk_widget_unref (toplevel); - + + ec = em_config_new(E_CONFIG_BOOK, "com.novell.evolution.mail.prefs"); + l = NULL; + for (i=0;i<sizeof(emmp_items)/sizeof(emmp_items[0]);i++) + l = g_slist_prepend(l, &emmp_items[i]); + e_config_add_items((EConfig *)ec, l, NULL, NULL, emmp_free, prefs); + /* General tab */ /* Message Display */ @@ -964,6 +1001,12 @@ em_mailer_prefs_construct (EMMailerPrefs *prefs) toggle_button_init (prefs, prefs->sa_local_tests_only, TRUE, "/apps/evolution/mail/junk/sa/local_only", G_CALLBACK (toggle_button_toggled_not)); + + /* get our toplevel widget */ + target = em_config_target_new_prefs(ec, prefs->gconf); + e_config_set_target((EConfig *)ec, (EConfigTarget *)target); + toplevel = e_config_create_widget((EConfig *)ec); + gtk_container_add (GTK_CONTAINER (prefs), toplevel); } GtkWidget * diff --git a/mail/em-menu.c b/mail/em-menu.c new file mode 100644 index 0000000000..79a5564f51 --- /dev/null +++ b/mail/em-menu.c @@ -0,0 +1,338 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Authors: Michael Zucchi <notzed@ximian.com> + * + * Copyright 2004 Ximian, Inc. (www.ximian.com) + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> +#include <stdlib.h> + +#include <glib.h> + +#include <gtk/gtkmenu.h> +#include <gtk/gtkmenuitem.h> +#include <gtk/gtkimagemenuitem.h> +#include <gtk/gtkcheckmenuitem.h> +#include <gtk/gtkradiomenuitem.h> +#include <gtk/gtkseparatormenuitem.h> +#include <gtk/gtklabel.h> +#include <gtk/gtkimage.h> + +#include <libgnome/gnome-url.h> +#include <libgnomevfs/gnome-vfs-mime.h> + +#include "em-menu.h" +#include "e-util/e-msgport.h" +#include <e-util/e-icon-factory.h> +#include "em-utils.h" +#include "em-composer-utils.h" + +#include <camel/camel-store.h> +#include <camel/camel-folder.h> +#include <camel/camel-mime-message.h> +#include <camel/camel-string-utils.h> +#include <camel/camel-mime-utils.h> +#include <camel/camel-mime-part.h> +#include <camel/camel-url.h> + +#include <camel/camel-vee-folder.h> +#include <camel/camel-vtrash-folder.h> + +#include <gconf/gconf.h> +#include <gconf/gconf-client.h> + +#include <gal/util/e-util.h> + +static void emp_standard_menu_factory(EMenu *emp, void *data); + +static GObjectClass *emp_parent; + +static void +emp_init(GObject *o) +{ + /*EMMenu *emp = (EMMenu *)o; */ +} + +static void +emp_finalise(GObject *o) +{ + ((GObjectClass *)emp_parent)->finalize(o); +} + +static void +emp_target_free(EMenu *ep, EMenuTarget *t) +{ + switch (t->type) { + case EM_MENU_TARGET_SELECT: { + EMMenuTargetSelect *s = (EMMenuTargetSelect *)t; + + if (s->folder) + camel_object_unref(s->folder); + g_free(s->uri); + if (s->uids) + em_utils_uids_free(s->uids); + break; } + } + + ((EMenuClass *)emp_parent)->target_free(ep, t); +} + +static void +emp_class_init(GObjectClass *klass) +{ + printf("em menu class init\n"); + + klass->finalize = emp_finalise; + ((EMenuClass *)klass)->target_free = emp_target_free; + + e_menu_class_add_factory((EMenuClass *)klass, NULL, (EMenuFactoryFunc)emp_standard_menu_factory, NULL); +} + +GType +em_menu_get_type(void) +{ + static GType type = 0; + + if (type == 0) { + static const GTypeInfo info = { + sizeof(EMMenuClass), + NULL, NULL, + (GClassInitFunc)emp_class_init, + NULL, NULL, + sizeof(EMMenu), 0, + (GInstanceInitFunc)emp_init + }; + emp_parent = g_type_class_ref(e_menu_get_type()); + type = g_type_register_static(e_menu_get_type(), "EMMenu", &info, 0); + } + + return type; +} + +EMMenu *em_menu_new(const char *menuid) +{ + EMMenu *emp = g_object_new(em_menu_get_type(), 0); + + e_menu_construct(&emp->popup, menuid); + + return emp; +} + +/** + * em_menu_target_new_select: + * @folder: The selection will ref this for the life of it. + * @folder_uri: + * @uids: The selection will free this when done with it. + * + * Create a new selection popup target. + * + * Return value: + **/ +EMMenuTargetSelect * +em_menu_target_new_select(EMMenu *emp, struct _CamelFolder *folder, const char *folder_uri, GPtrArray *uids) +{ + EMMenuTargetSelect *t = e_menu_target_new(&emp->popup, EM_MENU_TARGET_SELECT, sizeof(*t)); + guint32 mask = ~0; + int i; + const char *tmp; + + /* NB: This is identical to em-popup-target-new-select function */ + + t->uids = uids; + t->folder = folder; + t->uri = g_strdup(folder_uri); + + if (folder == NULL) { + t->target.mask = mask; + + return t; + } + + camel_object_ref(folder); + mask &= ~EM_MENU_SELECT_FOLDER; + + if (em_utils_folder_is_sent(folder, folder_uri)) + mask &= ~EM_MENU_SELECT_EDIT; + + if (!(em_utils_folder_is_drafts(folder, folder_uri) + || em_utils_folder_is_outbox(folder, folder_uri)) + && uids->len == 1) + mask &= ~EM_MENU_SELECT_ADD_SENDER; + + if (uids->len == 1) + mask &= ~EM_MENU_SELECT_ONE; + + if (uids->len >= 1) + mask &= ~EM_MENU_SELECT_MANY; + + for (i = 0; i < uids->len; i++) { + CamelMessageInfo *info = camel_folder_get_message_info(folder, uids->pdata[i]); + + if (info == NULL) + continue; + + if (info->flags & CAMEL_MESSAGE_SEEN) + mask &= ~EM_MENU_SELECT_MARK_UNREAD; + else + mask &= ~EM_MENU_SELECT_MARK_READ; + + if (info->flags & CAMEL_MESSAGE_DELETED) + mask &= ~EM_MENU_SELECT_UNDELETE; + else + mask &= ~EM_MENU_SELECT_DELETE; + + if (info->flags & CAMEL_MESSAGE_FLAGGED) + mask &= ~EM_MENU_SELECT_MARK_UNIMPORTANT; + else + mask &= ~EM_MENU_SELECT_MARK_IMPORTANT; + + if (info->flags & CAMEL_MESSAGE_JUNK) + mask &= ~EM_MENU_SELECT_MARK_NOJUNK; + else + mask &= ~EM_MENU_SELECT_MARK_JUNK; + + tmp = camel_tag_get (&info->user_tags, "follow-up"); + if (tmp && *tmp) { + mask &= ~EM_MENU_SELECT_FLAG_CLEAR; + tmp = camel_tag_get(&info->user_tags, "completed-on"); + if (tmp == NULL || *tmp == 0) + mask &= ~EM_MENU_SELECT_FLAG_COMPLETED; + } else + mask &= ~EM_MENU_SELECT_FLAG_FOLLOWUP; + + if (i == 0 && uids->len == 1 + && (tmp = camel_message_info_mlist(info)) + && tmp[0] != 0) + mask &= ~EM_MENU_SELECT_MAILING_LIST; + + camel_folder_free_message_info(folder, info); + } + + t->target.mask = mask; + + return t; +} + +static void +emp_standard_menu_factory(EMenu *emp, void *data) +{ + /* noop */ +} + +/* ********************************************************************** */ + +/* menu plugin handler */ + +/* +<e-plugin + class="com.ximian.mail.plugin.popup:1.0" + id="com.ximian.mail.plugin.popup.item:1.0" + type="shlib" + location="/opt/gnome2/lib/camel/1.0/libcamelimap.so" + name="imap" + description="IMAP4 and IMAP4v1 mail store"> + <hook class="com.ximian.mail.popupMenu:1.0" + handler="HandlePopup"> + <menu id="any" target="select"> + <item + type="item|toggle|radio|image|submenu|bar" + active + path="foo/bar" + label="label" + icon="foo" + mask="select_one" + activate="emp_view_emacs"/> + </menu> + </extension> + +*/ + +static void *emph_parent_class; +#define emph ((EMMenuHook *)eph) + +static const EMenuHookTargetMask emph_select_masks[] = { + { "one", EM_MENU_SELECT_ONE }, + { "many", EM_MENU_SELECT_MANY }, + { "mark_read", EM_MENU_SELECT_MARK_READ }, + { "mark_unread", EM_MENU_SELECT_MARK_UNREAD }, + { "delete", EM_MENU_SELECT_DELETE }, + { "undelete", EM_MENU_SELECT_UNDELETE }, + { "mailing_list", EM_MENU_SELECT_MAILING_LIST }, + { "resend", EM_MENU_SELECT_EDIT }, + { "mark_important", EM_MENU_SELECT_MARK_IMPORTANT }, + { "mark_unimportant", EM_MENU_SELECT_MARK_UNIMPORTANT }, + { "flag_followup", EM_MENU_SELECT_FLAG_FOLLOWUP }, + { "flag_completed", EM_MENU_SELECT_FLAG_COMPLETED }, + { "flag_clear", EM_MENU_SELECT_FLAG_CLEAR }, + { "add_sender", EM_MENU_SELECT_ADD_SENDER }, + { "mark_junk", EM_MENU_SELECT_MARK_JUNK }, + { "mark_nojunk", EM_MENU_SELECT_MARK_NOJUNK }, + { "folder", EM_MENU_SELECT_FOLDER }, + { 0 } +}; + +static const EMenuHookTargetMap emph_targets[] = { + { "select", EM_MENU_TARGET_SELECT, emph_select_masks }, + { 0 } +}; + +static void +emph_finalise(GObject *o) +{ + /*EPluginHook *eph = (EPluginHook *)o;*/ + + ((GObjectClass *)emph_parent_class)->finalize(o); +} + +static void +emph_class_init(EPluginHookClass *klass) +{ + int i; + + ((GObjectClass *)klass)->finalize = emph_finalise; + ((EPluginHookClass *)klass)->id = "com.ximian.evolution.mail.bonobomenu:1.0"; + + for (i=0;emph_targets[i].type;i++) + e_menu_hook_class_add_target_map((EMenuHookClass *)klass, &emph_targets[i]); + + /* FIXME: leaks parent set class? */ + ((EMenuHookClass *)klass)->menu_class = g_type_class_ref(em_menu_get_type()); +} + +GType +em_menu_hook_get_type(void) +{ + static GType type = 0; + + if (!type) { + static const GTypeInfo info = { + sizeof(EMMenuHookClass), NULL, NULL, (GClassInitFunc) emph_class_init, NULL, NULL, + sizeof(EMMenuHook), 0, (GInstanceInitFunc) NULL, + }; + + emph_parent_class = g_type_class_ref(e_menu_hook_get_type()); + type = g_type_register_static(e_menu_hook_get_type(), "EMMenuHook", &info, 0); + } + + return type; +} diff --git a/mail/em-menu.h b/mail/em-menu.h new file mode 100644 index 0000000000..5f9183b860 --- /dev/null +++ b/mail/em-menu.h @@ -0,0 +1,113 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * + * Authors: Michel Zucchi <notzed@ximian.com> + * + * Copyright 2003 Ximian, Inc. (www.ximian.com) + * + * 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; either version 2 of the License, or + * (at your option) any later version. + * + * 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, write to the Free Software + * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA. + * + */ + +#ifndef __EM_MENU_H__ +#define __EM_MENU_H__ + +#include <glib-object.h> + +#include "e-util/e-menu.h" + +#ifdef __cplusplus +extern "C" { +#pragma } +#endif /* __cplusplus */ + +typedef struct _EMMenu EMMenu; +typedef struct _EMMenuClass EMMenuClass; + +/* Current target description */ +/* Types of popup tagets */ +enum _em_menu_target_t { + EM_MENU_TARGET_SELECT, +}; + +/* Flags that describe a TARGET_SELECT */ +enum { + EM_MENU_SELECT_ONE = 1<<1, + EM_MENU_SELECT_MANY = 1<<2, + EM_MENU_SELECT_MARK_READ = 1<<3, + EM_MENU_SELECT_MARK_UNREAD = 1<<4, + EM_MENU_SELECT_DELETE = 1<<5, + EM_MENU_SELECT_UNDELETE = 1<<6, + EM_MENU_SELECT_MAILING_LIST = 1<<7, + EM_MENU_SELECT_EDIT = 1<<8, + EM_MENU_SELECT_MARK_IMPORTANT = 1<<9, + EM_MENU_SELECT_MARK_UNIMPORTANT = 1<<10, + EM_MENU_SELECT_FLAG_FOLLOWUP = 1<<11, + EM_MENU_SELECT_FLAG_COMPLETED = 1<<12, + EM_MENU_SELECT_FLAG_CLEAR = 1<<13, + EM_MENU_SELECT_ADD_SENDER = 1<<14, + EM_MENU_SELECT_MARK_JUNK = 1<<15, + EM_MENU_SELECT_MARK_NOJUNK = 1<<16, + EM_MENU_SELECT_FOLDER = 1<<17, /* do we have any folder at all? */ + EM_MENU_SELECT_LAST = 1<<18 /* reserve 2 slots */ +}; + +typedef struct _EMMenuTargetSelect EMMenuTargetSelect; + +struct _EMMenuTargetSelect { + EMenuTarget target; + struct _CamelFolder *folder; + char *uri; + GPtrArray *uids; +}; + +typedef struct _EMenuItem EMMenuItem; + +/* The object */ +struct _EMMenu { + EMenu popup; + + struct _EMMenuPrivate *priv; +}; + +struct _EMMenuClass { + EMenuClass popup_class; +}; + +GType em_menu_get_type(void); + +EMMenu *em_menu_new(const char *menuid); + +EMMenuTargetSelect *em_menu_target_new_select(EMMenu *emp, struct _CamelFolder *folder, const char *folder_uri, GPtrArray *uids); + +/* ********************************************************************** */ + +typedef struct _EMMenuHook EMMenuHook; +typedef struct _EMMenuHookClass EMMenuHookClass; + +struct _EMMenuHook { + EMenuHook hook; +}; + +struct _EMMenuHookClass { + EMenuHookClass hook_class; +}; + +GType em_menu_hook_get_type(void); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __EM_MENU_H__ */ diff --git a/mail/em-message-browser.c b/mail/em-message-browser.c index 4f3a2aaa2c..98fc1bd319 100644 --- a/mail/em-message-browser.c +++ b/mail/em-message-browser.c @@ -41,6 +41,7 @@ #include "em-format-html-display.h" #include "em-message-browser.h" +#include "em-menu.h" #include "evolution-shell-component-utils.h" /* Pixmap stuff, sigh */ @@ -175,6 +176,8 @@ GtkWidget *em_message_browser_new(void) { EMMessageBrowser *emmb = g_object_new(em_message_browser_get_type(), 0); + ((EMFolderView *)emmb)->menu = em_menu_new("com.novell.evolution.mail.messagebrowser"); + return (GtkWidget *)emmb; } diff --git a/mail/em-popup.c b/mail/em-popup.c index 28e5121c51..8b580e3147 100644 --- a/mail/em-popup.c +++ b/mail/em-popup.c @@ -40,6 +40,7 @@ #include <libgnome/gnome-url.h> #include <libgnomevfs/gnome-vfs-mime.h> +#include <libgnome/gnome-i18n.h> #include "em-popup.h" #include "e-util/e-msgport.h" @@ -63,71 +64,69 @@ #include <gal/util/e-util.h> -static void emp_standard_menu_factory(EMPopup *emp, EMPopupTarget *target, void *data); - -struct _EMPopupFactory { - struct _EMPopupFactory *next, *prev; - - char *menuid; - EMPopupFactoryFunc factory; - void *factory_data; -}; - -struct _menu_node { - struct _menu_node *next, *prev; - - GSList *menu; - GDestroyNotify freefunc; -}; - -struct _EMPopupPrivate { - EDList menus; -}; - -static EDList emp_factories = E_DLIST_INITIALISER(emp_factories); +static void emp_standard_menu_factory(EPopup *emp, void *data); static GObjectClass *emp_parent; static void emp_init(GObject *o) { - EMPopup *emp = (EMPopup *)o; - struct _EMPopupPrivate *p; - - p = emp->priv = g_malloc0(sizeof(struct _EMPopupPrivate)); - - e_dlist_init(&p->menus); + /*EMPopup *emp = (EMPopup *)o; */ } static void emp_finalise(GObject *o) { - EMPopup *emp = (EMPopup *)o; - struct _EMPopupPrivate *p = emp->priv; - struct _menu_node *mnode, *nnode; + ((GObjectClass *)emp_parent)->finalize(o); +} + +static void +emp_target_free(EPopup *ep, EPopupTarget *t) +{ + switch (t->type) { + case EM_POPUP_TARGET_SELECT: { + EMPopupTargetSelect *s = (EMPopupTargetSelect *)t; + + if (s->folder) + camel_object_unref(s->folder); + g_free(s->uri); + if (s->uids) + em_utils_uids_free(s->uids); + break; } + case EM_POPUP_TARGET_URI: { + EMPopupTargetURI *s = (EMPopupTargetURI *)t; - g_free(emp->menuid); + g_free(s->uri); + break; } + case EM_POPUP_TARGET_PART: { + EMPopupTargetPart *s = (EMPopupTargetPart *)t; - mnode = (struct _menu_node *)p->menus.head; - nnode = mnode->next; - while (nnode) { - if (mnode->freefunc) - mnode->freefunc(mnode->menu); + camel_object_unref(s->part); + g_free(s->mime_type); + break; } + case EM_POPUP_TARGET_FOLDER: { + EMPopupTargetFolder *s = (EMPopupTargetFolder *)t; - g_free(mnode); - mnode = nnode; - nnode = nnode->next; - } + g_free(s->uri); + break; } + case EM_POPUP_TARGET_ATTACHMENTS: { + EMPopupTargetAttachments *s = (EMPopupTargetAttachments *)t; - g_free(p); + g_slist_foreach(s->attachments, (GFunc)g_object_unref, NULL); + g_slist_free(s->attachments); + break; } + } - ((GObjectClass *)emp_parent)->finalize(o); + ((EPopupClass *)emp_parent)->target_free(ep, t); } static void emp_class_init(GObjectClass *klass) { klass->finalize = emp_finalise; + ((EPopupClass *)klass)->target_free = emp_target_free; + + e_popup_class_add_factory((EPopupClass *)klass, NULL, emp_standard_menu_factory, NULL); } GType @@ -144,11 +143,8 @@ em_popup_get_type(void) sizeof(EMPopup), 0, (GInstanceInitFunc)emp_init }; - emp_parent = g_type_class_ref(G_TYPE_OBJECT); - type = g_type_register_static(G_TYPE_OBJECT, "EMPopup", &info, 0); - - /* FIXME: this should probably sit somewhere in global setup */ - em_popup_static_add_factory(NULL, (EMPopupFactoryFunc)emp_standard_menu_factory, NULL); + emp_parent = g_type_class_ref(e_popup_get_type()); + type = g_type_register_static(e_popup_get_type(), "EMPopup", &info, 0); } return type; @@ -158,291 +154,12 @@ EMPopup *em_popup_new(const char *menuid) { EMPopup *emp = g_object_new(em_popup_get_type(), 0); - emp->menuid = g_strdup(menuid); + e_popup_construct(&emp->popup, menuid); return emp; } /** - * em_popup_add_items: - * @emp: - * @items: - * @freefunc: - * - * Add new EMPopupItems to the menu's. Any with the same path - * will override previously defined menu items, at menu building - * time. - **/ -void -em_popup_add_items(EMPopup *emp, GSList *items, GDestroyNotify freefunc) -{ - struct _menu_node *node; - - node = g_malloc(sizeof(*node)); - node->menu = items; - node->freefunc = freefunc; - e_dlist_addtail(&emp->priv->menus, (EDListNode *)node); -} - -/** - * em_popup_add_static_items: - * @emp: - * @target: Target of this menu. - * - * Will load up any matching menu items from an installed - * popup factory. If the menuid of @emp is NULL, then this - * has no effect. - * - **/ -void -em_popup_add_static_items(EMPopup *emp, EMPopupTarget *target) -{ - struct _EMPopupFactory *f; - - if (emp->menuid == NULL || target == NULL) - return; - - /* setup the menu itself */ - f = (struct _EMPopupFactory *)emp_factories.head; - while (f->next) { - if (f->menuid == NULL - || !strcmp(f->menuid, emp->menuid)) { - f->factory(emp, target, f->factory_data); - } - f = f->next; - } -} - -static int -emp_cmp(const void *ap, const void *bp) -{ - struct _EMPopupItem *a = *((void **)ap); - struct _EMPopupItem *b = *((void **)bp); - - return strcmp(a->path, b->path); -} - -/** - * em_popup_create: - * @menuitems: - * @hide_mask: used to hide menu items, not sure of it's utility, - * since you could just 'not add them' in the first place. Saves - * copying logic anyway. - * @disable_mask: used to disable menu items. - * - * TEMPORARY code to create a menu from a list of items. - * - * The menu items are merged based on their path element, and - * built into a menu tree. - * - * Return value: - **/ -GtkMenu * -em_popup_create_menu(EMPopup *emp, guint32 hide_mask, guint32 disable_mask) -{ - struct _EMPopupPrivate *p = emp->priv; - struct _menu_node *mnode, *nnode; - GPtrArray *items = g_ptr_array_new(); - GSList *l; - GString *ppath = g_string_new(""); - GtkMenu *topmenu; - GHashTable *menu_hash = g_hash_table_new(g_str_hash, g_str_equal), - *group_hash = g_hash_table_new(g_str_hash, g_str_equal); - /*char *domain = NULL;*/ - int i; - - /* FIXME: need to override old ones with new names */ - mnode = (struct _menu_node *)p->menus.head; - nnode = mnode->next; - while (nnode) { - for (l=mnode->menu; l; l = l->next) - g_ptr_array_add(items, l->data); - mnode = nnode; - nnode = nnode->next; - } - - qsort(items->pdata, items->len, sizeof(items->pdata[0]), emp_cmp); - - topmenu = (GtkMenu *)gtk_menu_new(); - for (i=0;i<items->len;i++) { - GtkWidget *label; - struct _EMPopupItem *item = items->pdata[i]; - GtkMenu *thismenu; - GtkMenuItem *menuitem; - char *tmp; - - /* for bar's, the mask is exclusive or */ - if (item->mask) { - if ((item->type & EM_POPUP_TYPE_MASK) == EM_POPUP_BAR) { - if ((item->mask & hide_mask) == item->mask) - continue; - } else if (item->mask & hide_mask) - continue; - } - - g_string_truncate(ppath, 0); - tmp = strrchr(item->path, '/'); - if (tmp) { - g_string_append_len(ppath, item->path, tmp-item->path); - thismenu = g_hash_table_lookup(menu_hash, ppath->str); - g_assert(thismenu != NULL); - } else { - thismenu = topmenu; - } - - switch (item->type & EM_POPUP_TYPE_MASK) { - case EM_POPUP_ITEM: - if (item->image) { - GdkPixbuf *pixbuf; - GtkWidget *image; - - pixbuf = e_icon_factory_get_icon ((char *)item->image, E_ICON_SIZE_MENU); - image = gtk_image_new_from_pixbuf (pixbuf); - g_object_unref (pixbuf); - - gtk_widget_show(image); - menuitem = (GtkMenuItem *)gtk_image_menu_item_new(); - gtk_image_menu_item_set_image((GtkImageMenuItem *)menuitem, image); - } else { - menuitem = (GtkMenuItem *)gtk_menu_item_new(); - } - break; - case EM_POPUP_TOGGLE: - menuitem = (GtkMenuItem *)gtk_check_menu_item_new(); - gtk_check_menu_item_set_active((GtkCheckMenuItem *)menuitem, item->type & EM_POPUP_ACTIVE); - break; - case EM_POPUP_RADIO: - menuitem = (GtkMenuItem *)gtk_radio_menu_item_new(g_hash_table_lookup(group_hash, ppath->str)); - g_hash_table_insert(group_hash, ppath->str, gtk_radio_menu_item_get_group((GtkRadioMenuItem *)menuitem)); - gtk_check_menu_item_set_active((GtkCheckMenuItem *)menuitem, item->type & EM_POPUP_ACTIVE); - break; - case EM_POPUP_IMAGE: - menuitem = (GtkMenuItem *)gtk_image_menu_item_new(); - gtk_image_menu_item_set_image((GtkImageMenuItem *)menuitem, item->image); - break; - case EM_POPUP_SUBMENU: { - GtkMenu *submenu = (GtkMenu *)gtk_menu_new(); - - g_hash_table_insert(menu_hash, item->path, submenu); - menuitem = (GtkMenuItem *)gtk_menu_item_new(); - gtk_menu_item_set_submenu(menuitem, (GtkWidget *)submenu); - break; } - case EM_POPUP_BAR: - /* TODO: double-bar, end-bar stuff? */ - menuitem = (GtkMenuItem *)gtk_separator_menu_item_new(); - break; - default: - continue; - } - - if (item->label) { - label = gtk_label_new_with_mnemonic(_(item->label)); - gtk_misc_set_alignment((GtkMisc *)label, 0.0, 0.5); - gtk_widget_show(label); - gtk_container_add((GtkContainer *)menuitem, label); - } - - if (item->activate) - g_signal_connect(menuitem, "activate", item->activate, item->activate_data); - - gtk_menu_shell_append((GtkMenuShell *)thismenu, (GtkWidget *)menuitem); - - if (item->mask & disable_mask) - gtk_widget_set_sensitive((GtkWidget *)menuitem, FALSE); - - gtk_widget_show((GtkWidget *)menuitem); - } - - g_string_free(ppath, TRUE); - g_ptr_array_free(items, TRUE); - g_hash_table_destroy(menu_hash); - g_hash_table_destroy(group_hash); - - return topmenu; -} - -static void -emp_popup_done(GtkWidget *w, EMPopup *emp) -{ - gtk_widget_destroy(w); - g_object_unref(emp); -} - -/** - * em_popup_create_menu_once: - * @emp: EMPopup, once the menu is shown, this cannot be - * considered a valid pointer. - * @target: If set, the target of the selection. Static menu - * items will be added. The target will be freed once complete. - * @hide_mask: - * @disable_mask: - * - * Like popup_create_menu, but automatically sets up the menu - * so that it is destroyed once a selection takes place, and - * the EMPopup is unreffed. - * - * Return value: A menu, to popup. - **/ -GtkMenu * -em_popup_create_menu_once(EMPopup *emp, EMPopupTarget *target, guint32 hide_mask, guint32 disable_mask) -{ - GtkMenu *menu; - - if (target) - em_popup_add_static_items(emp, target); - - menu = em_popup_create_menu(emp, hide_mask, disable_mask); - - if (target) - g_signal_connect_swapped(menu, "selection_done", G_CALLBACK(em_popup_target_free), target); - g_signal_connect(menu, "selection_done", G_CALLBACK(emp_popup_done), emp); - - return menu; -} - -/* ********************************************************************** */ - -/** - * em_popup_static_add_factory: - * @menuid: - * @func: - * @data: - * - * Add a popup factory which will be called to add_items() any - * extra menu's if wants to do the current PopupTarget. - * - * TODO: Make the menuid a pattern? - * - * Return value: A handle to the factory. - **/ -EMPopupFactory * -em_popup_static_add_factory(const char *menuid, EMPopupFactoryFunc func, void *data) -{ - struct _EMPopupFactory *f = g_malloc0(sizeof(*f)); - - f->menuid = g_strdup(menuid); - f->factory = func; - f->factory_data = data; - e_dlist_addtail(&emp_factories, (EDListNode *)f); - - return f; -} - -/** - * em_popup_static_remove_factory: - * @f: - * - * Remove a popup factory. - **/ -void -em_popup_static_remove_factory(EMPopupFactory *f) -{ - e_dlist_remove((EDListNode *)f); - g_free(f->menuid); - g_free(f); -} - -/** * em_popup_target_new_select: * @folder: The selection will ref this for the life of it. * @folder_uri: @@ -452,21 +169,20 @@ em_popup_static_remove_factory(EMPopupFactory *f) * * Return value: **/ -EMPopupTarget * -em_popup_target_new_select(struct _CamelFolder *folder, const char *folder_uri, GPtrArray *uids) +EMPopupTargetSelect * +em_popup_target_new_select(EMPopup *emp, struct _CamelFolder *folder, const char *folder_uri, GPtrArray *uids) { - EMPopupTarget *t = g_malloc0(sizeof(*t)); + EMPopupTargetSelect *t = e_popup_target_new(&emp->popup, EM_POPUP_TARGET_SELECT, sizeof(*t)); guint32 mask = ~0; int i; const char *tmp; - t->type = EM_POPUP_TARGET_SELECT; - t->data.select.uids = uids; - t->data.select.folder = folder; - t->data.select.folder_uri = g_strdup(folder_uri); + t->uids = uids; + t->folder = folder; + t->uri = g_strdup(folder_uri); if (folder == NULL) { - t->mask = mask; + t->target.mask = mask; return t; } @@ -531,19 +247,18 @@ em_popup_target_new_select(struct _CamelFolder *folder, const char *folder_uri, camel_folder_free_message_info(folder, info); } - t->mask = mask; + t->target.mask = mask; return t; } -EMPopupTarget * -em_popup_target_new_uri(const char *uri) +EMPopupTargetURI * +em_popup_target_new_uri(EMPopup *emp, const char *uri) { - EMPopupTarget *t = g_malloc0(sizeof(*t)); + EMPopupTargetURI *t = e_popup_target_new(&emp->popup, EM_POPUP_TARGET_URI, sizeof(*t)); guint32 mask = ~0; - t->type = EM_POPUP_TARGET_URI; - t->data.uri = g_strdup(uri); + t->uri = g_strdup(uri); if (g_ascii_strncasecmp(uri, "http:", 5) == 0 || g_ascii_strncasecmp(uri, "https:", 6) == 0) @@ -553,48 +268,46 @@ em_popup_target_new_uri(const char *uri) else mask &= ~EM_POPUP_URI_NOT_MAILTO; - t->mask = mask; + t->target.mask = mask; return t; } -EMPopupTarget * -em_popup_target_new_part(struct _CamelMimePart *part, const char *mime_type) +EMPopupTargetPart * +em_popup_target_new_part(EMPopup *emp, struct _CamelMimePart *part, const char *mime_type) { - EMPopupTarget *t = g_malloc0(sizeof(*t)); + EMPopupTargetPart *t = e_popup_target_new(&emp->popup, EM_POPUP_TARGET_PART, sizeof(*t)); guint32 mask = ~0; - t->type = EM_POPUP_TARGET_PART; - t->data.part.part = part; + t->part = part; camel_object_ref(part); if (mime_type) - t->data.part.mime_type = g_strdup(mime_type); + t->mime_type = g_strdup(mime_type); else - t->data.part.mime_type = camel_data_wrapper_get_mime_type((CamelDataWrapper *)part); + t->mime_type = camel_data_wrapper_get_mime_type((CamelDataWrapper *)part); - camel_strdown(t->data.part.mime_type); + camel_strdown(t->mime_type); if (CAMEL_IS_MIME_MESSAGE(camel_medium_get_content_object((CamelMedium *)part))) mask &= ~EM_POPUP_PART_MESSAGE; - if (strncmp(t->data.part.mime_type, "image/", 6) == 0) + if (strncmp(t->mime_type, "image/", 6) == 0) mask &= ~EM_POPUP_PART_IMAGE; - t->mask = mask; + t->target.mask = mask; return t; } /* TODO: This should be based on the CamelFolderInfo, but ... em-folder-tree doesn't keep it? */ -EMPopupTarget * -em_popup_target_new_folder (const char *uri, guint32 info_flags, guint32 popup_flags) +EMPopupTargetFolder * +em_popup_target_new_folder (EMPopup *emp, const char *uri, guint32 info_flags, guint32 popup_flags) { - EMPopupTarget *t = g_malloc0(sizeof(*t)); + EMPopupTargetFolder *t = e_popup_target_new(&emp->popup, EM_POPUP_TARGET_FOLDER, sizeof(*t)); guint32 mask = ~0; CamelURL *url; - t->type = EM_POPUP_TARGET_FOLDER; - t->data.folder.folder_uri = g_strdup(uri); + t->uri = g_strdup(uri); if (popup_flags & EM_POPUP_FOLDER_STORE) mask &= ~(EM_POPUP_FOLDER_STORE|EM_POPUP_FOLDER_INFERIORS); @@ -629,91 +342,63 @@ em_popup_target_new_folder (const char *uri, guint32 info_flags, guint32 popup_f camel_url_free(url); done: - t->mask = mask; + t->target.mask = mask; return t; } -void -em_popup_target_free(EMPopupTarget *t) -{ - switch (t->type) { - case EM_POPUP_TARGET_SELECT: - if (t->data.select.folder) - camel_object_unref(t->data.select.folder); - g_free(t->data.select.folder_uri); - if (t->data.select.uids) - em_utils_uids_free(t->data.select.uids); - break; - case EM_POPUP_TARGET_URI: - g_free(t->data.uri); - break; - case EM_POPUP_TARGET_PART: - camel_object_unref(t->data.part.part); - g_free(t->data.part.mime_type); - break; - case EM_POPUP_TARGET_FOLDER: - g_free(t->data.folder.folder_uri); - break; - } - - g_free(t); -} - -/* ********************************************************************** */ - -#if 0 -/* TODO: flesh these out where possible */ -static void -emp_popup_open(GtkWidget *w, EMFolderView *emfv) +/** + * em_popup_target_new_attachments: + * @emp: + * @attachments: A list of EMsgComposerAttachment objects, reffed for + * the list. Will be unreff'd once finished with. + * + * Owns the list @attachments and their items after they're passed in. + * + * Return value: + **/ +EMPopupTargetAttachments * +em_popup_target_new_attachments(EMPopup *emp, GSList *attachments) { - em_folder_view_open_selected(emfv); -} + EMPopupTargetAttachments *t = e_popup_target_new(&emp->popup, EM_POPUP_TARGET_ATTACHMENTS, sizeof(*t)); + guint32 mask = ~0; + int len = g_slist_length(attachments); -static void -emp_popup_edit (GtkWidget *w, EMPopupTarget *t) -{ - if (!em_utils_check_user_can_send_mail(t->widget)) - return; - - em_utils_edit_messages(t->widget, t->data.select.folder, em_utils_uids_copy(t->data.select.uids), FALSE); -} + t->attachments = attachments; + if (len > 0) + mask &= ~ EM_POPUP_ATTACHMENTS_MANY; + if (len == 1) + mask &= ~ EM_POPUP_ATTACHMENTS_ONE; + t->target.mask = mask; -static void -emp_popup_saveas(GtkWidget *w, EMPopupTarget *t) -{ - em_utils_save_messages(t->widget, t->data.select.folder, em_utils_uids_copy(t->data.select.uids)); + return t; } -static EMPopupItem emp_standard_select_popups[] = { - /*{ EM_POPUP_ITEM, "00.select.00", N_("_Open"), G_CALLBACK(emp_popup_open), NULL, NULL, 0 },*/ - { EM_POPUP_ITEM, "00.select.01", N_("_Edit as New Message..."), G_CALLBACK(emp_popup_edit), NULL, NULL, EM_POPUP_SELECT_EDIT }, - { EM_POPUP_ITEM, "00.select.02", N_("_Save As..."), G_CALLBACK(emp_popup_saveas), NULL, "stock_save-as", 0 }, -}; -#endif - /* ********************************************************************** */ static void -emp_part_popup_saveas(GtkWidget *w, EMPopupTarget *t) +emp_part_popup_saveas(EPopup *ep, EPopupItem *item, void *data) { - em_utils_save_part(w, _("Save As..."), t->data.part.part); + EMPopupTargetPart *t = (EMPopupTargetPart *)ep->target; + + em_utils_save_part(ep->target->widget, _("Save As..."), t->part); } static void -emp_part_popup_set_background(GtkWidget *w, EMPopupTarget *t) +emp_part_popup_set_background(EPopup *ep, EPopupItem *item, void *data) { + EMPopupTargetPart *t = (EMPopupTargetPart *)ep->target; GConfClient *gconf; char *str, *filename, *path, *extension; unsigned int i=1; - filename = g_strdup(camel_mime_part_get_filename(t->data.part.part)); + filename = g_strdup(camel_mime_part_get_filename(t->part)); /* if filename is blank, create a default filename based on MIME type */ if (!filename || !filename[0]) { CamelContentType *ct; - ct = camel_mime_part_get_content_type(t->data.part.part); + ct = camel_mime_part_get_content_type(t->part); g_free (filename); filename = g_strdup_printf (_("untitled_image.%s"), ct->subtype); } @@ -737,7 +422,7 @@ emp_part_popup_set_background(GtkWidget *w, EMPopupTarget *t) g_free(filename); - if (em_utils_save_part_to_file(w, path, t->data.part.part)) { + if (em_utils_save_part_to_file(ep->target->widget, path, t->part)) { gconf = gconf_client_get_default(); /* if the filename hasn't changed, blank the filename before @@ -767,64 +452,68 @@ emp_part_popup_set_background(GtkWidget *w, EMPopupTarget *t) } static void -emp_part_popup_reply_sender (GtkWidget *w, EMPopupTarget *t) +emp_part_popup_reply_sender(EPopup *ep, EPopupItem *item, void *data) { + EMPopupTargetPart *t = (EMPopupTargetPart *)ep->target; CamelMimeMessage *message; - message = (CamelMimeMessage *) camel_medium_get_content_object ((CamelMedium *) t->data.part.part); - em_utils_reply_to_message (NULL, NULL, message, REPLY_MODE_SENDER, NULL); + message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *)t->part); + em_utils_reply_to_message(NULL, NULL, message, REPLY_MODE_SENDER, NULL); } static void -emp_part_popup_reply_list (GtkWidget *w, EMPopupTarget *t) +emp_part_popup_reply_list (EPopup *ep, EPopupItem *item, void *data) { + EMPopupTargetPart *t = (EMPopupTargetPart *)ep->target; CamelMimeMessage *message; - message = (CamelMimeMessage *) camel_medium_get_content_object ((CamelMedium *) t->data.part.part); - em_utils_reply_to_message (NULL, NULL, message, REPLY_MODE_LIST, NULL); + message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *)t->part); + em_utils_reply_to_message(NULL, NULL, message, REPLY_MODE_LIST, NULL); } static void -emp_part_popup_reply_all (GtkWidget *w, EMPopupTarget *t) +emp_part_popup_reply_all (EPopup *ep, EPopupItem *item, void *data) { + EMPopupTargetPart *t = (EMPopupTargetPart *)ep->target; CamelMimeMessage *message; - message = (CamelMimeMessage *) camel_medium_get_content_object ((CamelMedium *) t->data.part.part); - em_utils_reply_to_message (NULL, NULL, message, REPLY_MODE_ALL, NULL); + message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *)t->part); + em_utils_reply_to_message(NULL, NULL, message, REPLY_MODE_ALL, NULL); } static void -emp_part_popup_forward (GtkWidget *w, EMPopupTarget *t) +emp_part_popup_forward (EPopup *ep, EPopupItem *item, void *data) { + EMPopupTargetPart *t = (EMPopupTargetPart *)ep->target; CamelMimeMessage *message; /* TODO: have a emfv specific override so we can get the parent folder uri */ - message = (CamelMimeMessage *) camel_medium_get_content_object ((CamelMedium *) t->data.part.part); - em_utils_forward_message (message, NULL); + message = (CamelMimeMessage *)camel_medium_get_content_object((CamelMedium *) t->part); + em_utils_forward_message(message, NULL); } static EMPopupItem emp_standard_object_popups[] = { - { EM_POPUP_ITEM, "00.part.00", N_("_Save As..."), G_CALLBACK(emp_part_popup_saveas), NULL, "stock_save-as", 0 }, - { EM_POPUP_ITEM, "00.part.10", N_("Set as _Background"), G_CALLBACK(emp_part_popup_set_background), NULL, NULL, EM_POPUP_PART_IMAGE }, - { EM_POPUP_BAR, "10.part", NULL, NULL, NULL, NULL, EM_POPUP_PART_MESSAGE }, - { EM_POPUP_ITEM, "10.part.00", N_("_Reply to sender"), G_CALLBACK(emp_part_popup_reply_sender), NULL, "stock_mail-reply" , EM_POPUP_PART_MESSAGE }, - { EM_POPUP_ITEM, "10.part.01", N_("Reply to _List"), G_CALLBACK(emp_part_popup_reply_list), NULL, NULL, EM_POPUP_PART_MESSAGE}, - { EM_POPUP_ITEM, "10.part.03", N_("Reply to _All"), G_CALLBACK(emp_part_popup_reply_all), NULL, "stock_mail-reply-to-all", EM_POPUP_PART_MESSAGE}, - { EM_POPUP_BAR, "20.part", NULL, NULL, NULL, NULL, EM_POPUP_PART_MESSAGE }, - { EM_POPUP_ITEM, "20.part.00", N_("_Forward"), G_CALLBACK(emp_part_popup_forward), NULL, "stock_mail-forward", EM_POPUP_PART_MESSAGE }, - + { E_POPUP_ITEM, "00.part.00", N_("_Save As..."), emp_part_popup_saveas, NULL, "stock_save-as", 0 }, + { E_POPUP_ITEM, "00.part.10", N_("Set as _Background"), emp_part_popup_set_background, NULL, NULL, EM_POPUP_PART_IMAGE }, + { E_POPUP_BAR, "10.part", NULL, NULL, NULL, NULL, EM_POPUP_PART_MESSAGE }, + { E_POPUP_ITEM, "10.part.00", N_("_Reply to sender"), emp_part_popup_reply_sender, NULL, "stock_mail-reply" , EM_POPUP_PART_MESSAGE }, + { E_POPUP_ITEM, "10.part.01", N_("Reply to _List"), emp_part_popup_reply_list, NULL, NULL, EM_POPUP_PART_MESSAGE}, + { E_POPUP_ITEM, "10.part.03", N_("Reply to _All"), emp_part_popup_reply_all, NULL, "stock_mail-reply-to-all", EM_POPUP_PART_MESSAGE}, + { E_POPUP_BAR, "20.part", NULL, NULL, NULL, NULL, EM_POPUP_PART_MESSAGE }, + { E_POPUP_ITEM, "20.part.00", N_("_Forward"), emp_part_popup_forward, NULL, "stock_mail-forward", EM_POPUP_PART_MESSAGE }, }; -static const EMPopupItem emp_standard_part_apps_bar = { EM_POPUP_BAR, "99.object" }; +static const EPopupItem emp_standard_part_apps_bar = { E_POPUP_BAR, "99.object" }; /* ********************************************************************** */ static void -emp_uri_popup_link_open(GtkWidget *w, EMPopupTarget *t) +emp_uri_popup_link_open(EPopup *ep, EPopupItem *item, void *data) { + EMPopupTargetURI *t = (EMPopupTargetURI *)ep->target; GError *err = NULL; - gnome_url_show(t->data.uri, &err); + gnome_url_show(t->uri, &err); if (err) { g_warning("gnome_url_show: %s", err->message); g_error_free(err); @@ -832,33 +521,36 @@ emp_uri_popup_link_open(GtkWidget *w, EMPopupTarget *t) } static void -emp_uri_popup_address_send (GtkWidget *w, EMPopupTarget *t) +emp_uri_popup_address_send(EPopup *ep, EPopupItem *item, void *data) { + EMPopupTargetURI *t = (EMPopupTargetURI *)ep->target; + /* TODO: have an emfv specific override to get the from uri */ - em_utils_compose_new_message_with_mailto (t->data.uri, NULL); + em_utils_compose_new_message_with_mailto(t->uri, NULL); } static void -emp_uri_popup_address_add(GtkWidget *w, EMPopupTarget *t) +emp_uri_popup_address_add(EPopup *ep, EPopupItem *item, void *data) { + EMPopupTargetURI *t = (EMPopupTargetURI *)ep->target; CamelURL *url; - url = camel_url_new(t->data.uri, NULL); + url = camel_url_new(t->uri, NULL); if (url == NULL) { - g_warning("cannot parse url '%s'", t->data.uri); + g_warning("cannot parse url '%s'", t->uri); return; } if (url->path && url->path[0]) - em_utils_add_address(w, url->path); + em_utils_add_address(ep->target->widget, url->path); camel_url_free(url); } -static EMPopupItem emp_standard_uri_popups[] = { - { EM_POPUP_ITEM, "00.uri.00", N_("_Open Link in Browser"), G_CALLBACK(emp_uri_popup_link_open), NULL, NULL, EM_POPUP_URI_NOT_MAILTO }, - { EM_POPUP_ITEM, "00.uri.10", N_("Se_nd message to..."), G_CALLBACK(emp_uri_popup_address_send), NULL, NULL, EM_POPUP_URI_MAILTO }, - { EM_POPUP_ITEM, "00.uri.20", N_("_Add to Addressbook"), G_CALLBACK(emp_uri_popup_address_add), NULL, NULL, EM_POPUP_URI_MAILTO }, +static EPopupItem emp_standard_uri_popups[] = { + { E_POPUP_ITEM, "00.uri.00", N_("_Open Link in Browser"), emp_uri_popup_link_open, NULL, NULL, EM_POPUP_URI_NOT_MAILTO }, + { E_POPUP_ITEM, "00.uri.10", N_("Se_nd message to..."), emp_uri_popup_address_send, NULL, NULL, EM_POPUP_URI_MAILTO }, + { E_POPUP_ITEM, "00.uri.20", N_("_Add to Addressbook"), emp_uri_popup_address_add, NULL, NULL, EM_POPUP_URI_MAILTO }, }; /* ********************************************************************** */ @@ -867,23 +559,21 @@ static EMPopupItem emp_standard_uri_popups[] = { #include <libgnomevfs/gnome-vfs-mime-handlers.h> -struct _open_in_item { - EMPopupItem item; - EMPopupTarget *target; - GnomeVFSMimeApplication *app; -}; + EMPopupTargetPart *target; static void -emp_apps_open_in(GtkWidget *w, struct _open_in_item *item) +emp_apps_open_in(EPopup *ep, EPopupItem *item, void *data) { char *path; + EMPopupTargetPart *target = (EMPopupTargetPart *)ep->target; - path = em_utils_temp_save_part(item->target->widget, item->target->data.part.part); + path = em_utils_temp_save_part(target->target.widget, target->part); if (path) { - int douri = (item->app->expects_uris == GNOME_VFS_MIME_APPLICATION_ARGUMENT_TYPE_URIS); + GnomeVFSMimeApplication *app = item->user_data; + int douri = (app->expects_uris == GNOME_VFS_MIME_APPLICATION_ARGUMENT_TYPE_URIS); char *command; - if (item->app->requires_terminal) { + if (app->requires_terminal) { char *term, *args = NULL; GConfClient *gconf; @@ -896,11 +586,11 @@ emp_apps_open_in(GtkWidget *w, struct _open_in_item *item) return; command = g_strdup_printf ("%s%s%s %s %s%s &", term, args ? " " : "", args ? args : "", - item->app->command, douri ? "file://" : "", path); + app->command, douri ? "file://" : "", path); g_free (term); g_free (args); } else { - command = g_strdup_printf ("%s %s%s &", item->app->command, douri ? "file://" : "", path); + command = g_strdup_printf ("%s %s%s &", app->command, douri ? "file://" : "", path); } /* FIXME: Do not use system here */ @@ -911,14 +601,14 @@ emp_apps_open_in(GtkWidget *w, struct _open_in_item *item) } static void -emp_apps_popup_free(GSList *free_list) +emp_apps_popup_free(EPopup *ep, GSList *free_list, void *data) { while (free_list) { GSList *n = free_list->next; - struct _open_in_item *item = free_list->data; + EPopupItem *item = free_list->data; - g_free(item->item.path); - g_free(item->item.label); + g_free(item->path); + g_free(item->label); g_free(item); g_slist_free_1(free_list); @@ -927,13 +617,19 @@ emp_apps_popup_free(GSList *free_list) } static void -emp_standard_menu_factory(EMPopup *emp, EMPopupTarget *target, void *data) +emp_standard_items_free(EPopup *ep, GSList *items, void *data) +{ + g_slist_free(items); +} + +static void +emp_standard_menu_factory(EPopup *emp, void *data) { int i, len; - EMPopupItem *items; + EPopupItem *items; GSList *menus = NULL; - switch (target->type) { + switch (emp->target->type) { #if 0 case EM_POPUP_TARGET_SELECT: return; @@ -941,18 +637,21 @@ emp_standard_menu_factory(EMPopup *emp, EMPopupTarget *target, void *data) len = LEN(emp_standard_select_popups); break; #endif - case EM_POPUP_TARGET_URI: + case EM_POPUP_TARGET_URI: { + /*EMPopupTargetURI *t = (EMPopupTargetURI *)target;*/ + items = emp_standard_uri_popups; len = LEN(emp_standard_uri_popups); - break; + break; } case EM_POPUP_TARGET_PART: { - GList *apps = gnome_vfs_mime_get_short_list_applications(target->data.part.mime_type); + EMPopupTargetPart *t = (EMPopupTargetPart *)emp->target; + GList *apps = gnome_vfs_mime_get_short_list_applications(t->mime_type); /* FIXME: use the snoop_part stuff from em-format.c */ - if (apps == NULL && strcmp(target->data.part.mime_type, "application/octet-stream") == 0) { + if (apps == NULL && strcmp(t->mime_type, "application/octet-stream") == 0) { const char *filename, *name_type; - filename = camel_mime_part_get_filename(target->data.part.part); + filename = camel_mime_part_get_filename(t->part); if (filename) { /* GNOME-VFS will misidentify TNEF attachments as MPEG */ @@ -974,25 +673,23 @@ emp_standard_menu_factory(EMPopup *emp, EMPopupTarget *target, void *data) for (l = apps, i = 0; l; l = l->next, i++) { GnomeVFSMimeApplication *app = l->data; - struct _open_in_item *item; + EPopupItem *item; if (app->requires_terminal) continue; item = g_malloc0(sizeof(*item)); - item->item.type = EM_POPUP_ITEM; - item->item.path = g_strdup_printf("99.object.%02d", i); - item->item.label = g_strdup_printf(_("Open in %s..."), app->name); - item->item.activate = G_CALLBACK(emp_apps_open_in); - item->item.activate_data = item; - item->target = target; - item->app = app; + item->type = E_POPUP_ITEM; + item->path = g_strdup_printf("99.object.%02d", i); + item->label = g_strdup_printf(_("Open in %s..."), app->name); + item->activate = emp_apps_open_in; + item->user_data = app; open_menus = g_slist_prepend(open_menus, item); } if (open_menus) - em_popup_add_items(emp, open_menus, (GDestroyNotify)emp_apps_popup_free); + e_popup_add_items(emp, open_menus, emp_apps_popup_free, NULL); g_string_free(label, TRUE); g_list_free(apps); @@ -1007,12 +704,139 @@ emp_standard_menu_factory(EMPopup *emp, EMPopupTarget *target, void *data) } for (i=0;i<len;i++) { - if ((items[i].mask & target->mask) == 0) { - items[i].activate_data = target; + if ((items[i].visible & emp->target->mask) == 0) menus = g_slist_prepend(menus, &items[i]); - } } if (menus) - em_popup_add_items(emp, menus, (GDestroyNotify)g_slist_free); + e_popup_add_items(emp, menus, emp_standard_items_free, NULL); +} + +/* ********************************************************************** */ + +/* Popup menu plugin handler */ + +/* +<e-plugin + class="com.ximian.mail.plugin.popup:1.0" + id="com.ximian.mail.plugin.popup.item:1.0" + type="shlib" + location="/opt/gnome2/lib/camel/1.0/libcamelimap.so" + name="imap" + description="IMAP4 and IMAP4v1 mail store"> + <hook class="com.ximian.mail.popupMenu:1.0" + handler="HandlePopup"> + <menu id="any" target="select"> + <item + type="item|toggle|radio|image|submenu|bar" + active + path="foo/bar" + label="label" + icon="foo" + mask="select_one" + activate="emp_view_emacs"/> + </menu> + </extension> + +*/ + +static void *emph_parent_class; +#define emph ((EMPopupHook *)eph) + +static const EPopupHookTargetMask emph_select_masks[] = { + { "one", EM_POPUP_SELECT_ONE }, + { "many", EM_POPUP_SELECT_MANY }, + { "mark_read", EM_POPUP_SELECT_MARK_READ }, + { "mark_unread", EM_POPUP_SELECT_MARK_UNREAD }, + { "delete", EM_POPUP_SELECT_DELETE }, + { "undelete", EM_POPUP_SELECT_UNDELETE }, + { "mailing_list", EM_POPUP_SELECT_MAILING_LIST }, + { "resend", EM_POPUP_SELECT_EDIT }, + { "mark_important", EM_POPUP_SELECT_MARK_IMPORTANT }, + { "mark_unimportant", EM_POPUP_SELECT_MARK_UNIMPORTANT }, + { "flag_followup", EM_POPUP_SELECT_FLAG_FOLLOWUP }, + { "flag_completed", EM_POPUP_SELECT_FLAG_COMPLETED }, + { "flag_clear", EM_POPUP_SELECT_FLAG_CLEAR }, + { "add_sender", EM_POPUP_SELECT_ADD_SENDER }, + { "mark_junk", EM_POPUP_SELECT_MARK_JUNK }, + { "mark_nojunk", EM_POPUP_SELECT_MARK_NOJUNK }, + { "folder", EM_POPUP_SELECT_FOLDER }, + { 0 } +}; + +static const EPopupHookTargetMask emph_uri_masks[] = { + { "http", EM_POPUP_URI_HTTP }, + { "mailto", EM_POPUP_URI_MAILTO }, + { "notmailto", EM_POPUP_URI_NOT_MAILTO }, + { 0 } +}; + +static const EPopupHookTargetMask emph_part_masks[] = { + { "message", EM_POPUP_PART_MESSAGE }, + { "image", EM_POPUP_PART_IMAGE }, + { 0 } +}; + +static const EPopupHookTargetMask emph_folder_masks[] = { + { "folder", EM_POPUP_FOLDER_FOLDER }, + { "store", EM_POPUP_FOLDER_STORE }, + { "inferiors", EM_POPUP_FOLDER_INFERIORS }, + { "delete", EM_POPUP_FOLDER_DELETE }, + { "select", EM_POPUP_FOLDER_SELECT }, + { 0 } +}; + +static const EPopupHookTargetMask emph_attachments_masks[] = { + { "one", EM_POPUP_ATTACHMENTS_ONE }, + { "many", EM_POPUP_ATTACHMENTS_MANY }, + { 0 } +}; + +static const EPopupHookTargetMap emph_targets[] = { + { "select", EM_POPUP_TARGET_SELECT, emph_select_masks }, + { "uri", EM_POPUP_TARGET_URI, emph_uri_masks }, + { "part", EM_POPUP_TARGET_PART, emph_part_masks }, + { "folder", EM_POPUP_TARGET_FOLDER, emph_folder_masks }, + { "attachments", EM_POPUP_TARGET_ATTACHMENTS, emph_attachments_masks }, + { 0 } +}; + +static void +emph_finalise(GObject *o) +{ + /*EPluginHook *eph = (EPluginHook *)o;*/ + + ((GObjectClass *)emph_parent_class)->finalize(o); +} + +static void +emph_class_init(EPluginHookClass *klass) +{ + int i; + + ((GObjectClass *)klass)->finalize = emph_finalise; + ((EPluginHookClass *)klass)->id = "com.ximian.evolution.mail.popup:1.0"; + + for (i=0;emph_targets[i].type;i++) + e_popup_hook_class_add_target_map((EPopupHookClass *)klass, &emph_targets[i]); + + ((EPopupHookClass *)klass)->popup_class = g_type_class_ref(em_popup_get_type()); +} + +GType +em_popup_hook_get_type(void) +{ + static GType type = 0; + + if (!type) { + static const GTypeInfo info = { + sizeof(EMPopupHookClass), NULL, NULL, (GClassInitFunc) emph_class_init, NULL, NULL, + sizeof(EMPopupHook), 0, (GInstanceInitFunc) NULL, + }; + + emph_parent_class = g_type_class_ref(e_popup_hook_get_type()); + type = g_type_register_static(e_popup_hook_get_type(), "EMPopupHook", &info, 0); + } + + return type; } diff --git a/mail/em-popup.h b/mail/em-popup.h index 8f235d19e0..d35f171629 100644 --- a/mail/em-popup.h +++ b/mail/em-popup.h @@ -25,55 +25,71 @@ #include <glib-object.h> +#include "e-util/e-popup.h" + #ifdef __cplusplus extern "C" { #pragma } #endif /* __cplusplus */ -/* NB: This is TEMPORARY, to be replaced by EggMenu, if it does what we need? */ - typedef struct _EMPopup EMPopup; typedef struct _EMPopupClass EMPopupClass; -typedef struct _EMPopupItem EMPopupItem; -typedef struct _EMPopupFactory EMPopupFactory; /* anonymous type */ -typedef struct _EMPopupTarget EMPopupTarget; - -typedef void (*EMPopupFactoryFunc)(EMPopup *emp, EMPopupTarget *target, void *data); - -/* Menu item descriptions */ -enum _em_popup_t { - EM_POPUP_ITEM = 0, - EM_POPUP_TOGGLE, - EM_POPUP_RADIO, - EM_POPUP_IMAGE, - EM_POPUP_SUBMENU, - EM_POPUP_BAR, - EM_POPUP_TYPE_MASK = 0xffff, - EM_POPUP_ACTIVE = 0x10000, -}; - -struct _EMPopupItem { - enum _em_popup_t type; - char *path; /* absolute path! must sort ascii-lexographically into the right spot */ - char *label; - GCallback activate; - void *activate_data; - void *image; /* char* for item type, GtkWidget * for image type */ - guint32 mask; -}; - -/* Current target description */ -/* Types of popup tagets */ +/** + * enum _em_popup_target_t - A list of mail popup target types. + * + * @EM_POPUP_TARGET_SELECT: A selection of messages. + * @EM_POPUP_TARGET_URI: A URI. + * @EM_POPUP_TARGET_PART: A CamelMimePart message part. + * @EM_POPUP_TARGET_FOLDER: A folder URI. + * @EM_POPUP_TARGET_ATTACHMENTS: A list of attachments. + * + * Defines the value of the targetid for all EMPopup target types. + **/ enum _em_popup_target_t { EM_POPUP_TARGET_SELECT, EM_POPUP_TARGET_URI, EM_POPUP_TARGET_PART, EM_POPUP_TARGET_FOLDER, + EM_POPUP_TARGET_ATTACHMENTS, }; -/* Flags that describe a TARGET_SELECT */ -enum { +/** + * enum _em_popup_target_select_t - EMPopupTargetSelect qualifiers. + * + * @EM_POPUP_SELECT_ONE: Only one item is selected. + * @EM_POPUP_SELECT_MANY: One ore more items are selected. + * @EM_POPUP_SELECT_MARK_READ: Message(s) are unseen and can be + * marked seen. + * @EM_POPUP_SELECT_MARK_UNREAD: Message(s) are seen and can be + * marked unseen. + * @EM_POPUP_SELECT_DELETE: Message(s) are undeleted and can + * be marked deleted. + * @EM_POPUP_SELECT_UNDELETE: Message(s) are deleted and can be + * undeleted. + * @EM_POPUP_SELECT_MAILING_LIST: If one message is selected, and it + * contains a message list tag. + * @EM_POPUP_SELECT_EDIT: The message can be opened for editing (the + * folder is a sent folder). + * @EM_POPUP_SELECT_MARK_IMPORTANT: Message(s) are not marked + * important. + * @EM_POPUP_SELECT_MARK_UNIMPORTANT: Message(s) are marked + * important. + * @EM_POPUP_SELECT_FLAG_FOLLOWUP: Message(s) are not flagged for + * followup. + * @EM_POPUP_SELECT_FLAG_COMPLETED: Message(s) are not flagged completed. + * @EM_POPUP_SELECT_FLAG_CLEAR: Message(s) are flagged for followup. + * @EM_POPUP_SELECT_ADD_SENDER: The message contains sender addresses + * which might be added to the addressbook. i.e. it isn't a message in + * the Sent or Drafts folders. + * @EM_POPUP_SELECT_MARK_JUNK: Message(s) are not marked as junk. + * @EM_POPUP_SELECT_MARK_NOJUNK: Message(s) are marked as junk. + * @EM_POPUP_SELECT_FOLDER: A folder is set on the selection. + * @EM_POPUP_SELECT_LAST: The last bit used, can be used to add + * additional types from derived application code. + * + **/ +enum _em_popup_target_select_t { EM_POPUP_SELECT_ONE = 1<<1, EM_POPUP_SELECT_MANY = 1<<2, EM_POPUP_SELECT_MARK_READ = 1<<3, @@ -91,24 +107,47 @@ enum { EM_POPUP_SELECT_MARK_JUNK = 1<<15, EM_POPUP_SELECT_MARK_NOJUNK = 1<<16, EM_POPUP_SELECT_FOLDER = 1<<17, /* do we have any folder at all? */ - EM_POPUP_SELECT_LAST = 1<<18 /* reserve 2 slots */ + EM_POPUP_SELECT_LAST = 1<<18, /* reserve 2 slots */ }; -/* Flags that describe a TARGET_URI */ -enum { +/** + * enum _em_popup_target_uri_t - EMPopupTargetURI qualifiers. + * + * @EM_POPUP_URI_HTTP: This is a HTTP or HTTPS url. + * @EM_POPUP_URI_MAILTO: This is a MAILTO url. + * @EM_POPUP_URI_NOT_MAILTO: This is not a MAILTO url. + * + **/ +enum _em_popup_target_uri_t { EM_POPUP_URI_HTTP = 1<<0, EM_POPUP_URI_MAILTO = 1<<1, EM_POPUP_URI_NOT_MAILTO = 1<<2, }; -/* Flags that describe TARGET_PART */ -enum { +/** + * enum _em_popup_target_part_t - EMPopupTargetPart qualifiers. + * + * @EM_POPUP_PART_MESSAGE: This is a message type. + * @EM_POPUP_PART_IMAGE: This is an image type. + * + **/ +enum _em_popup_target_part_t { EM_POPUP_PART_MESSAGE = 1<<0, EM_POPUP_PART_IMAGE = 1<<1, }; -/* Flags that describe TARGET_FOLDER */ -enum { +/** + * enum _em_popup_target_folder_t - EMPopupTargetFolder qualifiers. + * + * @EM_POPUP_FOLDER_FOLDER: This is a normal folder. + * @EM_POPUP_FOLDER_STORE: This is a store. + * @EM_POPUP_FOLDER_INFERIORS: This folder may have child folders. + * @EM_POPUP_FOLDER_DELETE: This folder can be deleted or renamed. + * @EM_POPUP_FOLDER_SELECT: This folder exists and can be selected or + * opened. + * + **/ +enum _em_popup_target_folder_t { EM_POPUP_FOLDER_FOLDER = 1<<0, /* normal folder */ EM_POPUP_FOLDER_STORE = 1<<1, /* root/nonselectable folder, i.e. store */ EM_POPUP_FOLDER_INFERIORS = 1<<2, /* folder can have children */ @@ -116,57 +155,137 @@ enum { EM_POPUP_FOLDER_SELECT = 1<<4, /* folder can be selected/opened */ }; -struct _EMPopupTarget { - enum _em_popup_target_t type; - guint32 mask; /* depends on type, see above */ - struct _GtkWidget *widget; /* used if you need a parent toplevel, if available */ - union { - char *uri; - struct { - struct _CamelFolder *folder; - char *folder_uri; - GPtrArray *uids; - } select; - struct { - char *mime_type; - struct _CamelMimePart *part; - } part; - struct { - char *folder_uri; - } folder; - } data; +/** + * enum _em_popup_target_attachments_t - EMPopupTargetAttachments qualifiers. + * + * @EM_POPUP_ATTACHMENTS_ONE: There is one and only one attachment selected. + * @EM_POPUP_ATTACHMENTS_MANY: There is one or more attachments selected. + * + **/ +enum _em_popup_target_attachments_t { + EM_POPUP_ATTACHMENTS_ONE = 1<<0, /* only 1 selected */ + EM_POPUP_ATTACHMENTS_MANY = 1<<1, /* one or more selected */ +}; + +typedef struct _EMPopupTargetSelect EMPopupTargetSelect; +typedef struct _EMPopupTargetURI EMPopupTargetURI; +typedef struct _EMPopupTargetPart EMPopupTargetPart; +typedef struct _EMPopupTargetFolder EMPopupTargetFolder; +typedef struct _EMPopupTargetAttachments EMPopupTargetAttachments; + +/** + * struct _EMPopupTargetURI - An inline URI. + * + * @target: Superclass. + * @uri: The encoded URI to which this target applies. + * + * Used to represent popup-menu context on any URI object. + **/ +struct _EMPopupTargetURI { + EPopupTarget target; + char *uri; +}; + +/** + * struct _EMPopupTargetSelect - A list of messages. + * + * @target: Superclass. + * @folder: The CamelFolder of the selected messages. + * @uri: The encoded URI represending this folder. + * @uids: An array of UID strings of messages within @folder. + * + * Used to represent a selection of messages as context for a popup + * menu. All items may be NULL if the current view has no active + * folder selected. + **/ +struct _EMPopupTargetSelect { + EPopupTarget target; + struct _CamelFolder *folder; + char *uri; + GPtrArray *uids; +}; + +/** + * struct _EMPopupTargetPart - A Camel object. + * + * @target: Superclass. + * @mime_type: MIME type of the part. This may be a calculated type + * not matching the @part's MIME type. + * @part: A CamelMimePart representing a message or attachment. + * + * Used to represent a message part as context for a popup menu. This + * is used for both attachments and inline-images. + **/ +struct _EMPopupTargetPart { + EPopupTarget target; + char *mime_type; + struct _CamelMimePart *part; +}; + +/** + * struct _EMPopupTargetFolder - A folder uri. + * + * @target: Superclass. + * @uri: A folder URI. + * + * This target is used to represent folder context. + **/ +struct _EMPopupTargetFolder { + EPopupTarget target; + char *uri; +}; + +/** + * struct _EMPopupTargetAttachments - A list of composer attachments. + * + * @target: Superclass. + * @attachments: A GSList list of EMsgComposer attachments. + * + * This target is used to represent a selected list of attachments in + * the message composer attachment area. + **/ +struct _EMPopupTargetAttachments { + EPopupTarget target; + GSList *attachments; }; +typedef struct _EPopupItem EMPopupItem; + /* The object */ struct _EMPopup { - GObject object; + EPopup popup; struct _EMPopupPrivate *priv; - - char *menuid; }; struct _EMPopupClass { - GObjectClass object_class; + EPopupClass popup_class; }; GType em_popup_get_type(void); -/* Static class methods */ -EMPopupFactory *em_popup_static_add_factory(const char *menuid, EMPopupFactoryFunc func, void *data); -void em_popup_static_remove_factory(EMPopupFactory *f); - EMPopup *em_popup_new(const char *menuid); -void em_popup_add_items(EMPopup *, GSList *items, GDestroyNotify freefunc); -void em_popup_add_static_items(EMPopup *emp, EMPopupTarget *target); -struct _GtkMenu *em_popup_create_menu(EMPopup *, guint32 hide_mask, guint32 disable_mask); -struct _GtkMenu *em_popup_create_menu_once(EMPopup *emp, EMPopupTarget *, guint32 hide_mask, guint32 disable_mask); - -EMPopupTarget *em_popup_target_new_uri(const char *uri); -EMPopupTarget *em_popup_target_new_select(struct _CamelFolder *folder, const char *folder_uri, GPtrArray *uids); -EMPopupTarget *em_popup_target_new_part(struct _CamelMimePart *part, const char *mime_type); -EMPopupTarget *em_popup_target_new_folder(const char *uri, guint32 info_flags, guint32 popup_flags); -void em_popup_target_free(EMPopupTarget *target); + +EMPopupTargetURI *em_popup_target_new_uri(EMPopup *emp, const char *uri); +EMPopupTargetSelect *em_popup_target_new_select(EMPopup *emp, struct _CamelFolder *folder, const char *folder_uri, GPtrArray *uids); +EMPopupTargetPart *em_popup_target_new_part(EMPopup *emp, struct _CamelMimePart *part, const char *mime_type); +EMPopupTargetFolder *em_popup_target_new_folder(EMPopup *emp, const char *uri, guint32 info_flags, guint32 popup_flags); +EMPopupTargetAttachments *em_popup_target_new_attachments(EMPopup *emp, GSList *attachments); + +/* ********************************************************************** */ + +typedef struct _EMPopupHook EMPopupHook; +typedef struct _EMPopupHookClass EMPopupHookClass; + +struct _EMPopupHook { + EPopupHook hook; +}; + +struct _EMPopupHookClass { + EPopupHookClass hook_class; +}; + +GType em_popup_hook_get_type(void); #ifdef __cplusplus } diff --git a/mail/em-subscribe-editor.c b/mail/em-subscribe-editor.c index da53eb1a53..08954e9c8c 100644 --- a/mail/em-subscribe-editor.c +++ b/mail/em-subscribe-editor.c @@ -43,6 +43,7 @@ #include "mail-config.h" #include <glade/glade.h> +#include <libgnome/gnome-i18n.h> #include <gtk/gtkdialog.h> #include <gtk/gtkscrolledwindow.h> diff --git a/mail/em-utils.c b/mail/em-utils.c index 8c22fe8926..2adf723f67 100644 --- a/mail/em-utils.c +++ b/mail/em-utils.c @@ -44,13 +44,13 @@ #include <libgnomevfs/gnome-vfs-mime.h> #include <libgnomevfs/gnome-vfs-mime-utils.h> #include <libgnomevfs/gnome-vfs-mime-handlers.h> +#include <libgnome/gnome-i18n.h> #include "mail-component.h" #include "mail-mt.h" #include "mail-ops.h" #include "mail-tools.h" #include "mail-config.h" -#include "mail-config-druid.h" #include "message-tag-followup.h" #include <e-util/e-mktemp.h> @@ -63,6 +63,7 @@ #include "em-utils.h" #include "em-composer-utils.h" #include "em-format-quote.h" +#include "em-account-editor.h" static void emu_save_part_done (CamelMimePart *part, char *name, int done, void *data); @@ -178,19 +179,18 @@ druid_destroy_cb (gpointer user_data, GObject *deadbeef) gboolean em_utils_configure_account (GtkWidget *parent) { - MailConfigDruid *druid; - - druid = mail_config_druid_new (); - + EMAccountEditor *emae; + + emae = em_account_editor_new(NULL, EMAE_DRUID); if (parent != NULL) - e_dialog_set_transient_for ((GtkWindow *) druid, parent); - - g_object_weak_ref ((GObject *) druid, (GWeakNotify) druid_destroy_cb, NULL); - gtk_widget_show ((GtkWidget *) druid); - gtk_grab_add ((GtkWidget *) druid); - gtk_main (); + e_dialog_set_transient_for((GtkWindow *)emae->editor, parent); + + g_object_weak_ref((GObject *)emae->editor, (GWeakNotify) druid_destroy_cb, NULL); + gtk_widget_show(emae->editor); + gtk_grab_add(emae->editor); + gtk_main(); - return mail_config_is_configured (); + return mail_config_is_configured(); } /** diff --git a/mail/importers/evolution-mbox-importer.c b/mail/importers/evolution-mbox-importer.c index 78b6c7d27b..3630277cdd 100644 --- a/mail/importers/evolution-mbox-importer.c +++ b/mail/importers/evolution-mbox-importer.c @@ -41,6 +41,7 @@ #include <gtk/gtkprogressbar.h> #include <bonobo/bonobo-control.h> +#include <libgnome/gnome-i18n.h> #include <camel/camel-exception.h> diff --git a/mail/importers/evolution-outlook-importer.c b/mail/importers/evolution-outlook-importer.c index bf05c6316d..4b78cd3b81 100644 --- a/mail/importers/evolution-outlook-importer.c +++ b/mail/importers/evolution-outlook-importer.c @@ -40,6 +40,7 @@ #include <gtk/gtkprogressbar.h> #include <bonobo/bonobo-control.h> +#include <libgnome/gnome-i18n.h> #include <camel/camel-exception.h> #include <camel/camel-folder.h> diff --git a/mail/importers/mail-importer.c b/mail/importers/mail-importer.c index 582efb761a..b9e022ac29 100644 --- a/mail/importers/mail-importer.c +++ b/mail/importers/mail-importer.c @@ -36,6 +36,7 @@ #include <gmodule.h> #include <libgnome/gnome-util.h> +#include <libgnome/gnome-i18n.h> #include <camel/camel-folder.h> #include <camel/camel-store.h> #include <camel/camel-mime-message.h> diff --git a/mail/mail-account-editor.c b/mail/mail-account-editor.c index bf5b265aab..347c78f90a 100644 --- a/mail/mail-account-editor.c +++ b/mail/mail-account-editor.c @@ -36,6 +36,7 @@ #include <gtk/gtknotebook.h> #include <gtk/gtkstock.h> +#include <libgnome/gnome-i18n.h> #include "widgets/misc/e-error.h" diff --git a/mail/mail-account-gui.c b/mail/mail-account-gui.c index 5de9dc8211..6e5328ef87 100644 --- a/mail/mail-account-gui.c +++ b/mail/mail-account-gui.c @@ -45,6 +45,7 @@ #include <gtk/gtknotebook.h> #include <gtk/gtkhbox.h> #include <gtk/gtkdialog.h> +#include <libgnome/gnome-i18n.h> #ifdef USE_GTKFILECHOOSER #include <gtk/gtkfilechooser.h> #include <gtk/gtkradiobutton.h> @@ -2442,8 +2443,6 @@ mail_account_gui_save (MailAccountGui *gui) mail_config_save_accounts (); - mail_autoreceive_setup (); - return TRUE; } diff --git a/mail/mail-component.c b/mail/mail-component.c index 6d2201937a..4ac09c0ce3 100644 --- a/mail/mail-component.c +++ b/mail/mail-component.c @@ -36,6 +36,7 @@ #include <errno.h> #include "em-popup.h" +#include "em-menu.h" #include "em-utils.h" #include "em-composer-utils.h" #include "em-format.h" @@ -75,6 +76,7 @@ #include <gal/e-table/e-tree.h> #include <gal/e-table/e-tree-memory.h> +#include <libgnome/gnome-i18n.h> #include <camel/camel-file-utils.h> #include <camel/camel-vtrash-folder.h> @@ -319,6 +321,24 @@ mc_startup(MailComponent *mc) mc_setup_local_store(mc); load_accounts(mc, mail_config_get_accounts()); vfolder_load_storage(); + +#ifdef ENABLE_MONO + if (getenv("EVOLUTION_DISABLE_MONO") == NULL) + e_plugin_register_type(e_plugin_mono_get_type()); +#endif + e_plugin_register_type(e_plugin_lib_get_type()); + e_plugin_hook_register_type(em_popup_hook_get_type()); + e_plugin_hook_register_type(em_menu_hook_get_type()); + e_plugin_hook_register_type(em_config_hook_get_type()); + + e_plugin_hook_register_type(em_format_hook_get_type()); + em_format_hook_register_type(em_format_get_type()); + em_format_hook_register_type(em_format_html_get_type()); + em_format_hook_register_type(em_format_html_display_get_type()); + + e_plugin_hook_register_type(em_event_hook_get_type()); + + e_plugin_load_plugins(); } static void @@ -857,7 +877,7 @@ mail_component_init (MailComponent *component) priv->async_event = mail_async_event_new(); priv->store_hash = g_hash_table_new (NULL, NULL); - mail_autoreceive_setup(); + mail_autoreceive_init(); offline = mail_offline_handler_new(); bonobo_object_add_interface((BonoboObject *)component, (BonoboObject *)offline); diff --git a/mail/mail-config-druid.c b/mail/mail-config-druid.c index 65e397f368..22f26b69ea 100644 --- a/mail/mail-config-druid.c +++ b/mail/mail-config-druid.c @@ -41,6 +41,7 @@ #include <libgnomeui/gnome-druid.h> #include <libgnomeui/gnome-druid-page-standard.h> #include <bonobo/bonobo-exception.h> +#include <libgnome/gnome-i18n.h> #include "mail-config-druid.h" #include "mail-config.h" diff --git a/mail/mail-config.glade b/mail/mail-config.glade index 2103e332e5..625b952991 100644 --- a/mail/mail-config.glade +++ b/mail/mail-config.glade @@ -47,6 +47,27 @@ Click "Forward" to begin. </property> <property name="spacing">0</property> <child> + <widget class="GtkLabel" id="identity_help"> + <property name="visible">True</property> + <property name="label" translatable="yes">Please enter your name and email address below. The "optional" fields below do not need to be filled in, unless you wish to include this information in email you send.</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_FILL</property> + <property name="wrap">True</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> <placeholder/> </child> </widget> @@ -67,24 +88,25 @@ Click "Forward" to begin. </property> <property name="spacing">0</property> <child> - <placeholder/> + <widget class="GtkLabel" id="extra_help"> + <property name="visible">True</property> + <property name="label" translatable="yes">Please select among the following options</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_FILL</property> + <property name="wrap">True</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> </child> - </widget> - </child> - </widget> - </child> - - <child> - <widget class="GnomeDruidPageStandard" id="extra_page"> - <property name="visible">True</property> - <property name="title" translatable="yes">Receiving Email</property> - - <child internal-child="vbox"> - <widget class="GtkVBox" id="druid_extra_vbox"> - <property name="border_width">16</property> - <property name="visible">True</property> - <property name="homogeneous">False</property> - <property name="spacing">0</property> <child> <placeholder/> @@ -107,6 +129,27 @@ Click "Forward" to begin. </property> <property name="spacing">0</property> <child> + <widget class="GtkLabel" id="transport_help"> + <property name="visible">True</property> + <property name="label" translatable="yes">Please enter information about the way you will send mail. If you are not sure, ask your system administrator or Internet Service Provider.</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_FILL</property> + <property name="wrap">True</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> <placeholder/> </child> </widget> @@ -127,6 +170,27 @@ Click "Forward" to begin. </property> <property name="spacing">0</property> <child> + <widget class="GtkLabel" id="management_help"> + <property name="visible">True</property> + <property name="label" translatable="yes">You are almost done with the mail configuration process. The identity, incoming mail server and outgoing mail transport method which you provided will be grouped together to make an Evolution mail account. Please enter a name for this account in the space below. This name will be used for display purposes only.</property> + <property name="use_underline">False</property> + <property name="use_markup">False</property> + <property name="justify">GTK_JUSTIFY_FILL</property> + <property name="wrap">True</property> + <property name="selectable">False</property> + <property name="xalign">0.5</property> + <property name="yalign">0.5</property> + <property name="xpad">0</property> + <property name="ypad">0</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">True</property> + </packing> + </child> + + <child> <placeholder/> </child> </widget> @@ -626,7 +690,7 @@ For example: "Work" or "Personal"</property> <property name="yalign">0.5</property> <property name="xpad">0</property> <property name="ypad">0</property> - <property name="mnemonic_widget">sigOption</property> + <property name="mnemonic_widget">signature_dropdown</property> </widget> <packing> <property name="left_attach">0</property> @@ -645,24 +709,12 @@ For example: "Work" or "Personal"</property> <property name="spacing">6</property> <child> - <widget class="GtkOptionMenu" id="sigOption"> + <widget class="Custom" id="signature_dropdown"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="history">0</property> - - <child internal-child="menu"> - <widget class="GtkMenu" id="convertwidget1"> - <property name="visible">True</property> - - <child> - <widget class="GtkMenuItem" id="convertwidget2"> - <property name="visible">True</property> - <property name="label" translatable="yes">Default</property> - <property name="use_underline">True</property> - </widget> - </child> - </widget> - </child> + <property name="creation_function">em_account_editor_dropdown_new</property> + <property name="int1">0</property> + <property name="int2">0</property> + <property name="last_modification_time">Mon, 06 Sep 2004 01:00:22 GMT</property> </widget> <packing> <property name="padding">0</property> @@ -894,7 +946,7 @@ For example: "Work" or "Personal"</property> <property name="yalign">0.5</property> <property name="xpad">0</property> <property name="ypad">0</property> - <property name="mnemonic_widget">source_type_omenu</property> + <property name="mnemonic_widget">source_type_dropdown</property> </widget> <packing> <property name="left_attach">0</property> @@ -955,56 +1007,12 @@ For example: "Work" or "Personal"</property> </child> <child> - <widget class="GtkOptionMenu" id="source_type_omenu"> + <widget class="Custom" id="source_type_dropdown"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="history">0</property> - - <child internal-child="menu"> - <widget class="GtkMenu" id="convertwidget3"> - <property name="visible">True</property> - - <child> - <widget class="GtkMenuItem" id="convertwidget4"> - <property name="visible">True</property> - <property name="label" translatable="yes">POP</property> - <property name="use_underline">True</property> - </widget> - </child> - - <child> - <widget class="GtkMenuItem" id="convertwidget5"> - <property name="visible">True</property> - <property name="label" translatable="yes">IMAPv4 </property> - <property name="use_underline">True</property> - </widget> - </child> - - <child> - <widget class="GtkMenuItem" id="convertwidget6"> - <property name="visible">True</property> - <property name="label" translatable="yes">Standard Unix mbox</property> - <property name="use_underline">True</property> - </widget> - </child> - - <child> - <widget class="GtkMenuItem" id="convertwidget7"> - <property name="visible">True</property> - <property name="label" translatable="yes">Qmail maildir </property> - <property name="use_underline">True</property> - </widget> - </child> - - <child> - <widget class="GtkMenuItem" id="convertwidget8"> - <property name="visible">True</property> - <property name="label" translatable="yes">None</property> - <property name="use_underline">True</property> - </widget> - </child> - </widget> - </child> + <property name="creation_function">em_account_editor_dropdown_new</property> + <property name="int1">0</property> + <property name="int2">0</property> + <property name="last_modification_time">Thu, 29 Jul 2004 05:31:24 GMT</property> </widget> <packing> <property name="left_attach">1</property> @@ -1373,40 +1381,12 @@ For example: "Work" or "Personal"</property> </child> <child> - <widget class="GtkOptionMenu" id="source_use_ssl"> + <widget class="Custom" id="source_use_ssl"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="history">0</property> - - <child internal-child="menu"> - <widget class="GtkMenu" id="convertwidget9"> - <property name="visible">True</property> - - <child> - <widget class="GtkMenuItem" id="convertwidget10"> - <property name="visible">True</property> - <property name="label" translatable="yes">Always</property> - <property name="use_underline">True</property> - </widget> - </child> - - <child> - <widget class="GtkMenuItem" id="convertwidget11"> - <property name="visible">True</property> - <property name="label" translatable="yes">Whenever Possible</property> - <property name="use_underline">True</property> - </widget> - </child> - - <child> - <widget class="GtkMenuItem" id="convertwidget12"> - <property name="visible">True</property> - <property name="label" translatable="yes">Never</property> - <property name="use_underline">True</property> - </widget> - </child> - </widget> - </child> + <property name="creation_function">em_account_editor_ssl_selector_new</property> + <property name="int1">0</property> + <property name="int2">0</property> + <property name="last_modification_time">Tue, 03 Aug 2004 07:22:52 GMT</property> </widget> <packing> <property name="padding">0</property> @@ -1561,32 +1541,12 @@ For example: "Work" or "Personal"</property> <property name="spacing">6</property> <child> - <widget class="GtkOptionMenu" id="source_auth_omenu"> + <widget class="Custom" id="source_auth_dropdown"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="history">0</property> - - <child internal-child="menu"> - <widget class="GtkMenu" id="convertwidget13"> - <property name="visible">True</property> - - <child> - <widget class="GtkMenuItem" id="convertwidget14"> - <property name="visible">True</property> - <property name="label" translatable="yes">Password</property> - <property name="use_underline">True</property> - </widget> - </child> - - <child> - <widget class="GtkMenuItem" id="convertwidget15"> - <property name="visible">True</property> - <property name="label" translatable="yes">Kerberos </property> - <property name="use_underline">True</property> - </widget> - </child> - </widget> - </child> + <property name="creation_function">em_account_editor_dropdown_new</property> + <property name="int1">0</property> + <property name="int2">0</property> + <property name="last_modification_time">Thu, 29 Jul 2004 08:38:30 GMT</property> </widget> <packing> <property name="padding">0</property> @@ -1673,229 +1633,9 @@ For example: "Work" or "Personal"</property> </child> <child> - <widget class="GtkLabel" id="label32"> - <property name="visible">True</property> - <property name="label" translatable="yes">Receiving Mail</property> - <property name="use_underline">True</property> - <property name="use_markup">False</property> - <property name="justify">GTK_JUSTIFY_CENTER</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0.5</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - </widget> - <packing> - <property name="type">tab</property> - </packing> - </child> - - <child> - <widget class="GtkVBox" id="vboxExtraTableBorder"> - <property name="border_width">12</property> - <property name="visible">True</property> - <property name="homogeneous">False</property> - <property name="spacing">12</property> - - <child> - <widget class="GtkTable" id="extra_table"> - <property name="visible">True</property> - <property name="n_rows">1</property> - <property name="n_columns">2</property> - <property name="homogeneous">False</property> - <property name="row_spacing">18</property> - <property name="column_spacing">6</property> - - <child> - <widget class="GtkVBox" id="extra_mailcheck_frame"> - <property name="visible">True</property> - <property name="homogeneous">False</property> - <property name="spacing">6</property> - - <child> - <widget class="GtkTable" id="extra_mailcheck_table"> - <property name="visible">True</property> - <property name="n_rows">1</property> - <property name="n_columns">2</property> - <property name="homogeneous">False</property> - <property name="row_spacing">6</property> - <property name="column_spacing">6</property> - - <child> - <widget class="GtkTable" id="extra_table"> - <property name="visible">True</property> - <property name="n_rows">1</property> - <property name="n_columns">2</property> - <property name="homogeneous">False</property> - <property name="row_spacing">6</property> - <property name="column_spacing">0</property> - - <child> - <widget class="GtkVBox" id="extra_mailcheck_frame"> - <property name="visible">True</property> - <property name="homogeneous">False</property> - <property name="spacing">0</property> - - <child> - <widget class="GtkLabel" id="lblMailCheck"> - <property name="visible">True</property> - <property name="label" translatable="yes"><span weight="bold">Checking for New Mail</span></property> - <property name="use_underline">False</property> - <property name="use_markup">True</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - </widget> - <packing> - <property name="padding">0</property> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - - <child> - <widget class="GtkTable" id="extra_mailcheck_table"> - <property name="border_width">12</property> - <property name="visible">True</property> - <property name="n_rows">1</property> - <property name="n_columns">2</property> - <property name="homogeneous">False</property> - <property name="row_spacing">0</property> - <property name="column_spacing">0</property> - - <child> - <widget class="GtkHBox" id="extra_mailcheck_hbox"> - <property name="visible">True</property> - <property name="homogeneous">False</property> - <property name="spacing">4</property> - - <child> - <widget class="GtkCheckButton" id="extra_auto_check"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="label" translatable="yes">Automatically check for _new mail every</property> - <property name="use_underline">True</property> - <property name="relief">GTK_RELIEF_NORMAL</property> - <property name="focus_on_click">True</property> - <property name="active">False</property> - <property name="inconsistent">False</property> - <property name="draw_indicator">True</property> - </widget> - <packing> - <property name="padding">0</property> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - - <child> - <widget class="GtkSpinButton" id="extra_auto_check_min"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="climb_rate">1</property> - <property name="digits">0</property> - <property name="numeric">True</property> - <property name="update_policy">GTK_UPDATE_ALWAYS</property> - <property name="snap_to_ticks">False</property> - <property name="wrap">False</property> - <property name="adjustment">10 1 1440 1 10 10</property> - </widget> - <packing> - <property name="padding">0</property> - <property name="expand">False</property> - <property name="fill">True</property> - </packing> - </child> - - <child> - <widget class="GtkLabel" id="lblMinutes"> - <property name="visible">True</property> - <property name="label" translatable="yes">minutes</property> - <property name="use_underline">False</property> - <property name="use_markup">False</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0.5</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - </widget> - <packing> - <property name="padding">0</property> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - </widget> - <packing> - <property name="left_attach">0</property> - <property name="right_attach">2</property> - <property name="top_attach">0</property> - <property name="bottom_attach">1</property> - </packing> - </child> - </widget> - <packing> - <property name="padding">0</property> - <property name="expand">True</property> - <property name="fill">True</property> - </packing> - </child> - </widget> - <packing> - <property name="left_attach">0</property> - <property name="right_attach">2</property> - <property name="top_attach">0</property> - <property name="bottom_attach">1</property> - </packing> - </child> - </widget> - <packing> - <property name="left_attach">0</property> - <property name="right_attach">2</property> - <property name="top_attach">0</property> - <property name="bottom_attach">1</property> - </packing> - </child> - </widget> - <packing> - <property name="padding">0</property> - <property name="expand">False</property> - <property name="fill">False</property> - </packing> - </child> - </widget> - <packing> - <property name="left_attach">0</property> - <property name="right_attach">2</property> - <property name="top_attach">0</property> - <property name="bottom_attach">1</property> - </packing> - </child> - </widget> - <packing> - <property name="padding">0</property> - <property name="expand">False</property> - <property name="fill">True</property> - </packing> - </child> - </widget> - <packing> - <property name="tab_expand">False</property> - <property name="tab_fill">True</property> - </packing> - </child> - - <child> <widget class="GtkLabel" id="label33"> <property name="visible">True</property> - <property name="label" translatable="yes">Receiving Options</property> + <property name="label" translatable="yes">Receiving Email</property> <property name="use_underline">True</property> <property name="use_markup">False</property> <property name="justify">GTK_JUSTIFY_CENTER</property> @@ -1946,7 +1686,7 @@ For example: "Work" or "Personal"</property> <property name="yalign">0</property> <property name="xpad">0</property> <property name="ypad">0</property> - <property name="mnemonic_widget">transport_type_omenu</property> + <property name="mnemonic_widget">transport_type_dropdown</property> </widget> <packing> <property name="left_attach">0</property> @@ -1982,32 +1722,12 @@ For example: "Work" or "Personal"</property> </child> <child> - <widget class="GtkOptionMenu" id="transport_type_omenu"> + <widget class="Custom" id="transport_type_dropdown"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="history">0</property> - - <child internal-child="menu"> - <widget class="GtkMenu" id="convertwidget16"> - <property name="visible">True</property> - - <child> - <widget class="GtkMenuItem" id="convertwidget17"> - <property name="visible">True</property> - <property name="label" translatable="yes">SMTP</property> - <property name="use_underline">True</property> - </widget> - </child> - - <child> - <widget class="GtkMenuItem" id="convertwidget18"> - <property name="visible">True</property> - <property name="label" translatable="yes">Sendmail</property> - <property name="use_underline">True</property> - </widget> - </child> - </widget> - </child> + <property name="creation_function">em_account_editor_dropdown_new</property> + <property name="int1">0</property> + <property name="int2">0</property> + <property name="last_modification_time">Thu, 29 Jul 2004 05:42:00 GMT</property> </widget> <packing> <property name="left_attach">1</property> @@ -2335,40 +2055,12 @@ For example: "Work" or "Personal"</property> </child> <child> - <widget class="GtkOptionMenu" id="transport_use_ssl"> + <widget class="Custom" id="transport_use_ssl"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="history">0</property> - - <child internal-child="menu"> - <widget class="GtkMenu" id="convertwidget19"> - <property name="visible">True</property> - - <child> - <widget class="GtkMenuItem" id="convertwidget20"> - <property name="visible">True</property> - <property name="label" translatable="yes">Always</property> - <property name="use_underline">True</property> - </widget> - </child> - - <child> - <widget class="GtkMenuItem" id="convertwidget21"> - <property name="visible">True</property> - <property name="label" translatable="yes">Whenever Possible</property> - <property name="use_underline">True</property> - </widget> - </child> - - <child> - <widget class="GtkMenuItem" id="convertwidget22"> - <property name="visible">True</property> - <property name="label" translatable="yes">Never</property> - <property name="use_underline">True</property> - </widget> - </child> - </widget> - </child> + <property name="creation_function">em_account_editor_ssl_selector_new</property> + <property name="int1">0</property> + <property name="int2">0</property> + <property name="last_modification_time">Tue, 03 Aug 2004 07:23:50 GMT</property> </widget> <packing> <property name="padding">0</property> @@ -2547,7 +2239,7 @@ For example: "Work" or "Personal"</property> <property name="yalign">0.5</property> <property name="xpad">0</property> <property name="ypad">0</property> - <property name="mnemonic_widget">transport_auth_omenu</property> + <property name="mnemonic_widget">transport_auth_dropdown</property> </widget> <packing> <property name="left_attach">0</property> @@ -2612,32 +2304,12 @@ For example: "Work" or "Personal"</property> <property name="spacing">6</property> <child> - <widget class="GtkOptionMenu" id="transport_auth_omenu"> + <widget class="Custom" id="transport_auth_dropdown"> <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="history">0</property> - - <child internal-child="menu"> - <widget class="GtkMenu" id="convertwidget23"> - <property name="visible">True</property> - - <child> - <widget class="GtkMenuItem" id="convertwidget24"> - <property name="visible">True</property> - <property name="label" translatable="yes">Password</property> - <property name="use_underline">True</property> - </widget> - </child> - - <child> - <widget class="GtkMenuItem" id="convertwidget25"> - <property name="visible">True</property> - <property name="label" translatable="yes">Kerberos </property> - <property name="use_underline">True</property> - </widget> - </child> - </widget> - </child> + <property name="creation_function">em_account_editor_dropdown_new</property> + <property name="int1">0</property> + <property name="int2">0</property> + <property name="last_modification_time">Thu, 29 Jul 2004 08:37:13 GMT</property> </widget> <packing> <property name="padding">0</property> @@ -4352,7 +4024,7 @@ For example: "Work" or "Personal"</property> <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> <child> - <widget class="GtkNotebook" id="toplevel"> + <widget class="GtkNotebook" id="preferences_toplevel"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="show_tabs">True</property> @@ -6450,7 +6122,7 @@ For example: "Work" or "Personal"</property> <property name="gravity">GDK_GRAVITY_NORTH_WEST</property> <child> - <widget class="GtkNotebook" id="toplevel"> + <widget class="GtkNotebook" id="composer_toplevel"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="show_tabs">True</property> diff --git a/mail/mail-dialogs.glade b/mail/mail-dialogs.glade index d0aba915ac..9f90948f7e 100644 --- a/mail/mail-dialogs.glade +++ b/mail/mail-dialogs.glade @@ -795,7 +795,7 @@ </child> </widget> -<widget class="GtkDialog" id="lic_dialog"> +<widget class="GtkDialog" id="license_dialog"> <property name="visible">True</property> <property name="title" translatable="yes">License Agreement</property> <property name="type">GTK_WINDOW_TOPLEVEL</property> @@ -909,7 +909,7 @@ <property name="spacing">0</property> <child> - <widget class="GtkLabel" id="lic_top_label"> + <widget class="GtkLabel" id="license_top_label"> <property name="visible">True</property> <property name="label" translatable="yes"> Please read carefully the license agreement displayed @@ -942,7 +942,7 @@ <property name="window_placement">GTK_CORNER_TOP_LEFT</property> <child> - <widget class="GtkTextView" id="textview1"> + <widget class="GtkTextView" id="license_textview"> <property name="width_request">500</property> <property name="height_request">400</property> <property name="visible">True</property> @@ -969,7 +969,7 @@ </child> <child> - <widget class="GtkCheckButton" id="lic_checkbutton"> + <widget class="GtkCheckButton" id="license_checkbutton"> <property name="visible">True</property> <property name="can_focus">True</property> <property name="label" translatable="yes">Tick this to accept the license agreement</property> diff --git a/mail/mail-errors.xml b/mail/mail-errors.xml index 9e32d5aba2..44717434d3 100644 --- a/mail/mail-errors.xml +++ b/mail/mail-errors.xml @@ -311,6 +311,13 @@ You can choose to ignore this folder, overwrite or append its contents, or quit. <button label="_Append" response="GTK_RESPONSE_OK"/> </error> + <error id="no-load-license" type="error"> + <primary>Unable to read license file.</primary> + <secondary>Cannot read the license file "{0}", due to an + installation problem. You will not be able to use this provider until + you can accept its license.</secondary> + </error> + <error id="gw-accountsetup-error" type="error"> <primary><span weight="bold" size="larger">Unable to connect to the GroupWise server.</span></primary> diff --git a/mail/mail-folder-cache.c b/mail/mail-folder-cache.c index 52765b4ffd..91616dc536 100644 --- a/mail/mail-folder-cache.c +++ b/mail/mail-folder-cache.c @@ -34,6 +34,7 @@ #include <time.h> #include <libgnome/gnome-sound.h> +#include <libgnome/gnome-i18n.h> #include <bonobo/bonobo-exception.h> #include <camel/camel-store.h> #include <camel/camel-folder.h> @@ -53,6 +54,8 @@ #include "mail-config.h" #include "em-folder-tree-model.h" +#include "em-event.h" + #define w(x) #define d(x) @@ -238,6 +241,14 @@ real_flush_updates(void *o, void *event_data, void *data) if (notify_type != 0 && up->new && notify_idle_id == 0 && (now - last_notify >= 5)) notify_idle_id = g_idle_add_full (G_PRIORITY_LOW, notify_idle_cb, NULL, NULL); + if (up->uri) { + EMEvent *e = em_event_peek(); + EMEventTargetFolder *t = em_event_target_new_folder(e, up->uri, up->new?EM_EVENT_FOLDER_NEWMAIL:0); + + /* EVENT: folder.changed definition */ + e_event_emit((EEvent *)e, "folder.changed", (EEventTarget *)t); + } + free_update(up); LOCK(info_lock); @@ -357,6 +368,7 @@ update_1folder(struct _folder_info *mfi, int new, CamelFolderInfo *info) up->unread = unread; up->new = new ? 1 : 0; up->store = mfi->store_info->store; + up->uri = g_strdup(mfi->uri); camel_object_ref(up->store); e_dlist_addtail(&updates, (EDListNode *)up); flush_updates(); diff --git a/mail/mail-ops.c b/mail/mail-ops.c index d6351fe435..013eb4a184 100644 --- a/mail/mail-ops.c +++ b/mail/mail-ops.c @@ -36,6 +36,7 @@ #include <errno.h> #include <libgnome/gnome-exec.h> #include <gal/util/e-util.h> +#include <libgnome/gnome-i18n.h> #include <camel/camel-mime-filter-from.h> #include <camel/camel-stream-filter.h> diff --git a/mail/mail-send-recv.c b/mail/mail-send-recv.c index 99dbe5620b..bb3af5aa48 100644 --- a/mail/mail-send-recv.c +++ b/mail/mail-send-recv.c @@ -38,6 +38,7 @@ #include <gtk/gtkimage.h> #include <gtk/gtkbox.h> #include <libgnomeui/gnome-window-icon.h> +#include <libgnome/gnome-i18n.h> #include "e-util/e-gtk-utils.h" #include "e-util/e-account-list.h" @@ -761,8 +762,7 @@ GtkWidget *mail_send_receive (void) } struct _auto_data { - char *uri; - int keep; /* keep on server flag */ + EAccount *account; int period; /* in seconds */ int timeout_id; }; @@ -774,85 +774,100 @@ auto_timeout(void *data) { struct _auto_data *info = data; - if (camel_session_is_online(session)) - mail_receive_uri(info->uri, info->keep); + if (camel_session_is_online(session)) { + const char *uri = e_account_get_string(info->account, E_ACCOUNT_SOURCE_URL); + int keep = e_account_get_bool(info->account, E_ACCOUNT_SOURCE_KEEP_ON_SERVER); + + mail_receive_uri(uri, keep); + } return TRUE; } -static void auto_setup_set(void *key, struct _auto_data *info, GHashTable *set) +static void +auto_account_removed(EAccountList *eal, EAccount *ea, void *dummy) { - g_hash_table_insert(set, info->uri, info); + struct _auto_data *info = g_object_get_data((GObject *)ea, "mail-autoreceive"); + + g_return_if_fail(info != NULL); + + if (info->timeout_id) { + g_source_remove(info->timeout_id); + info->timeout_id = 0; + } } -static void auto_clean_set(void *key, struct _auto_data *info, GHashTable *set) +static void +auto_account_finalised(EAccount *ea, struct _auto_data *info) { - d(printf("removing auto-check for %s %p\n", info->uri, info)); - g_hash_table_remove(set, info->uri); - g_source_remove(info->timeout_id); - g_free(info->uri); + if (info->timeout_id) + g_source_remove(info->timeout_id); g_free(info); } +static void +auto_account_commit(struct _auto_data *info) +{ + int period, check; + + check = info->account->enabled + && e_account_get_bool(info->account, E_ACCOUNT_SOURCE_AUTO_CHECK) + && e_account_get_string(info->account, E_ACCOUNT_SOURCE_URL); + period = e_account_get_int(info->account, E_ACCOUNT_SOURCE_AUTO_CHECK_TIME)*60; + period = MAX(60, period); + + if (info->timeout_id + && (!check + || period != info->period)) { + g_source_remove(info->timeout_id); + info->timeout_id = 0; + } + info->period = period; + if (check && info->timeout_id == 0) + info->timeout_id = g_timeout_add(info->period*1000, auto_timeout, info); +} + +static void +auto_account_added(EAccountList *eal, EAccount *ea, void *dummy) +{ + struct _auto_data *info; + + info = g_malloc0(sizeof(*info)); + info->account = ea; + g_object_set_data_full((GObject *)ea, "mail-autoreceive", info, (GDestroyNotify)auto_account_finalised); + auto_account_commit(info); +} + +static void +auto_account_changed(EAccountList *eal, EAccount *ea, void *dummy) +{ + struct _auto_data *info = g_object_get_data((GObject *)ea, "mail-autoreceive"); + + g_return_if_fail(info != NULL); + + auto_account_commit(info); +} + /* call to setup initial, and after changes are made to the config */ /* FIXME: Need a cleanup funciton for when object is deactivated */ void -mail_autoreceive_setup (void) +mail_autoreceive_init(void) { EAccountList *accounts; - GHashTable *set_hash; EIterator *iter; + if (auto_active) + return; + accounts = mail_config_get_accounts (); - - if (auto_active == NULL) - auto_active = g_hash_table_new(g_str_hash, g_str_equal); - - set_hash = g_hash_table_new(g_str_hash, g_str_equal); - g_hash_table_foreach(auto_active, (GHFunc)auto_setup_set, set_hash); - - iter = e_list_get_iterator ((EList *) accounts); - while (e_iterator_is_valid (iter)) { - EAccountService *source; - EAccount *account; - - account = (EAccount *) e_iterator_get (iter); - source = account->source; - - if (account->enabled && source->url && source->auto_check) { - struct _auto_data *info; - - d(printf("setting up auto-receive mail for : %s %dm\n", source->url, source->auto_check_time)); - - g_hash_table_remove(set_hash, source->url); - info = g_hash_table_lookup(auto_active, source->url); - if (info) { - info->keep = source->keep_on_server; - if (info->period != source->auto_check_time*60) { - info->period = MAX(source->auto_check_time*60, 60); - g_source_remove(info->timeout_id); - info->timeout_id = g_timeout_add(info->period*1000, auto_timeout, info); - } - } else { - info = g_malloc0(sizeof(*info)); - info->uri = g_strdup(source->url); - info->keep = source->keep_on_server; - info->period = MAX(source->auto_check_time*60, 60); - info->timeout_id = g_timeout_add(info->period*1000, auto_timeout, info); - g_hash_table_insert(auto_active, info->uri, info); - /* If we do this at startup, it can cause the logon dialog to be hidden, - so lets not */ - /*mail_receive_uri(source->url, source->keep_on_server);*/ - } - } - - e_iterator_next (iter); - } - - g_object_unref (iter); - - g_hash_table_foreach(set_hash, (GHFunc)auto_clean_set, auto_active); - g_hash_table_destroy(set_hash); + auto_active = g_hash_table_new(g_str_hash, g_str_equal); + + g_signal_connect(accounts, "account-added", G_CALLBACK(auto_account_added), NULL); + g_signal_connect(accounts, "account-removed", G_CALLBACK(auto_account_removed), NULL); + g_signal_connect(accounts, "account-changed", G_CALLBACK(auto_account_changed), NULL); + + for (iter = e_list_get_iterator((EList *)accounts);e_iterator_is_valid(iter);e_iterator_next(iter)) + auto_account_added(accounts, (EAccount *)e_iterator_get(iter), NULL); } /* we setup the download info's in a hashtable, if we later need to build the gui, we insert diff --git a/mail/mail-send-recv.h b/mail/mail-send-recv.h index d97f06222e..dab199466a 100644 --- a/mail/mail-send-recv.h +++ b/mail/mail-send-recv.h @@ -36,7 +36,7 @@ GtkWidget *mail_send_receive(void); void mail_receive_uri(const char *uri, int keep); void mail_send (void); /* setup auto receive stuff */ -void mail_autoreceive_setup(void); +void mail_autoreceive_init(void); #ifdef __cplusplus } diff --git a/mail/mail-session.c b/mail/mail-session.c index 12ba0004e1..3109c47c30 100644 --- a/mail/mail-session.c +++ b/mail/mail-session.c @@ -42,6 +42,7 @@ #include <camel/camel.h> /* FIXME: this is where camel_init is defined, it shouldn't include everything else */ #include "camel/camel-filter-driver.h" +#include <camel/camel-i18n.h> #include "em-filter-context.h" #include "em-filter-rule.h" diff --git a/mail/mail-tools.c b/mail/mail-tools.c index 7cf0878a2e..59dd3613ec 100644 --- a/mail/mail-tools.c +++ b/mail/mail-tools.c @@ -36,6 +36,7 @@ #include <gconf/gconf.h> #include <gconf/gconf-client.h> +#include <libgnome/gnome-i18n.h> #include <camel/camel-vee-folder.h> #include <camel/camel-file-utils.h> diff --git a/mail/message-list.c b/mail/message-list.c index 4c0fdff1fd..c34a4ccf1e 100644 --- a/mail/message-list.c +++ b/mail/message-list.c @@ -39,6 +39,7 @@ #include <gtk/gtkmain.h> #include <gtk/gtkinvisible.h> +#include <libgnome/gnome-i18n.h> #include <gal/util/e-util.h> #include <gal/widgets/e-gui-utils.h> @@ -1678,34 +1679,48 @@ ml_drop_action(struct _drop_msg *m) } static void -ml_drop_popup_copy(GtkWidget *item, struct _drop_msg *m) +ml_drop_popup_copy(EPopup *ep, EPopupItem *item, void *data) { + struct _drop_msg *m = data; + m->action = GDK_ACTION_COPY; ml_drop_action(m); } static void -ml_drop_popup_move(GtkWidget *item, struct _drop_msg *m) +ml_drop_popup_move(EPopup *ep, EPopupItem *item, void *data) { + struct _drop_msg *m = data; + m->action = GDK_ACTION_MOVE; ml_drop_action(m); } static void -ml_drop_popup_cancel(GtkWidget *item, struct _drop_msg *m) +ml_drop_popup_cancel(EPopup *ep, EPopupItem *item, void *data) { + struct _drop_msg *m = data; + m->aborted = TRUE; mail_msg_free(&m->msg); } -static EMPopupItem ml_drop_popup_menu[] = { - { EM_POPUP_ITEM, "00.emc.02", N_("_Copy"), G_CALLBACK(ml_drop_popup_copy), NULL, "stock_folder-copy", 0 }, - { EM_POPUP_ITEM, "00.emc.03", N_("_Move"), G_CALLBACK(ml_drop_popup_move), NULL, "stock_folder-move", 0 }, - { EM_POPUP_BAR, "10.emc" }, - { EM_POPUP_ITEM, "99.emc.00", N_("Cancel _Drag"), G_CALLBACK(ml_drop_popup_cancel), NULL, NULL, 0 }, +static EPopupItem ml_drop_popup_menu[] = { + { E_POPUP_ITEM, "00.emc.02", N_("_Copy"), ml_drop_popup_copy, NULL, "stock_folder-copy", 0 }, + { E_POPUP_ITEM, "00.emc.03", N_("_Move"), ml_drop_popup_move, NULL, "stock_folder-move", 0 }, + { E_POPUP_BAR, "10.emc" }, + { E_POPUP_ITEM, "99.emc.00", N_("Cancel _Drag"), ml_drop_popup_cancel, NULL, NULL, 0 }, }; static void +ml_drop_popup_free(EPopup *ep, GSList *items, void *data) +{ + g_slist_free(items); + + /* FIXME: free data if no item was selected? */ +} + +static void ml_tree_drag_data_received (ETree *tree, int row, ETreePath path, int col, GdkDragContext *context, gint x, gint y, GtkSelectionData *data, guint info, @@ -1738,14 +1753,11 @@ ml_tree_drag_data_received (ETree *tree, int row, ETreePath path, int col, int i; emp = em_popup_new("com.ximian.mail.messagelist.popup.drop"); - for (i=0;i<sizeof(ml_drop_popup_menu)/sizeof(ml_drop_popup_menu[0]);i++) { - EMPopupItem *item = &ml_drop_popup_menu[i]; + for (i=0;i<sizeof(ml_drop_popup_menu)/sizeof(ml_drop_popup_menu[0]);i++) + menus = g_slist_append(menus, &ml_drop_popup_menu[i]); - item->activate_data = m; - menus = g_slist_append(menus, item); - } - em_popup_add_items(emp, menus, (GDestroyNotify)g_slist_free); - menu = em_popup_create_menu_once(emp, NULL, 0, 0); + e_popup_add_items((EPopup *)emp, menus, ml_drop_popup_free, m); + menu = e_popup_create_menu_once((EPopup *)emp, NULL, 0, 0); gtk_menu_popup(menu, NULL, NULL, NULL, NULL, 0, gtk_get_current_event_time()); } else { ml_drop_action(m); @@ -1848,7 +1860,7 @@ message_list_destroy(GtkObject *object) mail_async_event_destroy(message_list->async_event); message_list->async_event = NULL; } - + if (message_list->folder) { /* need to do this before removing folder, folderinfo's might not exist after */ save_tree_state(message_list); @@ -2738,7 +2750,7 @@ folder_changed (CamelObject *o, gpointer event_data, gpointer user_data) { CamelFolderChangeInfo *changes; MessageList *ml = MESSAGE_LIST (user_data); - + if (event_data) { changes = camel_folder_change_info_new(); camel_folder_change_info_cat(changes, (CamelFolderChangeInfo *)event_data); diff --git a/mail/message-tag-followup.c b/mail/message-tag-followup.c index edc015eb0b..3c456e926e 100644 --- a/mail/message-tag-followup.c +++ b/mail/message-tag-followup.c @@ -54,6 +54,7 @@ #include <gconf/gconf-client.h> #include <libgnomeui/gnome-pixmap.h> +#include <libgnome/gnome-i18n.h> #include "message-tag-followup.h" #include "mail-config.h" |