diff options
Diffstat (limited to 'mail')
40 files changed, 4042 insertions, 1731 deletions
diff --git a/mail/Makefile.am b/mail/Makefile.am index 0859c55c06..8310cff129 100644 --- a/mail/Makefile.am +++ b/mail/Makefile.am @@ -46,6 +46,9 @@ libevolution_mail_la_CPPFLAGS = \ mailinclude_HEADERS = \ e-mail.h \ + e-mail-account-manager.h \ + e-mail-account-store.h \ + e-mail-account-tree-view.h \ e-mail-attachment-bar.h \ e-mail-backend.h \ e-mail-browser.h \ @@ -61,7 +64,6 @@ mailinclude_HEADERS = \ e-mail-label-list-store.h \ e-mail-label-manager.h \ e-mail-label-tree-view.h \ - e-mail-local.h \ e-mail-message-pane.h \ e-mail-migrate.h \ e-mail-notebook-view.h \ @@ -72,7 +74,6 @@ mailinclude_HEADERS = \ e-mail-session.h \ e-mail-sidebar.h \ e-mail-store-utils.h \ - e-mail-store.h \ e-mail-tag-editor.h \ e-mail-view.h \ em-account-editor.h \ @@ -121,6 +122,9 @@ mailinclude_HEADERS += \ endif libevolution_mail_la_SOURCES = \ + e-mail-account-manager.c \ + e-mail-account-store.c \ + e-mail-account-tree-view.c \ e-mail-attachment-bar.c \ e-mail-backend.c \ e-mail-browser.c \ @@ -135,7 +139,6 @@ libevolution_mail_la_SOURCES = \ e-mail-label-list-store.c \ e-mail-label-manager.c \ e-mail-label-tree-view.c \ - e-mail-local.c \ e-mail-message-pane.c \ e-mail-migrate.c \ e-mail-notebook-view.c \ @@ -146,7 +149,6 @@ libevolution_mail_la_SOURCES = \ e-mail-session.c \ e-mail-sidebar.c \ e-mail-store-utils.c \ - e-mail-store.c \ e-mail-tag-editor.c \ e-mail-view.c \ em-account-editor.c \ diff --git a/mail/e-mail-account-manager.c b/mail/e-mail-account-manager.c new file mode 100644 index 0000000000..97a4fe3fe0 --- /dev/null +++ b/mail/e-mail-account-manager.c @@ -0,0 +1,565 @@ +/* + * e-mail-account-manager.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#include "e-mail-account-manager.h" + +#include <config.h> +#include <glib/gi18n-lib.h> +#include <gdk/gdkkeysyms.h> + +#include <mail/e-mail-account-tree-view.h> + +#define E_MAIL_ACCOUNT_MANAGER_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_MAIL_ACCOUNT_MANAGER, EMailAccountManagerPrivate)) + +#define DEFAULT_ORDER_RESPONSE GTK_RESPONSE_APPLY + +struct _EMailAccountManagerPrivate { + EMailAccountStore *store; + gulong row_changed_handler_id; + + GtkWidget *tree_view; /* not referenced */ + GtkWidget *add_button; /* not referenced */ + GtkWidget *edit_button; /* not referenced */ + GtkWidget *delete_button; /* not referenced */ + GtkWidget *default_button; /* not referenced */ +}; + +enum { + PROP_0, + PROP_STORE +}; + +enum { + ADD_ACCOUNT, + EDIT_ACCOUNT, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +G_DEFINE_TYPE ( + EMailAccountManager, + e_mail_account_manager, + GTK_TYPE_TABLE) + +static void +mail_account_manager_add_cb (EMailAccountManager *manager) +{ + e_mail_account_manager_add_account (manager); +} + +static void +mail_account_manager_edit_cb (EMailAccountManager *manager) +{ + EMailAccountTreeView *tree_view; + EAccount *account; + CamelService *service; + const gchar *uid; + + tree_view = E_MAIL_ACCOUNT_TREE_VIEW (manager->priv->tree_view); + service = e_mail_account_tree_view_get_selected_service (tree_view); + + uid = camel_service_get_uid (service); + account = e_get_account_by_uid (uid); + g_return_if_fail (account != NULL); + + e_mail_account_manager_edit_account (manager, account); +} + +static void +mail_account_manager_remove_cb (EMailAccountManager *manager) +{ + EMailAccountTreeView *tree_view; + EMailAccountStore *store; + CamelService *service; + gpointer parent; + + tree_view = E_MAIL_ACCOUNT_TREE_VIEW (manager->priv->tree_view); + service = e_mail_account_tree_view_get_selected_service (tree_view); + + parent = gtk_widget_get_toplevel (GTK_WIDGET (manager)); + parent = gtk_widget_is_toplevel (parent) ? parent : NULL; + + store = e_mail_account_manager_get_store (manager); + e_mail_account_store_remove_service (store, parent, service); +} + +static void +mail_account_manager_enable_cb (EMailAccountManager *manager) +{ + EMailAccountTreeView *tree_view; + EMailAccountStore *store; + CamelService *service; + gpointer parent; + + tree_view = E_MAIL_ACCOUNT_TREE_VIEW (manager->priv->tree_view); + service = e_mail_account_tree_view_get_selected_service (tree_view); + + parent = gtk_widget_get_toplevel (GTK_WIDGET (manager)); + parent = gtk_widget_is_toplevel (parent) ? parent : NULL; + + store = e_mail_account_manager_get_store (manager); + e_mail_account_store_enable_service (store, parent, service); +} + +static void +mail_account_manager_disable_cb (EMailAccountManager *manager) +{ + EMailAccountTreeView *tree_view; + EMailAccountStore *store; + CamelService *service; + gpointer parent; + + tree_view = E_MAIL_ACCOUNT_TREE_VIEW (manager->priv->tree_view); + service = e_mail_account_tree_view_get_selected_service (tree_view); + + parent = gtk_widget_get_toplevel (GTK_WIDGET (manager)); + parent = gtk_widget_is_toplevel (parent) ? parent : NULL; + + store = e_mail_account_manager_get_store (manager); + e_mail_account_store_disable_service (store, parent, service); +} + +static void +mail_account_manager_default_cb (EMailAccountManager *manager) +{ + EMailAccountTreeView *tree_view; + EMailAccountStore *store; + CamelService *service; + + tree_view = E_MAIL_ACCOUNT_TREE_VIEW (manager->priv->tree_view); + service = e_mail_account_tree_view_get_selected_service (tree_view); + + store = e_mail_account_manager_get_store (manager); + e_mail_account_store_set_default_service (store, service); +} + +static void +mail_account_manager_info_bar_response_cb (EMailAccountManager *manager, + gint response) +{ + EMailAccountStore *store; + + store = e_mail_account_manager_get_store (manager); + + if (response == DEFAULT_ORDER_RESPONSE) + e_mail_account_store_reorder_services (store, NULL); +} + +static gboolean +mail_account_manager_key_press_event_cb (EMailAccountManager *manager, + GdkEventKey *event) +{ + if (event->keyval == GDK_KEY_Delete) { + mail_account_manager_remove_cb (manager); + return TRUE; + } + + return FALSE; +} + +static void +mail_account_manager_row_changed_cb (GtkTreeModel *tree_model, + GtkTreePath *path, + GtkTreeIter *iter, + EMailAccountManager *manager) +{ + GtkTreeView *tree_view; + GtkTreeSelection *selection; + + tree_view = GTK_TREE_VIEW (manager->priv->tree_view); + selection = gtk_tree_view_get_selection (tree_view); + + /* Update buttons for the selected row (which is not + * necessarily the row that changed, but do it anyway). */ + g_signal_emit_by_name (selection, "changed"); +} + +static void +mail_account_manager_selection_changed_cb (EMailAccountManager *manager, + GtkTreeSelection *selection) +{ + GtkTreeModel *tree_model; + GtkTreeIter iter; + EMailAccountStore *store; + CamelService *default_service; + CamelService *service; + GtkWidget *add_button; + GtkWidget *edit_button; + GtkWidget *delete_button; + GtkWidget *default_button; + gboolean builtin; + gboolean sensitive; + gboolean not_default; + + add_button = manager->priv->add_button; + edit_button = manager->priv->edit_button; + delete_button = manager->priv->delete_button; + default_button = manager->priv->default_button; + + if (gtk_tree_selection_get_selected (selection, &tree_model, &iter)) { + gtk_tree_model_get ( + tree_model, &iter, + E_MAIL_ACCOUNT_STORE_COLUMN_SERVICE, &service, + E_MAIL_ACCOUNT_STORE_COLUMN_BUILTIN, &builtin, + -1); + } else { + service = NULL; + builtin = FALSE; + } + + store = e_mail_account_manager_get_store (manager); + default_service = e_mail_account_store_get_default_service (store); + not_default = (service != default_service); + + if (service == NULL) + gtk_widget_grab_focus (add_button); + + sensitive = (service != NULL && !builtin); + gtk_widget_set_sensitive (edit_button, sensitive); + + sensitive = (service != NULL && !builtin); + gtk_widget_set_sensitive (delete_button, sensitive); + + sensitive = (service != NULL && !builtin && not_default); + gtk_widget_set_sensitive (default_button, sensitive); +} + +static void +mail_account_manager_set_store (EMailAccountManager *manager, + EMailAccountStore *store) +{ + g_return_if_fail (E_IS_MAIL_ACCOUNT_STORE (store)); + g_return_if_fail (manager->priv->store == NULL); + + manager->priv->store = g_object_ref (store); +} + +static void +mail_account_manager_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_STORE: + mail_account_manager_set_store ( + E_MAIL_ACCOUNT_MANAGER (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +mail_account_manager_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_STORE: + g_value_set_object ( + value, + e_mail_account_manager_get_store ( + E_MAIL_ACCOUNT_MANAGER (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +mail_account_manager_dispose (GObject *object) +{ + EMailAccountManagerPrivate *priv; + + priv = E_MAIL_ACCOUNT_MANAGER_GET_PRIVATE (object); + + if (priv->store != NULL) { + g_signal_handler_disconnect ( + priv->store, priv->row_changed_handler_id); + g_object_unref (priv->store); + priv->store = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (e_mail_account_manager_parent_class)->dispose (object); +} + +static void +mail_account_manager_constructed (GObject *object) +{ + EMailAccountManager *manager; + EMailAccountStore *store; + GtkTreeSelection *selection; + GtkWidget *container; + GtkWidget *widget; + gulong handler_id; + + manager = E_MAIL_ACCOUNT_MANAGER (object); + store = e_mail_account_manager_get_store (manager); + + /* Chain up to parent's constructed() method. */ + G_OBJECT_CLASS (e_mail_account_manager_parent_class)-> + constructed (object); + + g_object_bind_property ( + store, "busy", + manager, "sensitive", + G_BINDING_SYNC_CREATE | + G_BINDING_INVERT_BOOLEAN); + + handler_id = g_signal_connect ( + store, "row-changed", + G_CALLBACK (mail_account_manager_row_changed_cb), + manager); + + /* We disconnect the handler in dispose(). */ + manager->priv->row_changed_handler_id = handler_id; + + gtk_table_resize (GTK_TABLE (manager), 2, 2); + gtk_table_set_col_spacings (GTK_TABLE (manager), 6); + gtk_table_set_row_spacings (GTK_TABLE (manager), 0); + + container = GTK_WIDGET (manager); + + widget = gtk_scrolled_window_new (NULL, NULL); + gtk_scrolled_window_set_policy ( + GTK_SCROLLED_WINDOW (widget), + GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); + gtk_scrolled_window_set_shadow_type ( + GTK_SCROLLED_WINDOW (widget), GTK_SHADOW_IN); + gtk_table_attach ( + GTK_TABLE (container), widget, 0, 1, 0, 1, + GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0); + gtk_widget_show (widget); + + container = widget; + + widget = e_mail_account_tree_view_new (store); + gtk_container_add (GTK_CONTAINER (container), widget); + manager->priv->tree_view = widget; /* not referenced */ + gtk_widget_show (widget); + + g_signal_connect_swapped ( + widget, "enable", + G_CALLBACK (mail_account_manager_enable_cb), manager); + + g_signal_connect_swapped ( + widget, "disable", + G_CALLBACK (mail_account_manager_disable_cb), manager); + + g_signal_connect_swapped ( + widget, "key-press-event", + G_CALLBACK (mail_account_manager_key_press_event_cb), + manager); + + g_signal_connect_swapped ( + widget, "row-activated", + G_CALLBACK (mail_account_manager_edit_cb), manager); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (widget)); + + g_signal_connect_swapped ( + selection, "changed", + G_CALLBACK (mail_account_manager_selection_changed_cb), + manager); + + container = GTK_WIDGET (manager); + + widget = gtk_frame_new (NULL); + gtk_frame_set_shadow_type ( + GTK_FRAME (widget), GTK_SHADOW_IN); + gtk_table_attach ( + GTK_TABLE (container), widget, + 0, 1, 1, 2, GTK_FILL, 0, 0, 0); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_info_bar_new (); + gtk_info_bar_set_message_type ( + GTK_INFO_BAR (widget), GTK_MESSAGE_INFO); + gtk_info_bar_add_button ( + GTK_INFO_BAR (widget), + _("_Restore Default"), + DEFAULT_ORDER_RESPONSE); + gtk_container_add (GTK_CONTAINER (container), widget); + gtk_widget_show (widget); + + g_signal_connect_swapped ( + widget, "response", + G_CALLBACK (mail_account_manager_info_bar_response_cb), + manager); + + container = gtk_info_bar_get_content_area (GTK_INFO_BAR (widget)); + + widget = gtk_label_new ( + _("You can drag and drop account names to reorder them.")); + gtk_misc_set_alignment (GTK_MISC (widget), 0.0, 0.5); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + gtk_widget_show (widget); + + container = GTK_WIDGET (manager); + + widget = gtk_vbutton_box_new (); + gtk_button_box_set_layout ( + GTK_BUTTON_BOX (widget), GTK_BUTTONBOX_START); + gtk_box_set_spacing (GTK_BOX (widget), 6); + gtk_table_attach ( + GTK_TABLE (container), widget, + 1, 2, 0, 2, 0, GTK_FILL, 0, 0); + gtk_widget_show (widget); + + container = widget; + + widget = gtk_button_new_from_stock (GTK_STOCK_ADD); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + manager->priv->add_button = widget; /* not referenced */ + gtk_widget_show (widget); + + g_signal_connect_swapped ( + widget, "clicked", + G_CALLBACK (mail_account_manager_add_cb), manager); + + widget = gtk_button_new_from_stock (GTK_STOCK_EDIT); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + manager->priv->edit_button = widget; /* not referenced */ + gtk_widget_show (widget); + + g_signal_connect_swapped ( + widget, "clicked", + G_CALLBACK (mail_account_manager_edit_cb), manager); + + widget = gtk_button_new_from_stock (GTK_STOCK_DELETE); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + manager->priv->delete_button = widget; /* not referenced */ + gtk_widget_show (widget); + + g_signal_connect_swapped ( + widget, "clicked", + G_CALLBACK (mail_account_manager_remove_cb), manager); + + widget = gtk_button_new_with_mnemonic (_("De_fault")); + gtk_button_set_image ( + GTK_BUTTON (widget), + gtk_image_new_from_icon_name ( + "emblem-default", GTK_ICON_SIZE_BUTTON)); + gtk_box_pack_start (GTK_BOX (container), widget, TRUE, TRUE, 0); + manager->priv->default_button = widget; /* not referenced */ + gtk_widget_show (widget); + + g_signal_connect_swapped ( + widget, "clicked", + G_CALLBACK (mail_account_manager_default_cb), manager); + + /* Initialize button states. */ + g_signal_emit_by_name (selection, "changed"); +} + +static void +e_mail_account_manager_class_init (EMailAccountManagerClass *class) +{ + GObjectClass *object_class; + + g_type_class_add_private (class, sizeof (EMailAccountManagerPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = mail_account_manager_set_property; + object_class->get_property = mail_account_manager_get_property; + object_class->dispose = mail_account_manager_dispose; + object_class->constructed = mail_account_manager_constructed; + + g_object_class_install_property ( + object_class, + PROP_STORE, + g_param_spec_object ( + "store", + "Store", + NULL, + E_TYPE_MAIL_ACCOUNT_STORE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + signals[ADD_ACCOUNT] = g_signal_new ( + "add-account", + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EMailAccountManagerClass, add_account), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[EDIT_ACCOUNT] = g_signal_new ( + "edit-account", + G_OBJECT_CLASS_TYPE (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EMailAccountManagerClass, edit_account), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + E_TYPE_ACCOUNT); +} + +static void +e_mail_account_manager_init (EMailAccountManager *manager) +{ + manager->priv = E_MAIL_ACCOUNT_MANAGER_GET_PRIVATE (manager); +} + +GtkWidget * +e_mail_account_manager_new (EMailAccountStore *store) +{ + g_return_val_if_fail (E_IS_MAIL_ACCOUNT_STORE (store), NULL); + + return g_object_new ( + E_TYPE_MAIL_ACCOUNT_MANAGER, + "store", store, NULL); +} + +EMailAccountStore * +e_mail_account_manager_get_store (EMailAccountManager *manager) +{ + g_return_val_if_fail (E_IS_MAIL_ACCOUNT_MANAGER (manager), NULL); + + return manager->priv->store; +} + +void +e_mail_account_manager_add_account (EMailAccountManager *manager) +{ + g_return_if_fail (E_IS_MAIL_ACCOUNT_MANAGER (manager)); + + g_signal_emit (manager, signals[ADD_ACCOUNT], 0); +} + +void +e_mail_account_manager_edit_account (EMailAccountManager *manager, + EAccount *account) +{ + g_return_if_fail (E_IS_MAIL_ACCOUNT_MANAGER (manager)); + g_return_if_fail (E_IS_ACCOUNT (account)); + + g_signal_emit (manager, signals[EDIT_ACCOUNT], 0, account); +} + diff --git a/mail/e-mail-account-manager.h b/mail/e-mail-account-manager.h new file mode 100644 index 0000000000..23f7890500 --- /dev/null +++ b/mail/e-mail-account-manager.h @@ -0,0 +1,78 @@ +/* + * e-mail-account-manager.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#ifndef E_MAIL_ACCOUNT_MANAGER_H +#define E_MAIL_ACCOUNT_MANAGER_H + +#include <gtk/gtk.h> +#include <e-util/e-account-utils.h> +#include <mail/e-mail-account-store.h> + +/* Standard GObject macros */ +#define E_TYPE_MAIL_ACCOUNT_MANAGER \ + (e_mail_account_manager_get_type ()) +#define E_MAIL_ACCOUNT_MANAGER(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_MAIL_ACCOUNT_MANAGER, EMailAccountManager)) +#define E_MAIL_ACCOUNT_MANAGER_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_MAIL_ACCOUNT_MANAGER, EMailAccountManagerClass)) +#define E_IS_MAIL_ACCOUNT_MANAGER(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_MAIL_ACCOUNT_MANAGER)) +#define E_IS_MAIL_ACCOUNT_MANAGER_CLASS(cls) \ + (G_TYPE_CHECK_INSTANCE_CLASS \ + ((cls), E_TYPE_MAIL_ACCOUNT_MANAGER)) +#define E_MAIL_ACCOUNT_MANAGER_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_MAIL_ACCOUNT_MANAGER, EMailAccountManagerClass)) + +G_BEGIN_DECLS + +typedef struct _EMailAccountManager EMailAccountManager; +typedef struct _EMailAccountManagerClass EMailAccountManagerClass; +typedef struct _EMailAccountManagerPrivate EMailAccountManagerPrivate; + +struct _EMailAccountManager { + GtkTable parent; + EMailAccountManagerPrivate *priv; +}; + +struct _EMailAccountManagerClass { + GtkTableClass parent_class; + + /* Signals */ + void (*add_account) (EMailAccountManager *manager); + void (*edit_account) (EMailAccountManager *manager, + EAccount *account); +}; + +GType e_mail_account_manager_get_type (void) G_GNUC_CONST; +GtkWidget * e_mail_account_manager_new (EMailAccountStore *store); +EMailAccountStore * + e_mail_account_manager_get_store + (EMailAccountManager *manager); +void e_mail_account_manager_add_account + (EMailAccountManager *manager); +void e_mail_account_manager_edit_account + (EMailAccountManager *manager, + EAccount *account); + +G_END_DECLS + +#endif /* E_MAIL_ACCOUNT_MANAGER_H */ diff --git a/mail/e-mail-account-store.c b/mail/e-mail-account-store.c new file mode 100644 index 0000000000..ccfbe3b879 --- /dev/null +++ b/mail/e-mail-account-store.c @@ -0,0 +1,1439 @@ +/* + * e-mail-account-store.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#include "e-mail-account-store.h" + +#include <config.h> +#include <glib/gstdio.h> +#include <glib/gi18n-lib.h> + +#include <libebackend/e-extensible.h> + +#include <e-util/e-marshal.h> +#include <e-util/e-account-utils.h> +#include <e-util/e-alert-dialog.h> +#include <mail/mail-ops.h> +#include <mail/mail-vfolder.h> + +#define E_MAIL_ACCOUNT_STORE_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_MAIL_ACCOUNT_STORE, EMailAccountStorePrivate)) + +typedef struct _IndexItem IndexItem; + +struct _EMailAccountStorePrivate { + CamelService *default_service; + GHashTable *service_index; + gchar *sort_order_filename; + gboolean express_mode; + gpointer session; /* weak pointer */ + guint busy_count; +}; + +struct _IndexItem { + CamelService *service; + GtkTreeRowReference *reference; + gulong notify_handler_id; +}; + +enum { + PROP_0, + PROP_BUSY, + PROP_DEFAULT_SERVICE, + PROP_EXPRESS_MODE, + PROP_SESSION +}; + +enum { + SERVICE_ADDED, + SERVICE_REMOVED, + SERVICE_ENABLED, + SERVICE_DISABLED, + SERVICES_REORDERED, + REMOVE_REQUESTED, + ENABLE_REQUESTED, + DISABLE_REQUESTED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +/* Forward Declarations */ +static void e_mail_account_store_interface_init + (GtkTreeModelIface *interface); + +G_DEFINE_TYPE_WITH_CODE ( + EMailAccountStore, + e_mail_account_store, + GTK_TYPE_LIST_STORE, + G_IMPLEMENT_INTERFACE ( + GTK_TYPE_TREE_MODEL, + e_mail_account_store_interface_init) + G_IMPLEMENT_INTERFACE ( + E_TYPE_EXTENSIBLE, NULL)) + +static void +index_item_free (IndexItem *item) +{ + g_signal_handler_disconnect ( + item->service, item->notify_handler_id); + + g_object_unref (item->service); + gtk_tree_row_reference_free (item->reference); + + g_slice_free (IndexItem, item); +} + +static void +mail_account_store_save_default (EMailAccountStore *store) +{ + EAccountList *account_list; + EAccount *account; + CamelService *service; + const gchar *uid; + + service = e_mail_account_store_get_default_service (store); + + account_list = e_get_account_list (); + uid = camel_service_get_uid (service); + account = e_get_account_by_uid (uid); + g_return_if_fail (account != NULL); + + e_account_list_set_default (account_list, account); +} + +static gboolean +mail_account_store_get_iter (EMailAccountStore *store, + CamelService *service, + GtkTreeIter *iter) +{ + IndexItem *item; + GtkTreeModel *model; + GtkTreePath *path; + gboolean iter_set; + + g_return_val_if_fail (service != NULL, FALSE); + + item = g_hash_table_lookup (store->priv->service_index, service); + + if (item == NULL) + return FALSE; + + if (!gtk_tree_row_reference_valid (item->reference)) + return FALSE; + + model = gtk_tree_row_reference_get_model (item->reference); + path = gtk_tree_row_reference_get_path (item->reference); + iter_set = gtk_tree_model_get_iter (model, iter, path); + gtk_tree_path_free (path); + + return iter_set; +} + +static gint +mail_account_store_default_compare (CamelService *service_a, + CamelService *service_b, + EMailAccountStore *store) +{ + const gchar *display_name_a; + const gchar *display_name_b; + const gchar *uid_a; + const gchar *uid_b; + + uid_a = camel_service_get_uid (service_a); + uid_b = camel_service_get_uid (service_b); + + /* Check for special cases first. */ + + if (e_mail_account_store_get_express_mode (store)) { + if (g_str_equal (uid_a, E_MAIL_SESSION_LOCAL_UID) && + g_str_equal (uid_b, E_MAIL_SESSION_VFOLDER_UID)) + return -1; + else if (g_str_equal (uid_b, E_MAIL_SESSION_LOCAL_UID) && + g_str_equal (uid_a, E_MAIL_SESSION_VFOLDER_UID)) + return 1; + else if (g_str_equal (uid_a, E_MAIL_SESSION_LOCAL_UID)) + return 1; + else if (g_str_equal (uid_b, E_MAIL_SESSION_LOCAL_UID)) + return -1; + else if (g_str_equal (uid_a, E_MAIL_SESSION_VFOLDER_UID)) + return 1; + else if (g_str_equal (uid_a, E_MAIL_SESSION_VFOLDER_UID)) + return -1; + } else { + if (g_str_equal (uid_a, E_MAIL_SESSION_LOCAL_UID)) + return -1; + else if (g_str_equal (uid_b, E_MAIL_SESSION_LOCAL_UID)) + return 1; + else if (g_str_equal (uid_a, E_MAIL_SESSION_VFOLDER_UID)) + return 1; + else if (g_str_equal (uid_b, E_MAIL_SESSION_VFOLDER_UID)) + return -1; + } + + /* Otherwise sort them alphabetically. */ + + display_name_a = camel_service_get_display_name (service_a); + display_name_b = camel_service_get_display_name (service_b); + + if (display_name_a == NULL) + display_name_a = ""; + + if (display_name_b == NULL) + display_name_b = ""; + + return g_utf8_collate (display_name_a, display_name_b); +} + +static void +mail_account_store_update_row (EMailAccountStore *store, + CamelService *service, + GtkTreeIter *iter) +{ + CamelProvider *provider; + gboolean is_default; + const gchar *backend_name; + const gchar *display_name; + + is_default = (service == store->priv->default_service); + display_name = camel_service_get_display_name (service); + + provider = camel_service_get_provider (service); + backend_name = (provider != NULL) ? provider->protocol : NULL; + + gtk_list_store_set ( + GTK_LIST_STORE (store), iter, + E_MAIL_ACCOUNT_STORE_COLUMN_DEFAULT, is_default, + E_MAIL_ACCOUNT_STORE_COLUMN_BACKEND_NAME, backend_name, + E_MAIL_ACCOUNT_STORE_COLUMN_DISPLAY_NAME, display_name, + -1); +} + +static void +mail_account_store_service_notify_cb (CamelService *service, + GParamSpec *pspec, + EMailAccountStore *store) +{ + GtkTreeIter iter; + + if (mail_account_store_get_iter (store, service, &iter)) + mail_account_store_update_row (store, service, &iter); +} + +static void +mail_account_store_clean_index (EMailAccountStore *store) +{ + GQueue trash = G_QUEUE_INIT; + GHashTable *hash_table; + GHashTableIter iter; + gpointer key, value; + + hash_table = store->priv->service_index; + g_hash_table_iter_init (&iter, hash_table); + + /* Remove index items with invalid GtkTreeRowReferences. */ + + while (g_hash_table_iter_next (&iter, &key, &value)) { + IndexItem *item = value; + + if (!gtk_tree_row_reference_valid (item->reference)) + g_queue_push_tail (&trash, key); + } + + while ((key = g_queue_pop_head (&trash)) != NULL) + g_hash_table_remove (hash_table, key); +} + +static void +mail_account_store_update_index (EMailAccountStore *store, + GtkTreePath *path, + GtkTreeIter *iter) +{ + CamelService *service = NULL; + GHashTable *hash_table; + GtkTreeModel *model; + IndexItem *item; + + model = GTK_TREE_MODEL (store); + hash_table = store->priv->service_index; + + gtk_tree_model_get ( + model, iter, + E_MAIL_ACCOUNT_STORE_COLUMN_SERVICE, &service, -1); + + if (service == NULL) + return; + + item = g_hash_table_lookup (hash_table, service); + + if (item == NULL) { + item = g_slice_new0 (IndexItem); + item->service = g_object_ref (service); + + item->notify_handler_id = g_signal_connect ( + service, "notify", G_CALLBACK ( + mail_account_store_service_notify_cb), store); + + g_hash_table_insert (hash_table, item->service, item); + } + + /* Update the row reference so the IndexItem will survive + * drag-and-drop (new row is inserted, old row is deleted). */ + gtk_tree_row_reference_free (item->reference); + item->reference = gtk_tree_row_reference_new (model, path); + + g_object_unref (service); +} + +static void +mail_account_store_set_session (EMailAccountStore *store, + EMailSession *session) +{ + g_return_if_fail (E_IS_MAIL_SESSION (session)); + g_return_if_fail (store->priv->session == NULL); + + store->priv->session = session; + + g_object_add_weak_pointer ( + G_OBJECT (store->priv->session), + &store->priv->session); +} + +static void +mail_account_store_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_DEFAULT_SERVICE: + e_mail_account_store_set_default_service ( + E_MAIL_ACCOUNT_STORE (object), + g_value_get_object (value)); + return; + + case PROP_EXPRESS_MODE: + e_mail_account_store_set_express_mode ( + E_MAIL_ACCOUNT_STORE (object), + g_value_get_boolean (value)); + return; + + case PROP_SESSION: + mail_account_store_set_session ( + E_MAIL_ACCOUNT_STORE (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +mail_account_store_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_BUSY: + g_value_set_boolean ( + value, + e_mail_account_store_get_busy ( + E_MAIL_ACCOUNT_STORE (object))); + return; + + case PROP_DEFAULT_SERVICE: + g_value_set_object ( + value, + e_mail_account_store_get_default_service ( + E_MAIL_ACCOUNT_STORE (object))); + return; + + case PROP_EXPRESS_MODE: + g_value_set_boolean ( + value, + e_mail_account_store_get_express_mode ( + E_MAIL_ACCOUNT_STORE (object))); + return; + + case PROP_SESSION: + g_value_set_object ( + value, + e_mail_account_store_get_session ( + E_MAIL_ACCOUNT_STORE (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +mail_account_store_dispose (GObject *object) +{ + EMailAccountStorePrivate *priv; + + priv = E_MAIL_ACCOUNT_STORE_GET_PRIVATE (object); + + if (priv->session != NULL) { + g_object_remove_weak_pointer ( + G_OBJECT (priv->session), &priv->session); + priv->session = NULL; + } + + if (priv->default_service != NULL) { + g_object_unref (priv->default_service); + priv->default_service = NULL; + } + + g_hash_table_remove_all (priv->service_index); + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (e_mail_account_store_parent_class)->dispose (object); +} + +static void +mail_account_store_finalize (GObject *object) +{ + EMailAccountStorePrivate *priv; + + priv = E_MAIL_ACCOUNT_STORE_GET_PRIVATE (object); + + g_warn_if_fail (priv->busy_count == 0); + g_hash_table_destroy (priv->service_index); + g_free (priv->sort_order_filename); + + /* Chain up to parent's finalize() method. */ + G_OBJECT_CLASS (e_mail_account_store_parent_class)->finalize (object); +} + +static void +mail_account_store_constructed (GObject *object) +{ + EMailAccountStore *store; + const gchar *config_dir; + + /* Chain up to parent's constructed() method. */ + G_OBJECT_CLASS (e_mail_account_store_parent_class)->constructed (object); + + store = E_MAIL_ACCOUNT_STORE (object); + config_dir = mail_session_get_config_dir (); + + /* XXX Should we take the filename as a constructor property? */ + store->priv->sort_order_filename = g_build_filename ( + config_dir, "sortorder.ini", NULL); + + /* XXX This is kinda lame, but should work until EAccount dies. */ + g_signal_connect ( + object, "notify::default-service", + G_CALLBACK (mail_account_store_save_default), NULL); + + e_extensible_load_extensions (E_EXTENSIBLE (object)); +} + +static void +mail_account_store_service_added (EMailAccountStore *store, + CamelService *service) +{ + /* Placeholder so subclasses can safely chain up. */ +} + +static void +mail_account_store_service_removed (EMailAccountStore *store, + CamelService *service) +{ + /* XXX On the account-mgmt branch this operation is asynchronous. + * The 'busy_count' is bumped until changes are written back + * to the D-Bus service. For now I guess we'll just block. */ + + EAccountList *account_list; + EAccount *account; + const gchar *uid; + + account_list = e_get_account_list (); + uid = camel_service_get_uid (service); + account = e_get_account_by_uid (uid); + g_return_if_fail (account != NULL); + + if (account->enabled) { + CamelProvider *provider; + + provider = camel_service_get_provider (service); + g_return_if_fail (provider != NULL); + + if (provider->flags & CAMEL_PROVIDER_IS_STORAGE) + mail_disconnect_store (CAMEL_STORE (service)); + } + + /* Remove all the proxies the account has created. + * FIXME This proxy stuff belongs in evolution-groupwise. */ + e_account_list_remove_account_proxies (account_list, account); + + e_account_list_remove (account_list, account); + + e_account_list_save (account_list); +} + +static void +mail_account_store_service_enabled (EMailAccountStore *store, + CamelService *service) +{ + /* XXX On the account-mgmt branch this operation is asynchronous. + * The 'busy_count' is bumped until changes are written back + * to the D-Bus service. For now I guess we'll just block. */ + + GSettings *settings; + const gchar *uid; + + uid = camel_service_get_uid (service); + + /* Handle built-in services that don't have an EAccount. */ + + if (g_strcmp0 (uid, E_MAIL_SESSION_LOCAL_UID) == 0) { + settings = g_settings_new ("org.gnome.evolution.mail"); + g_settings_set_boolean (settings, "enable-local", TRUE); + g_object_unref (settings); + + } else if (g_strcmp0 (uid, E_MAIL_SESSION_VFOLDER_UID) == 0) { + settings = g_settings_new ("org.gnome.evolution.mail"); + g_settings_set_boolean (settings, "enable-vfolders", TRUE); + g_object_unref (settings); + + } else { + EAccountList *account_list; + EAccount *account; + + account_list = e_get_account_list (); + account = e_get_account_by_uid (uid); + g_return_if_fail (account != NULL); + + account->enabled = TRUE; + + e_account_list_change (account_list, account); + e_account_list_save (account_list); + } +} + +static void +mail_account_store_service_disabled (EMailAccountStore *store, + CamelService *service) +{ + /* XXX On the account-mgmt branch this operation is asynchronous. + * The 'busy_count' is bumped until changes are written back + * to the D-Bus service. For now I guess we'll just block. */ + + GSettings *settings; + const gchar *uid; + + uid = camel_service_get_uid (service); + + /* Handle built-in services that don't have an EAccount. */ + + if (g_strcmp0 (uid, E_MAIL_SESSION_LOCAL_UID) == 0) { + settings = g_settings_new ("org.gnome.evolution.mail"); + g_settings_set_boolean (settings, "enable-local", FALSE); + g_object_unref (settings); + + } else if (g_strcmp0 (uid, E_MAIL_SESSION_VFOLDER_UID) == 0) { + settings = g_settings_new ("org.gnome.evolution.mail"); + g_settings_set_boolean (settings, "enable-vfolders", FALSE); + g_object_unref (settings); + + } else { + EAccountList *account_list; + EAccount *account; + CamelProvider *provider; + + account_list = e_get_account_list (); + account = e_get_account_by_uid (uid); + g_return_if_fail (account != NULL); + + account->enabled = FALSE; + + provider = camel_service_get_provider (service); + g_return_if_fail (provider != NULL); + + if (provider->flags & CAMEL_PROVIDER_IS_STORAGE) + mail_disconnect_store (CAMEL_STORE (service)); + + /* FIXME This proxy stuff belongs in evolution-groupwise. */ + e_account_list_remove_account_proxies (account_list, account); + + if (account->parent_uid != NULL) + e_account_list_remove (account_list, account); + + e_account_list_change (account_list, account); + e_account_list_save (account_list); + } +} + +static void +mail_account_store_services_reordered (EMailAccountStore *store, + gboolean default_restored) +{ + /* XXX Should this be made asynchronous? */ + + GError *error = NULL; + + if (default_restored) { + const gchar *filename; + + filename = store->priv->sort_order_filename; + + if (g_file_test (filename, G_FILE_TEST_EXISTS)) + g_unlink (filename); + + return; + } + + if (!e_mail_account_store_save_sort_order (store, &error)) { + g_warning ("%s: %s", G_STRFUNC, error->message); + g_error_free (error); + } +} + +static gboolean +mail_account_store_remove_requested (EMailAccountStore *store, + GtkWindow *parent_window, + CamelService *service) +{ + EAccountList *account_list; + EAccount *account; + const gchar *alert; + const gchar *uid; + gint response; + + account_list = e_get_account_list (); + uid = camel_service_get_uid (service); + account = e_get_account_by_uid (uid); + + g_return_val_if_fail (account != NULL, FALSE); + + /* FIXME This proxy stuff belongs in evolution-groupwise. */ + if (e_account_list_account_has_proxies (account_list, account)) + alert = "mail:ask-delete-account-with-proxies"; + else + alert = "mail:ask-delete-account"; + + response = e_alert_run_dialog_for_args (parent_window, alert, NULL); + + return (response == GTK_RESPONSE_YES); +} + +static gboolean +mail_account_store_enable_requested (EMailAccountStore *store, + GtkWindow *parent_window, + CamelService *service) +{ + return TRUE; +} + +static gboolean +mail_account_store_disable_requested (EMailAccountStore *store, + GtkWindow *parent_window, + CamelService *service) +{ + EAccountList *account_list; + EAccount *account; + const gchar *uid; + gint response; + + account_list = e_get_account_list (); + uid = camel_service_get_uid (service); + account = e_get_account_by_uid (uid); + + /* "On This Computer" and "Search Folders" do not have + * EAccounts, so just silently return TRUE if we failed + * to find a matching EAccount for the CamelService. */ + + /* Silently return TRUE if we failed to find a matching + * EAccount since "On This Computer" and "Search Folders" + * do not have EAccounts. */ + if (account == NULL) + return TRUE; + + /* FIXME This proxy stuff belongs in evolution-groupwise. */ + if (e_account_list_account_has_proxies (account_list, account)) + response = e_alert_run_dialog_for_args ( + parent_window, + "mail:ask-delete-proxy-accounts", NULL); + else + response = GTK_RESPONSE_YES; + + return (response == GTK_RESPONSE_YES); +} + +static void +mail_account_store_row_changed (GtkTreeModel *tree_model, + GtkTreePath *path, + GtkTreeIter *iter) +{ + EMailAccountStore *store; + + /* Neither GtkTreeModel nor GtkListStore implements + * this method, so there is nothing to chain up to. */ + + store = E_MAIL_ACCOUNT_STORE (tree_model); + mail_account_store_update_index (store, path, iter); +} + +static void +mail_account_store_row_inserted (GtkTreeModel *tree_model, + GtkTreePath *path, + GtkTreeIter *iter) +{ + EMailAccountStore *store; + + /* Neither GtkTreeModel nor GtkListStore implements + * this method, so there is nothing to chain up to. */ + + store = E_MAIL_ACCOUNT_STORE (tree_model); + mail_account_store_update_index (store, path, iter); +} + +static gboolean +mail_account_store_true_proceed (GSignalInvocationHint *ihint, + GValue *return_accumulator, + const GValue *handler_return, + gpointer not_used) +{ + gboolean proceed; + + proceed = g_value_get_boolean (handler_return); + g_value_set_boolean (return_accumulator, proceed); + + return proceed; +} + +static void +e_mail_account_store_class_init (EMailAccountStoreClass *class) +{ + GObjectClass *object_class; + + g_type_class_add_private (class, sizeof (EMailAccountStorePrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->set_property = mail_account_store_set_property; + object_class->get_property = mail_account_store_get_property; + object_class->dispose = mail_account_store_dispose; + object_class->finalize = mail_account_store_finalize; + object_class->constructed = mail_account_store_constructed; + + class->service_added = mail_account_store_service_added; + class->service_removed = mail_account_store_service_removed; + class->service_enabled = mail_account_store_service_enabled; + class->service_disabled = mail_account_store_service_disabled; + class->services_reordered = mail_account_store_services_reordered; + class->remove_requested = mail_account_store_remove_requested; + class->enable_requested = mail_account_store_enable_requested; + class->disable_requested = mail_account_store_disable_requested; + + g_object_class_install_property ( + object_class, + PROP_BUSY, + g_param_spec_boolean ( + "busy", + "Busy", + "Whether async operations are in progress", + FALSE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property ( + object_class, + PROP_DEFAULT_SERVICE, + g_param_spec_object ( + "default-service", + "Default Service", + "Default mail store", + CAMEL_TYPE_SERVICE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property ( + object_class, + PROP_EXPRESS_MODE, + g_param_spec_boolean ( + "express-mode", + "Express Mode", + "Whether express mode is enabled", + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property ( + object_class, + PROP_SESSION, + g_param_spec_object ( + "session", + "Session", + "Mail session", + E_TYPE_MAIL_SESSION, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + signals[SERVICE_ADDED] = g_signal_new ( + "service-added", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EMailAccountStoreClass, service_added), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + CAMEL_TYPE_SERVICE); + + signals[SERVICE_REMOVED] = g_signal_new ( + "service-removed", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EMailAccountStoreClass, service_removed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + CAMEL_TYPE_SERVICE); + + signals[SERVICE_ENABLED] = g_signal_new ( + "service-enabled", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EMailAccountStoreClass, service_enabled), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + CAMEL_TYPE_SERVICE); + + signals[SERVICE_DISABLED] = g_signal_new ( + "service-disabled", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EMailAccountStoreClass, service_disabled), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, + CAMEL_TYPE_SERVICE); + + signals[SERVICES_REORDERED] = g_signal_new ( + "services-reordered", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EMailAccountStoreClass, services_reordered), + NULL, NULL, + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, 1, + G_TYPE_BOOLEAN); + + signals[REMOVE_REQUESTED] = g_signal_new ( + "remove-requested", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EMailAccountStoreClass, remove_requested), + mail_account_store_true_proceed, NULL, + e_marshal_BOOLEAN__OBJECT_OBJECT, + G_TYPE_BOOLEAN, 2, + GTK_TYPE_WINDOW, + CAMEL_TYPE_SERVICE); + + signals[ENABLE_REQUESTED] = g_signal_new ( + "enable-requested", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EMailAccountStoreClass, enable_requested), + mail_account_store_true_proceed, NULL, + e_marshal_BOOLEAN__OBJECT_OBJECT, + G_TYPE_BOOLEAN, 2, + GTK_TYPE_WINDOW, + CAMEL_TYPE_SERVICE); + + signals[DISABLE_REQUESTED] = g_signal_new ( + "disable-requested", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EMailAccountStoreClass, disable_requested), + mail_account_store_true_proceed, NULL, + e_marshal_BOOLEAN__OBJECT_OBJECT, + G_TYPE_BOOLEAN, 2, + GTK_TYPE_WINDOW, + CAMEL_TYPE_SERVICE); +} + +static void +e_mail_account_store_interface_init (GtkTreeModelIface *interface) +{ + interface->row_changed = mail_account_store_row_changed; + interface->row_inserted = mail_account_store_row_inserted; +} + +static void +e_mail_account_store_init (EMailAccountStore *store) +{ + GType types[E_MAIL_ACCOUNT_STORE_NUM_COLUMNS]; + GHashTable *service_index; + gint ii = 0; + + service_index = g_hash_table_new_full ( + (GHashFunc) g_direct_hash, + (GEqualFunc) g_direct_equal, + (GDestroyNotify) NULL, + (GDestroyNotify) index_item_free); + + store->priv = E_MAIL_ACCOUNT_STORE_GET_PRIVATE (store); + store->priv->service_index = service_index; + + types[ii++] = CAMEL_TYPE_SERVICE; /* COLUMN_SERVICE */ + types[ii++] = G_TYPE_BOOLEAN; /* COLUMN_BUILTIN */ + types[ii++] = G_TYPE_BOOLEAN; /* COLUMN_ENABLED */ + types[ii++] = G_TYPE_BOOLEAN; /* COLUMN_DEFAULT */ + types[ii++] = G_TYPE_STRING; /* COLUMN_BACKEND_NAME */ + types[ii++] = G_TYPE_STRING; /* COLUMN_DISPLAY_NAME */ + + g_assert (ii == E_MAIL_ACCOUNT_STORE_NUM_COLUMNS); + + gtk_list_store_set_column_types ( + GTK_LIST_STORE (store), + G_N_ELEMENTS (types), types); +} + +EMailAccountStore * +e_mail_account_store_new (EMailSession *session) +{ + g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); + + return g_object_new ( + E_TYPE_MAIL_ACCOUNT_STORE, + "session", session, NULL); +} + +void +e_mail_account_store_clear (EMailAccountStore *store) +{ + g_return_if_fail (E_IS_MAIL_ACCOUNT_STORE (store)); + + gtk_list_store_clear (GTK_LIST_STORE (store)); + g_hash_table_remove_all (store->priv->service_index); +} + +gboolean +e_mail_account_store_get_busy (EMailAccountStore *store) +{ + g_return_val_if_fail (E_IS_MAIL_ACCOUNT_STORE (store), FALSE); + + return (store->priv->busy_count > 0); +} + +EMailSession * +e_mail_account_store_get_session (EMailAccountStore *store) +{ + g_return_val_if_fail (E_IS_MAIL_ACCOUNT_STORE (store), NULL); + + return E_MAIL_SESSION (store->priv->session); +} + +CamelService * +e_mail_account_store_get_default_service (EMailAccountStore *store) +{ + g_return_val_if_fail (E_IS_MAIL_ACCOUNT_STORE (store), NULL); + + return store->priv->default_service; +} + +void +e_mail_account_store_set_default_service (EMailAccountStore *store, + CamelService *service) +{ + GtkTreeModel *model; + GtkTreeIter iter; + gboolean iter_set; + + g_return_if_fail (E_IS_MAIL_ACCOUNT_STORE (store)); + + if (service == store->priv->default_service) + return; + + if (service != NULL) { + g_return_if_fail (CAMEL_IS_SERVICE (service)); + g_object_ref (service); + } + + if (store->priv->default_service != NULL) + g_object_unref (store->priv->default_service); + + store->priv->default_service = service; + + model = GTK_TREE_MODEL (store); + iter_set = gtk_tree_model_get_iter_first (model, &iter); + + while (iter_set) { + CamelService *candidate; + + gtk_tree_model_get ( + model, &iter, + E_MAIL_ACCOUNT_STORE_COLUMN_SERVICE, + &candidate, -1); + + gtk_list_store_set ( + GTK_LIST_STORE (model), &iter, + E_MAIL_ACCOUNT_STORE_COLUMN_DEFAULT, + service == candidate, -1); + + g_object_unref (candidate); + + iter_set = gtk_tree_model_iter_next (model, &iter); + } + + g_object_notify (G_OBJECT (store), "default-service"); +} + +gboolean +e_mail_account_store_get_express_mode (EMailAccountStore *store) +{ + g_return_val_if_fail (E_IS_MAIL_ACCOUNT_STORE (store), FALSE); + + return store->priv->express_mode; +} + +void +e_mail_account_store_set_express_mode (EMailAccountStore *store, + gboolean express_mode) +{ + g_return_if_fail (E_IS_MAIL_ACCOUNT_STORE (store)); + + store->priv->express_mode = express_mode; + + g_object_notify (G_OBJECT (store), "express-mode"); +} + +void +e_mail_account_store_add_service (EMailAccountStore *store, + CamelService *service) +{ + GSettings *settings; + GtkTreeIter iter; + const gchar *filename; + const gchar *uid; + gboolean builtin; + gboolean enabled; + + g_return_if_fail (E_IS_MAIL_ACCOUNT_STORE (store)); + g_return_if_fail (CAMEL_IS_SERVICE (service)); + + /* Avoid duplicate services in the account store. */ + if (mail_account_store_get_iter (store, service, &iter)) + g_return_if_reached (); + + uid = camel_service_get_uid (service); + + /* Handle built-in services that don't have an EAccount. */ + + if (g_strcmp0 (uid, E_MAIL_SESSION_LOCAL_UID) == 0) { + builtin = TRUE; + + settings = g_settings_new ("org.gnome.evolution.mail"); + enabled = g_settings_get_boolean (settings, "enable-local"); + g_object_unref (settings); + + } else if (g_strcmp0 (uid, E_MAIL_SESSION_VFOLDER_UID) == 0) { + builtin = TRUE; + + settings = g_settings_new ("org.gnome.evolution.mail"); + enabled = g_settings_get_boolean (settings, "enable-vfolders"); + g_object_unref (settings); + + } else { + EAccount *account; + + account = e_get_account_by_uid (uid); + g_return_if_fail (account != NULL); + + builtin = FALSE; + enabled = account->enabled; + } + + /* Where do we insert new services now that accounts can be + * reordered? This is just a simple policy I came up with. + * It's certainly subject to debate and tweaking. + * + * Always insert new services in row 0 initially. Then test + * for the presence of the sort order file. If present, the + * user has messed around with the ordering so leave the new + * service at row 0. If not present, services are sorted in + * their default order. So re-apply the default order using + * e_mail_account_store_reorder_services(store, NULL) so the + * new service moves to its proper default position. */ + + gtk_list_store_prepend (GTK_LIST_STORE (store), &iter); + + gtk_list_store_set ( + GTK_LIST_STORE (store), &iter, + E_MAIL_ACCOUNT_STORE_COLUMN_SERVICE, service, + E_MAIL_ACCOUNT_STORE_COLUMN_BUILTIN, builtin, + E_MAIL_ACCOUNT_STORE_COLUMN_ENABLED, enabled, + -1); + + /* This populates the rest of the columns. */ + mail_account_store_update_row (store, service, &iter); + + g_signal_emit (store, signals[SERVICE_ADDED], 0, service); + + if (enabled) + g_signal_emit (store, signals[SERVICE_ENABLED], 0, service); + else + g_signal_emit (store, signals[SERVICE_DISABLED], 0, service); + + filename = store->priv->sort_order_filename; + + if (!g_file_test (filename, G_FILE_TEST_EXISTS)) + e_mail_account_store_reorder_services (store, NULL); +} + +void +e_mail_account_store_remove_service (EMailAccountStore *store, + GtkWindow *parent_window, + CamelService *service) +{ + GtkTreeIter iter; + gboolean proceed; + + g_return_if_fail (E_IS_MAIL_ACCOUNT_STORE (store)); + g_return_if_fail (CAMEL_IS_SERVICE (service)); + + if (!mail_account_store_get_iter (store, service, &iter)) + g_return_if_reached (); + + /* Possibly request user confirmation. */ + g_signal_emit ( + store, signals[REMOVE_REQUESTED], 0, + parent_window, service, &proceed); + + if (proceed) { + g_object_ref (service); + + gtk_list_store_remove (GTK_LIST_STORE (store), &iter); + + mail_account_store_clean_index (store); + + g_signal_emit (store, signals[SERVICE_REMOVED], 0, service); + + g_object_unref (service); + } +} + +void +e_mail_account_store_enable_service (EMailAccountStore *store, + GtkWindow *parent_window, + CamelService *service) +{ + GtkTreeIter iter; + gboolean proceed; + + g_return_if_fail (E_IS_MAIL_ACCOUNT_STORE (store)); + g_return_if_fail (CAMEL_IS_SERVICE (service)); + + if (!mail_account_store_get_iter (store, service, &iter)) + g_return_if_reached (); + + /* Possibly request user confirmation. */ + g_signal_emit ( + store, signals[ENABLE_REQUESTED], 0, + parent_window, service, &proceed); + + if (proceed) { + gtk_list_store_set ( + GTK_LIST_STORE (store), &iter, + E_MAIL_ACCOUNT_STORE_COLUMN_ENABLED, TRUE, -1); + + g_signal_emit (store, signals[SERVICE_ENABLED], 0, service); + } +} + +void +e_mail_account_store_disable_service (EMailAccountStore *store, + GtkWindow *parent_window, + CamelService *service) +{ + GtkTreeIter iter; + gboolean proceed; + + g_return_if_fail (E_IS_MAIL_ACCOUNT_STORE (store)); + g_return_if_fail (CAMEL_IS_SERVICE (service)); + + if (!mail_account_store_get_iter (store, service, &iter)) + g_return_if_reached (); + + /* Possibly request user confirmation. */ + g_signal_emit ( + store, signals[DISABLE_REQUESTED], 0, + parent_window, service, &proceed); + + if (proceed) { + gtk_list_store_set ( + GTK_LIST_STORE (store), &iter, + E_MAIL_ACCOUNT_STORE_COLUMN_ENABLED, FALSE, -1); + + g_signal_emit (store, signals[SERVICE_DISABLED], 0, service); + } +} + +void +e_mail_account_store_reorder_services (EMailAccountStore *store, + GQueue *ordered_services) +{ + GQueue *current_order = NULL; + GQueue *default_order = NULL; + GtkTreeModel *tree_model; + GtkTreeIter iter; + gboolean use_default_order; + gboolean iter_set; + GList *head, *link; + gint *new_order; + gint n_children; + gint new_pos = 0; + guint length; + + g_return_if_fail (E_IS_MAIL_ACCOUNT_STORE (store)); + + tree_model = GTK_TREE_MODEL (store); + n_children = gtk_tree_model_iter_n_children (tree_model, NULL); + + /* Treat NULL queues and empty queues the same. */ + if (ordered_services != NULL && g_queue_is_empty (ordered_services)) + ordered_services = NULL; + + use_default_order = (ordered_services == NULL); + + if (ordered_services != NULL) { + length = g_queue_get_length (ordered_services); + g_return_if_fail (length == n_children); + } + + current_order = g_queue_new (); + iter_set = gtk_tree_model_get_iter_first (tree_model, &iter); + + /* Build a queue of CamelServices in the order they appear in + * the list store. We'll use this to construct the mapping to + * pass to gtk_list_store_reorder(). */ + while (iter_set) { + GValue value = G_VALUE_INIT; + const gint column = E_MAIL_ACCOUNT_STORE_COLUMN_SERVICE; + + gtk_tree_model_get_value (tree_model, &iter, column, &value); + g_queue_push_tail (current_order, g_value_get_object (&value)); + g_value_unset (&value); + + iter_set = gtk_tree_model_iter_next (tree_model, &iter); + } + + /* If a custom ordering was not given, revert to default. */ + if (use_default_order) { + default_order = g_queue_copy (current_order); + + g_queue_sort ( + default_order, (GCompareDataFunc) + mail_account_store_default_compare, store); + + ordered_services = default_order; + } + + new_order = g_new0 (gint, n_children); + head = g_queue_peek_head_link (ordered_services); + + for (link = head; link != NULL; link = g_list_next (link)) { + GList *matching_link; + gint old_pos; + + matching_link = g_queue_find (current_order, link->data); + + if (matching_link == NULL || matching_link->data == NULL) + break; + + old_pos = g_queue_link_index (current_order, matching_link); + + matching_link->data = NULL; + new_order[new_pos++] = old_pos; + } + + if (new_pos == n_children) { + gtk_list_store_reorder (GTK_LIST_STORE (store), new_order); + g_signal_emit ( + store, signals[SERVICES_REORDERED], 0, + use_default_order); + } + + g_free (new_order); + + if (current_order != NULL) + g_queue_free (current_order); + + if (default_order != NULL) + g_queue_free (default_order); +} + +gint +e_mail_account_store_compare_services (EMailAccountStore *store, + CamelService *service_a, + CamelService *service_b) +{ + GtkTreeModel *model; + GtkTreePath *path_a; + GtkTreePath *path_b; + GtkTreeIter iter_a; + GtkTreeIter iter_b; + gboolean iter_a_set; + gboolean iter_b_set; + gint result; + + g_return_val_if_fail (E_IS_MAIL_ACCOUNT_STORE (store), -1); + g_return_val_if_fail (CAMEL_IS_SERVICE (service_a), -1); + g_return_val_if_fail (CAMEL_IS_SERVICE (service_b), -1); + + /* XXX This is horribly inefficient but should be + * over a small enough set to not be noticable. */ + + iter_a_set = mail_account_store_get_iter (store, service_a, &iter_a); + iter_b_set = mail_account_store_get_iter (store, service_b, &iter_b); + + if (!iter_a_set && !iter_b_set) + return 0; + + if (!iter_a_set) + return -1; + + if (!iter_b_set) + return 1; + + model = GTK_TREE_MODEL (store); + + path_a = gtk_tree_model_get_path (model, &iter_a); + path_b = gtk_tree_model_get_path (model, &iter_b); + + result = gtk_tree_path_compare (path_a, path_b); + + gtk_tree_path_free (path_a); + gtk_tree_path_free (path_b); + + return result; +} + +gboolean +e_mail_account_store_load_sort_order (EMailAccountStore *store, + GError **error) +{ + GQueue service_queue = G_QUEUE_INIT; + EMailSession *session; + GKeyFile *key_file; + const gchar *filename; + gchar **service_uids; + gboolean success = TRUE; + gsize ii, length; + + g_return_val_if_fail (E_IS_MAIL_ACCOUNT_STORE (store), FALSE); + + session = e_mail_account_store_get_session (store); + + key_file = g_key_file_new (); + filename = store->priv->sort_order_filename; + + if (g_file_test (filename, G_FILE_TEST_EXISTS)) + success = g_key_file_load_from_file ( + key_file, filename, G_KEY_FILE_NONE, error); + + if (!success) { + g_key_file_free (key_file); + return FALSE; + } + + /* If the key is not present, length is set to zero. */ + service_uids = g_key_file_get_string_list ( + key_file, "Accounts", "SortOrder", &length, NULL); + + for (ii = 0; ii < length; ii++) { + CamelService *service; + + service = camel_session_get_service ( + CAMEL_SESSION (session), service_uids[ii]); + if (service != NULL) + g_queue_push_tail (&service_queue, service); + } + + e_mail_account_store_reorder_services (store, &service_queue); + + g_queue_clear (&service_queue); + g_strfreev (service_uids); + + g_key_file_free (key_file); + + return TRUE; +} + +gboolean +e_mail_account_store_save_sort_order (EMailAccountStore *store, + GError **error) +{ + GKeyFile *key_file; + GtkTreeModel *model; + GtkTreeIter iter; + const gchar **service_uids; + const gchar *filename; + gchar *contents; + gboolean iter_set; + gboolean success; + gsize length; + gsize ii = 0; + + g_return_val_if_fail (E_IS_MAIL_ACCOUNT_STORE (store), FALSE); + + model = GTK_TREE_MODEL (store); + length = gtk_tree_model_iter_n_children (model, NULL); + + /* Empty store, nothing to save. */ + if (length == 0) + return TRUE; + + service_uids = g_new0 (const gchar *, length); + + iter_set = gtk_tree_model_get_iter_first (model, &iter); + + while (iter_set) { + GValue value = G_VALUE_INIT; + const gint column = E_MAIL_ACCOUNT_STORE_COLUMN_SERVICE; + CamelService *service; + + gtk_tree_model_get_value (model, &iter, column, &value); + service = g_value_get_object (&value); + service_uids[ii++] = camel_service_get_uid (service); + g_value_unset (&value); + + iter_set = gtk_tree_model_iter_next (model, &iter); + } + + key_file = g_key_file_new (); + filename = store->priv->sort_order_filename; + + g_key_file_set_string_list ( + key_file, "Accounts", "SortOrder", service_uids, length); + + contents = g_key_file_to_data (key_file, &length, NULL); + success = g_file_set_contents (filename, contents, length, error); + g_free (contents); + + g_key_file_free (key_file); + + g_free (service_uids); + + return success; +} + diff --git a/mail/e-mail-account-store.h b/mail/e-mail-account-store.h new file mode 100644 index 0000000000..e4355da3a8 --- /dev/null +++ b/mail/e-mail-account-store.h @@ -0,0 +1,144 @@ +/* + * e-mail-account-store.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#ifndef E_MAIL_ACCOUNT_STORE_H +#define E_MAIL_ACCOUNT_STORE_H + +#include <gtk/gtk.h> +#include <camel/camel.h> + +/* Standard GObject macros */ +#define E_TYPE_MAIL_ACCOUNT_STORE \ + (e_mail_account_store_get_type ()) +#define E_MAIL_ACCOUNT_STORE(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_MAIL_ACCOUNT_STORE, EMailAccountStore)) +#define E_MAIL_ACCOUNT_STORE_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_MAIL_ACCOUNT_STORE, EMailAccountStoreClass)) +#define E_IS_MAIL_ACCOUNT_STORE(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_MAIL_ACCOUNT_STORE)) +#define E_IS_MAIL_ACOCUNT_STORE_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_MAIL_ACCOUNT_STORE)) +#define E_MAIL_ACCOUNT_STORE_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_MAIL_ACCOUNT_STORE, EMailAccountStoreClass)) + +G_BEGIN_DECLS + +/* Avoid a circular dependency. */ +typedef struct _EMailSession EMailSession; + +typedef enum { + E_MAIL_ACCOUNT_STORE_COLUMN_SERVICE, + E_MAIL_ACCOUNT_STORE_COLUMN_BUILTIN, + E_MAIL_ACCOUNT_STORE_COLUMN_ENABLED, + E_MAIL_ACCOUNT_STORE_COLUMN_DEFAULT, + E_MAIL_ACCOUNT_STORE_COLUMN_BACKEND_NAME, + E_MAIL_ACCOUNT_STORE_COLUMN_DISPLAY_NAME, + E_MAIL_ACCOUNT_STORE_NUM_COLUMNS +} EMailAccountStoreColumn; + +typedef struct _EMailAccountStore EMailAccountStore; +typedef struct _EMailAccountStoreClass EMailAccountStoreClass; +typedef struct _EMailAccountStorePrivate EMailAccountStorePrivate; + +struct _EMailAccountStore { + GtkListStore parent; + EMailAccountStorePrivate *priv; +}; + +struct _EMailAccountStoreClass { + GtkListStoreClass parent_class; + + /* Signals */ + void (*service_added) (EMailAccountStore *store, + CamelService *service); + void (*service_removed) (EMailAccountStore *store, + CamelService *service); + void (*service_enabled) (EMailAccountStore *store, + CamelService *service); + void (*service_disabled) (EMailAccountStore *store, + CamelService *service); + void (*services_reordered) (EMailAccountStore *store, + gboolean default_restored); + + /* These signals are for confirmation dialogs. + * Signal handler should return FALSE to abort. */ + gboolean (*remove_requested) (EMailAccountStore *store, + GtkWindow *parent_window, + CamelService *service); + gboolean (*enable_requested) (EMailAccountStore *store, + GtkWindow *parent_window, + CamelService *service); + gboolean (*disable_requested) (EMailAccountStore *store, + GtkWindow *parent_window, + CamelService *service); +}; + +GType e_mail_account_store_get_type (void) G_GNUC_CONST; +EMailAccountStore * + e_mail_account_store_new (EMailSession *session); +void e_mail_account_store_clear (EMailAccountStore *store); +gboolean e_mail_account_store_get_busy (EMailAccountStore *store); +EMailSession * e_mail_account_store_get_session + (EMailAccountStore *store); +CamelService * e_mail_account_store_get_default_service + (EMailAccountStore *store); +void e_mail_account_store_set_default_service + (EMailAccountStore *store, + CamelService *service); +gboolean e_mail_account_store_get_express_mode + (EMailAccountStore *store); +void e_mail_account_store_set_express_mode + (EMailAccountStore *store, + gboolean express_mode); +void e_mail_account_store_add_service + (EMailAccountStore *store, + CamelService *service); +void e_mail_account_store_remove_service + (EMailAccountStore *store, + GtkWindow *parent_window, + CamelService *service); +void e_mail_account_store_enable_service + (EMailAccountStore *store, + GtkWindow *parent_window, + CamelService *service); +void e_mail_account_store_disable_service + (EMailAccountStore *store, + GtkWindow *parent_window, + CamelService *service); +void e_mail_account_store_reorder_services + (EMailAccountStore *store, + GQueue *ordered_services); +gint e_mail_account_store_compare_services + (EMailAccountStore *store, + CamelService *service_a, + CamelService *service_b); +gboolean e_mail_account_store_load_sort_order + (EMailAccountStore *store, + GError **error); +gboolean e_mail_account_store_save_sort_order + (EMailAccountStore *store, + GError **error); + +G_END_DECLS + +#endif /* E_MAIL_ACCOUNT_STORE_H */ diff --git a/mail/e-mail-account-tree-view.c b/mail/e-mail-account-tree-view.c new file mode 100644 index 0000000000..269a03d777 --- /dev/null +++ b/mail/e-mail-account-tree-view.c @@ -0,0 +1,283 @@ +/* + * e-mail-account-tree-view.c + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#include "e-mail-account-tree-view.h" + +#include <config.h> +#include <glib/gi18n-lib.h> + +#define E_MAIL_ACCOUNT_TREE_VIEW_GET_PRIVATE(obj) \ + (G_TYPE_INSTANCE_GET_PRIVATE \ + ((obj), E_TYPE_MAIL_ACCOUNT_TREE_VIEW, EMailAccountTreeViewPrivate)) + +struct _EMailAccountTreeViewPrivate { + gint placeholder; +}; + +enum { + ENABLE, + DISABLE, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +G_DEFINE_TYPE ( + EMailAccountTreeView, + e_mail_account_tree_view, + GTK_TYPE_TREE_VIEW) + +static void +mail_account_tree_view_enabled_toggled_cb (GtkCellRendererToggle *cell_renderer, + const gchar *path_string, + EMailAccountTreeView *tree_view) +{ + GtkTreeSelection *selection; + GtkTreePath *path; + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)); + + /* Change the selection first so we act on the correct service. */ + path = gtk_tree_path_new_from_string (path_string); + gtk_tree_selection_select_path (selection, path); + gtk_tree_path_free (path); + + if (gtk_cell_renderer_toggle_get_active (cell_renderer)) + g_signal_emit (tree_view, signals[DISABLE], 0); + else + g_signal_emit (tree_view, signals[ENABLE], 0); +} + +static void +mail_account_tree_view_constructed (GObject *object) +{ + GtkTreeView *tree_view; + GtkTreeViewColumn *column; + GtkCellRenderer *cell_renderer; + + /* Chain up to parent's constructed() method. */ + G_OBJECT_CLASS (e_mail_account_tree_view_parent_class)-> + constructed (object); + + tree_view = GTK_TREE_VIEW (object); + + gtk_tree_view_set_reorderable (tree_view, TRUE); + + /* Column: Enabled */ + + column = gtk_tree_view_column_new (); + gtk_tree_view_column_set_expand (column, FALSE); + gtk_tree_view_column_set_title (column, _("Enabled")); + + cell_renderer = gtk_cell_renderer_toggle_new (); + gtk_tree_view_column_pack_start (column, cell_renderer, TRUE); + + g_signal_connect ( + cell_renderer, "toggled", + G_CALLBACK (mail_account_tree_view_enabled_toggled_cb), + tree_view); + + gtk_tree_view_column_add_attribute ( + column, cell_renderer, "active", + E_MAIL_ACCOUNT_STORE_COLUMN_ENABLED); + + gtk_tree_view_append_column (tree_view, column); + + /* Column: Account Name */ + + column = gtk_tree_view_column_new (); + gtk_tree_view_column_set_expand (column, TRUE); + gtk_tree_view_column_set_title (column, _("Account Name")); + + cell_renderer = gtk_cell_renderer_text_new (); + g_object_set (cell_renderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL); + gtk_tree_view_column_pack_start (column, cell_renderer, TRUE); + + gtk_tree_view_column_add_attribute ( + column, cell_renderer, "text", + E_MAIL_ACCOUNT_STORE_COLUMN_DISPLAY_NAME); + + cell_renderer = gtk_cell_renderer_text_new (); + g_object_set (cell_renderer, "text", _("Default"), NULL); + gtk_tree_view_column_pack_end (column, cell_renderer, FALSE); + + gtk_tree_view_column_add_attribute ( + column, cell_renderer, "visible", + E_MAIL_ACCOUNT_STORE_COLUMN_DEFAULT); + + cell_renderer = gtk_cell_renderer_pixbuf_new (); + g_object_set ( + cell_renderer, "icon-name", "emblem-default", + "stock-size", GTK_ICON_SIZE_MENU, NULL); + gtk_tree_view_column_pack_end (column, cell_renderer, FALSE); + + gtk_tree_view_column_add_attribute ( + column, cell_renderer, "visible", + E_MAIL_ACCOUNT_STORE_COLUMN_DEFAULT); + + gtk_tree_view_append_column (tree_view, column); + + /* Column: Type */ + + column = gtk_tree_view_column_new (); + gtk_tree_view_column_set_expand (column, FALSE); + gtk_tree_view_column_set_title (column, _("Type")); + + cell_renderer = gtk_cell_renderer_text_new (); + gtk_tree_view_column_pack_start (column, cell_renderer, TRUE); + + gtk_tree_view_column_add_attribute ( + column, cell_renderer, "text", + E_MAIL_ACCOUNT_STORE_COLUMN_BACKEND_NAME); + + gtk_tree_view_append_column (tree_view, column); +} + +static void +mail_account_tree_view_drag_end (GtkWidget *widget, + GdkDragContext *context) +{ + GtkTreeModel *tree_model; + + /* Chain up to parent's drag_end() method. */ + GTK_WIDGET_CLASS (e_mail_account_tree_view_parent_class)-> + drag_end (widget, context); + + tree_model = gtk_tree_view_get_model (GTK_TREE_VIEW (widget)); + g_return_if_fail (E_IS_MAIL_ACCOUNT_STORE (tree_model)); + + g_signal_emit_by_name (tree_model, "services-reordered", FALSE); +} + +static void +e_mail_account_tree_view_class_init (EMailAccountTreeViewClass *class) +{ + GObjectClass *object_class; + GtkWidgetClass *widget_class; + + g_type_class_add_private (class, sizeof (EMailAccountTreeViewPrivate)); + + object_class = G_OBJECT_CLASS (class); + object_class->constructed = mail_account_tree_view_constructed; + + widget_class = GTK_WIDGET_CLASS (class); + widget_class->drag_end = mail_account_tree_view_drag_end; + + signals[ENABLE] = g_signal_new ( + "enable", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EMailAccountTreeViewClass, enable), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[DISABLE] = g_signal_new ( + "disable", + G_TYPE_FROM_CLASS (class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (EMailAccountTreeViewClass, disable), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static void +e_mail_account_tree_view_init (EMailAccountTreeView *tree_view) +{ + tree_view->priv = E_MAIL_ACCOUNT_TREE_VIEW_GET_PRIVATE (tree_view); +} + +GtkWidget * +e_mail_account_tree_view_new (EMailAccountStore *store) +{ + g_return_val_if_fail (E_IS_MAIL_ACCOUNT_STORE (store), NULL); + + return g_object_new ( + E_TYPE_MAIL_ACCOUNT_TREE_VIEW, + "model", store, NULL); +} + +CamelService * +e_mail_account_tree_view_get_selected_service (EMailAccountTreeView *tree_view) +{ + GtkTreeSelection *selection; + GtkTreeModel *tree_model; + GtkTreeIter iter; + CamelService *service; + GValue value = G_VALUE_INIT; + gint column; + + g_return_val_if_fail (E_IS_MAIL_ACCOUNT_TREE_VIEW (tree_view), NULL); + + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)); + + if (!gtk_tree_selection_get_selected (selection, &tree_model, &iter)) + return NULL; + + /* By convention, "get" functions don't return a new object + * reference, so use gtk_tree_model_get_value() to avoid it. + * The caller can always reference the object if needed. */ + + column = E_MAIL_ACCOUNT_STORE_COLUMN_SERVICE; + gtk_tree_model_get_value (tree_model, &iter, column, &value); + service = g_value_get_object (&value); + g_value_unset (&value); + + g_warn_if_fail (CAMEL_IS_SERVICE (service)); + + return service; +} + +void +e_mail_account_tree_view_set_selected_service (EMailAccountTreeView *tree_view, + CamelService *service) +{ + GtkTreeSelection *selection; + GtkTreeModel *tree_model; + GtkTreeIter iter; + gboolean iter_set; + + g_return_if_fail (E_IS_MAIL_ACCOUNT_TREE_VIEW (tree_view)); + g_return_if_fail (CAMEL_IS_SERVICE (service)); + + tree_model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view)); + selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view)); + + iter_set = gtk_tree_model_get_iter_first (tree_model, &iter); + + while (iter_set) { + GValue value = G_VALUE_INIT; + CamelService *candidate; + gint column; + + column = E_MAIL_ACCOUNT_STORE_COLUMN_SERVICE; + gtk_tree_model_get_value (tree_model, &iter, column, &value); + candidate = g_value_get_object (&value); + g_value_unset (&value); + + g_warn_if_fail (CAMEL_IS_SERVICE (candidate)); + + if (service == candidate) { + gtk_tree_selection_select_iter (selection, &iter); + break; + } + + iter_set = gtk_tree_model_iter_next (tree_model, &iter); + } +} diff --git a/mail/e-mail-account-tree-view.h b/mail/e-mail-account-tree-view.h new file mode 100644 index 0000000000..e1fff8385a --- /dev/null +++ b/mail/e-mail-account-tree-view.h @@ -0,0 +1,75 @@ +/* + * e-mail-account-tree-view.h + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) version 3. + * + * 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the program; if not, see <http://www.gnu.org/licenses/> + * + */ + +#ifndef E_MAIL_ACCOUNT_TREE_VIEW_H +#define E_MAIL_ACCOUNT_TREE_VIEW_H + +#include <gtk/gtk.h> +#include <mail/e-mail-account-store.h> + +/* Standard GObject macros */ +#define E_TYPE_MAIL_ACCOUNT_TREE_VIEW \ + (e_mail_account_tree_view_get_type ()) +#define E_MAIL_ACCOUNT_TREE_VIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST \ + ((obj), E_TYPE_MAIL_ACCOUNT_TREE_VIEW, EMailAccountTreeView)) +#define E_MAIL_ACCOUNT_TREE_VIEW_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_CAST \ + ((cls), E_TYPE_MAIL_ACCOUNT_TREE_VIEW, EMailAccountTreeViewClass)) +#define E_IS_MAIL_ACCOUNT_TREE_VIEW(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE \ + ((obj), E_TYPE_MAIL_ACCOUNT_TREE_VIEW)) +#define E_IS_MAIL_ACCOUNT_TREE_VIEW_CLASS(cls) \ + (G_TYPE_CHECK_CLASS_TYPE \ + ((cls), E_TYPE_MAIL_ACCOUNT_TREE_VIEW)) +#define E_MAIL_ACCOUNT_TREE_VIEW_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS \ + ((obj), E_TYPE_MAIL_ACCOUNT_TREE_VIEW, EMailAccountTreeViewClass)) + +G_BEGIN_DECLS + +typedef struct _EMailAccountTreeView EMailAccountTreeView; +typedef struct _EMailAccountTreeViewClass EMailAccountTreeViewClass; +typedef struct _EMailAccountTreeViewPrivate EMailAccountTreeViewPrivate; + +struct _EMailAccountTreeView { + GtkTreeView parent; + EMailAccountTreeViewPrivate *priv; +}; + +struct _EMailAccountTreeViewClass { + GtkTreeViewClass parent_class; + + /* Signals */ + void (*enable) (EMailAccountTreeView *tree_view); + void (*disable) (EMailAccountTreeView *tree_view); +}; + +GType e_mail_account_tree_view_get_type + (void) G_GNUC_CONST; +GtkWidget * e_mail_account_tree_view_new + (EMailAccountStore *store); +CamelService * e_mail_account_tree_view_get_selected_service + (EMailAccountTreeView *tree_view); +void e_mail_account_tree_view_set_selected_service + (EMailAccountTreeView *tree_view, + CamelService *service); + +G_END_DECLS + +#endif /* E_MAIL_ACCOUNT_TREE_VIEW_H */ diff --git a/mail/e-mail-backend.c b/mail/e-mail-backend.c index aedbdd2626..0640c7ff53 100644 --- a/mail/e-mail-backend.c +++ b/mail/e-mail-backend.c @@ -41,10 +41,8 @@ #include "shell/e-shell.h" #include "mail/e-mail-folder-utils.h" -#include "mail/e-mail-local.h" #include "mail/e-mail-migrate.h" #include "mail/e-mail-session.h" -#include "mail/e-mail-store.h" #include "mail/e-mail-store-utils.h" #include "mail/em-event.h" #include "mail/em-folder-tree-model.h" @@ -71,16 +69,9 @@ enum { PROP_SESSION }; -enum { - ACCOUNT_SORT_ORDER_CHANGED, - LAST_SIGNAL -}; - /* FIXME Kill this thing. It's a horrible hack. */ extern gint camel_application_is_exiting; -static guint signals[LAST_SIGNAL]; - G_DEFINE_ABSTRACT_TYPE ( EMailBackend, e_mail_backend, @@ -135,18 +126,6 @@ mail_backend_store_operation_done_cb (CamelStore *store, g_object_unref (activity); } -/* Helper for mail_backend_prepare_for_offline_cb() */ -static void -mail_store_prepare_for_offline_cb (CamelService *service, - EActivity *activity) -{ - /* FIXME Not passing a GCancellable. */ - e_mail_store_go_offline ( - CAMEL_STORE (service), G_PRIORITY_DEFAULT, NULL, - (GAsyncReadyCallback) mail_backend_store_operation_done_cb, - g_object_ref (activity)); -} - static void mail_backend_prepare_for_offline_cb (EShell *shell, EActivity *activity, @@ -154,6 +133,7 @@ mail_backend_prepare_for_offline_cb (EShell *shell, { GtkWindow *window; EMailSession *session; + GList *list, *link; gboolean synchronize = FALSE; window = e_shell_get_active_window (shell); @@ -170,20 +150,25 @@ mail_backend_prepare_for_offline_cb (EShell *shell, CAMEL_SESSION (session), FALSE); } - e_mail_store_foreach ( - session, (GFunc) mail_store_prepare_for_offline_cb, activity); -} + list = camel_session_list_services (CAMEL_SESSION (session)); -/* Helper for mail_backend_prepare_for_online_cb() */ -static void -mail_store_prepare_for_online_cb (CamelService *service, - EActivity *activity) -{ - /* FIXME Not passing a GCancellable. */ - e_mail_store_go_online ( - CAMEL_STORE (service), G_PRIORITY_DEFAULT, NULL, - (GAsyncReadyCallback) mail_backend_store_operation_done_cb, - g_object_ref (activity)); + for (link = list; link != NULL; link = g_list_next (link)) { + CamelService *service; + + service = CAMEL_SERVICE (link->data); + + if (!CAMEL_IS_STORE (service)) + continue; + + /* FIXME Not passing a GCancellable. */ + e_mail_store_go_offline ( + CAMEL_STORE (service), G_PRIORITY_DEFAULT, + NULL, (GAsyncReadyCallback) + mail_backend_store_operation_done_cb, + g_object_ref (activity)); + } + + g_list_free (list); } static void @@ -192,17 +177,35 @@ mail_backend_prepare_for_online_cb (EShell *shell, EMailBackend *backend) { EMailSession *session; + GList *list, *link; session = e_mail_backend_get_session (backend); camel_session_set_online (CAMEL_SESSION (session), TRUE); - e_mail_store_foreach ( - session, (GFunc) mail_store_prepare_for_online_cb, activity); + list = camel_session_list_services (CAMEL_SESSION (session)); + + for (link = list; link != NULL; link = g_list_next (link)) { + CamelService *service; + + service = CAMEL_SERVICE (link->data); + + if (!CAMEL_IS_STORE (service)) + continue; + + /* FIXME Not passing a GCancellable. */ + e_mail_store_go_online ( + CAMEL_STORE (service), G_PRIORITY_DEFAULT, + NULL, (GAsyncReadyCallback) + mail_backend_store_operation_done_cb, + g_object_ref (activity)); + } + + g_list_free (link); } /* Helper for mail_backend_prepare_for_quit_cb() */ static void -mail_backend_delete_junk (CamelStore *store, +mail_backend_delete_junk (CamelService *service, EMailBackend *backend) { CamelFolder *folder; @@ -212,7 +215,8 @@ mail_backend_delete_junk (CamelStore *store, guint ii; /* FIXME camel_store_get_junk_folder_sync() may block. */ - folder = camel_store_get_junk_folder_sync (store, NULL, NULL); + folder = camel_store_get_junk_folder_sync ( + CAMEL_STORE (service), NULL, NULL); if (folder == NULL) return; @@ -232,24 +236,6 @@ mail_backend_delete_junk (CamelStore *store, } /* Helper for mail_backend_prepare_for_quit_cb() */ -static void -mail_backend_final_sync (CamelStore *store, - gpointer user_data) -{ - struct { - EActivity *activity; - gboolean empty_trash; - } *sync_data = user_data; - - /* FIXME Not passing a GCancellable. */ - /* FIXME This operation should be queued. */ - camel_store_synchronize ( - store, sync_data->empty_trash, G_PRIORITY_DEFAULT, NULL, - (GAsyncReadyCallback) mail_backend_store_operation_done_cb, - g_object_ref (sync_data->activity)); -} - -/* Helper for mail_backend_prepare_for_quit_cb() */ static gboolean mail_backend_poll_to_quit (EActivity *activity) { @@ -273,14 +259,10 @@ mail_backend_prepare_for_quit_cb (EShell *shell, { EAccountList *account_list; EMailSession *session; + GList *list, *link; gboolean delete_junk; gboolean empty_trash; - struct { - EActivity *activity; - gboolean empty_trash; - } sync_data; - session = e_mail_backend_get_session (backend); delete_junk = e_mail_backend_delete_junk_policy_decision (backend); @@ -296,15 +278,40 @@ mail_backend_prepare_for_quit_cb (EShell *shell, /* Cancel all pending activities. */ mail_cancel_all (); - if (delete_junk) - e_mail_store_foreach ( - session, (GFunc) mail_backend_delete_junk, backend); + list = camel_session_list_services (CAMEL_SESSION (session)); + + if (delete_junk) { + for (link = list; link != NULL; link = g_list_next (link)) { + CamelService *service; + + service = CAMEL_SERVICE (link->data); + + if (!CAMEL_IS_STORE (service)) + continue; + + mail_backend_delete_junk (service, backend); + } + } + + for (link = list; link != NULL; link = g_list_next (link)) { + CamelService *service; - sync_data.activity = activity; - sync_data.empty_trash = empty_trash; + service = CAMEL_SERVICE (link->data); - e_mail_store_foreach ( - session, (GFunc) mail_backend_final_sync, &sync_data); + if (!CAMEL_IS_STORE (service)) + continue; + + /* FIXME Not passing a GCancellable. */ + /* FIXME This operation should be queued. */ + camel_store_synchronize ( + CAMEL_STORE (service), + empty_trash, G_PRIORITY_DEFAULT, + NULL, (GAsyncReadyCallback) + mail_backend_store_operation_done_cb, + g_object_ref (activity)); + } + + g_list_free (list); /* Now we poll until all activities are actually cancelled or finished. * Reffing the activity delays quitting; the reference count @@ -324,6 +331,8 @@ mail_backend_quit_requested_cb (EShell *shell, EShellQuitReason reason, EShellBackend *mail_shell_backend) { + EMailBackend *backend; + EMailSession *session; CamelFolder *folder; GtkWindow *window; gint response; @@ -348,7 +357,11 @@ mail_backend_quit_requested_cb (EShell *shell, /* Check Outbox for any unsent messages. */ - folder = e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_OUTBOX); + backend = E_MAIL_BACKEND (mail_shell_backend); + session = e_mail_backend_get_session (backend); + + folder = e_mail_session_get_local_folder ( + session, E_MAIL_LOCAL_FOLDER_OUTBOX); if (folder == NULL) return; @@ -373,6 +386,7 @@ mail_backend_folder_deleted_cb (MailFolderCache *folder_cache, CamelStoreClass *class; EAccountList *account_list; EIterator *iterator; + EMailSession *session; const gchar *local_drafts_folder_uri; const gchar *local_sent_folder_uri; gboolean write_config = FALSE; @@ -385,10 +399,15 @@ mail_backend_folder_deleted_cb (MailFolderCache *folder_cache, class = CAMEL_STORE_GET_CLASS (store); g_return_if_fail (class->compare_folder_name != NULL); + session = e_mail_backend_get_session (backend); + local_drafts_folder_uri = - e_mail_local_get_folder_uri (E_MAIL_LOCAL_FOLDER_DRAFTS); + e_mail_session_get_local_folder_uri ( + session, E_MAIL_LOCAL_FOLDER_DRAFTS); + local_sent_folder_uri = - e_mail_local_get_folder_uri (E_MAIL_LOCAL_FOLDER_SENT); + e_mail_session_get_local_folder_uri ( + session, E_MAIL_LOCAL_FOLDER_SENT); uri = e_mail_folder_uri_build (store, folder_name); @@ -744,7 +763,6 @@ mail_backend_constructed (GObject *object) EMailBackendPrivate *priv; EShell *shell; EShellBackend *shell_backend; - EMFolderTreeModel *folder_tree_model; MailFolderCache *folder_cache; priv = E_MAIL_BACKEND_GET_PRIVATE (object); @@ -779,14 +797,6 @@ mail_backend_constructed (GObject *object) * Give EAccountComboBox a CamelSession property. */ e_account_combo_box_set_session (CAMEL_SESSION (priv->session)); - /* FIXME EMailBackend should own the default EMFolderTreeModel. */ - folder_tree_model = em_folder_tree_model_get_default (); - - /* FIXME This is creating a circular reference. Perhaps the - * should only hold a weak pointer to EMailBackend? */ - em_folder_tree_model_set_backend ( - folder_tree_model, E_MAIL_BACKEND (object)); - g_signal_connect ( shell, "prepare-for-offline", G_CALLBACK (mail_backend_prepare_for_offline_cb), @@ -856,15 +866,6 @@ e_mail_backend_class_init (EMailBackendClass *class) NULL, E_TYPE_MAIL_SESSION, G_PARAM_READABLE)); - - signals[ACCOUNT_SORT_ORDER_CHANGED] = g_signal_new ( - "account-sort-order-changed", - G_TYPE_FROM_CLASS (class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (EMailBackendClass, account_sort_order_changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); } static void @@ -965,11 +966,3 @@ e_mail_backend_submit_alert (EMailBackend *backend, va_end (va); } -void -e_mail_backend_account_sort_order_changed (EMailBackend *backend) -{ - g_return_if_fail (backend != NULL); - g_return_if_fail (E_IS_MAIL_BACKEND (backend)); - - g_signal_emit (backend, signals[ACCOUNT_SORT_ORDER_CHANGED], 0); -} diff --git a/mail/e-mail-backend.h b/mail/e-mail-backend.h index 4d3cc10799..6d425197f3 100644 --- a/mail/e-mail-backend.h +++ b/mail/e-mail-backend.h @@ -67,10 +67,6 @@ struct _EMailBackendClass { (EMailBackend *backend); gboolean (*empty_trash_policy_decision) (EMailBackend *backend); - - /* Signals */ - void (*account_sort_order_changed) - (EMailBackend *backend); }; GType e_mail_backend_get_type (void); @@ -83,9 +79,6 @@ void e_mail_backend_submit_alert (EMailBackend *backend, const gchar *tag, ...) G_GNUC_NULL_TERMINATED; -void e_mail_backend_account_sort_order_changed - (EMailBackend *backend); - G_END_DECLS #endif /* E_MAIL_BACKEND_H */ diff --git a/mail/e-mail-local.c b/mail/e-mail-local.c deleted file mode 100644 index 28d174e303..0000000000 --- a/mail/e-mail-local.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * e-mail-local.c - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see <http://www.gnu.org/licenses/> - * - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "e-mail-local.h" - -#include <glib/gi18n.h> - -#include "e-mail-folder-utils.h" - -#define CHECK_LOCAL_FOLDER_TYPE(type) \ - ((type) < G_N_ELEMENTS (default_local_folders)) - -/* The array elements correspond to EMailLocalFolder. */ -static struct { - const gchar *display_name; - CamelFolder *folder; - gchar *folder_uri; -} default_local_folders[] = { - { N_("Inbox") }, - { N_("Drafts") }, - { N_("Outbox") }, - { N_("Sent") }, - { N_("Templates") }, - { "Inbox" } /* "always local" inbox */ -}; - -static CamelStore *local_store; -static gboolean mail_local_initialized = FALSE; - -void -e_mail_local_init (EMailSession *session, - const gchar *data_dir) -{ - CamelSettings *settings; - CamelService *service; - gchar *path; - gint ii; - GError *error = NULL; - - if (mail_local_initialized) - return; - - g_return_if_fail (E_IS_MAIL_SESSION (session)); - g_return_if_fail (data_dir != NULL); - - mail_local_initialized = TRUE; - - service = camel_session_add_service ( - CAMEL_SESSION (session), - "local", "maildir", - CAMEL_PROVIDER_STORE, &error); - - camel_service_set_display_name (service, _("On This Computer")); - - settings = camel_service_get_settings (service); - - path = g_build_filename (data_dir, "local", NULL); - g_object_set (settings, "path", path, NULL); - g_free (path); - - /* Shouldn't need to worry about other mail applications - * altering files in our local mail store. */ - g_object_set (service, "need-summary-check", FALSE, NULL); - - if (error != NULL) - goto fail; - - /* Populate the rest of the default_local_folders array. */ - for (ii = 0; ii < G_N_ELEMENTS (default_local_folders); ii++) { - const gchar *display_name; - - display_name = default_local_folders[ii].display_name; - - default_local_folders[ii].folder_uri = - e_mail_folder_uri_build ( - CAMEL_STORE (service), display_name); - - /* FIXME camel_store_get_folder() may block. */ - if (!strcmp (display_name, "Inbox")) - default_local_folders[ii].folder = - camel_store_get_inbox_folder_sync ( - CAMEL_STORE (service), NULL, &error); - else - default_local_folders[ii].folder = - camel_store_get_folder_sync ( - CAMEL_STORE (service), display_name, - CAMEL_STORE_FOLDER_CREATE, NULL, &error); - - if (error != NULL) { - g_critical ("%s", error->message); - g_clear_error (&error); - } - } - - local_store = g_object_ref (service); - - return; - -fail: - g_critical ( - "Could not initialize local store/folder: %s", - error->message); - - g_error_free (error); -} - -CamelFolder * -e_mail_local_get_folder (EMailLocalFolder type) -{ - g_return_val_if_fail (mail_local_initialized, NULL); - g_return_val_if_fail (CHECK_LOCAL_FOLDER_TYPE (type), NULL); - - return default_local_folders[type].folder; -} - -const gchar * -e_mail_local_get_folder_uri (EMailLocalFolder type) -{ - g_return_val_if_fail (mail_local_initialized, NULL); - g_return_val_if_fail (CHECK_LOCAL_FOLDER_TYPE (type), NULL); - - return default_local_folders[type].folder_uri; -} - -CamelStore * -e_mail_local_get_store (void) -{ - g_return_val_if_fail (mail_local_initialized, NULL); - g_return_val_if_fail (CAMEL_IS_STORE (local_store), NULL); - - return local_store; -} diff --git a/mail/e-mail-local.h b/mail/e-mail-local.h deleted file mode 100644 index 282a0feacb..0000000000 --- a/mail/e-mail-local.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * e-mail-local.h - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see <http://www.gnu.org/licenses/> - * - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef E_MAIL_LOCAL_H -#define E_MAIL_LOCAL_H - -#include <camel/camel.h> -#include <mail/e-mail-enums.h> -#include <mail/e-mail-session.h> - -G_BEGIN_DECLS - -void e_mail_local_init (EMailSession *session, - const gchar *data_dir); -CamelFolder * e_mail_local_get_folder (EMailLocalFolder type); -const gchar * e_mail_local_get_folder_uri (EMailLocalFolder type); -CamelStore * e_mail_local_get_store (void); - -G_END_DECLS - -#endif /* E_MAIL_LOCAL_H */ diff --git a/mail/e-mail-migrate.c b/mail/e-mail-migrate.c index f3ce503012..fdf5684e0a 100644 --- a/mail/e-mail-migrate.c +++ b/mail/e-mail-migrate.c @@ -64,8 +64,6 @@ #include "e-mail-backend.h" #include "e-mail-folder-utils.h" -#include "e-mail-local.h" -#include "e-mail-store.h" #include "em-utils.h" #define d(x) x @@ -277,7 +275,7 @@ emm_setup_initial (const gchar *data_dir) d(printf("Setting up initial mail tree\n")); - base = g_build_filename(data_dir, "local", NULL); + base = g_build_filename (data_dir, "local", NULL); if (g_mkdir_with_parents (base, 0700) == -1 && errno != EEXIST) { g_free (base); return FALSE; @@ -671,7 +669,7 @@ create_mbox_account (EShellBackend *shell_backend, { EMailBackend *mail_backend; EMailSession *mail_session; - CamelStore *store; + CamelService *service; CamelURL *url; EAccountList *accounts; EAccount *account; @@ -682,9 +680,6 @@ create_mbox_account (EShellBackend *shell_backend, mail_session = e_mail_backend_get_session (mail_backend); data_dir = e_shell_backend_get_data_dir (shell_backend); - /* Initialize the mail stores early so we can add a new one. */ - e_mail_store_init (mail_session, data_dir); - account = e_account_new (); account->enabled = TRUE; @@ -716,15 +711,20 @@ create_mbox_account (EShellBackend *shell_backend, goto exit; } + /* This will also add it to the EMailSession. */ e_account_list_add (accounts, account); - store = e_mail_store_add_by_account (mail_session, account); - folder_uri = e_mail_folder_uri_build (store, "Sent"); + service = camel_session_get_service ( + CAMEL_SESSION (mail_session), account->uid); + + folder_uri = e_mail_folder_uri_build ( + CAMEL_STORE (service), "Sent"); e_account_set_string ( account, E_ACCOUNT_SENT_FOLDER_URI, folder_uri); g_free (folder_uri); - folder_uri = e_mail_folder_uri_build (store, "Drafts"); + folder_uri = e_mail_folder_uri_build ( + CAMEL_STORE (service), "Drafts"); e_account_set_string ( account, E_ACCOUNT_DRAFTS_FOLDER_URI, folder_uri); g_free (folder_uri); @@ -743,6 +743,8 @@ exit: static void change_sent_and_drafts_local_folders (EShellBackend *shell_backend) { + EMailBackend *backend; + EMailSession *session; EAccountList *accounts; EIterator *iter; const gchar *data_dir; @@ -754,6 +756,9 @@ change_sent_and_drafts_local_folders (EShellBackend *shell_backend) if (!accounts) return; + backend = E_MAIL_BACKEND (shell_backend); + session = e_mail_backend_get_session (backend); + data_dir = e_shell_backend_get_data_dir (shell_backend); tmp_uri = g_strconcat ("mbox:", data_dir, "/", "local", NULL); @@ -797,8 +802,8 @@ change_sent_and_drafts_local_folders (EShellBackend *shell_backend) changed = TRUE; e_account_set_string ( account, E_ACCOUNT_DRAFTS_FOLDER_URI, - e_mail_local_get_folder_uri ( - E_MAIL_LOCAL_FOLDER_DRAFTS)); + e_mail_session_get_local_folder_uri ( + session, E_MAIL_LOCAL_FOLDER_DRAFTS)); } uri = e_account_get_string (account, E_ACCOUNT_SENT_FOLDER_URI); @@ -806,8 +811,8 @@ change_sent_and_drafts_local_folders (EShellBackend *shell_backend) changed = TRUE; e_account_set_string ( account, E_ACCOUNT_SENT_FOLDER_URI, - e_mail_local_get_folder_uri ( - E_MAIL_LOCAL_FOLDER_SENT)); + e_mail_session_get_local_folder_uri ( + session, E_MAIL_LOCAL_FOLDER_SENT)); } } diff --git a/mail/e-mail-reader-utils.c b/mail/e-mail-reader-utils.c index a58eb1f441..ffca3d89ac 100644 --- a/mail/e-mail-reader-utils.c +++ b/mail/e-mail-reader-utils.c @@ -40,7 +40,6 @@ #include "mail/e-mail-backend.h" #include "mail/e-mail-browser.h" #include "mail/e-mail-folder-utils.h" -#include "mail/e-mail-local.h" #include "mail/em-composer-utils.h" #include "mail/em-format-html-print.h" #include "mail/em-utils.h" @@ -191,15 +190,16 @@ void e_mail_reader_delete_folder (EMailReader *reader, CamelFolder *folder) { - CamelStore *local_store; - CamelStore *parent_store; EMailBackend *backend; EMailSession *session; EAlertSink *alert_sink; + CamelStore *parent_store; MailFolderCache *folder_cache; GtkWindow *parent = e_shell_get_active_window (NULL); GtkWidget *dialog; + gboolean store_is_local; const gchar *full_name; + const gchar *uid; CamelFolderInfoFlags flags = 0; gboolean have_flags; @@ -209,14 +209,16 @@ e_mail_reader_delete_folder (EMailReader *reader, full_name = camel_folder_get_full_name (folder); parent_store = camel_folder_get_parent_store (folder); + uid = camel_service_get_uid (CAMEL_SERVICE (parent_store)); + store_is_local = (g_strcmp0 (uid, E_MAIL_SESSION_LOCAL_UID) == 0); + backend = e_mail_reader_get_backend (reader); session = e_mail_backend_get_session (backend); - local_store = e_mail_local_get_store (); alert_sink = e_mail_reader_get_alert_sink (reader); folder_cache = e_mail_session_get_folder_cache (session); - if (parent_store == local_store && + if (store_is_local && mail_reader_is_special_local_folder (full_name)) { e_mail_backend_submit_alert ( backend, "mail:no-delete-special-folder", diff --git a/mail/e-mail-session-utils.c b/mail/e-mail-session-utils.c index eca58bcad0..f1c27a3425 100644 --- a/mail/e-mail-session-utils.c +++ b/mail/e-mail-session-utils.c @@ -27,7 +27,6 @@ #include <glib/gi18n-lib.h> #include <mail/mail-tools.h> -#include <mail/e-mail-local.h> #include <mail/e-mail-folder-utils.h> #include <e-util/e-account-utils.h> #include <filter/e-filter-rule.h> @@ -508,7 +507,9 @@ mail_session_send_to_thread (GSimpleAsyncResult *simple, /* Append the sent message to a Sent folder. */ - local_sent_folder = e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_SENT); + local_sent_folder = + e_mail_session_get_local_folder ( + session, E_MAIL_LOCAL_FOLDER_SENT); /* Try to extract a CamelFolder from the Sent folder URI. */ if (context->sent_folder_uri != NULL) { diff --git a/mail/e-mail-session.c b/mail/e-mail-session.c index 03f4961206..6d04c2c23d 100644 --- a/mail/e-mail-session.c +++ b/mail/e-mail-session.c @@ -52,9 +52,9 @@ #include "e-util/e-alert-dialog.h" #include "e-util/e-util-private.h" +#include "e-mail-account-store.h" #include "e-mail-folder-utils.h" #include "e-mail-junk-filter.h" -#include "e-mail-local.h" #include "e-mail-session.h" #include "em-composer-utils.h" #include "em-filter-context.h" @@ -71,13 +71,26 @@ ((obj), E_TYPE_MAIL_SESSION, EMailSessionPrivate)) typedef struct _AsyncContext AsyncContext; +typedef struct _SourceContext SourceContext; struct _EMailSessionPrivate { + EMailAccountStore *account_store; MailFolderCache *folder_cache; + EAccountList *account_list; + gulong account_added_handler_id; + gulong account_changed_handler_id; + + CamelStore *local_store; + CamelStore *vfolder_store; + FILE *filter_logfile; GHashTable *junk_filters; EProxy *proxy; + + /* Local folder cache. */ + GPtrArray *local_folders; + GPtrArray *local_folder_uris; }; struct _AsyncContext { @@ -90,10 +103,27 @@ struct _AsyncContext { CamelFolder *folder; }; +struct _SourceContext { + EMailSession *session; + CamelService *service; +}; + enum { PROP_0, + PROP_ACCOUNT_STORE, PROP_FOLDER_CACHE, - PROP_JUNK_FILTER_NAME + PROP_JUNK_FILTER_NAME, + PROP_LOCAL_STORE, + PROP_VFOLDER_STORE +}; + +static const gchar *local_folder_names[E_MAIL_NUM_LOCAL_FOLDERS] = { + N_("Inbox"), /* E_MAIL_LOCAL_FOLDER_INBOX */ + N_("Drafts"), /* E_MAIL_LOCAL_FOLDER_DRAFTS */ + N_("Outbox"), /* E_MAIL_LOCAL_FOLDER_OUTBOX */ + N_("Sent"), /* E_MAIL_LOCAL_FOLDER_SENT */ + N_("Templates"), /* E_MAIL_LOCAL_FOLDER_TEMPLATES */ + "Inbox" /* E_MAIL_LOCAL_FOLDER_LOCAL_INBOX */ }; static gchar *mail_data_dir; @@ -463,6 +493,18 @@ async_context_free (AsyncContext *context) g_slice_free (AsyncContext, context); } +static void +source_context_free (SourceContext *context) +{ + if (context->session != NULL) + g_object_unref (context->session); + + if (context->service != NULL) + g_object_unref (context->service); + + g_slice_free (SourceContext, context); +} + static gchar * mail_session_make_key (CamelService *service, const gchar *item) @@ -553,6 +595,270 @@ mail_session_set_junk_filter_name (EMailSession *session, } static void +mail_session_add_by_account (EMailSession *session, + EAccount *account) +{ + CamelService *service = NULL; + CamelProvider *provider; + CamelURL *url; + gboolean transport_only; + GError *error = NULL; + + /* check whether it's transport-only accounts */ + transport_only = + (account->source == NULL) || + (account->source->url == NULL) || + (*account->source->url == '\0'); + if (transport_only) + goto handle_transport; + + /* Load the service, but don't connect. Check its provider, + * and if this belongs in the folder tree model, add it. */ + + url = camel_url_new (account->source->url, NULL); + if (url != NULL) { + provider = camel_provider_get (url->protocol, NULL); + camel_url_free (url); + } else { + provider = NULL; + } + + if (provider == NULL) { + /* In case we do not have a provider here, we handle + * the special case of having multiple mail identities + * eg. a dummy account having just SMTP server defined */ + goto handle_transport; + } + + service = camel_session_add_service ( + CAMEL_SESSION (session), + account->uid, provider->protocol, + CAMEL_PROVIDER_STORE, &error); + + if (error != NULL) { + g_warning ( + "Failed to add service: %s: %s", + account->name, error->message); + g_error_free (error); + return; + } + + camel_service_set_display_name (service, account->name); + +handle_transport: + + /* While we're at it, add the account's transport (if it has one) + * to the CamelSession. The transport's UID is a kludge for now. + * We take the EAccount's UID and tack on "-transport". */ + + if (account->transport) { + GError *transport_error = NULL; + + url = camel_url_new ( + account->transport->url, + &transport_error); + + if (url != NULL) { + provider = camel_provider_get ( + url->protocol, &transport_error); + camel_url_free (url); + } else + provider = NULL; + + if (provider != NULL) { + gchar *transport_uid; + + transport_uid = g_strconcat ( + account->uid, "-transport", NULL); + + camel_session_add_service ( + CAMEL_SESSION (session), + transport_uid, provider->protocol, + CAMEL_PROVIDER_TRANSPORT, &transport_error); + + g_free (transport_uid); + } + + if (transport_error) { + g_warning ( + "%s: Failed to add transport service: %s", + G_STRFUNC, transport_error->message); + g_error_free (transport_error); + } + } +} + +static void +mail_session_account_added_cb (EAccountList *account_list, + EAccount *account, + EMailSession *session) +{ + mail_session_add_by_account (session, account); +} + +static void +mail_session_account_changed_cb (EAccountList *account_list, + EAccount *account, + EMailSession *session) +{ + EMFolderTreeModel *folder_tree_model; + CamelService *service; + + service = camel_session_get_service ( + CAMEL_SESSION (session), account->uid); + + if (!CAMEL_IS_STORE (service)) + return; + + /* Update the display name of the corresponding CamelStore. + * EMailAccountStore listens for "notify" signals from each + * service so it will detect this and update the model. + * + * XXX If EAccount defined GObject properties we could just + * bind EAccount:name to CamelService:display-name and + * be done with it. Oh well. + */ + + camel_service_set_display_name (service, account->name); + + /* Remove the store from the folder tree model and, if the + * account is still enabled, re-add it. Easier than trying + * to update the model with the store in place. + * + * em_folder_tree_model_add_store() already knows which types + * of stores to disregard, so we don't have to deal with that + * here. */ + + folder_tree_model = em_folder_tree_model_get_default (); + + em_folder_tree_model_remove_store ( + folder_tree_model, CAMEL_STORE (service)); + + if (account->enabled) + em_folder_tree_model_add_store ( + folder_tree_model, CAMEL_STORE (service)); +} + +static gboolean +mail_session_add_service_cb (SourceContext *context) +{ + EMailAccountStore *store; + + store = e_mail_session_get_account_store (context->session); + e_mail_account_store_add_service (store, context->service); + + return FALSE; +} + +static void +mail_session_add_local_store (EMailSession *session) +{ + CamelLocalSettings *local_settings; + CamelSession *camel_session; + CamelSettings *settings; + CamelService *service; + const gchar *data_dir; + gchar *path; + gint ii; + GError *error = NULL; + + camel_session = CAMEL_SESSION (session); + + service = camel_session_add_service ( + camel_session, E_MAIL_SESSION_LOCAL_UID, + "maildir", CAMEL_PROVIDER_STORE, &error); + + /* XXX One could argue this is a fatal error + * since we depend on it in so many places. */ + if (error != NULL) { + g_critical ("%s: %s", G_STRFUNC, error->message); + g_error_free (error); + return; + } + + g_return_if_fail (CAMEL_IS_SERVICE (service)); + + camel_service_set_display_name (service, _("On This Computer")); + + settings = camel_service_get_settings (service); + local_settings = CAMEL_LOCAL_SETTINGS (settings); + data_dir = camel_session_get_user_data_dir (camel_session); + + path = g_build_filename (data_dir, E_MAIL_SESSION_LOCAL_UID, NULL); + camel_local_settings_set_path (local_settings, path); + g_free (path); + + /* Shouldn't need to worry about other mail applications + * altering files in our local mail store. */ + g_object_set (service, "need-summary-check", FALSE, NULL); + + /* Populate the local folder cache. */ + for (ii = 0; ii < E_MAIL_NUM_LOCAL_FOLDERS; ii++) { + CamelFolder *folder; + gchar *folder_uri; + const gchar *display_name; + GError *error = NULL; + + display_name = local_folder_names[ii]; + + /* XXX This blocks but should be fast. */ + if (ii == E_MAIL_LOCAL_FOLDER_LOCAL_INBOX) + folder = camel_store_get_inbox_folder_sync ( + CAMEL_STORE (service), NULL, &error); + else + folder = camel_store_get_folder_sync ( + CAMEL_STORE (service), display_name, + CAMEL_STORE_FOLDER_CREATE, NULL, &error); + + folder_uri = e_mail_folder_uri_build ( + CAMEL_STORE (service), display_name); + + /* The arrays take ownership of the items added. */ + g_ptr_array_add (session->priv->local_folders, folder); + g_ptr_array_add (session->priv->local_folder_uris, folder_uri); + + if (error != NULL) { + g_critical ("%s: %s", G_STRFUNC, error->message); + g_error_free (error); + } + } + + session->priv->local_store = g_object_ref (service); +} + +static void +mail_session_add_vfolder_store (EMailSession *session) +{ + CamelSession *camel_session; + CamelService *service; + GError *error = NULL; + + camel_session = CAMEL_SESSION (session); + + service = camel_session_add_service ( + camel_session, E_MAIL_SESSION_VFOLDER_UID, + "vfolder", CAMEL_PROVIDER_STORE, &error); + + if (error != NULL) { + g_critical ("%s: %s", G_STRFUNC, error->message); + g_error_free (error); + return; + } + + g_return_if_fail (CAMEL_IS_SERVICE (service)); + + camel_service_set_display_name (service, _("Search Folders")); + em_utils_connect_service_sync (service, NULL, NULL); + + /* XXX There's more configuration to do in vfolder_load_storage() + * but it requires an EMailBackend, which we don't have access + * to from here, so it has to be called from elsewhere. Kinda + * thinking about reworking that... */ + + session->priv->vfolder_store = g_object_ref (service); +} + +static void mail_session_set_property (GObject *object, guint property_id, const GValue *value, @@ -576,6 +882,13 @@ mail_session_get_property (GObject *object, GParamSpec *pspec) { switch (property_id) { + case PROP_ACCOUNT_STORE: + g_value_set_object ( + value, + e_mail_session_get_account_store ( + E_MAIL_SESSION (object))); + return; + case PROP_FOLDER_CACHE: g_value_set_object ( value, @@ -589,6 +902,20 @@ mail_session_get_property (GObject *object, mail_session_get_junk_filter_name ( E_MAIL_SESSION (object))); return; + + case PROP_LOCAL_STORE: + g_value_set_object ( + value, + e_mail_session_get_local_store ( + E_MAIL_SESSION (object))); + return; + + case PROP_VFOLDER_STORE: + g_value_set_object ( + value, + e_mail_session_get_vfolder_store ( + E_MAIL_SESSION (object))); + return; } G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); @@ -601,11 +928,41 @@ mail_session_dispose (GObject *object) priv = E_MAIL_SESSION_GET_PRIVATE (object); + if (priv->account_store != NULL) { + e_mail_account_store_clear (priv->account_store); + g_object_unref (priv->account_store); + priv->account_store = NULL; + } + if (priv->folder_cache != NULL) { g_object_unref (priv->folder_cache); priv->folder_cache = NULL; } + if (priv->account_list != NULL) { + g_signal_handler_disconnect ( + priv->account_list, + priv->account_added_handler_id); + g_signal_handler_disconnect ( + priv->account_list, + priv->account_changed_handler_id); + g_object_unref (priv->account_list); + priv->account_list = NULL; + } + + if (priv->local_store != NULL) { + g_object_unref (priv->local_store); + priv->local_store = NULL; + } + + if (priv->vfolder_store != NULL) { + g_object_unref (priv->vfolder_store); + priv->vfolder_store = NULL; + } + + g_ptr_array_set_size (priv->local_folders, 0); + g_ptr_array_set_size (priv->local_folder_uris, 0); + /* Chain up to parent's dispose() method. */ G_OBJECT_CLASS (e_mail_session_parent_class)->dispose (object); } @@ -620,6 +977,9 @@ mail_session_finalize (GObject *object) g_hash_table_destroy (priv->junk_filters); g_object_unref (priv->proxy); + g_ptr_array_free (priv->local_folders, TRUE); + g_ptr_array_free (priv->local_folder_uris, TRUE); + g_free (mail_data_dir); g_free (mail_config_dir); @@ -642,17 +1002,87 @@ mail_session_notify (GObject *object, static void mail_session_constructed (GObject *object) { - EMailSessionPrivate *priv; + EMFolderTreeModel *folder_tree_model; + EMailSession *session; EExtensible *extensible; GType extension_type; - GList *list, *iter; + GList *list, *link; GSettings *settings; + EAccountList *account_list; + EIterator *iter; + EAccount *account; + gulong handler_id; - priv = E_MAIL_SESSION_GET_PRIVATE (object); + session = E_MAIL_SESSION (object); /* Chain up to parent's constructed() method. */ G_OBJECT_CLASS (e_mail_session_parent_class)->constructed (object); + account_list = e_get_account_list (); + session->priv->account_list = g_object_ref (account_list); + + session->priv->account_store = e_mail_account_store_new (session); + + /* This must be created after the account store. */ + session->priv->folder_cache = mail_folder_cache_new (session); + + /* XXX Make sure the folder tree model is created before we + * add built-in CamelStores so it gets signals from the + * EMailAccountStore. + * + * XXX This is creating a circular reference. Perhaps the + * model should only hold a weak pointer to EMailSession? + * + * FIXME EMailSession should just own the default instance. + */ + folder_tree_model = em_folder_tree_model_get_default (); + em_folder_tree_model_set_session (folder_tree_model, session); + + /* Add built-in CamelStores. */ + + mail_session_add_local_store (session); + mail_session_add_vfolder_store (session); + + /* Load user-defined mail accounts. */ + + iter = e_list_get_iterator (E_LIST (account_list)); + + while (e_iterator_is_valid (iter)) { + /* XXX EIterator misuses const. */ + account = (EAccount *) e_iterator_get (iter); + + if (account->enabled) + mail_session_add_by_account (session, account); + + e_iterator_next (iter); + } + + g_object_unref (iter); + + /* Initialize which account is default. */ + + account = e_get_default_account (); + if (account != NULL) { + CamelService *service; + + service = camel_session_get_service ( + CAMEL_SESSION (session), account->uid); + e_mail_account_store_set_default_service ( + session->priv->account_store, service); + } + + /* Listen for account list updates. */ + + handler_id = g_signal_connect ( + account_list, "account-added", + G_CALLBACK (mail_session_account_added_cb), session); + session->priv->account_added_handler_id = handler_id; + + handler_id = g_signal_connect ( + account_list, "account-changed", + G_CALLBACK (mail_session_account_changed_cb), session); + session->priv->account_changed_handler_id = handler_id; + extensible = E_EXTENSIBLE (object); e_extensible_load_extensions (extensible); @@ -661,11 +1091,11 @@ mail_session_constructed (GObject *object) extension_type = E_TYPE_MAIL_JUNK_FILTER; list = e_extensible_list_extensions (extensible, extension_type); - for (iter = list; iter != NULL; iter = g_list_next (iter)) { + for (link = list; link != NULL; link = g_list_next (link)) { EMailJunkFilter *junk_filter; EMailJunkFilterClass *class; - junk_filter = E_MAIL_JUNK_FILTER (iter->data); + junk_filter = E_MAIL_JUNK_FILTER (link->data); class = E_MAIL_JUNK_FILTER_GET_CLASS (junk_filter); if (!CAMEL_IS_JUNK_FILTER (junk_filter)) { @@ -693,17 +1123,21 @@ mail_session_constructed (GObject *object) /* No need to reference the EMailJunkFilter since * EMailSession owns the reference to it already. */ g_hash_table_insert ( - priv->junk_filters, + session->priv->junk_filters, (gpointer) class->filter_name, junk_filter); } g_list_free (list); - /* Bind the "junk-default-plugin" GSettings key to our "junk-filter-name" property. */ + /* Bind the "junk-default-plugin" GSettings + * key to our "junk-filter-name" property. */ settings = g_settings_new ("org.gnome.evolution.mail"); - g_settings_bind (settings, "junk-default-plugin", object, "junk-filter-name", G_SETTINGS_BIND_DEFAULT); + g_settings_bind ( + settings, "junk-default-plugin", + object, "junk-filter-name", + G_SETTINGS_BIND_DEFAULT); g_object_unref (settings); } @@ -765,6 +1199,22 @@ mail_session_add_service (CamelSession *session, } } + /* Inform the EMailAccountStore of the new CamelService + * from an idle callback so the service has a chance to + * fully initialize first. */ + if (CAMEL_IS_STORE (service)) { + SourceContext *context; + + context = g_slice_new0 (SourceContext); + context->session = g_object_ref (session); + context->service = g_object_ref (service); + + g_idle_add_full ( + G_PRIORITY_DEFAULT_IDLE, + (GSourceFunc) mail_session_add_service_cb, + context, (GDestroyNotify) source_context_free); + } + return service; } @@ -1073,7 +1523,8 @@ mail_session_forward_to (CamelSession *session, /* and send it */ info = camel_message_info_new (NULL); - out_folder = e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_OUTBOX); + out_folder = e_mail_session_get_local_folder ( + E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_OUTBOX); camel_message_info_set_flags ( info, CAMEL_MESSAGE_SEEN, CAMEL_MESSAGE_SEEN); @@ -1300,6 +1751,28 @@ e_mail_session_class_init (EMailSessionClass *class) NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property ( + object_class, + PROP_LOCAL_STORE, + g_param_spec_object ( + "local-store", + "Local Store", + "Built-in local store", + CAMEL_TYPE_STORE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property ( + object_class, + PROP_VFOLDER_STORE, + g_param_spec_object ( + "vfolder-store", + "Search Folder Store", + "Built-in search folder store", + CAMEL_TYPE_STORE, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); } static void @@ -1308,11 +1781,17 @@ e_mail_session_init (EMailSession *session) GSettings *settings; session->priv = E_MAIL_SESSION_GET_PRIVATE (session); - session->priv->folder_cache = mail_folder_cache_new (); session->priv->junk_filters = g_hash_table_new ( (GHashFunc) g_str_hash, (GEqualFunc) g_str_equal); session->priv->proxy = e_proxy_new (); + session->priv->local_folders = + g_ptr_array_new_with_free_func ( + (GDestroyNotify) g_object_unref); + session->priv->local_folder_uris = + g_ptr_array_new_with_free_func ( + (GDestroyNotify) g_free); + /* Initialize the EAccount setup. */ e_account_writable (NULL, E_ACCOUNT_SOURCE_SAVE_PASSWD); @@ -1348,6 +1827,14 @@ e_mail_session_new (void) NULL); } +EMailAccountStore * +e_mail_session_get_account_store (EMailSession *session) +{ + g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); + + return session->priv->account_store; +} + MailFolderCache * e_mail_session_get_folder_cache (EMailSession *session) { @@ -1356,6 +1843,58 @@ e_mail_session_get_folder_cache (EMailSession *session) return session->priv->folder_cache; } +CamelStore * +e_mail_session_get_local_store (EMailSession *session) +{ + g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); + + return session->priv->local_store; +} + +CamelStore * +e_mail_session_get_vfolder_store (EMailSession *session) +{ + g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); + + return session->priv->vfolder_store; +} + +CamelFolder * +e_mail_session_get_local_folder (EMailSession *session, + EMailLocalFolder type) +{ + GPtrArray *local_folders; + CamelFolder *folder; + + g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); + + local_folders = session->priv->local_folders; + g_return_val_if_fail (type < local_folders->len, NULL); + + folder = g_ptr_array_index (local_folders, type); + g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL); + + return folder; +} + +const gchar * +e_mail_session_get_local_folder_uri (EMailSession *session, + EMailLocalFolder type) +{ + GPtrArray *local_folder_uris; + const gchar *folder_uri; + + g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); + + local_folder_uris = session->priv->local_folder_uris; + g_return_val_if_fail (type < local_folder_uris->len, NULL); + + folder_uri = g_ptr_array_index (local_folder_uris, type); + g_return_val_if_fail (folder_uri != NULL, NULL); + + return folder_uri; +} + GList * e_mail_session_get_available_junk_filters (EMailSession *session) { diff --git a/mail/e-mail-session.h b/mail/e-mail-session.h index 165b335a19..e10e3c3d1f 100644 --- a/mail/e-mail-session.h +++ b/mail/e-mail-session.h @@ -26,6 +26,8 @@ #define E_MAIL_SESSION_H #include <camel/camel.h> +#include <mail/e-mail-enums.h> +#include <mail/e-mail-account-store.h> #include <mail/mail-folder-cache.h> /* Standard GObject macros */ @@ -47,8 +49,15 @@ (G_TYPE_INSTANCE_GET_CLASS \ ((obj), E_TYPE_MAIL_SESSION, EMailSessionClass)) +/* Built-in CamelServices */ +#define E_MAIL_SESSION_LOCAL_UID "local" /* "On This Computer" */ +#define E_MAIL_SESSION_VFOLDER_UID "vfolder" /* "Search Folders" */ + G_BEGIN_DECLS +/* Avoids a circular dependency. */ +typedef struct _EMailAccountStore EMailAccountStore; + typedef struct _EMailSession EMailSession; typedef struct _EMailSessionClass EMailSessionClass; typedef struct _EMailSessionPrivate EMailSessionPrivate; @@ -64,8 +73,19 @@ struct _EMailSessionClass { GType e_mail_session_get_type (void); EMailSession * e_mail_session_new (void); +EMailAccountStore * + e_mail_session_get_account_store + (EMailSession *session); MailFolderCache * e_mail_session_get_folder_cache (EMailSession *session); +CamelStore * e_mail_session_get_local_store (EMailSession *session); +CamelStore * e_mail_session_get_vfolder_store + (EMailSession *session); +CamelFolder * e_mail_session_get_local_folder (EMailSession *session, + EMailLocalFolder type); +const gchar * e_mail_session_get_local_folder_uri + (EMailSession *session, + EMailLocalFolder type); GList * e_mail_session_get_available_junk_filters (EMailSession *session); CamelFolder * e_mail_session_get_inbox_sync (EMailSession *session, diff --git a/mail/e-mail-sidebar.c b/mail/e-mail-sidebar.c index 35048f8293..9a935819c8 100644 --- a/mail/e-mail-sidebar.c +++ b/mail/e-mail-sidebar.c @@ -28,7 +28,6 @@ #include <string.h> #include <camel/camel.h> -#include "mail/e-mail-local.h" #include "mail/em-utils.h" #define E_MAIL_SIDEBAR_GET_PRIVATE(obj) \ @@ -338,6 +337,8 @@ mail_sidebar_check_state (EMailSidebar *sidebar) GtkTreeIter iter; CamelStore *store; gchar *full_name; + const gchar *uid; + gboolean store_is_local; gboolean allows_children = TRUE; gboolean can_delete = TRUE; gboolean is_junk = FALSE; @@ -360,12 +361,12 @@ mail_sidebar_check_state (EMailSidebar *sidebar) COL_BOOL_IS_STORE, &is_store, COL_UINT_FLAGS, &folder_flags, -1); + uid = camel_service_get_uid (CAMEL_SERVICE (store)); + store_is_local = (g_strcmp0 (uid, E_MAIL_SESSION_LOCAL_UID) == 0); + if (!is_store && full_name != NULL) { - CamelStore *local_store; guint32 folder_type; - local_store = e_mail_local_get_store (); - /* Is this a virtual junk or trash folder? */ is_junk = (strcmp (full_name, CAMEL_VJUNK_NAME) == 0); is_trash = (strcmp (full_name, CAMEL_VTRASH_NAME) == 0); @@ -378,7 +379,7 @@ mail_sidebar_check_state (EMailSidebar *sidebar) allows_children = !(is_junk || is_trash); /* Don't allow deletion of special local folders. */ - if (store == local_store) { + if (store_is_local) { can_delete = (strcmp (full_name, "Drafts") != 0) && (strcmp (full_name, "Inbox") != 0) && diff --git a/mail/e-mail-store.c b/mail/e-mail-store.c deleted file mode 100644 index 283a8608e9..0000000000 --- a/mail/e-mail-store.c +++ /dev/null @@ -1,500 +0,0 @@ -/* - * e-mail-store.c - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see <http://www.gnu.org/licenses/> - * - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "e-mail-store.h" - -#include <glib/gi18n.h> -#include <camel/camel.h> -#include <libedataserver/e-account.h> -#include <libedataserver/e-account-list.h> - -#include "e-util/e-account-utils.h" - -#include "mail/e-mail-local.h" -#include "mail/em-folder-tree-model.h" -#include "mail/em-utils.h" -#include "mail/mail-folder-cache.h" -#include "mail/mail-mt.h" -#include "mail/mail-ops.h" - -#include "shell/e-shell.h" -#include "shell/e-shell-settings.h" - -typedef struct _StoreInfo StoreInfo; - -typedef void (*AddStoreCallback) (MailFolderCache *folder_cache, - CamelStore *store, - CamelFolderInfo *info, - StoreInfo *store_info); - -struct _StoreInfo { - gint ref_count; - - CamelStore *store; - - /* Hold a reference to keep them alive. */ - CamelFolder *vtrash; - CamelFolder *vjunk; - - AddStoreCallback callback; - - guint removed : 1; -}; - -static GHashTable *store_table; - -static StoreInfo * -store_info_new (CamelStore *store) -{ - StoreInfo *store_info; - - g_return_val_if_fail (CAMEL_IS_STORE (store), NULL); - - store_info = g_slice_new0 (StoreInfo); - store_info->ref_count = 1; - - store_info->store = g_object_ref (store); - - /* If these are vfolders then they need to be opened now, - * otherwise they won't keep track of all folders. */ - if (store->flags & CAMEL_STORE_VTRASH) - store_info->vtrash = - camel_store_get_trash_folder_sync (store, NULL, NULL); - if (store->flags & CAMEL_STORE_VJUNK) - store_info->vjunk = - camel_store_get_junk_folder_sync (store, NULL, NULL); - - return store_info; -} - -static StoreInfo * -store_info_ref (StoreInfo *store_info) -{ - g_return_val_if_fail (store_info != NULL, store_info); - g_return_val_if_fail (store_info->ref_count > 0, store_info); - - g_atomic_int_inc (&store_info->ref_count); - - return store_info; -} - -static void -store_info_unref (StoreInfo *store_info) -{ - g_return_if_fail (store_info != NULL); - g_return_if_fail (store_info->ref_count > 0); - - if (g_atomic_int_dec_and_test (&store_info->ref_count)) { - - g_object_unref (store_info->store); - - if (store_info->vtrash != NULL) - g_object_unref (store_info->vtrash); - - if (store_info->vjunk != NULL) - g_object_unref (store_info->vjunk); - - g_slice_free (StoreInfo, store_info); - } -} - -static void -store_table_free (StoreInfo *store_info) -{ - store_info->removed = 1; - store_info_unref (store_info); -} - -static gboolean -mail_store_note_store_cb (MailFolderCache *folder_cache, - CamelStore *store, - CamelFolderInfo *info, - gpointer user_data) -{ - StoreInfo *store_info = user_data; - - if (store_info->callback != NULL) - store_info->callback ( - folder_cache, store, info, store_info); - - if (!store_info->removed) { - /* This keeps message counters up-to-date. */ - if (store_info->vtrash != NULL) - mail_folder_cache_note_folder ( - folder_cache, store_info->vtrash); - if (store_info->vjunk != NULL) - mail_folder_cache_note_folder ( - folder_cache, store_info->vjunk); - } - - store_info_unref (store_info); - - return TRUE; -} - -static gboolean -special_mail_store_is_enabled (CamelStore *store) -{ - CamelService *service; - EShell *shell; - EShellSettings *shell_settings; - const gchar *uid, *prop = NULL; - - service = CAMEL_SERVICE (store); - g_return_val_if_fail (service, FALSE); - - uid = camel_service_get_uid (service); - if (g_strcmp0 (uid, "local") == 0) - prop = "mail-enable-local-folders"; - else if (g_strcmp0 (uid, "vfolder") == 0) - prop = "mail-enable-search-folders"; - - if (!prop) - return TRUE; - - shell = e_shell_get_default (); - shell_settings = e_shell_get_shell_settings (shell); - - return e_shell_settings_get_boolean (shell_settings, prop); -} - -static void -mail_store_add (EMailSession *session, - CamelStore *store, - AddStoreCallback callback) -{ - EMFolderTreeModel *default_model; - MailFolderCache *folder_cache; - StoreInfo *store_info; - - g_return_if_fail (store_table != NULL); - g_return_if_fail (CAMEL_IS_STORE (store)); - - default_model = em_folder_tree_model_get_default (); - folder_cache = e_mail_session_get_folder_cache (session); - - store_info = store_info_new (store); - store_info->callback = callback; - - g_hash_table_insert (store_table, store, store_info); - - if (special_mail_store_is_enabled (store)) - em_folder_tree_model_add_store (default_model, store); - - mail_folder_cache_note_store ( - folder_cache, store, NULL, - mail_store_note_store_cb, store_info_ref (store_info)); -} - -static void -mail_store_add_local_done_cb (MailFolderCache *folder_cache, - CamelStore *store, - CamelFolderInfo *info, - StoreInfo *store_info) -{ - CamelFolder *folder; - gint ii; - - for (ii = 0; ii < E_MAIL_NUM_LOCAL_FOLDERS; ii++) { - folder = e_mail_local_get_folder (ii); - if (folder == NULL) - continue; - mail_folder_cache_note_folder (folder_cache, folder); - } -} - -static void -mail_store_load_accounts (EMailSession *session, - const gchar *data_dir) -{ - CamelStore *local_store; - EAccountList *account_list; - EIterator *iter; - - /* Add the local store. */ - - e_mail_local_init (session, data_dir); - local_store = e_mail_local_get_store (); - - mail_store_add ( - session, local_store, (AddStoreCallback) - mail_store_add_local_done_cb); - - /* Add mail accounts.. */ - - account_list = e_get_account_list (); - - for (iter = e_list_get_iterator ((EList *) account_list); - e_iterator_is_valid (iter); e_iterator_next (iter)) { - EAccount *account; - - account = (EAccount *) e_iterator_get (iter); - - if (!account->enabled) - continue; - - e_mail_store_add_by_account (session, account); - } - - g_object_unref (iter); -} - -void -e_mail_store_init (EMailSession *session, - const gchar *data_dir) -{ - static gboolean initialized = FALSE; - - g_return_if_fail (E_IS_MAIL_SESSION (session)); - - /* This function is idempotent because mail - * migration code may need to call it early. */ - if (initialized) - return; - - /* Initialize global variables. */ - - store_table = g_hash_table_new_full ( - g_direct_hash, g_direct_equal, - (GDestroyNotify) NULL, - (GDestroyNotify) store_table_free); - - mail_store_load_accounts (session, data_dir); - - initialized = TRUE; -} - -void -e_mail_store_add (EMailSession *session, - CamelStore *store) -{ - g_return_if_fail (E_IS_MAIL_SESSION (session)); - g_return_if_fail (CAMEL_IS_STORE (store)); - - mail_store_add (session, store, NULL); -} - -CamelStore * -e_mail_store_add_by_account (EMailSession *session, - EAccount *account) -{ - CamelService *service = NULL; - CamelProvider *provider; - CamelURL *url; - gboolean transport_only; - gboolean service_is_local_delivery; - gboolean service_belongs_in_tree_model; - GError *error = NULL; - - g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); - g_return_val_if_fail (E_IS_ACCOUNT (account), NULL); - - /* check whether it's transport-only accounts */ - transport_only = - (account->source == NULL) || - (account->source->url == NULL) || - (*account->source->url == '\0'); - if (transport_only) - goto handle_transport; - - /* Load the service, but don't connect. Check its provider, - * and if this belongs in the folder tree model, add it. */ - - url = camel_url_new (account->source->url, NULL); - if (url != NULL) { - service_is_local_delivery = - em_utils_is_local_delivery_mbox_file (url); - provider = camel_provider_get (url->protocol, NULL); - camel_url_free (url); - } else { - service_is_local_delivery = FALSE; - provider = NULL; - } - - if (provider == NULL) { - /* In case we do not have a provider here, we handle - * the special case of having multiple mail identities - * eg. a dummy account having just SMTP server defined */ - goto handle_transport; - } - - service = camel_session_add_service ( - CAMEL_SESSION (session), - account->uid, provider->protocol, - CAMEL_PROVIDER_STORE, &error); - - if (!CAMEL_IS_STORE (service)) - goto fail; - - camel_service_set_display_name (service, account->name); - - service_belongs_in_tree_model = - (provider->flags & CAMEL_PROVIDER_IS_STORAGE) && - !service_is_local_delivery; - - if (service_belongs_in_tree_model && store_table != NULL) - e_mail_store_add (session, CAMEL_STORE (service)); - -handle_transport: - - /* While we're at it, add the account's transport (if it has one) - * to the CamelSession. The transport's UID is a kludge for now. - * We take the EAccount's UID and tack on "-transport". */ - - if (account->transport) { - GError *transport_error = NULL; - - url = camel_url_new ( - account->transport->url, - &transport_error); - - if (url != NULL) { - provider = camel_provider_get ( - url->protocol, &transport_error); - camel_url_free (url); - } else - provider = NULL; - - if (provider != NULL) { - gchar *transport_uid; - - transport_uid = g_strconcat ( - account->uid, "-transport", NULL); - - camel_session_add_service ( - CAMEL_SESSION (session), - transport_uid, provider->protocol, - CAMEL_PROVIDER_TRANSPORT, &transport_error); - - g_free (transport_uid); - } - - if (transport_error) { - g_warning ( - "%s: Failed to add transport service: %s", - G_STRFUNC, transport_error->message); - g_error_free (transport_error); - } - } - - if (transport_only) - return NULL; - - return CAMEL_STORE (service); - -fail: - /* FIXME: Show an error dialog. */ - g_warning ( - "Couldn't get service: %s: %s", account->name, - error ? error->message : "Not a CamelStore"); - if (error) - g_error_free (error); - - return NULL; -} - -void -e_mail_store_remove (EMailSession *session, - CamelStore *store) -{ - MailFolderCache *folder_cache; - EMFolderTreeModel *default_model; - - g_return_if_fail (E_IS_MAIL_SESSION (session)); - g_return_if_fail (CAMEL_IS_STORE (store)); - g_return_if_fail (store_table != NULL); - - /* Because the store table holds a reference to each store used - * as a key in it, none of them will ever be gc'ed, meaning any - * call to camel_session_get_{service,store} with the same URL - * will always return the same object. So this works. */ - - if (g_hash_table_lookup (store_table, store) == NULL) - return; - - g_object_ref (store); - - g_hash_table_remove (store_table, store); - - folder_cache = e_mail_session_get_folder_cache (session); - mail_folder_cache_note_store_remove (folder_cache, store); - - default_model = em_folder_tree_model_get_default (); - em_folder_tree_model_remove_store (default_model, store); - - mail_disconnect_store (store); - - g_object_unref (store); -} - -void -e_mail_store_remove_by_account (EMailSession *session, - EAccount *account) -{ - CamelService *service; - CamelProvider *provider; - const gchar *uid; - - g_return_if_fail (E_IS_MAIL_SESSION (session)); - g_return_if_fail (E_IS_ACCOUNT (account)); - - uid = account->uid; - - service = camel_session_get_service (CAMEL_SESSION (session), uid); - g_return_if_fail (CAMEL_IS_STORE (service)); - - provider = camel_service_get_provider (service); - g_return_if_fail (provider != NULL); - - if (!(provider->flags & CAMEL_PROVIDER_IS_STORAGE) || store_table == NULL) - return; - - e_mail_store_remove (session, CAMEL_STORE (service)); -} - -void -e_mail_store_foreach (EMailSession *session, - GFunc func, - gpointer user_data) -{ - GList *list, *link; - - /* XXX This is a silly convenience function. - * Could probably just get rid of it. */ - - g_return_if_fail (E_IS_MAIL_SESSION (session)); - g_return_if_fail (func != NULL); - - list = camel_session_list_services (CAMEL_SESSION (session)); - - for (link = list; link != NULL; link = g_list_next (link)) { - CamelService *service = CAMEL_SERVICE (link->data); - - if (CAMEL_IS_STORE (service)) - func (service, user_data); - } - - g_list_free (list); -} diff --git a/mail/e-mail-store.h b/mail/e-mail-store.h deleted file mode 100644 index 5dca416e09..0000000000 --- a/mail/e-mail-store.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * e-mail-store.h - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) version 3. - * - * 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 - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with the program; if not, see <http://www.gnu.org/licenses/> - * - * - * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com) - * - */ - -#ifndef E_MAIL_STORE_H -#define E_MAIL_STORE_H - -#include <camel/camel.h> -#include <mail/e-mail-session.h> -#include <libedataserver/e-account.h> - -G_BEGIN_DECLS - -void e_mail_store_init (EMailSession *session, - const gchar *data_dir); -void e_mail_store_add (EMailSession *session, - CamelStore *store); -CamelStore * e_mail_store_add_by_account (EMailSession *session, - EAccount *account); -void e_mail_store_remove (EMailSession *session, - CamelStore *store); -void e_mail_store_remove_by_account (EMailSession *session, - EAccount *account); -void e_mail_store_foreach (EMailSession *session, - GFunc func, - gpointer user_data); - -G_END_DECLS - -#endif /* E_MAIL_STORE_H */ diff --git a/mail/e-mail.h b/mail/e-mail.h index 7c40b20947..02c169cd10 100644 --- a/mail/e-mail.h +++ b/mail/e-mail.h @@ -32,7 +32,6 @@ #include <mail/e-mail-label-list-store.h> #include <mail/e-mail-label-manager.h> #include <mail/e-mail-label-tree-view.h> -#include <mail/e-mail-local.h> #include <mail/e-mail-message-pane.h> #include <mail/e-mail-migrate.h> #include <mail/e-mail-notebook-view.h> @@ -42,7 +41,6 @@ #include <mail/e-mail-session.h> #include <mail/e-mail-session-utils.h> #include <mail/e-mail-sidebar.h> -#include <mail/e-mail-store.h> #include <mail/e-mail-store-utils.h> #include <mail/e-mail-tag-editor.h> #include <mail/e-mail-view.h> diff --git a/mail/em-account-editor.c b/mail/em-account-editor.c index 6bd96ef299..7b84112a34 100644 --- a/mail/em-account-editor.c +++ b/mail/em-account-editor.c @@ -60,8 +60,6 @@ #include "e-mail-backend.h" #include "e-mail-folder-utils.h" #include "e-mail-junk-options.h" -#include "e-mail-local.h" -#include "e-mail-store.h" #include "em-config.h" #include "em-folder-selection-button.h" #include "em-account-editor.h" @@ -301,26 +299,10 @@ emae_set_original_account (EMAccountEditor *emae, modified_account = e_account_new (); modified_account->enabled = TRUE; emae->priv->new_account = TRUE; - - e_account_set_string ( - modified_account, E_ACCOUNT_DRAFTS_FOLDER_URI, - e_mail_local_get_folder_uri (E_MAIL_LOCAL_FOLDER_DRAFTS)); - - e_account_set_string ( - modified_account, E_ACCOUNT_SENT_FOLDER_URI, - e_mail_local_get_folder_uri (E_MAIL_LOCAL_FOLDER_SENT)); - - /* encrypt to self by default */ - e_account_set_bool (modified_account, E_ACCOUNT_PGP_ENCRYPT_TO_SELF, TRUE); - e_account_set_bool (modified_account, E_ACCOUNT_SMIME_ENCRYPT_TO_SELF, TRUE); } emae->priv->original_account = original_account; emae->priv->modified_account = modified_account; - - g_signal_connect_swapped ( - emae->priv->modified_account, "changed", - G_CALLBACK (emae_config_target_changed_cb), emae); } static void @@ -909,6 +891,52 @@ emae_finalize (GObject *object) } static void +emae_constructed (GObject *object) +{ + EMAccountEditor *emae; + + emae = EM_ACCOUNT_EDITOR (object); + + /* Chain up to parent's constructed() method. */ + G_OBJECT_CLASS (em_account_editor_parent_class)->constructed (object); + + /* Set some defaults on the new account before we get started. */ + if (emae->priv->new_account) { + EMailBackend *backend; + EMailSession *session; + + backend = em_account_editor_get_backend (emae); + session = e_mail_backend_get_session (backend); + + /* Pick local Drafts folder. */ + e_account_set_string ( + emae->priv->modified_account, + E_ACCOUNT_DRAFTS_FOLDER_URI, + e_mail_session_get_local_folder_uri ( + session, E_MAIL_LOCAL_FOLDER_DRAFTS)); + + /* Pick local Sent folder. */ + e_account_set_string ( + emae->priv->modified_account, + E_ACCOUNT_SENT_FOLDER_URI, + e_mail_session_get_local_folder_uri ( + session, E_MAIL_LOCAL_FOLDER_SENT)); + + /* Encrypt to self by default. */ + e_account_set_bool ( + emae->priv->modified_account, + E_ACCOUNT_PGP_ENCRYPT_TO_SELF, TRUE); + e_account_set_bool ( + emae->priv->modified_account, + E_ACCOUNT_SMIME_ENCRYPT_TO_SELF, TRUE); + } + + g_signal_connect_swapped ( + emae->priv->modified_account, "changed", + G_CALLBACK (emae_config_target_changed_cb), emae); +} + +static void em_account_editor_class_init (EMAccountEditorClass *class) { GObjectClass *object_class; @@ -920,6 +948,7 @@ em_account_editor_class_init (EMAccountEditorClass *class) object_class->get_property = emae_get_property; object_class->dispose = emae_dispose; object_class->finalize = emae_finalize; + object_class->constructed = emae_constructed; g_object_class_install_property ( object_class, @@ -1295,15 +1324,29 @@ default_folders_clicked (GtkButton *button, gpointer user_data) { EMAccountEditor *emae = user_data; - const gchar *uri; + EMFolderSelectionButton *folder_button; + EMailBackend *backend; + EMailSession *session; + const gchar *folder_uri; - uri = e_mail_local_get_folder_uri (E_MAIL_LOCAL_FOLDER_DRAFTS); - em_folder_selection_button_set_folder_uri ((EMFolderSelectionButton *) emae->priv->drafts_folder_button, uri); - emae_account_folder_changed ((EMFolderSelectionButton *) emae->priv->drafts_folder_button, emae); + backend = em_account_editor_get_backend (emae); + session = e_mail_backend_get_session (backend); - uri = e_mail_local_get_folder_uri (E_MAIL_LOCAL_FOLDER_SENT); - em_folder_selection_button_set_folder_uri ((EMFolderSelectionButton *) emae->priv->sent_folder_button, uri); - emae_account_folder_changed ((EMFolderSelectionButton *) emae->priv->sent_folder_button, emae); + folder_button = + EM_FOLDER_SELECTION_BUTTON ( + emae->priv->drafts_folder_button); + folder_uri = e_mail_session_get_local_folder_uri ( + session, E_MAIL_LOCAL_FOLDER_DRAFTS); + em_folder_selection_button_set_folder_uri (folder_button, folder_uri); + emae_account_folder_changed (folder_button, emae); + + folder_button = + EM_FOLDER_SELECTION_BUTTON ( + emae->priv->sent_folder_button); + folder_uri = e_mail_session_get_local_folder_uri ( + session, E_MAIL_LOCAL_FOLDER_SENT); + em_folder_selection_button_set_folder_uri (folder_button, folder_uri); + emae_account_folder_changed (folder_button, emae); gtk_toggle_button_set_active (emae->priv->trash_folder_check, FALSE); gtk_toggle_button_set_active (emae->priv->junk_folder_check, FALSE); @@ -1805,10 +1848,12 @@ emae_account_folder (EMAccountEditor *emae, EAccount *account; EMFolderSelectionButton *folder; EMailBackend *backend; + EMailSession *session; const gchar *uri; account = em_account_editor_get_modified_account (emae); backend = em_account_editor_get_backend (emae); + session = e_mail_backend_get_session (backend); folder = (EMFolderSelectionButton *) e_builder_get_widget (builder, name); em_folder_selection_button_set_backend (folder, backend); @@ -1817,7 +1862,7 @@ emae_account_folder (EMAccountEditor *emae, if (uri != NULL) { em_folder_selection_button_set_folder_uri (folder, uri); } else { - uri = e_mail_local_get_folder_uri (deffolder); + uri = e_mail_session_get_local_folder_uri (session, deffolder); em_folder_selection_button_set_folder_uri (folder, uri); } @@ -5136,7 +5181,6 @@ emae_commit (EConfig *ec, camel_url_free (url); if (original_account != NULL) { - d (printf ("Committing account '%s'\n", e_account_get_string (modified_account, E_ACCOUNT_NAME))); forget_password_if_needed (original_account, modified_account, E_ACCOUNT_SOURCE_SAVE_PASSWD, E_ACCOUNT_SOURCE_URL); forget_password_if_needed (original_account, modified_account, E_ACCOUNT_TRANSPORT_SAVE_PASSWD, E_ACCOUNT_TRANSPORT_URL); @@ -5144,30 +5188,25 @@ emae_commit (EConfig *ec, account = original_account; e_account_list_change (accounts, account); } else { - CamelProvider *provider; - - d (printf ("Adding new account '%s'\n", e_account_get_string (modified_account, E_ACCOUNT_NAME))); e_account_list_add (accounts, modified_account); account = modified_account; + } - provider = emae_get_store_provider (emae); + if (gtk_toggle_button_get_active (emae->priv->default_account)) { + EMailBackend *backend; + EMailSession *session; + EMailAccountStore *store; + CamelService *service; - /* 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 - && provider != NULL - && (provider->flags & CAMEL_PROVIDER_IS_STORAGE)) { - EMailBackend *backend; - EMailSession *session; - - backend = em_account_editor_get_backend (emae); - session = e_mail_backend_get_session (backend); - e_mail_store_add_by_account (session, account); - } - } + backend = em_account_editor_get_backend (emae); + session = e_mail_backend_get_session (backend); - if (gtk_toggle_button_get_active (emae->priv->default_account)) - e_account_list_set_default (accounts, account); + service = camel_session_get_service ( + CAMEL_SESSION (session), account->uid); + + store = e_mail_session_get_account_store (session); + e_mail_account_store_set_default_service (store, service); + } e_account_list_save (accounts); } diff --git a/mail/em-composer-utils.c b/mail/em-composer-utils.c index 0eceeea228..f6a938bdac 100644 --- a/mail/em-composer-utils.c +++ b/mail/em-composer-utils.c @@ -45,7 +45,6 @@ #include "shell/e-shell.h" #include "e-mail-folder-utils.h" -#include "e-mail-local.h" #include "e-mail-session.h" #include "e-mail-session-utils.h" #include "em-utils.h" @@ -74,6 +73,7 @@ typedef struct _ForwardData ForwardData; struct _AsyncContext { CamelMimeMessage *message; + EMailSession *session; EMsgComposer *composer; EActivity *activity; EMailReader *reader; @@ -98,6 +98,9 @@ async_context_free (AsyncContext *context) if (context->message != NULL) g_object_unref (context->message); + if (context->session != NULL) + g_object_unref (context->session); + if (context->composer != NULL) g_object_unref (context->composer); @@ -206,7 +209,8 @@ is_group_definition (const gchar *str) } static gboolean -composer_presend_check_recipients (EMsgComposer *composer) +composer_presend_check_recipients (EMsgComposer *composer, + EMailSession *session) { EDestination **recipients; EDestination **recipients_bcc; @@ -358,7 +362,8 @@ finished: } static gboolean -composer_presend_check_account (EMsgComposer *composer) +composer_presend_check_account (EMsgComposer *composer, + EMailSession *session) { EComposerHeaderTable *table; EAccount *account; @@ -377,7 +382,8 @@ composer_presend_check_account (EMsgComposer *composer) } static gboolean -composer_presend_check_downloads (EMsgComposer *composer) +composer_presend_check_downloads (EMsgComposer *composer, + EMailSession *session) { EAttachmentView *view; EAttachmentStore *store; @@ -396,7 +402,8 @@ composer_presend_check_downloads (EMsgComposer *composer) } static gboolean -composer_presend_check_plugins (EMsgComposer *composer) +composer_presend_check_plugins (EMsgComposer *composer, + EMailSession *session) { EMEvent *eme; EMEventTargetComposer *target; @@ -428,7 +435,8 @@ composer_presend_check_plugins (EMsgComposer *composer) } static gboolean -composer_presend_check_subject (EMsgComposer *composer) +composer_presend_check_subject (EMsgComposer *composer, + EMailSession *session) { EComposerHeaderTable *table; const gchar *subject; @@ -446,7 +454,8 @@ composer_presend_check_subject (EMsgComposer *composer) } static gboolean -composer_presend_check_unwanted_html (EMsgComposer *composer) +composer_presend_check_unwanted_html (EMsgComposer *composer, + EMailSession *session) { EDestination **recipients; EComposerHeaderTable *table; @@ -556,10 +565,10 @@ exit: static void em_utils_composer_send_cb (EMsgComposer *composer, CamelMimeMessage *message, - EActivity *activity) + EActivity *activity, + EMailSession *session) { AsyncContext *context; - CamelSession *session; GCancellable *cancellable; context = g_slice_new0 (AsyncContext); @@ -568,10 +577,9 @@ em_utils_composer_send_cb (EMsgComposer *composer, context->activity = g_object_ref (activity); cancellable = e_activity_get_cancellable (activity); - session = e_msg_composer_get_session (context->composer); e_mail_session_send_to ( - E_MAIL_SESSION (session), message, + session, message, G_PRIORITY_DEFAULT, cancellable, NULL, NULL, (GAsyncReadyCallback) composer_send_completed, context); @@ -593,6 +601,7 @@ composer_set_no_change (EMsgComposer *composer) /* delete original messages from Outbox folder */ static void manage_x_evolution_replace_outbox (EMsgComposer *composer, + EMailSession *session, CamelMimeMessage *message, GCancellable *cancellable) { @@ -610,7 +619,8 @@ manage_x_evolution_replace_outbox (EMsgComposer *composer, if (!message_uid) return; - outbox = e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_OUTBOX); + outbox = e_mail_session_get_local_folder ( + session, E_MAIL_LOCAL_FOLDER_OUTBOX); g_return_if_fail (outbox != NULL); camel_folder_set_message_flags ( @@ -708,7 +718,8 @@ composer_save_to_drafts_append_mail (AsyncContext *context, CamelMessageInfo *info; local_drafts_folder = - e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_DRAFTS); + e_mail_session_get_local_folder ( + context->session, E_MAIL_LOCAL_FOLDER_DRAFTS); if (drafts_folder == NULL) drafts_folder = g_object_ref (local_drafts_folder); @@ -778,24 +789,24 @@ composer_save_to_drafts_got_folder (EMailSession *session, static void em_utils_composer_save_to_drafts_cb (EMsgComposer *composer, CamelMimeMessage *message, - EActivity *activity) + EActivity *activity, + EMailSession *session) { AsyncContext *context; EComposerHeaderTable *table; const gchar *drafts_folder_uri = NULL; const gchar *local_drafts_folder_uri; - CamelSession *session; EAccount *account; context = g_slice_new0 (AsyncContext); context->message = g_object_ref (message); + context->session = g_object_ref (session); context->composer = g_object_ref (composer); context->activity = g_object_ref (activity); - session = e_msg_composer_get_session (composer); - local_drafts_folder_uri = - e_mail_local_get_folder_uri (E_MAIL_LOCAL_FOLDER_DRAFTS); + e_mail_session_get_local_folder_uri ( + session, E_MAIL_LOCAL_FOLDER_DRAFTS); table = e_msg_composer_get_header_table (composer); account = e_composer_header_table_get_account (table); @@ -816,9 +827,9 @@ em_utils_composer_save_to_drafts_cb (EMsgComposer *composer, context->folder_uri = g_strdup (drafts_folder_uri); e_mail_session_uri_to_folder ( - E_MAIL_SESSION (session), - drafts_folder_uri, 0, G_PRIORITY_DEFAULT, - cancellable, (GAsyncReadyCallback) + session, drafts_folder_uri, 0, + G_PRIORITY_DEFAULT, cancellable, + (GAsyncReadyCallback) composer_save_to_drafts_got_folder, context); } } @@ -851,7 +862,7 @@ composer_save_to_outbox_completed (CamelFolder *outbox_folder, /* special processing for Outbox folder */ manage_x_evolution_replace_outbox ( - context->composer, context->message, + context->composer, context->session, context->message, e_activity_get_cancellable (context->activity)); e_activity_set_state (context->activity, E_ACTIVITY_COMPLETED); @@ -869,7 +880,8 @@ exit: static void em_utils_composer_save_to_outbox_cb (EMsgComposer *composer, CamelMimeMessage *message, - EActivity *activity) + EActivity *activity, + EMailSession *session) { AsyncContext *context; CamelFolder *outbox_folder; @@ -878,11 +890,15 @@ em_utils_composer_save_to_outbox_cb (EMsgComposer *composer, context = g_slice_new0 (AsyncContext); context->message = g_object_ref (message); + context->session = g_object_ref (session); context->composer = g_object_ref (composer); context->activity = g_object_ref (activity); cancellable = e_activity_get_cancellable (activity); - outbox_folder = e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_OUTBOX); + + outbox_folder = + e_mail_session_get_local_folder ( + session, E_MAIL_LOCAL_FOLDER_OUTBOX); info = camel_message_info_new (NULL); camel_message_info_set_flags (info, CAMEL_MESSAGE_SEEN, ~0); @@ -900,7 +916,8 @@ static void em_utils_composer_print_cb (EMsgComposer *composer, GtkPrintOperationAction action, CamelMimeMessage *message, - EActivity *activity) + EActivity *activity, + EMailSession *session) { EMFormatHTMLPrint *efhp; @@ -2719,7 +2736,7 @@ em_utils_reply_to_message (EShell *shell, static void post_header_clicked_cb (EComposerPostHeader *header, - EMsgComposer *composer) + EMailSession *session) { EShell *shell; EShellBackend *shell_backend; @@ -2731,14 +2748,14 @@ post_header_clicked_cb (EComposerPostHeader *header, GList *list; /* FIXME Figure out a way to pass the mail backend in. */ - shell = e_msg_composer_get_shell (composer); + shell = e_shell_get_default (); shell_backend = e_shell_get_backend_by_name (shell, "mail"); /* FIXME Limit the folder tree to the NNTP account? */ model = em_folder_tree_model_get_default (); dialog = em_folder_selector_new ( - GTK_WINDOW (composer), + /* FIXME GTK_WINDOW (composer) */ NULL, E_MAIL_BACKEND (shell_backend), model, EM_FOLDER_SELECTOR_CAN_CREATE, _("Posting destination"), @@ -2788,13 +2805,15 @@ exit: * things the #EMsgComposer instance can't do itself. **/ void -em_configure_new_composer (EMsgComposer *composer) +em_configure_new_composer (EMsgComposer *composer, + EMailSession *session) { EComposerHeaderTable *table; EComposerHeaderType header_type; EComposerHeader *header; g_return_if_fail (E_IS_MSG_COMPOSER (composer)); + g_return_if_fail (E_IS_MAIL_SESSION (session)); header_type = E_COMPOSER_HEADER_POST_TO; table = e_msg_composer_get_header_table (composer); @@ -2802,43 +2821,43 @@ em_configure_new_composer (EMsgComposer *composer) g_signal_connect ( composer, "presend", - G_CALLBACK (composer_presend_check_recipients), NULL); + G_CALLBACK (composer_presend_check_recipients), session); g_signal_connect ( composer, "presend", - G_CALLBACK (composer_presend_check_account), NULL); + G_CALLBACK (composer_presend_check_account), session); g_signal_connect ( composer, "presend", - G_CALLBACK (composer_presend_check_downloads), NULL); + G_CALLBACK (composer_presend_check_downloads), session); g_signal_connect ( composer, "presend", - G_CALLBACK (composer_presend_check_plugins), NULL); + G_CALLBACK (composer_presend_check_plugins), session); g_signal_connect ( composer, "presend", - G_CALLBACK (composer_presend_check_subject), NULL); + G_CALLBACK (composer_presend_check_subject), session); g_signal_connect ( composer, "presend", - G_CALLBACK (composer_presend_check_unwanted_html), NULL); + G_CALLBACK (composer_presend_check_unwanted_html), session); g_signal_connect ( composer, "send", - G_CALLBACK (em_utils_composer_send_cb), NULL); + G_CALLBACK (em_utils_composer_send_cb), session); g_signal_connect ( composer, "save-to-drafts", - G_CALLBACK (em_utils_composer_save_to_drafts_cb), NULL); + G_CALLBACK (em_utils_composer_save_to_drafts_cb), session); g_signal_connect ( composer, "save-to-outbox", - G_CALLBACK (em_utils_composer_save_to_outbox_cb), NULL); + G_CALLBACK (em_utils_composer_save_to_outbox_cb), session); g_signal_connect ( composer, "print", - G_CALLBACK (em_utils_composer_print_cb), NULL); + G_CALLBACK (em_utils_composer_print_cb), session); /* Handle "Post To:" button clicks, which displays a folder tree * widget. The composer doesn't know about folder tree widgets, @@ -2849,5 +2868,5 @@ em_configure_new_composer (EMsgComposer *composer) * the folder selector dialog. See the handler function. */ g_signal_connect ( header, "clicked", - G_CALLBACK (post_header_clicked_cb), composer); + G_CALLBACK (post_header_clicked_cb), session); } diff --git a/mail/em-composer-utils.h b/mail/em-composer-utils.h index 215e6bb2bc..093001dfd0 100644 --- a/mail/em-composer-utils.h +++ b/mail/em-composer-utils.h @@ -79,7 +79,8 @@ EMsgComposer * em_utils_reply_to_message (EShell *shell, CamelInternetAddress *address); EDestination ** em_utils_camel_address_to_destination (CamelInternetAddress *iaddr); -void em_configure_new_composer (EMsgComposer *composer); +void em_configure_new_composer (EMsgComposer *composer, + EMailSession *session); G_END_DECLS diff --git a/mail/em-folder-properties.c b/mail/em-folder-properties.c index 310aa76740..9dbffba2e2 100644 --- a/mail/em-folder-properties.c +++ b/mail/em-folder-properties.c @@ -34,7 +34,6 @@ #include "e-mail-backend.h" #include "e-mail-folder-utils.h" -#include "e-mail-local.h" #include "mail-ops.h" #include "mail-mt.h" #include "mail-vfolder.h" @@ -249,25 +248,26 @@ emfp_dialog_run (AsyncContext *context) EMConfigTargetFolder *target; EShellWindow *shell_window; EShellView *shell_view; - CamelStore *local_store; CamelStore *parent_store; + CamelFolderSummary *summary; + gboolean store_is_local; gboolean hide_deleted; GSettings *settings; const gchar *name; + const gchar *uid; shell_view = context->shell_view; shell_window = e_shell_view_get_shell_window (shell_view); - local_store = e_mail_local_get_store (); parent_store = camel_folder_get_parent_store (context->folder); /* Get number of VISIBLE and DELETED messages, instead of TOTAL * messages. VISIBLE+DELETED gives the correct count that matches * the label below the Send & Receive button. */ - name = camel_folder_get_display_name (context->folder); - context->total = camel_folder_summary_get_visible_count (context->folder->summary); - context->unread = camel_folder_summary_get_unread_count (context->folder->summary); - deleted = camel_folder_summary_get_deleted_count (context->folder->summary); + summary = context->folder->summary; + context->total = camel_folder_summary_get_visible_count (summary); + context->unread = camel_folder_summary_get_unread_count (summary); + deleted = camel_folder_summary_get_deleted_count (summary); settings = g_settings_new ("org.gnome.evolution.mail"); hide_deleted = !g_settings_get_boolean (settings, "show-deleted"); @@ -290,7 +290,12 @@ emfp_dialog_run (AsyncContext *context) context->total = camel_folder_summary_count ( context->folder->summary); - if (parent_store == local_store + name = camel_folder_get_display_name (context->folder); + + uid = camel_service_get_uid (CAMEL_SERVICE (parent_store)); + store_is_local = (g_strcmp0 (uid, E_MAIL_SESSION_LOCAL_UID) == 0); + + if (store_is_local && (!strcmp (name, "Drafts") || !strcmp (name, "Templates") || !strcmp (name, "Inbox") @@ -474,7 +479,7 @@ em_folder_properties_show (EShellView *shell_view, /* Show the Edit Rule dialog for Search Folders, but not "Unmatched". * "Unmatched" is a special Search Folder which can't be modified. */ - if (g_strcmp0 (uid, "vfolder") == 0) { + if (g_strcmp0 (uid, E_MAIL_SESSION_VFOLDER_UID) == 0) { if (g_strcmp0 (folder_name, CAMEL_UNMATCHED_NAME) != 0) { gchar *folder_uri; diff --git a/mail/em-folder-selection-button.c b/mail/em-folder-selection-button.c index 1b8ef6cd71..1532e42364 100644 --- a/mail/em-folder-selection-button.c +++ b/mail/em-folder-selection-button.c @@ -258,6 +258,7 @@ folder_selection_button_clicked (GtkButton *button) EMFolderSelector *selector; EMFolderTree *folder_tree; EMFolderTreeModel *model = NULL; + EMailSession *session; GtkWidget *dialog; GtkTreeSelection *selection; gpointer parent; @@ -267,9 +268,11 @@ folder_selection_button_clicked (GtkButton *button) parent = gtk_widget_get_toplevel (GTK_WIDGET (button)); parent = gtk_widget_is_toplevel (parent) ? parent : NULL; + session = e_mail_backend_get_session (priv->backend); + if (priv->store != NULL) { model = em_folder_tree_model_new (); - em_folder_tree_model_set_backend (model, priv->backend); + em_folder_tree_model_set_session (model, session); em_folder_tree_model_add_store (model, priv->store); } diff --git a/mail/em-folder-tree-model.c b/mail/em-folder-tree-model.c index 27fa44aea4..dea9daa7ff 100644 --- a/mail/em-folder-tree-model.c +++ b/mail/em-folder-tree-model.c @@ -51,8 +51,6 @@ #include "em-event.h" #include "e-mail-folder-utils.h" -#include "e-mail-local.h" -#include "e-mail-store.h" #include "shell/e-shell.h" #define EM_FOLDER_TREE_MODEL_GET_PRIVATE(obj) \ @@ -67,24 +65,20 @@ struct _EMFolderTreeModelPrivate { * mimic the sidebar. */ GtkTreeSelection *selection; /* weak reference */ - EAccountList *accounts; - EMailBackend *backend; + EMailSession *session; + EMailAccountStore *account_store; /* CamelStore -> EMFolderTreeStoreInfo */ GHashTable *store_index; /* URI -> GtkTreeRowReference */ GHashTable *uri_index; - - gulong account_changed_id; - gulong account_removed_id; - gulong account_added_id; }; enum { PROP_0, PROP_SELECTION, - PROP_BACKEND + PROP_SESSION }; enum { @@ -123,111 +117,66 @@ folder_tree_model_sort (GtkTreeModel *model, gpointer unused) { EMFolderTreeModel *folder_tree_model; - EMailBackend *backend; gchar *aname, *bname; - CamelStore *store; - gboolean is_store; + CamelService *service_a; + CamelService *service_b; + gboolean a_is_store; + gboolean b_is_store; const gchar *store_uid = NULL; - guint32 aflags, bflags; - guint asortorder, bsortorder; + guint32 flags_a, flags_b; gint rv = -2; folder_tree_model = EM_FOLDER_TREE_MODEL (model); - backend = em_folder_tree_model_get_backend (folder_tree_model); - g_return_val_if_fail (backend != NULL, -1); gtk_tree_model_get ( model, a, - COL_BOOL_IS_STORE, &is_store, - COL_POINTER_CAMEL_STORE, &store, + COL_BOOL_IS_STORE, &a_is_store, + COL_POINTER_CAMEL_STORE, &service_a, COL_STRING_DISPLAY_NAME, &aname, - COL_UINT_FLAGS, &aflags, - COL_UINT_SORTORDER, &asortorder, + COL_UINT_FLAGS, &flags_a, -1); gtk_tree_model_get ( model, b, + COL_BOOL_IS_STORE, &b_is_store, + COL_POINTER_CAMEL_STORE, &service_b, COL_STRING_DISPLAY_NAME, &bname, - COL_UINT_FLAGS, &bflags, - COL_UINT_SORTORDER, &bsortorder, + COL_UINT_FLAGS, &flags_b, -1); - if (CAMEL_IS_SERVICE (store)) - store_uid = camel_service_get_uid (CAMEL_SERVICE (store)); + if (CAMEL_IS_SERVICE (service_a)) + store_uid = camel_service_get_uid (service_a); - if (is_store) { - EShell *shell; - EShellBackend *shell_backend; - EShellSettings *shell_settings; - - shell_backend = E_SHELL_BACKEND (backend); - shell = e_shell_backend_get_shell (shell_backend); - shell_settings = e_shell_get_shell_settings (shell); - - if (e_shell_settings_get_boolean ( - shell_settings, "mail-sort-accounts-alpha")) { - const gchar *on_this_computer = _("On This Computer"); - const gchar *search_folders = _("Search Folders"); - - /* On This Computer is always first, and Search Folders - * is always last. */ - if (e_shell_get_express_mode (shell)) { - if (g_str_equal (aname, on_this_computer) && - g_str_equal (bname, search_folders)) - rv = -1; - else if (g_str_equal (bname, on_this_computer) && - g_str_equal (aname, search_folders)) - rv = 1; - else if (g_str_equal (aname, on_this_computer)) - rv = 1; - else if (g_str_equal (bname, on_this_computer)) - rv = -1; - else if (g_str_equal (aname, search_folders)) - rv = 1; - else if (g_str_equal (bname, search_folders)) - rv = -1; - } else { - if (g_str_equal (aname, on_this_computer)) - rv = -1; - else if (g_str_equal (bname, on_this_computer)) - rv = 1; - else if (g_str_equal (aname, search_folders)) - rv = 1; - else if (g_str_equal (bname, search_folders)) - rv = -1; - } - } else if (asortorder || bsortorder) { - if (asortorder < bsortorder) - rv = -1; - else if (asortorder > bsortorder) - rv = 1; - else - rv = 0; - } - } else if (g_strcmp0 (store_uid, "vfolder") == 0) { + if (a_is_store && b_is_store) { + rv = e_mail_account_store_compare_services ( + folder_tree_model->priv->account_store, + service_a, service_b); + + } else if (g_strcmp0 (store_uid, E_MAIL_SESSION_VFOLDER_UID) == 0) { /* UNMATCHED is always last. */ if (aname && !strcmp (aname, _("UNMATCHED"))) rv = 1; else if (bname && !strcmp (bname, _("UNMATCHED"))) rv = -1; + } else { /* Inbox is always first. */ - if ((aflags & CAMEL_FOLDER_TYPE_MASK) == CAMEL_FOLDER_TYPE_INBOX) + if ((flags_a & CAMEL_FOLDER_TYPE_MASK) == CAMEL_FOLDER_TYPE_INBOX) rv = -1; - else if ((bflags & CAMEL_FOLDER_TYPE_MASK) == CAMEL_FOLDER_TYPE_INBOX) + else if ((flags_b & CAMEL_FOLDER_TYPE_MASK) == CAMEL_FOLDER_TYPE_INBOX) rv = 1; } - if (aname == NULL) { - if (bname == NULL) + if (rv == -2) { + if (aname != NULL && bname != NULL) + rv = g_utf8_collate (aname, bname); + else if (aname == bname) rv = 0; - else + else if (aname == NULL) rv = -1; - } else if (bname == NULL) - rv = 1; - - if (rv == -2) - rv = g_utf8_collate (aname, bname); + else + rv = 1; + } g_free (aname); g_free (bname); @@ -236,175 +185,44 @@ folder_tree_model_sort (GtkTreeModel *model, } static void -account_changed_cb (EAccountList *accounts, - EAccount *account, - EMFolderTreeModel *model) +folder_tree_model_service_removed (EMailAccountStore *account_store, + CamelService *service, + EMFolderTreeModel *folder_tree_model) { - EMailBackend *backend; - EMailSession *session; - CamelService *service; - - backend = em_folder_tree_model_get_backend (model); - session = e_mail_backend_get_session (backend); - - service = camel_session_get_service ( - CAMEL_SESSION (session), account->uid); - - if (!CAMEL_IS_STORE (service)) - return; - - em_folder_tree_model_remove_store (model, CAMEL_STORE (service)); - - /* check if store needs to be added at all*/ - if (!account->enabled) - return; - - em_folder_tree_model_add_store (model, CAMEL_STORE (service)); + em_folder_tree_model_remove_store ( + folder_tree_model, CAMEL_STORE (service)); } static void -account_removed_cb (EAccountList *accounts, - EAccount *account, - EMFolderTreeModel *model) +folder_tree_model_service_enabled (EMailAccountStore *account_store, + CamelService *service, + EMFolderTreeModel *folder_tree_model) { - EMailBackend *backend; - EMailSession *session; - CamelService *service; - - backend = em_folder_tree_model_get_backend (model); - session = e_mail_backend_get_session (backend); - - service = camel_session_get_service ( - CAMEL_SESSION (session), account->uid); - - if (!CAMEL_IS_STORE (service)) - return; - - em_folder_tree_model_remove_store (model, CAMEL_STORE (service)); + em_folder_tree_model_add_store ( + folder_tree_model, CAMEL_STORE (service)); } -/* HACK: FIXME: the component should listen to the account object directly */ static void -account_added_cb (EAccountList *accounts, - EAccount *account, - EMFolderTreeModel *model) +folder_tree_model_service_disabled (EMailAccountStore *account_store, + CamelService *service, + EMFolderTreeModel *folder_tree_model) { - EMailBackend *backend; - EMailSession *session; - - backend = em_folder_tree_model_get_backend (model); - session = e_mail_backend_get_session (backend); - - e_mail_store_add_by_account (session, account); + em_folder_tree_model_remove_store ( + folder_tree_model, CAMEL_STORE (service)); } static void -folder_tree_model_sort_changed (EMFolderTreeModel *tree_model) +folder_tree_model_services_reordered (EMailAccountStore *account_store, + gboolean default_restored, + EMFolderTreeModel *folder_tree_model) { - GtkTreeModel *model; - - g_return_if_fail (tree_model != NULL); - g_return_if_fail (EM_IS_FOLDER_TREE_MODEL (tree_model)); - - model = GTK_TREE_MODEL (tree_model); - if (!model) - return; - - /* this invokes also sort on a GtkTreeStore */ + /* This forces the tree store to re-sort. */ gtk_tree_sortable_set_default_sort_func ( - GTK_TREE_SORTABLE (model), + GTK_TREE_SORTABLE (folder_tree_model), folder_tree_model_sort, NULL, NULL); } static void -account_sort_order_changed_cb (EMFolderTreeModel *folder_tree_model) -{ - EMailBackend *mail_backend; - GtkTreeModel *model; - GtkTreeStore *tree_store; - GtkTreeIter iter; - - g_return_if_fail (folder_tree_model != NULL); - - model = GTK_TREE_MODEL (folder_tree_model); - g_return_if_fail (model != NULL); - - tree_store = GTK_TREE_STORE (folder_tree_model); - g_return_if_fail (tree_store != NULL); - - if (!gtk_tree_model_get_iter_first (model, &iter)) - return; - - mail_backend = em_folder_tree_model_get_backend (folder_tree_model); - - do { - CamelStore *store = NULL; - - gtk_tree_model_get (model, &iter, COL_POINTER_CAMEL_STORE, &store, -1); - - if (store) { - const gchar *account_uid; - guint sortorder; - - account_uid = camel_service_get_uid (CAMEL_SERVICE (store)); - sortorder = em_utils_get_account_sort_order (mail_backend, account_uid); - - gtk_tree_store_set (tree_store, &iter, COL_UINT_SORTORDER, sortorder, -1); - } - } while (gtk_tree_model_iter_next (model, &iter)); - - folder_tree_model_sort_changed (folder_tree_model); -} - -static void -add_remove_special_folder (EMFolderTreeModel *model, - const gchar *account_uid, - gboolean add) -{ - EMailBackend *backend; - EMailSession *session; - CamelService *service; - - backend = em_folder_tree_model_get_backend (model); - session = e_mail_backend_get_session (backend); - - service = camel_session_get_service ( - CAMEL_SESSION (session), account_uid); - - if (!CAMEL_IS_STORE (service)) - return; - - if (add) - em_folder_tree_model_add_store (model, CAMEL_STORE (service)); - else - em_folder_tree_model_remove_store (model, CAMEL_STORE (service)); -} - -static void -enable_local_folders_changed_cb (EMFolderTreeModel *model, - GParamSpec *spec, - EShellSettings *shell_settings) -{ - g_return_if_fail (model != NULL); - g_return_if_fail (shell_settings != NULL); - - add_remove_special_folder (model, "local", - e_shell_settings_get_boolean (shell_settings, "mail-enable-local-folders")); -} - -static void -enable_search_folders_changed_cb (EMFolderTreeModel *model, - GParamSpec *spec, - EShellSettings *shell_settings) -{ - g_return_if_fail (model != NULL); - g_return_if_fail (shell_settings != NULL); - - add_remove_special_folder (model, "vfolder", - e_shell_settings_get_boolean (shell_settings, "mail-enable-search-folders")); -} - -static void folder_tree_model_selection_finalized_cb (EMFolderTreeModel *model) { model->priv->selection = NULL; @@ -425,8 +243,8 @@ folder_tree_model_set_property (GObject *object, g_value_get_object (value)); return; - case PROP_BACKEND: - em_folder_tree_model_set_backend ( + case PROP_SESSION: + em_folder_tree_model_set_session ( EM_FOLDER_TREE_MODEL (object), g_value_get_object (value)); return; @@ -449,10 +267,10 @@ folder_tree_model_get_property (GObject *object, EM_FOLDER_TREE_MODEL (object))); return; - case PROP_BACKEND: + case PROP_SESSION: g_value_set_object ( value, - em_folder_tree_model_get_backend ( + em_folder_tree_model_get_session ( EM_FOLDER_TREE_MODEL (object))); return; } @@ -474,26 +292,17 @@ folder_tree_model_dispose (GObject *object) priv->selection = NULL; } - if (priv->backend != NULL) { - EShell *shell; - EShellBackend *shell_backend; - EShellSettings *shell_settings; - - shell_backend = E_SHELL_BACKEND (priv->backend); - shell = e_shell_backend_get_shell (shell_backend); - shell_settings = e_shell_get_shell_settings (shell); - - g_signal_handlers_disconnect_by_func ( - priv->backend, account_sort_order_changed_cb, object); - g_signal_handlers_disconnect_by_func ( - shell_settings, account_sort_order_changed_cb, object); - g_signal_handlers_disconnect_by_func ( - shell_settings, enable_local_folders_changed_cb, object); - g_signal_handlers_disconnect_by_func ( - shell_settings, enable_search_folders_changed_cb, object); - - g_object_unref (priv->backend); - priv->backend = NULL; + if (priv->session != NULL) { + g_object_unref (priv->session); + priv->session = NULL; + } + + if (priv->account_store != NULL) { + g_signal_handlers_disconnect_matched ( + priv->account_store, G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, object); + g_object_unref (priv->account_store); + priv->account_store = NULL; } /* Chain up to parent's dispose() method. */ @@ -510,13 +319,6 @@ folder_tree_model_finalize (GObject *object) g_hash_table_destroy (priv->store_index); g_hash_table_destroy (priv->uri_index); - g_signal_handler_disconnect ( - priv->accounts, priv->account_changed_id); - g_signal_handler_disconnect ( - priv->accounts, priv->account_removed_id); - g_signal_handler_disconnect ( - priv->accounts, priv->account_added_id); - /* Chain up to parent's finalize() method. */ G_OBJECT_CLASS (parent_class)->finalize (object); } @@ -524,8 +326,6 @@ folder_tree_model_finalize (GObject *object) static void folder_tree_model_constructed (GObject *object) { - EMFolderTreeModelPrivate *priv; - GType col_types[] = { G_TYPE_STRING, /* display name */ G_TYPE_POINTER, /* store object */ @@ -542,8 +342,6 @@ folder_tree_model_constructed (GObject *object) G_TYPE_UINT /* user's sortorder */ }; - priv = EM_FOLDER_TREE_MODEL_GET_PRIVATE (object); - gtk_tree_store_set_column_types ( GTK_TREE_STORE (object), NUM_COLUMNS, col_types); gtk_tree_sortable_set_default_sort_func ( @@ -554,17 +352,6 @@ folder_tree_model_constructed (GObject *object) GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING); - priv->accounts = e_get_account_list (); - priv->account_changed_id = g_signal_connect ( - priv->accounts, "account-changed", - G_CALLBACK (account_changed_cb), object); - priv->account_removed_id = g_signal_connect ( - priv->accounts, "account-removed", - G_CALLBACK (account_removed_cb), object); - priv->account_added_id = g_signal_connect ( - priv->accounts, "account-added", - G_CALLBACK (account_added_cb), object); - /* Chain up to parent's constructed() method. */ G_OBJECT_CLASS (parent_class)->constructed (object); } @@ -586,12 +373,12 @@ em_folder_tree_model_class_init (EMFolderTreeModelClass *class) g_object_class_install_property ( object_class, - PROP_BACKEND, + PROP_SESSION, g_param_spec_object ( - "backend", + "session", NULL, NULL, - E_TYPE_MAIL_BACKEND, + E_TYPE_MAIL_SESSION, G_PARAM_READWRITE)); g_object_class_install_property ( @@ -754,60 +541,63 @@ em_folder_tree_model_set_selection (EMFolderTreeModel *model, g_object_notify (G_OBJECT (model), "selection"); } -EMailBackend * -em_folder_tree_model_get_backend (EMFolderTreeModel *model) +EMailSession * +em_folder_tree_model_get_session (EMFolderTreeModel *model) { g_return_val_if_fail (EM_IS_FOLDER_TREE_MODEL (model), NULL); - return model->priv->backend; + return model->priv->session; } void -em_folder_tree_model_set_backend (EMFolderTreeModel *model, - EMailBackend *backend) +em_folder_tree_model_set_session (EMFolderTreeModel *model, + EMailSession *session) { g_return_if_fail (EM_IS_FOLDER_TREE_MODEL (model)); - if (backend != NULL) { - g_return_if_fail (E_IS_MAIL_BACKEND (backend)); - g_object_ref (backend); + if (session != NULL) { + g_return_if_fail (E_IS_MAIL_SESSION (session)); + g_object_ref (session); } - if (model->priv->backend != NULL) - g_object_unref (model->priv->backend); + if (model->priv->session != NULL) + g_object_unref (model->priv->session); - model->priv->backend = backend; + model->priv->session = session; /* FIXME Technically we should be disconnecting this signal - * when replacing an old backend with a new backend, + * when replacing an old session with a new session, * but at present this function is only called once. */ - if (backend != NULL) { + if (session != NULL) { + EMailAccountStore *account_store; MailFolderCache *folder_cache; - EMailSession *session; - EShell *shell; - EShellBackend *shell_backend; - EShellSettings *shell_settings; - - shell_backend = E_SHELL_BACKEND (backend); - shell = e_shell_backend_get_shell (shell_backend); - shell_settings = e_shell_get_shell_settings (shell); - session = e_mail_backend_get_session (backend); folder_cache = e_mail_session_get_folder_cache (session); + account_store = e_mail_session_get_account_store (session); - g_signal_connect_swapped ( - backend, "account-sort-order-changed", - G_CALLBACK (account_sort_order_changed_cb), model); + /* Keep our own reference since we connect to its signals. */ + g_warn_if_fail (model->priv->account_store == NULL); + model->priv->account_store = g_object_ref (account_store); - g_signal_connect_swapped ( - shell_settings, "notify::mail-sort-accounts-alpha", - G_CALLBACK (account_sort_order_changed_cb), model); - g_signal_connect_swapped ( - shell_settings, "notify::mail-enable-local-folders", - G_CALLBACK (enable_local_folders_changed_cb), model); - g_signal_connect_swapped ( - shell_settings, "notify::mail-enable-search-folders", - G_CALLBACK (enable_search_folders_changed_cb), model); + g_signal_connect ( + account_store, "service-removed", + G_CALLBACK (folder_tree_model_service_removed), + model); + + g_signal_connect ( + account_store, "service-enabled", + G_CALLBACK (folder_tree_model_service_enabled), + model); + + g_signal_connect ( + account_store, "service-disabled", + G_CALLBACK (folder_tree_model_service_disabled), + model); + + g_signal_connect ( + account_store, "services-reordered", + G_CALLBACK (folder_tree_model_services_reordered), + model); g_signal_connect_swapped ( folder_cache, "folder-unread-updated", @@ -815,7 +605,7 @@ em_folder_tree_model_set_backend (EMFolderTreeModel *model, model); } - g_object_notify (G_OBJECT (model), "backend"); + g_object_notify (G_OBJECT (model), "session"); } void @@ -828,7 +618,6 @@ em_folder_tree_model_set_folder_info (EMFolderTreeModel *model, GtkTreeRowReference *uri_row, *path_row; GtkTreeStore *tree_store; MailFolderCache *folder_cache; - EMailBackend *backend; EMailSession *session; EAccount *account; guint unread; @@ -845,6 +634,7 @@ em_folder_tree_model_set_folder_info (EMFolderTreeModel *model, gboolean folder_is_drafts = FALSE; gboolean folder_is_outbox = FALSE; gboolean folder_is_templates = FALSE; + gboolean store_is_local; gchar *uri; /* Make sure we don't already know about it. */ @@ -853,11 +643,11 @@ em_folder_tree_model_set_folder_info (EMFolderTreeModel *model, tree_store = GTK_TREE_STORE (model); - backend = em_folder_tree_model_get_backend (model); - session = e_mail_backend_get_session (backend); + session = em_folder_tree_model_get_session (model); folder_cache = e_mail_session_get_folder_cache (session); uid = camel_service_get_uid (CAMEL_SERVICE (si->store)); + store_is_local = (g_strcmp0 (uid, E_MAIL_SESSION_LOCAL_UID) == 0); account = e_get_account_by_uid (uid); if (!fully_loaded) @@ -907,7 +697,7 @@ em_folder_tree_model_set_folder_info (EMFolderTreeModel *model, flags = fi->flags; display_name = fi->display_name; - if (si->store == e_mail_local_get_store ()) { + if (store_is_local) { if (strcmp (fi->full_name, "Drafts") == 0) { folder_is_drafts = TRUE; display_name = _("Drafts"); @@ -1202,7 +992,6 @@ void em_folder_tree_model_add_store (EMFolderTreeModel *model, CamelStore *store) { - EMailBackend *mail_backend; EMFolderTreeModelStoreInfo *si; GtkTreeRowReference *reference; GtkTreeStore *tree_store; @@ -1212,7 +1001,6 @@ em_folder_tree_model_add_store (EMFolderTreeModel *model, CamelProvider *provider; CamelURL *service_url; const gchar *display_name; - const gchar *account_uid; gchar *uri; g_return_if_fail (EM_IS_FOLDER_TREE_MODEL (model)); @@ -1223,7 +1011,6 @@ em_folder_tree_model_add_store (EMFolderTreeModel *model, service = CAMEL_SERVICE (store); provider = camel_service_get_provider (service); display_name = camel_service_get_display_name (service); - account_uid = camel_service_get_uid (service); /* Ignore stores that should not be added to the tree model. */ @@ -1245,8 +1032,6 @@ em_folder_tree_model_add_store (EMFolderTreeModel *model, if (si != NULL) em_folder_tree_model_remove_store (model, store); - mail_backend = em_folder_tree_model_get_backend (model); - /* Add the store to the tree. */ gtk_tree_store_append (tree_store, &iter, NULL); gtk_tree_store_set ( @@ -1257,7 +1042,6 @@ em_folder_tree_model_add_store (EMFolderTreeModel *model, COL_BOOL_LOAD_SUBDIRS, TRUE, COL_BOOL_IS_STORE, TRUE, COL_STRING_URI, uri, - COL_UINT_SORTORDER, em_utils_get_account_sort_order (mail_backend, account_uid), -1); path = gtk_tree_model_get_path (GTK_TREE_MODEL (model), &iter); diff --git a/mail/em-folder-tree-model.h b/mail/em-folder-tree-model.h index 0ed007aa96..1bf5483367 100644 --- a/mail/em-folder-tree-model.h +++ b/mail/em-folder-tree-model.h @@ -26,7 +26,6 @@ #include <gtk/gtk.h> #include <camel/camel.h> -#include <mail/e-mail-backend.h> #include <mail/e-mail-session.h> /* Standard GObject macros */ @@ -73,7 +72,6 @@ enum { * been added to the tree */ COL_UINT_UNREAD_LAST_SEL, /* last known unread count */ COL_BOOL_IS_DRAFT, /* %TRUE for a draft folder */ - COL_UINT_SORTORDER, /* user sort-order for the node */ NUM_COLUMNS }; @@ -120,11 +118,11 @@ GtkTreeSelection * void em_folder_tree_model_set_selection (EMFolderTreeModel *model, GtkTreeSelection *selection); -EMailBackend * em_folder_tree_model_get_backend +EMailSession * em_folder_tree_model_get_session (EMFolderTreeModel *model); -void em_folder_tree_model_set_backend +void em_folder_tree_model_set_session (EMFolderTreeModel *model, - EMailBackend *backend); + EMailSession *session); void em_folder_tree_model_set_folder_info (EMFolderTreeModel *model, GtkTreeIter *iter, diff --git a/mail/em-folder-tree.c b/mail/em-folder-tree.c index 48cf6af40d..5ef1845304 100644 --- a/mail/em-folder-tree.c +++ b/mail/em-folder-tree.c @@ -62,9 +62,7 @@ #include "em-event.h" #include "e-mail-folder-utils.h" -#include "e-mail-local.h" #include "e-mail-session.h" -#include "e-mail-store.h" #define d(x) @@ -720,15 +718,17 @@ folder_tree_render_display_name (GtkTreeViewColumn *column, GtkTreeModel *model, GtkTreeIter *iter) { + CamelService *service; PangoWeight weight; gboolean is_store, bold, subdirs_unread = FALSE; gboolean editable; guint unread; - gchar *display; gchar *name; gtk_tree_model_get ( - model, iter, COL_STRING_DISPLAY_NAME, &name, + model, iter, + COL_STRING_DISPLAY_NAME, &name, + COL_POINTER_CAMEL_STORE, &service, COL_BOOL_IS_STORE, &is_store, COL_UINT_UNREAD, &unread, -1); @@ -747,8 +747,17 @@ folder_tree_render_display_name (GtkTreeViewColumn *column, bold = !editable && (bold || subdirs_unread); weight = bold ? PANGO_WEIGHT_BOLD : PANGO_WEIGHT_NORMAL; + g_object_set (renderer, "weight", weight, NULL); + + if (is_store) { + const gchar *display_name; + + display_name = camel_service_get_display_name (service); + g_object_set (renderer, "text", display_name, NULL); + + } else if (!editable && unread > 0) { + gchar *name_and_unread; - if (!is_store && !editable && unread) { /* Translators: This is the string used for displaying the * folder names in folder trees. The first "%s" will be * replaced by the folder's name and "%u" will be replaced @@ -767,16 +776,17 @@ folder_tree_render_display_name (GtkTreeViewColumn *column, * Do not translate the "folder-display|" part. Remove it * from your translation. */ - display = g_strdup_printf ( + name_and_unread = g_strdup_printf ( C_("folder-display", "%s (%u%s)"), name, unread, subdirs_unread ? "+" : ""); - g_free (name); - } else - display = name; + g_object_set (renderer, "text", name_and_unread, NULL); + g_free (name_and_unread); - g_object_set (renderer, "text", display, "weight", weight, NULL); + } else { + g_object_set (renderer, "text", name, NULL); + } - g_free (display); + g_free (name); } static void @@ -1783,18 +1793,10 @@ em_folder_tree_new_with_model (EMailBackend *backend, EAlertSink *alert_sink, EMFolderTreeModel *model) { - EMailSession *session; - const gchar *data_dir; - g_return_val_if_fail (E_IS_MAIL_BACKEND (backend), NULL); g_return_val_if_fail (E_IS_ALERT_SINK (alert_sink), NULL); g_return_val_if_fail (EM_IS_FOLDER_TREE_MODEL (model), NULL); - session = e_mail_backend_get_session (backend); - data_dir = e_shell_backend_get_data_dir (E_SHELL_BACKEND (backend)); - - e_mail_store_init (session, data_dir); - return g_object_new ( EM_TYPE_FOLDER_TREE, "alert-sink", alert_sink, @@ -2283,7 +2285,6 @@ folder_tree_drop_target (EMFolderTree *folder_tree, EMFolderTreePrivate *p = folder_tree->priv; gchar *dst_full_name = NULL; gchar *src_full_name = NULL; - CamelStore *local; CamelStore *dst_store; CamelStore *src_store = NULL; GdkAtom atom = GDK_NONE; @@ -2292,6 +2293,7 @@ folder_tree_drop_target (EMFolderTree *folder_tree, GtkTreeIter iter; GList *targets; const gchar *uid; + gboolean src_is_local; gboolean src_is_vfolder; gboolean dst_is_vfolder; guint32 flags = 0; @@ -2314,10 +2316,8 @@ folder_tree_drop_target (EMFolderTree *folder_tree, COL_STRING_FULL_NAME, &dst_full_name, COL_UINT_FLAGS, &flags, -1); - local = e_mail_local_get_store (); - uid = camel_service_get_uid (CAMEL_SERVICE (dst_store)); - dst_is_vfolder = (g_strcmp0 (uid, "vfolder") == 0); + dst_is_vfolder = (g_strcmp0 (uid, E_MAIL_SESSION_VFOLDER_UID) == 0); targets = gdk_drag_context_list_targets (context); @@ -2392,13 +2392,17 @@ folder_tree_drop_target (EMFolderTree *folder_tree, if (src_store != NULL && src_full_name != NULL) { uid = camel_service_get_uid (CAMEL_SERVICE (src_store)); - src_is_vfolder = (g_strcmp0 (uid, "vfolder") == 0); + + src_is_local = + (g_strcmp0 (uid, E_MAIL_SESSION_LOCAL_UID) == 0); + src_is_vfolder = + (g_strcmp0 (uid, E_MAIL_SESSION_VFOLDER_UID) == 0); /* FIXME: this is a total hack, but i think all we can do at present */ /* Check for dragging from special folders which can't be moved/copied */ /* Don't allow moving any of the the special local folders. */ - if (src_store == local && is_special_local_folder (src_full_name)) { + if (src_is_local && is_special_local_folder (src_full_name)) { GdkAtom xfolder; /* force copy for special local folders */ diff --git a/mail/em-folder-utils.c b/mail/em-folder-utils.c index e72b8014ad..2ac87d7efd 100644 --- a/mail/em-folder-utils.c +++ b/mail/em-folder-utils.c @@ -59,9 +59,7 @@ #include "em-folder-properties.h" #include "e-mail-folder-utils.h" -#include "e-mail-local.h" #include "e-mail-session.h" -#include "e-mail-store.h" #include "e-mail-store-utils.h" #define d(x) @@ -339,15 +337,15 @@ emfu_copy_folder_selected (EMailBackend *backend, EMailSession *session; struct _copy_folder_data *cfd = data; CamelStore *tostore = NULL; - CamelStore *local_store; CamelService *service; + gboolean store_is_local; + const gchar *uid; gchar *tobase = NULL; GError *local_error = NULL; if (uri == NULL) goto fail; - local_store = e_mail_local_get_store (); session = e_mail_backend_get_session (backend); service = CAMEL_SERVICE (cfd->source_store); @@ -365,7 +363,10 @@ emfu_copy_folder_selected (EMailBackend *backend, g_return_if_fail (CAMEL_IS_STORE (service)); - if (cfd->delete && cfd->source_store == local_store && + uid = camel_service_get_uid (CAMEL_SERVICE (cfd->source_store)); + store_is_local = (g_strcmp0 (uid, E_MAIL_SESSION_LOCAL_UID) == 0); + + if (cfd->delete && store_is_local && emfu_is_special_local_folder (cfd->source_folder_name)) { e_mail_backend_submit_alert ( backend, "mail:no-rename-special-folder", @@ -426,7 +427,7 @@ emfu_copy_folder_exclude (EMFolderTree *tree, /* handles moving to/from vfolders */ uid = camel_service_get_uid (CAMEL_SERVICE (cfd->source_store)); - fromvfolder = (g_strcmp0 (uid, "vfolder") == 0); + fromvfolder = (g_strcmp0 (uid, E_MAIL_SESSION_VFOLDER_UID) == 0); gtk_tree_model_get ( model, iter, @@ -434,7 +435,7 @@ emfu_copy_folder_exclude (EMFolderTree *tree, COL_POINTER_CAMEL_STORE, &store, -1); uid = camel_service_get_uid (CAMEL_SERVICE (store)); - tovfolder = (g_strcmp0 (uid, "vfolder") == 0); + tovfolder = (g_strcmp0 (uid, E_MAIL_SESSION_VFOLDER_UID) == 0); /* moving from vfolder to normal- not allowed */ if (fromvfolder && !tovfolder && cfd->delete) @@ -566,9 +567,9 @@ em_folder_utils_create_folder (GtkWindow *parent, shell_settings = e_shell_get_shell_settings (shell); model = em_folder_tree_model_new (); - em_folder_tree_model_set_backend (model, backend); - session = e_mail_backend_get_session (backend); + em_folder_tree_model_set_session (model, session); + list = camel_session_list_services (CAMEL_SESSION (session)); for (link = list; link != NULL; link = g_list_next (link)) { @@ -587,9 +588,9 @@ em_folder_utils_create_folder (GtkWindow *parent, continue; uid = camel_service_get_uid (service); - if (g_strcmp0 (uid, "local") == 0) + if (g_strcmp0 (uid, E_MAIL_SESSION_LOCAL_UID) == 0) prop = "mail-enable-local-folders"; - else if (g_strcmp0 (uid, "vfolder") == 0) + else if (g_strcmp0 (uid, E_MAIL_SESSION_VFOLDER_UID) == 0) prop = "mail-enable-search-folders"; if (prop && !e_shell_settings_get_boolean (shell_settings, prop)) diff --git a/mail/em-utils.c b/mail/em-utils.c index c15f8b67b5..bfda4056be 100644 --- a/mail/em-utils.c +++ b/mail/em-utils.c @@ -71,7 +71,6 @@ #include "em-composer-utils.h" #include "em-format-quote.h" #include "e-mail-folder-utils.h" -#include "e-mail-local.h" #include "e-mail-session.h" /* XXX This is a dirty hack on a dirty hack. We really need @@ -84,8 +83,6 @@ extern const gchar *shell_builtin_backend; #define d(x) -static void free_account_sort_order_cache (void); - gboolean em_utils_ask_open_many (GtkWindow *parent, gint how_many) @@ -998,17 +995,18 @@ em_utils_folder_is_templates (CamelFolder *folder) g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); + store = camel_folder_get_parent_store (folder); + session = camel_service_get_session (CAMEL_SERVICE (store)); + local_templates_folder = - e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_TEMPLATES); + e_mail_session_get_local_folder ( + E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_TEMPLATES); if (folder == local_templates_folder) return TRUE; folder_uri = e_mail_folder_uri_from_folder (folder); - store = camel_folder_get_parent_store (folder); - session = camel_service_get_session (CAMEL_SERVICE (store)); - account_list = e_get_account_list (); iterator = e_list_get_iterator (E_LIST (account_list)); @@ -1053,17 +1051,18 @@ em_utils_folder_is_drafts (CamelFolder *folder) g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); + store = camel_folder_get_parent_store (folder); + session = camel_service_get_session (CAMEL_SERVICE (store)); + local_drafts_folder = - e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_DRAFTS); + e_mail_session_get_local_folder ( + E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_DRAFTS); if (folder == local_drafts_folder) return TRUE; folder_uri = e_mail_folder_uri_from_folder (folder); - store = camel_folder_get_parent_store (folder); - session = camel_service_get_session (CAMEL_SERVICE (store)); - account_list = e_get_account_list (); iterator = e_list_get_iterator (E_LIST (account_list)); @@ -1108,17 +1107,18 @@ em_utils_folder_is_sent (CamelFolder *folder) g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); + store = camel_folder_get_parent_store (folder); + session = camel_service_get_session (CAMEL_SERVICE (store)); + local_sent_folder = - e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_SENT); + e_mail_session_get_local_folder ( + E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_SENT); if (folder == local_sent_folder) return TRUE; folder_uri = e_mail_folder_uri_from_folder (folder); - store = camel_folder_get_parent_store (folder); - session = camel_service_get_session (CAMEL_SERVICE (store)); - account_list = e_get_account_list (); iterator = e_list_get_iterator (E_LIST (account_list)); @@ -1153,12 +1153,18 @@ em_utils_folder_is_sent (CamelFolder *folder) gboolean em_utils_folder_is_outbox (CamelFolder *folder) { + CamelStore *store; + CamelSession *session; CamelFolder *local_outbox_folder; g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE); + store = camel_folder_get_parent_store (folder); + session = camel_service_get_session (CAMEL_SERVICE (store)); + local_outbox_folder = - e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_OUTBOX); + e_mail_session_get_local_folder ( + E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_OUTBOX); return (folder == local_outbox_folder); } @@ -1911,8 +1917,6 @@ emu_free_mail_cache (void) photos_cache = NULL; G_UNLOCK (photos_cache); - - free_account_sort_order_cache (); } void @@ -2269,169 +2273,3 @@ em_utils_disconnect_service_sync (CamelService *service, return res; } -G_LOCK_DEFINE_STATIC (accounts_sort_order_cache); -static GHashTable *accounts_sort_order_cache = NULL; /* account_uid string to sort order uint */ - -static void -free_account_sort_order_cache (void) -{ - G_LOCK (accounts_sort_order_cache); - - if (accounts_sort_order_cache) { - g_hash_table_destroy (accounts_sort_order_cache); - accounts_sort_order_cache = NULL; - } - - G_UNLOCK (accounts_sort_order_cache); -} - -static void -fill_accounts_sort_order_cache (EMailBackend *backend, - gboolean force_reload) -{ - GSList *account_uids; - - G_LOCK (accounts_sort_order_cache); - - if (!force_reload && accounts_sort_order_cache) { - G_UNLOCK (accounts_sort_order_cache); - return; - } - - if (!accounts_sort_order_cache) - accounts_sort_order_cache = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); - else - g_hash_table_remove_all (accounts_sort_order_cache); - - account_uids = em_utils_load_accounts_sort_order (backend); - if (account_uids) { - GSList *iter; - guint index; - - for (index = 1, iter = account_uids; iter; index++, iter = iter->next) { - if (iter->data) - g_hash_table_insert (accounts_sort_order_cache, iter->data, GUINT_TO_POINTER (index)); - } - - /* items are stolen into the cache */ - /* g_slist_foreach (account_uids, (GFunc) g_free, NULL); */ - g_slist_free (account_uids); - } - - G_UNLOCK (accounts_sort_order_cache); -} - -static gchar * -emu_get_sort_order_filename (EMailBackend *backend) -{ - g_return_val_if_fail (backend != NULL, NULL); - - return g_build_filename ( - e_shell_backend_get_config_dir (E_SHELL_BACKEND (backend)), - "sortorder.ini", NULL); -} - -static GKeyFile * -emu_get_sort_order_key_file (EMailBackend *backend) -{ - gchar *filename; - GKeyFile *key_file; - - g_return_val_if_fail (backend != NULL, NULL); - - filename = emu_get_sort_order_filename (backend); - g_return_val_if_fail (filename != NULL, NULL); - - key_file = g_key_file_new (); - g_key_file_load_from_file (key_file, filename, G_KEY_FILE_NONE, NULL); - - g_free (filename); - - return key_file; -} - -void -em_utils_save_accounts_sort_order (EMailBackend *backend, - const GSList *account_uids) -{ - gchar *filename; - GKeyFile *key_file; - gint ii; - gchar key[32]; - gchar *content; - gsize length = 0; - - key_file = emu_get_sort_order_key_file (backend); - g_return_if_fail (key_file != NULL); - - filename = emu_get_sort_order_filename (backend); - g_return_if_fail (filename != NULL); - - g_key_file_remove_group (key_file, "accounts", NULL); - - for (ii = 0; account_uids; ii++, account_uids = account_uids->next) { - sprintf (key, "%d", ii); - - g_key_file_set_string (key_file, "accounts", key, account_uids->data); - } - - content = g_key_file_to_data (key_file, &length, NULL); - if (content) - g_file_set_contents (filename, content, length, NULL); - - g_free (content); - g_free (filename); - g_key_file_free (key_file); - - fill_accounts_sort_order_cache (backend, TRUE); - e_mail_backend_account_sort_order_changed (backend); -} - -GSList * -em_utils_load_accounts_sort_order (EMailBackend *backend) -{ - GKeyFile *key_file; - GSList *account_uids = NULL; - gchar key[32]; - gchar *value; - gint ii; - - key_file = emu_get_sort_order_key_file (backend); - g_return_val_if_fail (key_file != NULL, NULL); - - ii = 0; - do { - sprintf (key, "%d", ii); - ii++; - - value = g_key_file_get_string (key_file, "accounts", key, NULL); - if (!value) - break; - - account_uids = g_slist_prepend (account_uids, value); - } while (*key); - - g_key_file_free (key_file); - - return g_slist_reverse (account_uids); -} - -guint -em_utils_get_account_sort_order (EMailBackend *backend, - const gchar *account_uid) -{ - guint res; - - g_return_val_if_fail (backend != NULL, 0); - g_return_val_if_fail (account_uid != NULL, 0); - - fill_accounts_sort_order_cache (backend, FALSE); - - G_LOCK (accounts_sort_order_cache); - - res = GPOINTER_TO_UINT (g_hash_table_lookup (accounts_sort_order_cache, account_uid)); - - G_UNLOCK (accounts_sort_order_cache); - - return res; -} diff --git a/mail/em-utils.h b/mail/em-utils.h index b7e3ec6f49..0a27266d31 100644 --- a/mail/em-utils.h +++ b/mail/em-utils.h @@ -98,10 +98,6 @@ gboolean em_utils_is_local_delivery_mbox_file (CamelURL *url); gboolean em_utils_connect_service_sync (CamelService *service, GCancellable *cancellable, GError **error); gboolean em_utils_disconnect_service_sync (CamelService *service, gboolean clean, GCancellable *cancellable, GError **error); -void em_utils_save_accounts_sort_order (EMailBackend *backend, const GSList *account_uids); -GSList *em_utils_load_accounts_sort_order (EMailBackend *backend); -guint em_utils_get_account_sort_order (EMailBackend *backend, const gchar *account_uid); - G_END_DECLS #endif /* __EM_UTILS_H__ */ diff --git a/mail/em-vfolder-rule.c b/mail/em-vfolder-rule.c index 831059910c..3f0c2200aa 100644 --- a/mail/em-vfolder-rule.c +++ b/mail/em-vfolder-rule.c @@ -33,7 +33,6 @@ #include "em-vfolder-context.h" #include "em-vfolder-rule.h" #include "mail/e-mail-folder-utils.h" -#include "mail/e-mail-store.h" #include "mail/em-utils.h" #include "mail/em-folder-tree.h" #include "mail/em-folder-selector.h" diff --git a/mail/importers/evolution-mbox-importer.c b/mail/importers/evolution-mbox-importer.c index 3c97bd953b..b158d606a9 100644 --- a/mail/importers/evolution-mbox-importer.c +++ b/mail/importers/evolution-mbox-importer.c @@ -45,8 +45,6 @@ #include "shell/e-shell-sidebar.h" #include "mail/e-mail-backend.h" -#include "mail/e-mail-local.h" -#include "mail/e-mail-store.h" #include "mail/em-folder-selection-button.h" #include "mail/em-folder-tree-model.h" #include "mail/em-folder-tree.h" @@ -85,6 +83,8 @@ mbox_getwidget (EImport *ei, { EShell *shell; EShellBackend *shell_backend; + EMailBackend *backend; + EMailSession *session; GtkWindow *window; GtkWidget *hbox, *w; GtkLabel *label; @@ -96,6 +96,9 @@ mbox_getwidget (EImport *ei, shell = e_shell_get_default (); shell_backend = e_shell_get_backend_by_name (shell, "mail"); + backend = E_MAIL_BACKEND (shell_backend); + session = e_mail_backend_get_session (backend); + /* preselect the folder selected in a mail view */ window = e_shell_get_active_window (shell); if (E_IS_SHELL_WINDOW (window)) { @@ -129,7 +132,8 @@ mbox_getwidget (EImport *ei, if (!select_uri) { const gchar *uri; - uri = e_mail_local_get_folder_uri (E_MAIL_LOCAL_FOLDER_INBOX); + uri = e_mail_session_get_local_folder_uri ( + session, E_MAIL_LOCAL_FOLDER_INBOX); select_uri = g_strdup (uri); } diff --git a/mail/importers/mail-importer.c b/mail/importers/mail-importer.c index e28de37b3c..558359c636 100644 --- a/mail/importers/mail-importer.c +++ b/mail/importers/mail-importer.c @@ -41,7 +41,6 @@ #include "mail-mt.h" #include "mail-tools.h" -#include "e-mail-local.h" #include "e-mail-session.h" #include "mail-importer.h" @@ -124,7 +123,8 @@ import_mbox_exec (struct _import_mbox_msg *m, } if (m->uri == NULL || m->uri[0] == 0) - folder = e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_INBOX); + folder = e_mail_session_get_local_folder ( + m->session, E_MAIL_LOCAL_FOLDER_INBOX); else folder = e_mail_session_uri_to_folder_sync ( m->session, m->uri, CAMEL_STORE_FOLDER_CREATE, diff --git a/mail/mail-config.c b/mail/mail-config.c index bbad256d2f..883612b346 100644 --- a/mail/mail-config.c +++ b/mail/mail-config.c @@ -34,7 +34,6 @@ #include "e-util/e-account-utils.h" #include "e-util/e-signature-utils.h" -#include "e-mail-local.h" #include "e-mail-folder-utils.h" #include "mail-config.h" #include "mail-tools.h" diff --git a/mail/mail-folder-cache.c b/mail/mail-folder-cache.c index cab15c5e93..d9e3befa79 100644 --- a/mail/mail-folder-cache.c +++ b/mail/mail-folder-cache.c @@ -49,7 +49,6 @@ #include "em-utils.h" #include "e-mail-folder-utils.h" -#include "e-mail-local.h" #include "e-mail-session.h" #include "e-mail-store-utils.h" @@ -62,7 +61,12 @@ /* This code is a mess, there is no reason it should be so complicated. */ +typedef struct _StoreInfo StoreInfo; + struct _MailFolderCachePrivate { + gpointer session; /* weak pointer */ + EMailAccountStore *account_store; + /* source id for the ping timeout callback */ guint ping_id; /* Store to storeinfo table, active stores */ @@ -82,6 +86,11 @@ struct _MailFolderCachePrivate { }; enum { + PROP_0, + PROP_SESSION +}; + +enum { FOLDER_AVAILABLE, FOLDER_UNAVAILABLE, FOLDER_DELETED, @@ -94,7 +103,7 @@ enum { static guint signals[LAST_SIGNAL]; struct _folder_info { - struct _store_info *store_info; /* 'parent' link */ + StoreInfo *store_info; /* 'parent' link */ gchar *full_name; /* full name of folder/folderinfo */ @@ -124,14 +133,26 @@ struct _folder_update { gchar *msg_subject; /* ... and its subject. */ }; -struct _store_info { +struct _StoreInfo { GHashTable *folders; /* by full_name */ CamelStore *store; /* the store for these folders */ + gboolean first_update; /* TRUE initially, then FALSE forever */ + + /* Hold a reference to keep them alive. */ + CamelFolder *vjunk; + CamelFolder *vtrash; /* Outstanding folderinfo requests */ GQueue folderinfo_updates; }; +struct _update_data { + NoteDoneFunc done; + gpointer data; + MailFolderCache *cache; + GCancellable *cancellable; +}; + G_DEFINE_TYPE (MailFolderCache, mail_folder_cache, G_TYPE_OBJECT) static void @@ -147,6 +168,66 @@ free_update (struct _folder_update *up) g_free (up); } +static void +free_folder_info (struct _folder_info *mfi) +{ + g_free (mfi->full_name); + g_free (mfi); +} + +static StoreInfo * +store_info_new (CamelStore *store) +{ + StoreInfo *info; + GHashTable *folders; + + folders = g_hash_table_new_full ( + (GHashFunc) g_str_hash, + (GEqualFunc) g_str_equal, + (GDestroyNotify) NULL, + (GDestroyNotify) free_folder_info); + + info = g_slice_new0 (StoreInfo); + info->folders = folders; + info->store = g_object_ref (store); + info->first_update = TRUE; + + /* If these are vfolders then they need to be opened + * now, otherwise they won't keep track of all folders. */ + if (store->flags & CAMEL_STORE_VJUNK) + info->vjunk = camel_store_get_junk_folder_sync ( + store, NULL, NULL); + if (store->flags & CAMEL_STORE_VTRASH) + info->vtrash = camel_store_get_trash_folder_sync ( + store, NULL, NULL); + + g_queue_init (&info->folderinfo_updates); + + return info; +} + +static void +store_info_free (StoreInfo *info) +{ + struct _update_data *ud; + + while (!g_queue_is_empty (&info->folderinfo_updates)) { + ud = g_queue_pop_head (&info->folderinfo_updates); + g_cancellable_cancel (ud->cancellable); + } + + g_hash_table_destroy (info->folders); + g_object_unref (info->store); + + if (info->vjunk != NULL) + g_object_unref (info->vjunk); + + if (info->vtrash != NULL) + g_object_unref (info->vtrash); + + g_slice_free (StoreInfo, info); +} + static gboolean flush_updates_idle_cb (MailFolderCache *cache) { @@ -334,9 +415,10 @@ folder_changed_cb (CamelFolder *folder, CamelFolder *local_drafts; CamelFolder *local_outbox; CamelFolder *local_sent; + CamelSession *session; CamelStore *parent_store; CamelMessageInfo *info; - struct _store_info *si; + StoreInfo *si; struct _folder_info *mfi; const gchar *full_name; gint new = 0; @@ -346,6 +428,7 @@ folder_changed_cb (CamelFolder *folder, full_name = camel_folder_get_full_name (folder); parent_store = camel_folder_get_parent_store (folder); + session = camel_service_get_session (CAMEL_SERVICE (parent_store)); if (!last_newmail_per_folder) last_newmail_per_folder = g_hash_table_new (g_direct_hash, g_direct_equal); @@ -355,9 +438,12 @@ folder_changed_cb (CamelFolder *folder, g_hash_table_lookup (last_newmail_per_folder, folder)); new_latest_received = latest_received; - local_drafts = e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_DRAFTS); - local_outbox = e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_OUTBOX); - local_sent = e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_SENT); + local_drafts = e_mail_session_get_local_folder ( + E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_DRAFTS); + local_outbox = e_mail_session_get_local_folder ( + E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_OUTBOX); + local_sent = e_mail_session_get_local_folder ( + E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_SENT); if (!CAMEL_IS_VEE_FOLDER (folder) && folder != local_drafts @@ -451,16 +537,9 @@ unset_folder_info (MailFolderCache *cache, } static void -free_folder_info (struct _folder_info *mfi) -{ - g_free (mfi->full_name); - g_free (mfi); -} - -static void setup_folder (MailFolderCache *cache, CamelFolderInfo *fi, - struct _store_info *si) + StoreInfo *si) { struct _folder_info *mfi; struct _folder_update *up; @@ -493,7 +572,7 @@ setup_folder (MailFolderCache *cache, static void create_folders (MailFolderCache *cache, CamelFolderInfo *fi, - struct _store_info *si) + StoreInfo *si) { while (fi) { setup_folder (cache, fi, si); @@ -510,7 +589,7 @@ store_folder_subscribed_cb (CamelStore *store, CamelFolderInfo *info, MailFolderCache *cache) { - struct _store_info *si; + StoreInfo *si; g_mutex_lock (cache->priv->stores_mutex); si = g_hash_table_lookup (cache->priv->stores, store); @@ -543,7 +622,7 @@ store_folder_unsubscribed_cb (CamelStore *store, CamelFolderInfo *info, MailFolderCache *cache) { - struct _store_info *si; + StoreInfo *si; struct _folder_info *mfi; g_mutex_lock (cache->priv->stores_mutex); @@ -572,7 +651,7 @@ store_folder_deleted_cb (CamelStore *store, static void rename_folders (MailFolderCache *cache, - struct _store_info *si, + StoreInfo *si, const gchar *oldbase, const gchar *newbase, CamelFolderInfo *fi) @@ -678,7 +757,7 @@ store_folder_renamed_cb (CamelStore *store, CamelFolderInfo *info, MailFolderCache *cache) { - struct _store_info *si; + StoreInfo *si; g_mutex_lock (cache->priv->stores_mutex); si = g_hash_table_lookup (cache->priv->stores, store); @@ -703,13 +782,6 @@ store_folder_renamed_cb (CamelStore *store, g_mutex_unlock (cache->priv->stores_mutex); } -struct _update_data { - NoteDoneFunc done; - gpointer data; - MailFolderCache *cache; - GCancellable *cancellable; -}; - static void unset_folder_info_hash (gchar *path, struct _folder_info *mfi, @@ -720,11 +792,31 @@ unset_folder_info_hash (gchar *path, } static void -free_folder_info_hash (gchar *path, - struct _folder_info *mfi, - gpointer data) +mail_folder_cache_first_update (MailFolderCache *cache, + StoreInfo *info) { - free_folder_info (mfi); + EMailSession *session; + const gchar *uid; + + session = mail_folder_cache_get_session (cache); + uid = camel_service_get_uid (CAMEL_SERVICE (info->store)); + + if (info->vjunk != NULL) + mail_folder_cache_note_folder (cache, info->vjunk); + + if (info->vtrash != NULL) + mail_folder_cache_note_folder (cache, info->vtrash); + + /* Some extra work for the "On This Computer" store. */ + if (g_strcmp0 (uid, E_MAIL_SESSION_LOCAL_UID) == 0) { + CamelFolder *folder; + gint ii; + + for (ii = 0; ii < E_MAIL_NUM_LOCAL_FOLDERS; ii++) { + folder = e_mail_session_get_local_folder (session, ii); + mail_folder_cache_note_folder (cache, folder); + } + } } static void @@ -733,7 +825,7 @@ update_folders (CamelStore *store, struct _update_data *ud) { CamelFolderInfo *fi; - struct _store_info *si; + StoreInfo *si; GError *error = NULL; fi = camel_store_get_folder_info_finish (store, result, &error); @@ -756,6 +848,12 @@ update_folders (CamelStore *store, } g_mutex_unlock (ud->cache->priv->stores_mutex); + /* Do some extra work for the first update. */ + if (si != NULL && si->first_update) { + mail_folder_cache_first_update (ud->cache, si); + si->first_update = FALSE; + } + if (fi != NULL) { gboolean free_fi = TRUE; @@ -913,7 +1011,7 @@ struct _find_info { static void storeinfo_find_folder_info (CamelStore *store, - struct _store_info *si, + StoreInfo *si, struct _find_info *fi) { gchar *folder_name; @@ -933,34 +1031,175 @@ storeinfo_find_folder_info (CamelStore *store, } static void +mail_folder_cache_service_added (EMailAccountStore *account_store, + CamelService *service, + MailFolderCache *cache) +{ + mail_folder_cache_note_store ( + cache, CAMEL_STORE (service), NULL, NULL, NULL); +} + +static void +mail_folder_cache_service_removed (EMailAccountStore *account_store, + CamelService *service, + MailFolderCache *cache) +{ + StoreInfo *si; + + if (cache->priv->stores == NULL) + return; + + g_mutex_lock (cache->priv->stores_mutex); + + si = g_hash_table_lookup (cache->priv->stores, service); + if (si != NULL) { + g_hash_table_remove (cache->priv->stores, service); + + g_signal_handlers_disconnect_matched ( + service, G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, cache); + + g_hash_table_foreach ( + si->folders, (GHFunc) + unset_folder_info_hash, cache); + + store_info_free (si); + } + + g_mutex_unlock (cache->priv->stores_mutex); +} + +static void +mail_folder_cache_set_session (MailFolderCache *cache, + EMailSession *session) +{ + g_return_if_fail (E_IS_MAIL_SESSION (session)); + g_return_if_fail (cache->priv->session == NULL); + + cache->priv->session = session; + + g_object_add_weak_pointer ( + G_OBJECT (cache->priv->session), + &cache->priv->session); +} + +static void +mail_folder_cache_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_SESSION: + mail_folder_cache_set_session ( + MAIL_FOLDER_CACHE (object), + g_value_get_object (value)); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +mail_folder_cache_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) { + case PROP_SESSION: + g_value_set_object ( + value, + mail_folder_cache_get_session ( + MAIL_FOLDER_CACHE (object))); + return; + } + + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); +} + +static void +mail_folder_cache_dispose (GObject *object) +{ + MailFolderCachePrivate *priv; + + priv = MAIL_FOLDER_CACHE_GET_PRIVATE (object); + + if (priv->session != NULL) { + g_object_remove_weak_pointer ( + G_OBJECT (priv->session), &priv->session); + priv->session = NULL; + } + + if (priv->account_store != NULL) { + g_signal_handlers_disconnect_matched ( + priv->account_store, G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, object); + g_object_unref (priv->account_store); + priv->account_store = NULL; + } + + /* Chain up to parent's dispose() method. */ + G_OBJECT_CLASS (mail_folder_cache_parent_class)->dispose (object); +} + +static void mail_folder_cache_finalize (GObject *object) { - MailFolderCache *cache = (MailFolderCache *) object; + MailFolderCachePrivate *priv; - g_hash_table_destroy (cache->priv->stores); - g_mutex_free (cache->priv->stores_mutex); + priv = MAIL_FOLDER_CACHE_GET_PRIVATE (object); - if (cache->priv->ping_id > 0) { - g_source_remove (cache->priv->ping_id); - cache->priv->ping_id = 0; + g_hash_table_destroy (priv->stores); + g_mutex_free (priv->stores_mutex); + + if (priv->ping_id > 0) { + g_source_remove (priv->ping_id); + priv->ping_id = 0; } - if (cache->priv->update_id > 0) { - g_source_remove (cache->priv->update_id); - cache->priv->update_id = 0; + if (priv->update_id > 0) { + g_source_remove (priv->update_id); + priv->update_id = 0; } - while (!g_queue_is_empty (&cache->priv->local_folder_uris)) - g_free (g_queue_pop_head (&cache->priv->local_folder_uris)); + while (!g_queue_is_empty (&priv->local_folder_uris)) + g_free (g_queue_pop_head (&priv->local_folder_uris)); - while (!g_queue_is_empty (&cache->priv->remote_folder_uris)) - g_free (g_queue_pop_head (&cache->priv->remote_folder_uris)); + while (!g_queue_is_empty (&priv->remote_folder_uris)) + g_free (g_queue_pop_head (&priv->remote_folder_uris)); /* Chain up to parent's finalize() method. */ G_OBJECT_CLASS (mail_folder_cache_parent_class)->finalize (object); } static void +mail_folder_cache_constructed (GObject *object) +{ + MailFolderCache *cache; + EMailSession *session; + EMailAccountStore *account_store; + + cache = MAIL_FOLDER_CACHE (object); + + /* Chain up to parent's constructed() method. */ + G_OBJECT_CLASS (mail_folder_cache_parent_class)->constructed (object); + + session = mail_folder_cache_get_session (cache); + account_store = e_mail_session_get_account_store (session); + + cache->priv->account_store = g_object_ref (account_store); + + g_signal_connect ( + account_store, "service-added", + G_CALLBACK (mail_folder_cache_service_added), cache); + + g_signal_connect ( + account_store, "service-removed", + G_CALLBACK (mail_folder_cache_service_removed), cache); +} + +static void mail_folder_cache_folder_available (MailFolderCache *cache, CamelStore *store, const gchar *folder_name) @@ -1118,12 +1357,28 @@ mail_folder_cache_class_init (MailFolderCacheClass *class) g_type_class_add_private (class, sizeof (MailFolderCachePrivate)); object_class = G_OBJECT_CLASS (class); + object_class->set_property = mail_folder_cache_set_property; + object_class->get_property = mail_folder_cache_get_property; + object_class->dispose = mail_folder_cache_dispose; object_class->finalize = mail_folder_cache_finalize; + object_class->constructed = mail_folder_cache_constructed; class->folder_available = mail_folder_cache_folder_available; class->folder_unavailable = mail_folder_cache_folder_unavailable; class->folder_deleted = mail_folder_cache_folder_deleted; + g_object_class_install_property ( + object_class, + PROP_SESSION, + g_param_spec_object ( + "session", + "Session", + "Mail session", + E_TYPE_MAIL_SESSION, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + /** * MailFolderCache::folder-available * @store: the #CamelStore containing the folder @@ -1274,9 +1529,21 @@ mail_folder_cache_init (MailFolderCache *cache) } MailFolderCache * -mail_folder_cache_new (void) +mail_folder_cache_new (EMailSession *session) { - return g_object_new (MAIL_TYPE_FOLDER_CACHE, NULL); + g_return_val_if_fail (E_IS_MAIL_SESSION (session), NULL); + + return g_object_new ( + MAIL_TYPE_FOLDER_CACHE, + "session", session, NULL); +} + +EMailSession * +mail_folder_cache_get_session (MailFolderCache *cache) +{ + g_return_val_if_fail (MAIL_IS_FOLDER_CACHE (cache), NULL); + + return E_MAIL_SESSION (cache->priv->session); } /** @@ -1294,12 +1561,12 @@ mail_folder_cache_note_store (MailFolderCache *cache, gpointer data) { CamelSession *session; - struct _store_info *si; + StoreInfo *si; struct _update_data *ud; gint hook = 0; + g_return_if_fail (MAIL_IS_FOLDER_CACHE (cache)); g_return_if_fail (CAMEL_IS_STORE (store)); - g_return_if_fail (mail_in_main_thread ()); session = camel_service_get_session (CAMEL_SERVICE (store)); @@ -1307,11 +1574,8 @@ mail_folder_cache_note_store (MailFolderCache *cache, si = g_hash_table_lookup (cache->priv->stores, store); if (si == NULL) { - si = g_malloc0 (sizeof (*si)); - si->folders = g_hash_table_new (g_str_hash, g_str_equal); - si->store = g_object_ref (store); + si = store_info_new (store); g_hash_table_insert (cache->priv->stores, store, si); - g_queue_init (&si->folderinfo_updates); hook = TRUE; } @@ -1389,55 +1653,6 @@ mail_folder_cache_note_store (MailFolderCache *cache, } /** - * mail_folder_cache_note_store_remove: - * - * Notify the cache that the specified @store can be removed from the cache - */ -void -mail_folder_cache_note_store_remove (MailFolderCache *cache, - CamelStore *store) -{ - struct _store_info *si; - - g_return_if_fail (CAMEL_IS_STORE (store)); - - if (cache->priv->stores == NULL) - return; - - d(printf("store removed!!\n")); - g_mutex_lock (cache->priv->stores_mutex); - si = g_hash_table_lookup (cache->priv->stores, store); - if (si) { - GList *link; - - g_hash_table_remove (cache->priv->stores, store); - - g_signal_handlers_disconnect_matched ( - store, G_SIGNAL_MATCH_DATA, - 0, 0, NULL, NULL, cache); - - g_hash_table_foreach ( - si->folders, (GHFunc) - unset_folder_info_hash, cache); - - link = g_queue_peek_head_link (&si->folderinfo_updates); - - while (link != NULL) { - struct _update_data *ud = link->data; - g_cancellable_cancel (ud->cancellable); - link = g_list_next (link); - } - - g_object_unref (si->store); - g_hash_table_foreach (si->folders, (GHFunc) free_folder_info_hash, NULL); - g_hash_table_destroy (si->folders); - g_free (si); - } - - g_mutex_unlock (cache->priv->stores_mutex); -} - -/** * mail_folder_cache_note_folder: * * When a folder has been opened, notify it for watching. The folder must have @@ -1449,10 +1664,13 @@ mail_folder_cache_note_folder (MailFolderCache *cache, CamelFolder *folder) { CamelStore *parent_store; - struct _store_info *si; + StoreInfo *si; struct _folder_info *mfi; const gchar *full_name; + g_return_if_fail (MAIL_IS_FOLDER_CACHE (cache)); + g_return_if_fail (CAMEL_IS_FOLDER (folder)); + full_name = camel_folder_get_full_name (folder); parent_store = camel_folder_get_parent_store (folder); diff --git a/mail/mail-folder-cache.h b/mail/mail-folder-cache.h index 146ead5012..78d5fd94de 100644 --- a/mail/mail-folder-cache.h +++ b/mail/mail-folder-cache.h @@ -49,6 +49,9 @@ G_BEGIN_DECLS +/* Avoid a circular dependency. */ +typedef struct _EMailSession EMailSession; + typedef struct _MailFolderCache MailFolderCache; typedef struct _MailFolderCacheClass MailFolderCacheClass; typedef struct _MailFolderCachePrivate MailFolderCachePrivate; @@ -107,34 +110,32 @@ struct _MailFolderCacheClass { GType mail_folder_cache_get_type (void) G_GNUC_CONST; MailFolderCache * - mail_folder_cache_new (void); -void mail_folder_cache_note_store (MailFolderCache *self, + mail_folder_cache_new (EMailSession *session); +EMailSession * mail_folder_cache_get_session (MailFolderCache *cache); +void mail_folder_cache_note_store (MailFolderCache *cache, CamelStore *store, GCancellable *cancellable, NoteDoneFunc done, gpointer data); -void mail_folder_cache_note_store_remove - (MailFolderCache *self, - CamelStore *store); -void mail_folder_cache_note_folder (MailFolderCache *self, +void mail_folder_cache_note_folder (MailFolderCache *cache, CamelFolder *folder); gboolean mail_folder_cache_get_folder_from_uri - (MailFolderCache *self, + (MailFolderCache *cache, const gchar *uri, CamelFolder **folderp); gboolean mail_folder_cache_get_folder_info_flags - (MailFolderCache *self, + (MailFolderCache *cache, CamelFolder *folder, CamelFolderInfoFlags *flags); gboolean mail_folder_cache_get_folder_has_children - (MailFolderCache *self, + (MailFolderCache *cache, CamelFolder *folder, gboolean *found); void mail_folder_cache_get_local_folder_uris - (MailFolderCache *self, + (MailFolderCache *cache, GQueue *out_queue); void mail_folder_cache_get_remote_folder_uris - (MailFolderCache *self, + (MailFolderCache *cache, GQueue *out_queue); G_END_DECLS diff --git a/mail/mail-ops.c b/mail/mail-ops.c index 24a494ddac..4ff12b3955 100644 --- a/mail/mail-ops.c +++ b/mail/mail-ops.c @@ -43,7 +43,6 @@ #include "mail-ops.h" #include "mail-tools.h" -#include "e-mail-local.h" #include "e-mail-session.h" #include "e-mail-session-utils.h" @@ -213,18 +212,23 @@ fetch_mail_exec (struct _fetch_mail_msg *m, { struct _filter_mail_msg *fm = (struct _filter_mail_msg *) m; CamelFolder *folder = NULL; + CamelService *service; + CamelSession *session; CamelURL *url; gboolean is_local_delivery; const gchar *uid; gint i; - fm->destination = e_mail_local_get_folder ( - E_MAIL_LOCAL_FOLDER_LOCAL_INBOX); + service = CAMEL_SERVICE (m->store); + session = camel_service_get_session (service); + + fm->destination = e_mail_session_get_local_folder ( + E_MAIL_SESSION (session), E_MAIL_LOCAL_FOLDER_LOCAL_INBOX); if (fm->destination == NULL) goto fail; g_object_ref (fm->destination); - url = camel_service_new_camel_url (CAMEL_SERVICE (m->store)); + url = camel_service_new_camel_url (service); is_local_delivery = em_utils_is_local_delivery_mbox_file (url); if (is_local_delivery) { @@ -250,7 +254,7 @@ fetch_mail_exec (struct _fetch_mail_msg *m, g_free (path); g_free (url_string); } else { - uid = camel_service_get_uid (CAMEL_SERVICE (m->store)); + uid = camel_service_get_uid (service); folder = fm->source_folder = e_mail_session_get_inbox_sync ( @@ -344,7 +348,7 @@ fail: * there is no need to keep the connection alive forever */ if (!is_local_delivery) em_utils_disconnect_service_sync ( - CAMEL_SERVICE (m->store), TRUE, cancellable, NULL); + service, TRUE, cancellable, NULL); } static void @@ -670,7 +674,8 @@ mail_send_message (struct _send_queue_msg *m, } if (!folder) { - folder = e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_SENT); + folder = e_mail_session_get_local_folder ( + session, E_MAIL_LOCAL_FOLDER_SENT); g_object_ref (folder); } @@ -683,7 +688,8 @@ mail_send_message (struct _send_queue_msg *m, if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) goto exit; - sent_folder = e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_SENT); + sent_folder = e_mail_session_get_local_folder ( + session, E_MAIL_LOCAL_FOLDER_SENT); if (folder != sent_folder) { const gchar *description; @@ -801,6 +807,7 @@ send_queue_exec (struct _send_queue_msg *m, GCancellable *cancellable, GError **error) { + EMailSession *session; CamelFolder *sent_folder; GPtrArray *uids, *send_uids = NULL; gint i, j; @@ -808,7 +815,11 @@ send_queue_exec (struct _send_queue_msg *m, d(printf("sending queue\n")); - sent_folder = e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_SENT); + session = e_mail_backend_get_session (m->backend); + + sent_folder = + e_mail_session_get_local_folder ( + session, E_MAIL_LOCAL_FOLDER_SENT); if (!(uids = camel_folder_get_uids (m->queue))) return; @@ -1489,19 +1500,25 @@ expunge_folder_exec (struct _sync_folder_msg *m, GCancellable *cancellable, GError **error) { + EMailSession *session; CamelFolder *local_inbox; - CamelStore *local_store; CamelStore *parent_store; gboolean is_local_inbox_or_trash; + gboolean store_is_local; gboolean success = TRUE; + const gchar *uid; - local_inbox = e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_INBOX); - is_local_inbox_or_trash = (m->folder == local_inbox); - - local_store = e_mail_local_get_store (); + session = e_mail_backend_get_session (m->backend); parent_store = camel_folder_get_parent_store (m->folder); + uid = camel_service_get_uid (CAMEL_SERVICE (parent_store)); + store_is_local = (g_strcmp0 (uid, E_MAIL_SESSION_LOCAL_UID) == 0); + + local_inbox = + e_mail_session_get_local_folder ( + session, E_MAIL_LOCAL_FOLDER_INBOX); + is_local_inbox_or_trash = (m->folder == local_inbox); - if (!is_local_inbox_or_trash && local_store == parent_store) { + if (store_is_local && !is_local_inbox_or_trash) { CamelFolder *trash; trash = camel_store_get_trash_folder_sync ( @@ -1591,7 +1608,7 @@ empty_trash_exec (struct _empty_trash_msg *m, return; /* do this before expunge, to know which messages will be expunged */ - if (g_strcmp0 (uid, "local") == 0) + if (g_strcmp0 (uid, E_MAIL_SESSION_LOCAL_UID) == 0) success = expunge_pop3_stores ( trash, m->backend, cancellable, error); diff --git a/mail/mail-send-recv.c b/mail/mail-send-recv.c index 44c5158631..36c717619b 100644 --- a/mail/mail-send-recv.c +++ b/mail/mail-send-recv.c @@ -36,7 +36,6 @@ #include "e-util/e-util.h" #include "e-mail-folder-utils.h" -#include "e-mail-local.h" #include "e-mail-session.h" #include "em-event.h" #include "em-filter-rule.h" @@ -164,10 +163,13 @@ free_send_info (struct _send_info *info) } static struct _send_data * -setup_send_data (void) +setup_send_data (EMailBackend *backend) { + EMailSession *session; struct _send_data *data; + session = e_mail_backend_get_session (backend); + if (send_data == NULL) { send_data = data = g_malloc0 (sizeof (*data)); data->lock = g_mutex_new (); @@ -175,8 +177,9 @@ setup_send_data (void) g_str_hash, g_str_equal, (GDestroyNotify) NULL, (GDestroyNotify) free_folder_info); - data->inbox = e_mail_local_get_folder ( - E_MAIL_LOCAL_FOLDER_LOCAL_INBOX); + data->inbox = + e_mail_session_get_local_folder ( + session, E_MAIL_LOCAL_FOLDER_LOCAL_INBOX); g_object_ref (data->inbox); data->active = g_hash_table_new_full ( g_str_hash, g_str_equal, @@ -520,7 +523,7 @@ build_dialog (GtkWindow *parent, gtk_widget_show (scrolled_window); /* must bet setup after send_recv_dialog as it may re-trigger send-recv button */ - data = setup_send_data (); + data = setup_send_data (backend); row = 0; iter = e_list_get_iterator ((EList *) accounts); @@ -810,8 +813,9 @@ receive_done (gpointer data) session = e_mail_backend_get_session (info->backend); - local_outbox = e_mail_local_get_folder ( - E_MAIL_LOCAL_FOLDER_OUTBOX); + local_outbox = + e_mail_session_get_local_folder ( + session, E_MAIL_LOCAL_FOLDER_OUTBOX); service = camel_session_get_service ( CAMEL_SESSION (session), @@ -1126,7 +1130,10 @@ send_receive (GtkWindow *parent, accounts = e_get_account_list (); - local_outbox = e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_OUTBOX); + local_outbox = + e_mail_session_get_local_folder ( + session, E_MAIL_LOCAL_FOLDER_OUTBOX); + data = build_dialog ( parent, backend, accounts, local_outbox, account, allow_send); @@ -1280,11 +1287,12 @@ auto_account_changed (EAccountList *eal, EAccount *ea, gpointer dummy) { - struct _auto_data *info = g_object_get_data((GObject *)ea, "mail-autoreceive"); + struct _auto_data *info; - g_return_if_fail (info != NULL); + info = g_object_get_data (G_OBJECT (ea), "mail-autoreceive"); - auto_account_commit (info); + if (info != NULL) + auto_account_commit (info); } static void @@ -1394,7 +1402,7 @@ mail_receive_account (EMailBackend *backend, CamelURL *url; send_info_t type = SEND_INVALID; - data = setup_send_data (); + data = setup_send_data (backend); info = g_hash_table_lookup (data->active, account->uid); if (info != NULL) @@ -1450,8 +1458,9 @@ mail_receive_account (EMailBackend *backend, break; case SEND_SEND: /* todo, store the folder in info? */ - local_outbox = e_mail_local_get_folder ( - E_MAIL_LOCAL_FOLDER_OUTBOX); + local_outbox = + e_mail_session_get_local_folder ( + session, E_MAIL_LOCAL_FOLDER_OUTBOX); mail_send_queue ( info->backend, local_outbox, @@ -1487,7 +1496,7 @@ mail_send (EMailBackend *backend) if (account == NULL || account->transport->url == NULL) return; - data = setup_send_data (); + data = setup_send_data (backend); info = g_hash_table_lookup (data->active, SEND_URI_KEY); if (info != NULL) { info->again++; @@ -1525,11 +1534,13 @@ mail_send (EMailBackend *backend) g_hash_table_insert (data->active, (gpointer) SEND_URI_KEY, info); - /* todo, store the folder in info? */ - local_outbox = e_mail_local_get_folder (E_MAIL_LOCAL_FOLDER_OUTBOX); - session = e_mail_backend_get_session (backend); + /* todo, store the folder in info? */ + local_outbox = + e_mail_session_get_local_folder ( + session, E_MAIL_LOCAL_FOLDER_OUTBOX); + service = camel_session_get_service ( CAMEL_SESSION (session), transport_uid); diff --git a/mail/mail-vfolder.c b/mail/mail-vfolder.c index b37d042077..99caa6c0ec 100644 --- a/mail/mail-vfolder.c +++ b/mail/mail-vfolder.c @@ -49,11 +49,6 @@ #include "mail-tools.h" #include "mail-vfolder.h" -#include "e-mail-local.h" -#include "e-mail-store.h" - -#define VFOLDER_SERVICE_UID "vfolder" - #define d(x) /* (printf("%s:%s: ", G_STRLOC, G_STRFUNC), (x))*/ static EMVFolderContext *context; /* context remains open all time */ @@ -720,7 +715,7 @@ rule_changed (EFilterRule *rule, session = e_mail_backend_get_session (backend); service = camel_session_get_service ( - CAMEL_SESSION (session), VFOLDER_SERVICE_UID); + CAMEL_SESSION (session), E_MAIL_SESSION_VFOLDER_UID); g_return_if_fail (CAMEL_IS_SERVICE (service)); /* if the folder has changed name, then add it, then remove the old manually */ @@ -820,7 +815,7 @@ context_rule_added (ERuleContext *ctx, session = e_mail_backend_get_session (backend); service = camel_session_get_service ( - CAMEL_SESSION (session), VFOLDER_SERVICE_UID); + CAMEL_SESSION (session), E_MAIL_SESSION_VFOLDER_UID); g_return_if_fail (CAMEL_IS_SERVICE (service)); /* this always runs quickly */ @@ -853,7 +848,7 @@ context_rule_removed (ERuleContext *ctx, session = e_mail_backend_get_session (backend); service = camel_session_get_service ( - CAMEL_SESSION (session), VFOLDER_SERVICE_UID); + CAMEL_SESSION (session), E_MAIL_SESSION_VFOLDER_UID); g_return_if_fail (CAMEL_IS_SERVICE (service)); /* TODO: remove from folder info cache? */ @@ -1008,8 +1003,7 @@ vfolder_load_storage (EMailBackend *backend) /* lock for loading storage, it is safe to call it more than once */ G_LOCK_DEFINE_STATIC (vfolder_hash); - CamelService *service; - const gchar *key; + CamelStore *vfolder_store; const gchar *config_dir; gchar *user; EFilterRule *rule; @@ -1034,27 +1028,14 @@ vfolder_load_storage (EMailBackend *backend) config_dir = mail_session_get_config_dir (); session = e_mail_backend_get_session (backend); - - /* first, create the vfolder store, and set it up */ - service = camel_session_add_service ( - CAMEL_SESSION (session), "vfolder", - "vfolder", CAMEL_PROVIDER_STORE, NULL); - if (service != NULL) { - camel_service_set_display_name (service, _("Search Folders")); - em_utils_connect_service_sync (service, NULL, NULL); - } else { - g_warning("Cannot open vfolder store - no vfolders available"); - return; - } - - g_return_if_fail (CAMEL_IS_STORE (service)); + vfolder_store = e_mail_session_get_vfolder_store (session); g_signal_connect ( - service, "folder-deleted", + vfolder_store, "folder-deleted", G_CALLBACK (store_folder_deleted_cb), backend); g_signal_connect ( - service, "folder-renamed", + vfolder_store, "folder-renamed", G_CALLBACK (store_folder_renamed_cb), NULL); /* load our rules */ @@ -1076,9 +1057,6 @@ vfolder_load_storage (EMailBackend *backend) context, "rule_removed", G_CALLBACK (context_rule_removed), context); - /* load store to mail component */ - e_mail_store_add (session, CAMEL_STORE (service)); - /* and setup the rules we have */ rule = NULL; while ((rule = e_rule_context_next_rule ((ERuleContext *) context, rule, NULL))) { @@ -1092,9 +1070,7 @@ vfolder_load_storage (EMailBackend *backend) /* reenable the feature if required */ settings = g_settings_new ("org.gnome.evolution.mail"); - key = "enable-vfolders"; - if (!g_settings_get_boolean (settings, key)) - g_settings_set_boolean (settings, key, TRUE); + g_settings_set_boolean (settings, "enable-vfolders", TRUE); g_object_unref (settings); folder_cache = e_mail_session_get_folder_cache (session); |