]> git.0d.be Git - empathy.git/blobdiff - src/empathy-accounts-dialog.c
Merge remote-tracking branch 'jonny/ft'
[empathy.git] / src / empathy-accounts-dialog.c
index 5843c0d7437b34ce85805653be22fd830b434ddd..9e2fea781614e546c73271ae9d9477a1fcf3a837 100644 (file)
@@ -29,7 +29,7 @@
 #include <stdlib.h>
 
 #include <gtk/gtk.h>
-#include <glib/gi18n.h>
+#include <glib/gi18n-lib.h>
 #include <dbus/dbus-glib.h>
 
 #include <telepathy-glib/account-manager.h>
 #include <libempathy/empathy-utils.h>
 #include <libempathy/empathy-connection-managers.h>
 #include <libempathy/empathy-connectivity.h>
-#include <libempathy-gtk/empathy-ui-utils.h>
 
+#include <libempathy-gtk/empathy-ui-utils.h>
 #include <libempathy-gtk/empathy-protocol-chooser.h>
 #include <libempathy-gtk/empathy-account-widget.h>
 #include <libempathy-gtk/empathy-account-widget-irc.h>
 #include <libempathy-gtk/empathy-account-widget-sip.h>
 #include <libempathy-gtk/empathy-cell-renderer-activatable.h>
-#include <libempathy-gtk/empathy-conf.h>
 #include <libempathy-gtk/empathy-images.h>
 
 #include "empathy-accounts-dialog.h"
 #include "empathy-import-dialog.h"
 #include "empathy-import-utils.h"
-#include "ephy-spinner.h"
 
 #define DEBUG_FLAG EMPATHY_DEBUG_ACCOUNT
 #include <libempathy/empathy-debug.h>
 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAccountsDialog)
 G_DEFINE_TYPE (EmpathyAccountsDialog, empathy_accounts_dialog, GTK_TYPE_DIALOG);
 
+enum
+{
+  NOTEBOOK_PAGE_ACCOUNT = 0,
+  NOTEBOOK_PAGE_LOADING
+};
+
 typedef struct {
   GtkWidget *alignment_settings;
   GtkWidget *alignment_infobar;
@@ -81,6 +85,7 @@ typedef struct {
   GtkWidget *label_status;
   GtkWidget *image_status;
   GtkWidget *throbber;
+  GtkWidget *enabled_switch;
   GtkWidget *frame_no_protocol;
 
   GtkWidget *treeview;
@@ -97,12 +102,22 @@ typedef struct {
   GtkWidget *label_type;
   GtkWidget *settings_widget;
 
-  /* We have to keep a reference on the actual EmpathyAccountWidget, not just
-   * his GtkWidget. It is the only reliable source we can query to know if
+  GtkWidget *notebook_account;
+  GtkWidget *spinner;
+  gboolean loading;
+
+  /* We have to keep a weak reference on the actual EmpathyAccountWidget, not
+   * just its GtkWidget. It is the only reliable source we can query to know if
    * there are any unsaved changes to the currently selected account. We can't
    * look at the account settings because it does not contain everything that
    * can be changed using the EmpathyAccountWidget. For instance, it does not
-   * contain the state of the "Enabled" checkbox. */
+   * contain the state of the "Enabled" checkbox.
+   *
+   * Even if we create it ourself, we just get a weak ref and not a strong one
+   * as EmpathyAccountWidget unrefs itself when the GtkWidget is destroyed.
+   * That's kinda ugly; cf bgo #640417.
+   *
+   * */
   EmpathyAccountWidget *setting_widget_object;
 
   gboolean  connecting_show;
@@ -113,6 +128,7 @@ typedef struct {
 
   TpAccountManager *account_manager;
   EmpathyConnectionManagers *cms;
+  EmpathyConnectivity *connectivity;
 
   GtkWindow *parent_window;
   TpAccount *initial_selection;
@@ -124,8 +140,6 @@ typedef struct {
    * EmpathyAccountsDialog object. */
   gboolean force_change_row;
   GtkTreeRowReference *destination_row;
-
-  gboolean dispose_has_run;
 } EmpathyAccountsDialogPriv;
 
 enum {
@@ -190,18 +204,70 @@ accounts_dialog_update_name_label (EmpathyAccountsDialog *dialog,
   g_free (text);
 }
 
+static void
+accounts_dialog_status_infobar_set_message (EmpathyAccountsDialog *dialog,
+    const gchar *message)
+{
+  EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
+  gchar *message_markup;
+
+  message_markup = g_markup_printf_escaped ("<i>%s</i>", message);
+  gtk_label_set_markup (GTK_LABEL (priv->label_status), message_markup);
+  g_free (message_markup);
+}
+
+static void
+accounts_dialog_enable_account_cb (GObject *account,
+    GAsyncResult *result,
+    gpointer user_data)
+{
+  GError *error = NULL;
+
+  tp_account_set_enabled_finish (TP_ACCOUNT (account), result, &error);
+
+  if (error != NULL)
+    {
+      DEBUG ("Could not enable the account: %s", error->message);
+      g_error_free (error);
+    }
+  else
+    {
+      TpAccountManager *am = tp_account_manager_dup ();
+
+      empathy_connect_new_account (TP_ACCOUNT (account), am);
+      g_object_unref (am);
+    }
+}
+
+static void
+accounts_dialog_enable_switch_active_cb (GtkSwitch *sw,
+    GParamSpec *spec,
+    EmpathyAccountsDialog *dialog)
+{
+  EmpathyAccountSettings *settings;
+  TpAccount *account;
+
+  settings = accounts_dialog_model_get_selected_settings (dialog);
+  if (settings == NULL)
+    return;
+
+  account = empathy_account_settings_get_account (settings);
+  if (account == NULL)
+    return;
+
+  tp_account_set_enabled_async (account, gtk_switch_get_active (sw),
+      accounts_dialog_enable_account_cb, NULL);
+}
+
 static void
 accounts_dialog_update_status_infobar (EmpathyAccountsDialog *dialog,
     TpAccount *account)
 {
   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
-  const gchar               *message;
-  gchar                     *message_markup;
   gchar                     *status_message = NULL;
   guint                     status;
   guint                     reason;
   guint                     presence;
-  EmpathyConnectivity       *connectivity;
   GtkTreeView               *view;
   GtkTreeModel              *model;
   GtkTreeSelection          *selection;
@@ -209,6 +275,7 @@ accounts_dialog_update_status_infobar (EmpathyAccountsDialog *dialog,
   TpAccount                 *selected_account;
   gboolean                  account_enabled;
   gboolean                  creating_account;
+  TpStorageRestrictionFlags storage_restrictions = 0;
 
   view = GTK_TREE_VIEW (priv->treeview);
   selection = gtk_tree_view_get_selection (view);
@@ -243,6 +310,8 @@ accounts_dialog_update_status_infobar (EmpathyAccountsDialog *dialog,
        * (else no icon is shown in infobar)*/
       if (!account_enabled)
         presence = TP_CONNECTION_PRESENCE_TYPE_OFFLINE;
+
+      storage_restrictions = tp_account_get_storage_restrictions (account);
     }
   else
     {
@@ -255,30 +324,53 @@ accounts_dialog_update_status_infobar (EmpathyAccountsDialog *dialog,
   gtk_image_set_from_icon_name (GTK_IMAGE (priv->image_status),
       empathy_icon_name_for_presence (presence), GTK_ICON_SIZE_SMALL_TOOLBAR);
 
+  /* update the enabled switch */
+  g_signal_handlers_block_by_func (priv->enabled_switch,
+      accounts_dialog_enable_switch_active_cb, dialog);
+  gtk_switch_set_active (GTK_SWITCH (priv->enabled_switch),
+      account_enabled);
+  g_signal_handlers_unblock_by_func (priv->enabled_switch,
+      accounts_dialog_enable_switch_active_cb, dialog);
+
+  /* Display the Enable switch if account supports it */
+  gtk_widget_set_visible (priv->enabled_switch,
+      !(storage_restrictions & TP_STORAGE_RESTRICTION_FLAG_CANNOT_SET_ENABLED));
+
   if (account_enabled)
     {
       switch (status)
         {
           case TP_CONNECTION_STATUS_CONNECTING:
-            message = _("Connecting…");
+            accounts_dialog_status_infobar_set_message (dialog,
+                _("Connecting…"));
             gtk_info_bar_set_message_type (GTK_INFO_BAR (priv->infobar),
                 GTK_MESSAGE_INFO);
 
-            ephy_spinner_start (EPHY_SPINNER (priv->throbber));
+            gtk_spinner_start (GTK_SPINNER (priv->throbber));
             gtk_widget_show (priv->throbber);
             gtk_widget_hide (priv->image_status);
             break;
           case TP_CONNECTION_STATUS_CONNECTED:
             if (g_strcmp0 (status_message, "") == 0)
               {
+                gchar *message;
+
                 message = g_strdup_printf ("%s",
                     empathy_presence_get_default_message (presence));
+
+                accounts_dialog_status_infobar_set_message (dialog, message);
+                g_free (message);
               }
             else
               {
+                gchar *message;
+
                 message = g_strdup_printf ("%s — %s",
                     empathy_presence_get_default_message (presence),
                     status_message);
+
+                accounts_dialog_status_infobar_set_message (dialog, message);
+                g_free (message);
               }
             gtk_info_bar_set_message_type (GTK_INFO_BAR (priv->infobar),
                 GTK_MESSAGE_INFO);
@@ -287,54 +379,61 @@ accounts_dialog_update_status_infobar (EmpathyAccountsDialog *dialog,
             gtk_widget_hide (priv->throbber);
             break;
           case TP_CONNECTION_STATUS_DISCONNECTED:
-            message = g_strdup_printf (_("Disconnected — %s"),
-                empathy_status_reason_get_default_message (reason));
-
             if (reason == TP_CONNECTION_STATUS_REASON_REQUESTED)
               {
+                gchar *message;
+
                 message = g_strdup_printf (_("Offline — %s"),
-                    empathy_status_reason_get_default_message (reason));
+                    empathy_account_get_error_message (account, NULL));
                 gtk_info_bar_set_message_type (GTK_INFO_BAR (priv->infobar),
                     GTK_MESSAGE_WARNING);
+
+                accounts_dialog_status_infobar_set_message (dialog, message);
+                g_free (message);
               }
             else
               {
+                gchar *message;
+
+                message = g_strdup_printf (_("Disconnected — %s"),
+                    empathy_account_get_error_message (account, NULL));
                 gtk_info_bar_set_message_type (GTK_INFO_BAR (priv->infobar),
                     GTK_MESSAGE_ERROR);
+
+                accounts_dialog_status_infobar_set_message (dialog, message);
+                g_free (message);
               }
 
-            connectivity = empathy_connectivity_dup_singleton ();
-            if (!empathy_connectivity_is_online (connectivity))
-               message = _("Offline — No Network Connection");
+            if (!empathy_connectivity_is_online (priv->connectivity))
+               accounts_dialog_status_infobar_set_message (dialog,
+                    _("Offline — No Network Connection"));
 
-            g_object_unref (connectivity);
-            ephy_spinner_stop (EPHY_SPINNER (priv->throbber));
+            gtk_spinner_stop (GTK_SPINNER (priv->throbber));
             gtk_widget_show (priv->image_status);
             gtk_widget_hide (priv->throbber);
             break;
           default:
-            message = _("Unknown Status");
+            accounts_dialog_status_infobar_set_message (dialog, _("Unknown Status"));
             gtk_info_bar_set_message_type (GTK_INFO_BAR (priv->infobar),
                 GTK_MESSAGE_WARNING);
 
-            ephy_spinner_stop (EPHY_SPINNER (priv->throbber));
+            gtk_spinner_stop (GTK_SPINNER (priv->throbber));
             gtk_widget_hide (priv->image_status);
             gtk_widget_hide (priv->throbber);
         }
     }
   else
     {
-      message = _("Offline — Account Disabled");
+      accounts_dialog_status_infobar_set_message (dialog,
+          _("Offline — Account Disabled"));
 
       gtk_info_bar_set_message_type (GTK_INFO_BAR (priv->infobar),
           GTK_MESSAGE_WARNING);
-      ephy_spinner_stop (EPHY_SPINNER (priv->throbber));
+      gtk_spinner_stop (GTK_SPINNER (priv->throbber));
       gtk_widget_show (priv->image_status);
       gtk_widget_hide (priv->throbber);
     }
 
-  message_markup = g_markup_printf_escaped ("<i>%s</i>", message);
-  gtk_label_set_markup (GTK_LABEL (priv->label_status), message_markup);
   gtk_widget_show (priv->label_status);
 
   if (!creating_account)
@@ -343,13 +442,10 @@ accounts_dialog_update_status_infobar (EmpathyAccountsDialog *dialog,
     gtk_widget_hide (priv->infobar);
 
   g_free (status_message);
-  g_free (message_markup);
 }
 
-static void
-empathy_account_dialog_widget_cancelled_cb (
-    EmpathyAccountWidget *widget_object,
-    EmpathyAccountsDialog *dialog)
+void
+empathy_account_dialog_cancel (EmpathyAccountsDialog *dialog)
 {
   GtkTreeView *view;
   GtkTreeModel *model;
@@ -393,24 +489,23 @@ empathy_account_dialog_widget_cancelled_cb (
     g_object_unref (settings);
 }
 
+static void
+empathy_account_dialog_widget_cancelled_cb (
+    EmpathyAccountWidget *widget_object,
+    EmpathyAccountsDialog *dialog)
+{
+  empathy_account_dialog_cancel (dialog);
+}
+
 static void
 empathy_account_dialog_account_created_cb (EmpathyAccountWidget *widget_object,
     TpAccount *account,
     EmpathyAccountsDialog *dialog)
 {
-  gchar *display_name;
   EmpathyAccountSettings *settings =
       accounts_dialog_model_get_selected_settings (dialog);
   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
 
-  display_name = empathy_account_widget_get_default_display_name (
-      widget_object);
-
-  empathy_account_settings_set_display_name_async (settings,
-      display_name, NULL, NULL);
-
-  g_free (display_name);
-
   accounts_dialog_update_settings (dialog, settings);
   accounts_dialog_update_status_infobar (dialog,
       empathy_account_settings_get_account (settings));
@@ -420,11 +515,6 @@ empathy_account_dialog_account_created_cb (EmpathyAccountWidget *widget_object,
   gtk_widget_set_sensitive (priv->button_remove, TRUE);
   gtk_widget_set_sensitive (priv->button_import, TRUE);
 
-  empathy_signal_connect_weak (account, "status-changed",
-      G_CALLBACK (accounts_dialog_connection_changed_cb), G_OBJECT (dialog));
-  empathy_signal_connect_weak (account, "presence-changed",
-      G_CALLBACK (accounts_dialog_presence_changed_cb), G_OBJECT (dialog));
-
   if (settings)
     g_object_unref (settings);
 }
@@ -456,12 +546,19 @@ account_dialog_create_settings_widget (EmpathyAccountsDialog *dialog,
     EmpathyAccountSettings *settings)
 {
   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
-  gchar                     *icon_name;
+  const gchar               *icon_name;
   TpAccount                 *account;
 
+  if (priv->setting_widget_object != NULL)
+    g_object_remove_weak_pointer (G_OBJECT (priv->setting_widget_object),
+        (gpointer *) &priv->setting_widget_object);
+
   priv->setting_widget_object =
       empathy_account_widget_new_for_protocol (settings, FALSE);
 
+  g_object_add_weak_pointer (G_OBJECT (priv->setting_widget_object),
+      (gpointer *) &priv->setting_widget_object);
+
   if (accounts_dialog_has_valid_accounts (dialog))
     empathy_account_widget_set_other_accounts_exist (
         priv->setting_widget_object, TRUE);
@@ -558,44 +655,11 @@ accounts_dialog_setup_ui_to_add_account (EmpathyAccountsDialog *dialog)
 {
   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
   EmpathyAccountSettings *settings;
-  gchar *str;
-  const gchar *name, *display_name;
-  TpConnectionManager *cm;
-  TpConnectionManagerProtocol *proto;
-  gboolean is_gtalk, is_facebook;
-
-  cm = empathy_protocol_chooser_dup_selected (
-      EMPATHY_PROTOCOL_CHOOSER (priv->combobox_protocol), &proto, &is_gtalk,
-      &is_facebook);
-  if (cm == NULL)
-    return;
 
-  if (is_gtalk)
-    name = "gtalk";
-  else if (is_facebook)
-    name ="facebook";
-  else
-    name = proto->name;
-
-  display_name = empathy_protocol_name_to_display_name (name);
-  if (display_name == NULL)
-    display_name = proto->name;
-
-  /* Create account */
-  /* To translator: %s is the name of the protocol, such as "Google Talk" or
-   * "Yahoo!"
-   */
-  str = g_strdup_printf (_("New %s account"), display_name);
-  settings = empathy_account_settings_new (cm->name, proto->name, str);
-
-  g_free (str);
-
-  if (is_gtalk)
-    empathy_account_settings_set_icon_name_async (settings, "im-google-talk",
-        NULL, NULL);
-  else if (is_facebook)
-    empathy_account_settings_set_icon_name_async (settings, "im-facebook",
-        NULL, NULL);
+  settings = empathy_protocol_chooser_create_account_settings (
+      EMPATHY_PROTOCOL_CHOOSER (priv->combobox_protocol));
+  if (settings == NULL)
+    return;
 
   accounts_dialog_add (dialog, settings);
   accounts_dialog_model_set_selected (dialog, settings);
@@ -603,7 +667,6 @@ accounts_dialog_setup_ui_to_add_account (EmpathyAccountsDialog *dialog)
   gtk_widget_show_all (priv->hbox_protocol);
 
   g_object_unref (settings);
-  g_object_unref (cm);
 }
 
 static void
@@ -983,8 +1046,22 @@ accounts_dialog_row_changed_foreach (GtkTreeModel *model,
     GtkTreeIter *iter,
     gpointer user_data)
 {
-  gtk_tree_model_row_changed (model, path, iter);
+  TpAccount *account;
 
+  gtk_tree_model_get (model, iter, COL_ACCOUNT, &account, -1);
+
+  if (account == NULL)
+    return FALSE;
+
+  if (tp_account_get_connection_status (account, NULL) ==
+      TP_CONNECTION_STATUS_CONNECTING)
+    {
+      /* Only update the row where we have a connecting account as that's the
+       * ones having a blinking icon. */
+      gtk_tree_model_row_changed (model, path, iter);
+    }
+
+  g_object_unref (account);
   return FALSE;
 }
 
@@ -1132,12 +1209,10 @@ accounts_dialog_button_remove_clicked_cb (GtkWidget *button,
 {
   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
   GtkTreeView  *view;
-  GtkTreeModel *model;
   GtkTreeSelection *selection;
   GtkTreeIter iter;
 
   view = GTK_TREE_VIEW (priv->treeview);
-  model = gtk_tree_view_get_model (view);
   selection = gtk_tree_view_get_selection (view);
   if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
       return;
@@ -1277,7 +1352,8 @@ accounts_dialog_model_selection_changed (GtkTreeSelection *selection,
     }
 
   /* Update remove button sensitivity */
-  gtk_widget_set_sensitive (priv->button_remove, is_selection && !creating);
+  gtk_widget_set_sensitive (priv->button_remove, is_selection && !creating &&
+      !priv->loading);
 }
 
 static void
@@ -1413,14 +1489,12 @@ accounts_dialog_get_settings_iter (EmpathyAccountsDialog *dialog,
     GtkTreeIter *iter)
 {
   GtkTreeView      *view;
-  GtkTreeSelection *selection;
   GtkTreeModel     *model;
   gboolean          ok;
   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
 
   /* Update the status in the model */
   view = GTK_TREE_VIEW (priv->treeview);
-  selection = gtk_tree_view_get_selection (view);
   model = gtk_tree_view_get_model (view);
 
   for (ok = gtk_tree_model_get_iter_first (model, iter);
@@ -1450,14 +1524,12 @@ accounts_dialog_get_account_iter (EmpathyAccountsDialog *dialog,
     GtkTreeIter *iter)
 {
   GtkTreeView      *view;
-  GtkTreeSelection *selection;
   GtkTreeModel     *model;
   gboolean          ok;
   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
 
   /* Update the status in the model */
   view = GTK_TREE_VIEW (priv->treeview);
-  selection = gtk_tree_view_get_selection (view);
   model = gtk_tree_view_get_model (view);
 
   for (ok = gtk_tree_model_get_iter_first (model, iter);
@@ -1481,18 +1553,132 @@ accounts_dialog_get_account_iter (EmpathyAccountsDialog *dialog,
   return FALSE;
 }
 
+static void
+select_and_scroll_to_iter (EmpathyAccountsDialog *dialog,
+    GtkTreeIter *iter)
+{
+  EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
+  GtkTreeSelection *selection;
+  GtkTreePath *path;
+  GtkTreeModel *model;
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
+
+  gtk_tree_selection_select_iter (selection, iter);
+
+  model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->treeview));
+  path = gtk_tree_model_get_path (model, iter);
+
+  gtk_tree_view_scroll_to_cell (GTK_TREE_VIEW (priv->treeview), path, NULL,
+      TRUE, 0, 0.5);
+
+  gtk_tree_path_free (path);
+}
+
 static void
 accounts_dialog_model_set_selected (EmpathyAccountsDialog *dialog,
     EmpathyAccountSettings *settings)
 {
-  GtkTreeSelection *selection;
   GtkTreeIter       iter;
-  EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
 
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
   if (accounts_dialog_get_settings_iter (dialog, settings, &iter))
-    gtk_tree_selection_select_iter (selection, &iter);
+    select_and_scroll_to_iter (dialog, &iter);
 }
+
+static void
+accounts_dialog_treeview_enabled_cb (GtkMenuItem *item,
+    TpAccount *account)
+{
+  gboolean enabled;
+
+  enabled = tp_account_is_enabled (account);
+  tp_account_set_enabled_async (account, !enabled, NULL, NULL);
+}
+
+static gboolean
+accounts_dialog_treeview_button_press_event_cb (GtkTreeView *view,
+    GdkEventButton *event,
+    EmpathyAccountsDialog *dialog)
+{
+  EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
+  TpAccount *account = NULL;
+  GtkTreeModel *model = NULL;
+  GtkTreePath *path = NULL;
+  GtkTreeIter iter;
+  GtkWidget *menu;
+  GtkWidget *item_enable, *item_disable;
+  GtkWidget *image_enable, *image_disable;
+
+  /* ignore multiple clicks */
+  if (event->type != GDK_BUTTON_PRESS)
+    return TRUE;
+
+  if (event->button != 3)
+    goto finally;
+
+  /* Selection is not yet set, so we have to get account from event position */
+  model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->treeview));
+  if (!gtk_tree_view_get_path_at_pos (GTK_TREE_VIEW (priv->treeview),
+      event->x, event->y, &path, NULL, NULL, NULL))
+    goto finally;
+
+  if (!gtk_tree_model_get_iter (model, &iter, path))
+    goto finally;
+
+  gtk_tree_model_get (model, &iter, COL_ACCOUNT, &account, -1);
+
+  /* Create the menu */
+  menu = empathy_context_menu_new (GTK_WIDGET (view));
+
+  /* Get images for menu items */
+  image_enable = gtk_image_new_from_icon_name (empathy_icon_name_for_presence (
+        tp_account_manager_get_most_available_presence (
+          priv->account_manager, NULL, NULL)),
+      GTK_ICON_SIZE_MENU);
+  image_disable = gtk_image_new_from_icon_name (
+      empathy_icon_name_for_presence (TP_CONNECTION_PRESENCE_TYPE_OFFLINE),
+      GTK_ICON_SIZE_MENU);
+
+  /* Menu items: to enabled/disable the account */
+  item_enable = gtk_image_menu_item_new_with_mnemonic (_("_Enable"));
+  item_disable = gtk_image_menu_item_new_with_mnemonic (_("_Disable"));
+  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item_enable),
+      image_enable);
+  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (item_disable),
+      image_disable);
+
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item_enable);
+  gtk_menu_shell_append (GTK_MENU_SHELL (menu), item_disable);
+
+  if (tp_account_is_enabled (account))
+    {
+      tp_g_signal_connect_object (item_disable, "activate",
+          G_CALLBACK (accounts_dialog_treeview_enabled_cb), account, 0);
+      gtk_widget_set_sensitive (item_enable, FALSE);
+    }
+  else
+    {
+      tp_g_signal_connect_object (item_enable, "activate",
+          G_CALLBACK (accounts_dialog_treeview_enabled_cb), account, 0);
+      gtk_widget_set_sensitive (item_disable, FALSE);
+    }
+
+  gtk_widget_show (item_enable);
+  gtk_widget_show (item_disable);
+
+  /* FIXME: Add here presence items, to be able to set per-account presence */
+
+  /* Popup menu */
+  gtk_menu_popup (GTK_MENU (menu), NULL, NULL, NULL, NULL,
+      event->button, event->time);
+
+finally:
+  tp_clear_object (&account);
+  gtk_tree_path_free (path);
+
+  return FALSE;
+}
+
 static void
 accounts_dialog_add (EmpathyAccountsDialog *dialog,
     EmpathyAccountSettings *settings)
@@ -1636,18 +1822,26 @@ accounts_dialog_add_account (EmpathyAccountsDialog *dialog,
   GtkTreeIter         iter;
   TpConnectionStatus  status;
   const gchar        *name;
-  gboolean            enabled;
   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
+  gboolean selected = FALSE;
 
   model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->treeview));
   status = tp_account_get_connection_status (account, NULL);
   name = tp_account_get_display_name (account);
-  enabled = tp_account_is_enabled (account);
 
   settings = empathy_account_settings_new_for_account (account);
 
   if (!accounts_dialog_get_account_iter (dialog, account, &iter))
-    gtk_list_store_append (GTK_LIST_STORE (model), &iter);
+    {
+      gtk_list_store_append (GTK_LIST_STORE (model), &iter);
+    }
+  else
+    {
+      GtkTreeSelection *selection;
+
+      selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
+      selected = gtk_tree_selection_iter_is_selected (selection, &iter);
+    }
 
   gtk_list_store_set (GTK_LIST_STORE (model), &iter,
       COL_NAME, name,
@@ -1656,6 +1850,14 @@ accounts_dialog_add_account (EmpathyAccountsDialog *dialog,
       COL_ACCOUNT_SETTINGS, settings,
       -1);
 
+  if (selected)
+    {
+      /* We just modified the selected account. Its display name may have been
+       * changed and so it's place in the treeview. Scroll to it so it stays
+       * visible. */
+      select_and_scroll_to_iter (dialog, &iter);
+    }
+
   accounts_dialog_connection_changed_cb (account,
       0,
       status,
@@ -1664,9 +1866,14 @@ accounts_dialog_add_account (EmpathyAccountsDialog *dialog,
       NULL,
       dialog);
 
-  empathy_signal_connect_weak (account, "notify::display-name",
+  tp_g_signal_connect_object (account, "notify::display-name",
       G_CALLBACK (accounts_dialog_account_display_name_changed_cb),
-      G_OBJECT (dialog));
+      dialog, 0);
+
+  tp_g_signal_connect_object (account, "status-changed",
+      G_CALLBACK (accounts_dialog_connection_changed_cb), dialog, 0);
+  tp_g_signal_connect_object (account, "presence-changed",
+      G_CALLBACK (accounts_dialog_presence_changed_cb), dialog, 0);
 
   g_object_unref (settings);
 }
@@ -1680,7 +1887,7 @@ account_prepare_cb (GObject *source_object,
   TpAccount *account = TP_ACCOUNT (source_object);
   GError *error = NULL;
 
-  if (!tp_account_prepare_finish (account, result, &error))
+  if (!tp_proxy_prepare_finish (account, result, &error))
     {
       DEBUG ("Failed to prepare account: %s", error->message);
       g_error_free (error);
@@ -1696,7 +1903,7 @@ accounts_dialog_account_validity_changed_cb (TpAccountManager *manager,
     gboolean valid,
     EmpathyAccountsDialog *dialog)
 {
-  tp_account_prepare_async (account, NULL, account_prepare_cb, dialog);
+  tp_proxy_prepare_async (account, NULL, account_prepare_cb, dialog);
 }
 
 static void
@@ -1750,12 +1957,6 @@ enable_or_disable_account (EmpathyAccountsDialog *dialog,
     TpAccount *account,
     gboolean enabled)
 {
-  GtkTreeModel *model;
-  EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
-
-  /* Update the status in the model */
-  model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->treeview));
-
   /* Update the status-infobar in the details view */
   accounts_dialog_update_status_infobar (dialog, account);
 
@@ -1818,13 +2019,33 @@ static void
 accounts_dialog_set_selected_account (EmpathyAccountsDialog *dialog,
     TpAccount *account)
 {
-  GtkTreeSelection *selection;
   GtkTreeIter       iter;
-  EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
 
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
   if (accounts_dialog_get_account_iter (dialog, account, &iter))
-    gtk_tree_selection_select_iter (selection, &iter);
+    select_and_scroll_to_iter (dialog, &iter);
+}
+
+static void
+finished_loading (EmpathyAccountsDialog *self)
+{
+  EmpathyAccountsDialogPriv *priv = GET_PRIV (self);
+  GtkTreeSelection *selection;
+  gboolean has_selected;
+
+  priv->loading = FALSE;
+
+  gtk_widget_set_sensitive (priv->button_add, TRUE);
+  gtk_widget_set_sensitive (priv->button_import, TRUE);
+  gtk_widget_set_sensitive (priv->treeview, TRUE);
+
+  /* Sensitive the remove button if there is an account selected */
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->treeview));
+  has_selected = gtk_tree_selection_get_selected (selection, NULL, NULL);
+  gtk_widget_set_sensitive (priv->button_remove, has_selected);
+
+  gtk_spinner_stop (GTK_SPINNER (priv->spinner));
+  gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook_account),
+      NOTEBOOK_PAGE_ACCOUNT);
 }
 
 static void
@@ -1837,9 +2058,11 @@ accounts_dialog_cms_prepare_cb (GObject *source,
   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
 
   if (!empathy_connection_managers_prepare_finish (cms, result, NULL))
-    return;
+    goto out;
 
-  accounts_dialog_update_settings (dialog, NULL);
+  /* No need to update the settings if we are already preparing one */
+  if (priv->settings_ready == NULL)
+    accounts_dialog_update_settings (dialog, NULL);
 
   if (priv->initial_selection != NULL)
     {
@@ -1847,6 +2070,9 @@ accounts_dialog_cms_prepare_cb (GObject *source,
       g_object_unref (priv->initial_selection);
       priv->initial_selection = NULL;
     }
+
+out:
+  finished_loading (dialog);
 }
 
 static void
@@ -1873,11 +2099,6 @@ accounts_dialog_accounts_setup (EmpathyAccountsDialog *dialog)
   for (l = accounts; l; l = l->next)
     {
       accounts_dialog_add_account (dialog, l->data);
-
-      empathy_signal_connect_weak (l->data, "status-changed",
-          G_CALLBACK (accounts_dialog_connection_changed_cb), G_OBJECT (dialog));
-      empathy_signal_connect_weak (l->data, "presence-changed",
-          G_CALLBACK (accounts_dialog_presence_changed_cb), G_OBJECT (dialog));
     }
   g_list_free (accounts);
 
@@ -1897,7 +2118,7 @@ accounts_dialog_manager_ready_cb (GObject *source_object,
   TpAccountManager *manager = TP_ACCOUNT_MANAGER (source_object);
   GError *error = NULL;
 
-  if (!tp_account_manager_prepare_finish (manager, result, &error))
+  if (!tp_proxy_prepare_finish (manager, result, &error))
     {
       DEBUG ("Failed to prepare account manager: %s", error->message);
       g_error_free (error);
@@ -1956,8 +2177,11 @@ accounts_dialog_build_ui (EmpathyAccountsDialog *dialog)
   GtkBuilder                   *gui;
   gchar                        *filename;
   EmpathyAccountsDialogPriv    *priv = GET_PRIV (dialog);
-  GtkWidget                    *content_area;
-  GtkWidget *action_area, *vbox, *hbox, *align;
+  GtkWidget *content_area, *action_area;
+  GtkWidget *grid, *hbox;
+  GtkWidget *alig;
+  GtkWidget *sw, *toolbar;
+  GtkStyleContext *context;
 
   filename = empathy_file_lookup ("empathy-accounts-dialog.ui", "src");
 
@@ -1972,6 +2196,10 @@ accounts_dialog_build_ui (EmpathyAccountsDialog *dialog)
       "button_remove", &priv->button_remove,
       "button_import", &priv->button_import,
       "hbox_protocol", &priv->hbox_protocol,
+      "notebook_account", &priv->notebook_account,
+      "alignment_loading", &alig,
+      "accounts_sw", &sw,
+      "add_remove_toolbar", &toolbar,
       NULL);
   g_free (filename);
 
@@ -1981,11 +2209,13 @@ accounts_dialog_build_ui (EmpathyAccountsDialog *dialog)
       "button_add", "clicked", accounts_dialog_button_add_clicked_cb,
       "button_remove", "clicked", accounts_dialog_button_remove_clicked_cb,
       "button_import", "clicked", accounts_dialog_button_import_clicked_cb,
+      "treeview", "button-press-event",
+         accounts_dialog_treeview_button_press_event_cb,
       NULL);
 
   content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
 
-  gtk_container_add (GTK_CONTAINER (content_area), top_hbox);
+  gtk_box_pack_start (GTK_BOX (content_area), top_hbox, TRUE, TRUE, 0);
 
   g_object_unref (gui);
 
@@ -1996,9 +2226,28 @@ accounts_dialog_build_ui (EmpathyAccountsDialog *dialog)
   gtk_widget_hide (priv->button_remove);
 #endif /* HAVE_MEEGO */
 
-  /* Remove button is unsensitive until we have a selected account */
+  /* Display loading page */
+  priv->loading = TRUE;
+
+  priv->spinner = gtk_spinner_new ();
+
+  gtk_spinner_start (GTK_SPINNER (priv->spinner));
+  gtk_widget_show (priv->spinner);
+
+  gtk_container_add (GTK_CONTAINER (alig), priv->spinner);
+
+  gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook_account),
+      NOTEBOOK_PAGE_LOADING);
+
+  /* Remove button is insensitive until we have a selected account */
   gtk_widget_set_sensitive (priv->button_remove, FALSE);
 
+  /* Add and Import buttons and treeview are insensitive while the dialog
+   * is loading */
+  gtk_widget_set_sensitive (priv->button_add, FALSE);
+  gtk_widget_set_sensitive (priv->button_import, FALSE);
+  gtk_widget_set_sensitive (priv->treeview, FALSE);
+
   priv->combobox_protocol = empathy_protocol_chooser_new ();
   gtk_box_pack_start (GTK_BOX (priv->hbox_protocol), priv->combobox_protocol,
       TRUE, TRUE, 0);
@@ -2015,40 +2264,29 @@ accounts_dialog_build_ui (EmpathyAccountsDialog *dialog)
       priv->infobar);
   gtk_widget_show (priv->infobar);
 
-  content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (priv->infobar));
+  grid = gtk_grid_new ();
+  gtk_container_add (
+      GTK_CONTAINER (gtk_info_bar_get_content_area (
+          GTK_INFO_BAR (priv->infobar))),
+      grid);
 
   priv->image_type = gtk_image_new_from_stock (GTK_STOCK_CUT,
       GTK_ICON_SIZE_DIALOG);
   gtk_misc_set_alignment (GTK_MISC (priv->image_type), 0.0, 0.5);
-  gtk_box_pack_start (GTK_BOX (content_area), priv->image_type, FALSE, FALSE, 0);
-  gtk_widget_show (priv->image_type);
-
-  vbox = gtk_vbox_new (FALSE, 6);
-  gtk_box_pack_start (GTK_BOX (content_area), vbox, TRUE, TRUE, 0);
-  gtk_widget_show (vbox);
+  gtk_grid_attach (GTK_GRID (grid), priv->image_type, 0, 0, 1, 2);
 
   /* first row */
-  align = gtk_alignment_new (0.5, 0.0, 0.0, 0.0);
-  gtk_widget_show (align);
-
   priv->label_name = gtk_label_new (NULL);
-  gtk_container_add (GTK_CONTAINER (align), priv->label_name);
-  gtk_widget_show (priv->label_name);
-
-  gtk_box_pack_start (GTK_BOX (vbox), align, TRUE, TRUE, 0);
+  gtk_grid_attach (GTK_GRID (grid), priv->label_name, 1, 0, 1, 1);
 
   /* second row */
-  align = gtk_alignment_new (0.5, 0.0, 0.0, 0.0);
-  gtk_widget_show (align);
-  hbox = gtk_hbox_new (FALSE, 6);
-  gtk_widget_show (hbox);
-  gtk_container_add (GTK_CONTAINER (align), hbox);
-
-  gtk_box_pack_start (GTK_BOX (vbox), align, TRUE, TRUE, 0);
+  hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
+  gtk_widget_set_hexpand (hbox, TRUE);
+  gtk_widget_set_halign (hbox, GTK_ALIGN_CENTER);
+  gtk_grid_attach (GTK_GRID (grid), hbox, 1, 1, 1, 1);
 
   /* set up spinner */
-  priv->throbber = ephy_spinner_new ();
-  ephy_spinner_set_size (EPHY_SPINNER (priv->throbber), GTK_ICON_SIZE_SMALL_TOOLBAR);
+  priv->throbber = gtk_spinner_new ();
 
   priv->image_status = gtk_image_new_from_icon_name (
             empathy_icon_name_for_presence (
@@ -2056,21 +2294,34 @@ accounts_dialog_build_ui (EmpathyAccountsDialog *dialog)
 
   priv->label_status = gtk_label_new (NULL);
   gtk_label_set_line_wrap (GTK_LABEL (priv->label_status), TRUE);
-  gtk_widget_show (priv->label_status);
 
   gtk_box_pack_start (GTK_BOX (hbox), priv->throbber, FALSE, FALSE, 0);
-  gtk_box_pack_start (GTK_BOX (hbox), priv->image_status, FALSE, FALSE, 3);
-  gtk_box_pack_start (GTK_BOX (hbox), priv->label_status, TRUE, TRUE, 0);
+  gtk_box_pack_start (GTK_BOX (hbox), priv->image_status, FALSE, FALSE, 0);
+  gtk_box_pack_start (GTK_BOX (hbox), priv->label_status, FALSE, FALSE, 0);
+
+  /* enabled switch */
+  priv->enabled_switch = gtk_switch_new ();
+  gtk_widget_set_valign (priv->enabled_switch, GTK_ALIGN_CENTER);
+  g_signal_connect (priv->enabled_switch, "notify::active",
+      G_CALLBACK (accounts_dialog_enable_switch_active_cb), dialog);
+  gtk_grid_attach (GTK_GRID (grid), priv->enabled_switch, 2, 0, 1, 2);
+
+  gtk_widget_show_all (grid);
 
   /* Tweak the dialog */
-  gtk_window_set_title (GTK_WINDOW (dialog), _("Accounts"));
+  gtk_window_set_title (GTK_WINDOW (dialog), _("Messaging and VoIP Accounts"));
   gtk_window_set_role (GTK_WINDOW (dialog), "accounts");
 
-  gtk_window_set_default_size (GTK_WINDOW (dialog), 640, -1);
+  gtk_window_set_default_size (GTK_WINDOW (dialog), 640, 450);
 
   gtk_window_set_type_hint (GTK_WINDOW (dialog), GDK_WINDOW_TYPE_HINT_DIALOG);
 
-  gtk_dialog_set_has_separator (GTK_DIALOG (dialog), FALSE);
+  /* join the add/remove toolbar to the treeview */
+  context = gtk_widget_get_style_context (sw);
+  gtk_style_context_set_junction_sides (context, GTK_JUNCTION_BOTTOM);
+
+  context = gtk_widget_get_style_context (toolbar);
+  gtk_style_context_set_junction_sides (context, GTK_JUNCTION_TOP);
 
   /* add dialog buttons */
   gtk_button_box_set_layout (GTK_BUTTON_BOX (action_area), GTK_BUTTONBOX_END);
@@ -2092,38 +2343,12 @@ do_dispose (GObject *obj)
 {
   EmpathyAccountsDialog *dialog = EMPATHY_ACCOUNTS_DIALOG (obj);
   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
-  GtkTreeModel *model;
-
-  if (priv->dispose_has_run)
-    return;
-
-  priv->dispose_has_run = TRUE;
-
-  /* Disconnect signals */
-  model = gtk_tree_view_get_model (GTK_TREE_VIEW (priv->treeview));
-  g_signal_handlers_disconnect_by_func (model,
-      accounts_dialog_accounts_model_row_inserted_cb, dialog);
-  g_signal_handlers_disconnect_by_func (model,
-      accounts_dialog_accounts_model_row_deleted_cb, dialog);
 
-  g_signal_handlers_disconnect_by_func (priv->account_manager,
-      accounts_dialog_account_validity_changed_cb,
-      dialog);
-  g_signal_handlers_disconnect_by_func (priv->account_manager,
-      accounts_dialog_account_removed_cb,
-      dialog);
-  g_signal_handlers_disconnect_by_func (priv->account_manager,
-      accounts_dialog_account_enabled_cb,
-      dialog);
-  g_signal_handlers_disconnect_by_func (priv->account_manager,
-      accounts_dialog_account_disabled_cb,
-      dialog);
-  g_signal_handlers_disconnect_by_func (priv->account_manager,
-      accounts_dialog_manager_ready_cb,
-      dialog);
-
-  if (priv->connecting_id)
-    g_source_remove (priv->connecting_id);
+  if (priv->connecting_id != 0)
+    {
+      g_source_remove (priv->connecting_id);
+      priv->connecting_id = 0;
+    }
 
   if (priv->account_manager != NULL)
     {
@@ -2137,9 +2362,17 @@ do_dispose (GObject *obj)
       priv->cms = NULL;
     }
 
+  if (priv->connectivity)
+    {
+      g_object_unref (priv->connectivity);
+      priv->connectivity = NULL;
+    }
+
   if (priv->initial_selection != NULL)
-    g_object_unref (priv->initial_selection);
-  priv->initial_selection = NULL;
+    {
+      g_object_unref (priv->initial_selection);
+      priv->initial_selection = NULL;
+    }
 
   G_OBJECT_CLASS (empathy_accounts_dialog_parent_class)->dispose (obj);
 }
@@ -2185,7 +2418,6 @@ do_constructed (GObject *object)
 {
   EmpathyAccountsDialog *dialog = EMPATHY_ACCOUNTS_DIALOG (object);
   EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
-  gboolean import_asked;
   GtkTreeModel *model;
 
   accounts_dialog_build_ui (dialog);
@@ -2200,27 +2432,10 @@ do_constructed (GObject *object)
   /* Set up signalling */
   priv->account_manager = tp_account_manager_dup ();
 
-  tp_account_manager_prepare_async (priv->account_manager, NULL,
+  tp_proxy_prepare_async (priv->account_manager, NULL,
       accounts_dialog_manager_ready_cb, dialog);
 
-  empathy_conf_get_bool (empathy_conf_get (),
-      EMPATHY_PREFS_IMPORT_ASKED, &import_asked);
-
-  if (empathy_import_accounts_to_import ())
-    {
-      gtk_widget_show (priv->button_import);
-
-      if (!import_asked)
-        {
-          GtkWidget *import_dialog;
-
-          empathy_conf_set_bool (empathy_conf_get (),
-              EMPATHY_PREFS_IMPORT_ASKED, TRUE);
-          import_dialog = empathy_import_dialog_new (GTK_WINDOW (dialog),
-              FALSE);
-          gtk_widget_show (import_dialog);
-        }
-    }
+  priv->connectivity = empathy_connectivity_dup_singleton ();
 }
 
 static void
@@ -2286,70 +2501,48 @@ empathy_accounts_dialog_show (GtkWindow *parent,
 
 void
 empathy_accounts_dialog_show_application (GdkScreen *screen,
-    GChildWatchFunc application_exit_cb,
-    gpointer user_data,
     TpAccount *selected_account,
     gboolean if_needed,
     gboolean hidden)
 {
-  gint command_pid;
-  GError *error = NULL;
-  gchar *argv[4] = { NULL, };
-  gint i = 0;
-  gchar *account_option = NULL;
-  gchar *path;
+  GString *args;
 
-  g_return_if_fail (GDK_IS_SCREEN (screen));
   g_return_if_fail (!selected_account || TP_IS_ACCOUNT (selected_account));
 
-  /* Try to run from source directory if possible */
-  path = g_build_filename (g_getenv ("EMPATHY_SRCDIR"), "src",
-      "empathy-accounts", NULL);
-
-  if (!g_file_test (path, G_FILE_TEST_EXISTS))
-    {
-      g_free (path);
-      path = g_build_filename (BIN_DIR, "empathy-accounts", NULL);
-    }
+  args = g_string_new (NULL);
 
-  argv[i++] = path;
-
-  if (selected_account)
-    {
-      const gchar *account_path;
-
-      account_path = tp_proxy_get_object_path (TP_PROXY (selected_account));
-      account_option = g_strdup_printf ("--select-account=%s",
-          &account_path[strlen (TP_ACCOUNT_OBJECT_PATH_BASE)]);
-
-      argv[i++] = account_option;
-    }
+  if (selected_account != NULL)
+    g_string_append_printf (args, " --select-account=%s",
+        tp_account_get_path_suffix (selected_account));
 
   if (if_needed)
-    argv[i++] = "--if-needed";
+    g_string_append_printf (args, " --if-needed");
 
   if (hidden)
-    argv[i++] = "--hidden";
+    g_string_append_printf (args, " --hidden");
 
   DEBUG ("Launching empathy-accounts (if_needed: %d, hidden: %d, account: %s)",
     if_needed, hidden,
     selected_account == NULL ? "<none selected>" :
       tp_proxy_get_object_path (TP_PROXY (selected_account)));
 
-  gdk_spawn_on_screen (screen, NULL, argv, NULL,
-      G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL,
-      &command_pid, &error);
-  if (error)
-    {
-      g_warning ("Failed to open accounts dialog: %s", error->message);
-      g_error_free (error);
-    }
+  empathy_launch_program (BIN_DIR, "empathy-accounts", args->str);
 
-  /* XXX: unportable cast to GPid; then again, gdk_spawn_on_screen() seems
-   * unportable since it always takes a gint* for the PID */
-  if (application_exit_cb)
-    g_child_watch_add ((GPid) command_pid, application_exit_cb, NULL);
+  g_string_free (args, TRUE);
+}
+
+gboolean
+empathy_accounts_dialog_is_creating (EmpathyAccountsDialog *dialog)
+{
+  EmpathyAccountsDialogPriv *priv = GET_PRIV (dialog);
+  gboolean result = FALSE;
+
+  if (priv->setting_widget_object == NULL)
+    goto out;
+
+  g_object_get (priv->setting_widget_object,
+      "creating-account", &result, NULL);
 
-  g_free (account_option);
-  g_free (path);
+out:
+  return result;
 }