diff options
Diffstat (limited to 'src/empathy-import-mc4-accounts.c')
-rw-r--r-- | src/empathy-import-mc4-accounts.c | 531 |
1 files changed, 531 insertions, 0 deletions
diff --git a/src/empathy-import-mc4-accounts.c b/src/empathy-import-mc4-accounts.c new file mode 100644 index 000000000..968293bd2 --- /dev/null +++ b/src/empathy-import-mc4-accounts.c @@ -0,0 +1,531 @@ +/* + * Copyright (C) 2009 Collabora Ltd. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * Authors: Arnaud Maillet <arnaud.maillet@collabora.co.uk> + */ + +#include <stdio.h> +#include <string.h> +#include <glib.h> +#include <glib/gi18n.h> +#include <gconf/gconf-client.h> +#include <telepathy-glib/util.h> +#include <telepathy-glib/defs.h> +#include <dbus/dbus-protocol.h> +#include <gnome-keyring.h> +#include <libempathy/empathy-account-manager.h> +#include <libempathy/empathy-account-settings.h> +#include <libempathy/empathy-connection-managers.h> + +#include "empathy-import-mc4-accounts.h" + +#define DEBUG_FLAG EMPATHY_DEBUG_IMPORT_MC4_ACCOUNTS +#include <libempathy/empathy-debug.h> + +#define MC_ACCOUNTS_GCONF_BASE "/apps/telepathy/mc/accounts" +#define IMPORTED_MC4_ACCOUNTS "/apps/empathy/accounts/imported_mc4_accounts" + +typedef struct +{ + gchar *profile; + gchar *protocol; +} ProfileProtocolMapItem; + +static ProfileProtocolMapItem profile_protocol_map[] = +{ + { "ekiga", "sip" }, + { "fwd", "sip" }, + { "gtalk", "jabber" }, + { "msn-haze", "msn" }, + { "salut", "local-xmpp" }, + { "sipphone", "sip" }, + { "sofiasip", "sip" }, +}; + +typedef struct { + gchar *account_name; + gboolean enable; +} Misc; + +static gchar * +_account_name_from_key (const gchar *key) +{ + guint base_len = strlen (MC_ACCOUNTS_GCONF_BASE); + const gchar *base, *slash; + + g_assert (g_str_has_prefix (key, MC_ACCOUNTS_GCONF_BASE)); + g_assert (strlen (key) > base_len + 1); + + base = key + base_len + 1; + slash = strchr (base, '/'); + + if (slash == NULL) + return g_strdup (base); + else + return g_strndup (base, slash - base); +} + +static gchar * +_param_name_from_key (const gchar *key) +{ + const gchar *base, *slash; + gchar *account_name; + gchar *ret; + + account_name = _account_name_from_key (key); + base = strstr (key, account_name); + slash = strchr (base, '/'); + + ret = g_strdup (slash+1); + g_free (account_name); + + return ret; +} + +static gchar * +_create_default_display_name (const gchar *protocol) +{ + if (!tp_strdiff (protocol, "local-xmpp")) + return g_strdup (_("People Nearby")); + + return g_strdup_printf (_("%s account"), protocol); +} + +static const gchar * +_get_manager_for_protocol (EmpathyConnectionManagers *managers, + const gchar *protocol) +{ + GList *cms = empathy_connection_managers_get_cms (managers); + GList *l; + TpConnectionManager *haze = NULL; + TpConnectionManager *cm = NULL; + + for (l = cms; l; l = l->next) + { + TpConnectionManager *tp_cm = l->data; + + /* Only use haze if no other cm provides this protocol */ + if (!tp_strdiff (tp_connection_manager_get_name (tp_cm), "haze")) + { + haze = tp_cm; + continue; + } + + if (tp_connection_manager_has_protocol (tp_cm, protocol)) + { + cm = tp_cm; + goto out; + } + } + + if (haze != NULL && tp_connection_manager_has_protocol (haze, protocol)) + return tp_connection_manager_get_name (haze); + +out: + return cm != NULL ? tp_connection_manager_get_name (cm) : NULL; +} + +static void +_move_contents (const gchar *old, const gchar *new) +{ + GDir *source; + const gchar *f; + int ret; + + ret = g_mkdir_with_parents (new, 0777); + if (ret == -1) + return; + + source = g_dir_open (old, 0, NULL); + if (source == NULL) + return; + + while ((f = g_dir_read_name (source)) != NULL) + { + gchar *old_path; + gchar *new_path; + + old_path = g_build_path (G_DIR_SEPARATOR_S, old, f, NULL); + new_path = g_build_path (G_DIR_SEPARATOR_S, new, f, NULL); + + if (g_file_test (old_path, G_FILE_TEST_IS_DIR)) + { + _move_contents (old_path, new_path); + } + else + { + GFile *f_old, *f_new; + + f_old = g_file_new_for_path (old_path); + f_new = g_file_new_for_path (new_path); + + g_file_move (f_old, f_new, G_FILE_COPY_NONE, + NULL, NULL, NULL, NULL); + + g_object_unref (f_old); + g_object_unref (f_new); + } + + g_free (old_path); + g_free (new_path); + } + + g_dir_close (source); +} + +static void +_move_logs (EmpathyAccount *account, const gchar *account_name) +{ + gchar *old_path, *new_path, *escaped; + const gchar *name; + + name = empathy_account_get_unique_name (account); + if (g_str_has_prefix (name, TP_ACCOUNT_OBJECT_PATH_BASE)) + name += strlen (TP_ACCOUNT_OBJECT_PATH_BASE); + + escaped = g_strdelimit (g_strdup (name), "/", '_'); + new_path = g_build_path (G_DIR_SEPARATOR_S, g_get_user_data_dir (), + PACKAGE_NAME, "logs", escaped, NULL); + g_free (escaped); + + old_path = g_build_path (G_DIR_SEPARATOR_S, + g_get_home_dir (), + ".gnome2", PACKAGE_NAME, "logs", account_name, NULL); + + _move_contents (old_path, new_path); +} + +static void +_create_account_cb (GObject *source, + GAsyncResult *result, + gpointer user_data) +{ + EmpathyAccount *account; + GError *error = NULL; + Misc *misc = (Misc *) user_data; + + if (!empathy_account_settings_apply_finish ( + EMPATHY_ACCOUNT_SETTINGS (source), result, &error)) + { + DEBUG ("Failed to create account: %s", error->message); + g_error_free (error); + goto out; + } + + DEBUG ("account created\n"); + account = empathy_account_settings_get_account ( + EMPATHY_ACCOUNT_SETTINGS (source)); + + _move_logs (account, misc->account_name); + + empathy_account_set_enabled_async (account, + misc->enable, NULL, NULL); + + g_free (misc->account_name); + g_slice_free (Misc, misc); + +out: + g_object_unref (source); +} + +static gchar * +_get_protocol_from_profile (const gchar *profile) +{ + gint i; + + DEBUG ("profile: %s\n", profile); + + for (i = 0; i < G_N_ELEMENTS (profile_protocol_map); i++) + if (!tp_strdiff (profile, profile_protocol_map[i].profile)) + return g_strdup (profile_protocol_map[i].protocol); + + return g_strdup (profile); +} + +static void +_set_password_from_keyring (EmpathyAccountSettings *settings, + const gchar *account_name, const gchar *key) +{ + GnomeKeyringResult res; + gchar *password; + GnomeKeyringPasswordSchema keyring_schema = { + GNOME_KEYRING_ITEM_GENERIC_SECRET, + { + { "account", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, + { "param", GNOME_KEYRING_ATTRIBUTE_TYPE_STRING }, + { NULL, 0 } + } + }; + + res = gnome_keyring_find_password_sync (&keyring_schema, + &password, + "account", account_name, + "param", key, + NULL); + + if (res == GNOME_KEYRING_RESULT_OK) + { + empathy_account_settings_set_string (settings, key, password); + gnome_keyring_free_password (password); + } +} + +static void +_handle_entry (EmpathyAccountSettings *settings, const gchar *account_name, + const gchar *key, + GConfEntry *entry) +{ + const gchar *signature; + + signature = empathy_account_settings_get_dbus_signature (settings, key); + if (signature == NULL) + { + DEBUG ("Parameter %s is unknown", signature); + return; + } + + switch ((int)*signature) + { + case DBUS_TYPE_INT16: + case DBUS_TYPE_INT32: + { + gint v = gconf_value_get_int (gconf_entry_get_value (entry)); + empathy_account_settings_set_int32 (settings, key, v); + break; + } + case DBUS_TYPE_UINT16: + case DBUS_TYPE_UINT32: + { + gint v = gconf_value_get_int (gconf_entry_get_value (entry)); + empathy_account_settings_set_uint32 (settings, key, v); + break; + } + case DBUS_TYPE_STRING: + { + const gchar *v = gconf_value_get_string ( + gconf_entry_get_value (entry)); + + /* MC 4 would put password in the keyring and leave the password in + * gconf keyring */ + + if (!tp_strdiff (key, "password") && !tp_strdiff (v, "keyring")) + _set_password_from_keyring (settings, account_name, key); + else + empathy_account_settings_set_string (settings, key, v); + break; + } + case DBUS_TYPE_BOOLEAN: + { + gboolean v = gconf_value_get_bool ( + gconf_entry_get_value (entry)); + + empathy_account_settings_set_boolean (settings, key, v); + break; + } + default: + DEBUG ("Unsupported type in signature: %s", signature); + } +} + +static void +_recurse_account (GSList *entries, EmpathyAccountSettings *settings, + const gchar *account_name) +{ + GSList *tmp; + + for (tmp = entries; tmp != NULL; tmp = tmp->next) + { + + GConfEntry *entry; + gchar *param; + + entry = (GConfEntry *) tmp->data; + param = _param_name_from_key (gconf_entry_get_key (entry)); + + if (g_str_has_prefix (param, "param-")) + { + _handle_entry (settings, account_name, param + strlen ("param-"), + entry); + } + + g_free (param); + gconf_entry_unref (entry); + } +} + +static gboolean +import_one_account (const char *path, + EmpathyConnectionManagers *managers, + GConfClient *client) +{ + gchar *account_name = _account_name_from_key (path); + EmpathyAccountSettings *settings; + GError *error = NULL; + GSList *entries = NULL; + gchar *profile = NULL; + gchar *protocol = NULL; + const gchar *manager; + gchar *display_name; + gchar *key; + gboolean enabled = FALSE; + gboolean ret = FALSE; + Misc *misc; + + DEBUG ("Starting import of %s (%s)", path, account_name); + + key = g_strdup_printf ("%s/profile", path); + profile = gconf_client_get_string (client, key, NULL); + g_free (key); + + if (profile == NULL) + { + DEBUG ("Account is missing a profile entry\n"); + goto failed; + } + + protocol = _get_protocol_from_profile (profile); + manager = _get_manager_for_protocol (managers, protocol); + if (manager == NULL) + { + DEBUG ("No manager available for this protocol %s", protocol); + goto failed; + } + + key = g_strdup_printf ("%s/display_name", path); + display_name = gconf_client_get_string (client, key, NULL); + g_free (key); + + if (display_name == NULL) + display_name = _create_default_display_name (protocol); + + settings = empathy_account_settings_new (manager, protocol, display_name); + g_free (display_name); + + /* Bit of a hack, as we know EmpathyConnectionManagers is ready the + * EmpathyAccountSettings should be ready right away as well */ + g_assert (empathy_account_settings_is_ready (settings)); + + entries = gconf_client_all_entries (client, path, &error); + + if (entries == NULL) + { + DEBUG ("Failed to get all entries: %s\n", error->message); + g_error_free (error); + goto failed; + } + + _recurse_account (entries, settings, account_name); + + key = g_strdup_printf ("%s/enabled", path); + enabled = gconf_client_get_bool (client, key, NULL); + g_free (key); + + misc = g_slice_new (Misc); + misc->account_name = account_name; + misc->enable = enabled; + + empathy_account_settings_apply_async (settings, + _create_account_cb, misc); + ret = TRUE; + +out: + g_free (protocol); + g_free (profile); + g_slist_free (entries); + + return ret; + +failed: + DEBUG ("Failed to import %s", path); + g_free (account_name); + if (settings != NULL) + g_object_unref (settings); + goto out; +} + +gboolean +empathy_import_mc4_has_imported (void) +{ + GConfClient *client; + gboolean ret; + + client = gconf_client_get_default (); + + ret = gconf_client_get_bool (client, IMPORTED_MC4_ACCOUNTS, NULL); + g_object_unref (client); + + return ret; +} + +gboolean +empathy_import_mc4_accounts (EmpathyConnectionManagers *managers) +{ + GConfClient *client; + GError *error = NULL; + GSList *dir, *dirs = NULL; + gboolean imported_mc4_accounts; + gboolean imported = FALSE; + + g_return_val_if_fail (empathy_connection_managers_is_ready (managers), + FALSE); + + client = gconf_client_get_default (); + + imported_mc4_accounts = gconf_client_get_bool (client, + IMPORTED_MC4_ACCOUNTS, &error); + + if (error != NULL) + { + DEBUG ("Failed to get import_mc4_accounts key: %s\n", error->message); + g_error_free (error); + goto out; + } + + if (imported_mc4_accounts) + { + DEBUG ("Mc4 accounts previously imported"); + goto out; + } + + DEBUG ("MC 4 accounts are going to be imported\n"); + + dirs = gconf_client_all_dirs (client, MC_ACCOUNTS_GCONF_BASE, &error); + + if (error != NULL) + { + DEBUG ("Failed to get MC4 account dirs: %s\n", + error->message); + g_clear_error (&error); + g_object_unref (client); + goto out; + } + + for (dir = dirs; NULL != dir; dir = dir->next) + { + if (import_one_account ((gchar *) dir->data, managers, client)) + imported = TRUE; + g_free (dir->data); + } + +out: + gconf_client_set_bool (client, IMPORTED_MC4_ACCOUNTS, TRUE, NULL); + + g_slist_free (dirs); + g_object_unref (client); + return imported; +} |