aboutsummaryrefslogtreecommitdiffstats
path: root/mail/e-mail-account-store.c
diff options
context:
space:
mode:
authorMatthew Barnes <mbarnes@redhat.com>2011-12-09 23:34:55 +0800
committerMatthew Barnes <mbarnes@redhat.com>2011-12-11 10:34:19 +0800
commit7c0c40f83317228e0a725bfb5ca8854339d25588 (patch)
treedb1197dd9f336e175c590c3a41201dfa78ee303e /mail/e-mail-account-store.c
parent2f32e1cc68cd416f4530ecc3d2ff08b0e6498d45 (diff)
downloadgsoc2013-evolution-7c0c40f83317228e0a725bfb5ca8854339d25588.tar
gsoc2013-evolution-7c0c40f83317228e0a725bfb5ca8854339d25588.tar.gz
gsoc2013-evolution-7c0c40f83317228e0a725bfb5ca8854339d25588.tar.bz2
gsoc2013-evolution-7c0c40f83317228e0a725bfb5ca8854339d25588.tar.lz
gsoc2013-evolution-7c0c40f83317228e0a725bfb5ca8854339d25588.tar.xz
gsoc2013-evolution-7c0c40f83317228e0a725bfb5ca8854339d25588.tar.zst
gsoc2013-evolution-7c0c40f83317228e0a725bfb5ca8854339d25588.zip
Reorder accounts by drag-and-drop.
This implements https://bugzilla.gnome.org/show_bug.cgi?id=663527#c3. Account reordering is now done by drag-and-drop instead of up/down buttons. Turned out to be a wee bit more complicated than I initially thought. This scraps EAccountManager and EAccountTreeView and replaces them with new classes centered around EMailAccountStore, which EMailSession owns. EMailAccountStore is the model behind the account list in Preferences. The folder tree model now uses it to sort its own top-level rows using gtk_tree_path_compare(). It also broadcasts account operations through signals so we don't have to rely so heavily on EAccountList signals, since EAccountList is going away soon. Also as part of this work, the e-mail-local.h and e-mail-store.h APIs have been merged into EMailSession and MailFolderCache.
Diffstat (limited to 'mail/e-mail-account-store.c')
-rw-r--r--mail/e-mail-account-store.c1439
1 files changed, 1439 insertions, 0 deletions
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;
+}
+