aboutsummaryrefslogblamecommitdiffstats
path: root/src/empathy-import-mc4-accounts.c
blob: 6f2a02c831c16cacf95485be929cc6ef4c3c145d (plain) (tree)




















                                                                     
                  

                   
                       

                                
                               
                          
                                               
                                                







                                                            
                                                                            








                                                      

                     
                        
                        
                            

                        

  





                                                   
                                                            
























                                             

                                                    
 

                                           
 
                                                  

 


                                                               
 
                                                              
           

                                   



                                           


                                                                       
         







                                                               


         

                                                                          
 

                                                                 






                                    


                          

                                                         


                                                     

                           


                              



                                                  
 

                          

 

                                                 
 
         
 
                                   
 


                                                               
 

                            
 
           




























                                                                           



                         
 





                                                                          
 



                           
         


                                                                       
         

                            
         


                                                                       
         
                            
         

                                                   
 






                                                                             
                
         
                             
         

                                             
 

                                                                  
         



                                                              
 
           

                                                                    

              
 

                                                   
 

                        
 

                                                                 
 
                                             
         

                                                                           

         



                                
 
               













                                                      
                       
 
                                                           
 


                                                        
 




                                                     
 






                                                                    
 


                                                             
 

                                                           
 

                                                                            
 


                                                                     
 
                                                            
 

                      
 


                                                                

     
                                                     





                                                         

             




                         

             





                                      

 
        













                                                                    
                                                                 


                       
                            
                                 
                            
 

                                                                        
 

                                       

                                                        



                                                                            
                           
               

     
                            
     
                                                 
               







                                                                        
                                                    


                              
               



                                                

                                                                    
                         

     
    

                                                                    
                      
                          
                  
 
/*
 * Copyright (C) 2008 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 <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" },
};

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;

 account_name = _account_name_from_key (key);
 base = strstr (key, account_name);
 slash = strchr (base, '/');
 g_free (account_name);

 return g_strdup (slash+1);
}

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 account */
      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
_create_account_cb (GObject *source,
  GAsyncResult *result,
  gpointer user_data)
{
  EmpathyAccount *account;
  GError *error = NULL;

  if (!empathy_account_settings_apply_finish (
      EMPATHY_ACCOUNT_SETTINGS (source), result, &error))
    {
      DEBUG ("Failed to create account: %s",
          error ? error->message : "No error given");
      g_error_free (error);
      goto out;
    }

  DEBUG ("account created\n");
  account = empathy_account_settings_get_account (
    EMPATHY_ACCOUNT_SETTINGS (source));
  empathy_account_set_enabled_async (account,
      GPOINTER_TO_INT (user_data), NULL, NULL);

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;

  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);
  empathy_account_settings_apply_async (settings,
          _create_account_cb, GINT_TO_POINTER (enabled));
  ret = TRUE;

out:
  g_free (protocol);
  g_free (profile);
  g_slist_free (entries);
  g_free (account_name);

  return ret;

failed:
  DEBUG ("Failed to import %s", path);
  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;
}