+
+#if HAVE_GEOCLUE
+#define GEOCODE_SERVICE "org.freedesktop.Geoclue.Providers.Yahoo"
+#define GEOCODE_PATH "/org/freedesktop/Geoclue/Providers/Yahoo"
+
+/* This callback is called by geoclue when it found a position
+ * for the given address. A position is necessary for a contact
+ * to show up on the map
+ */
+static void
+geocode_cb (GeoclueGeocode *geocode,
+ GeocluePositionFields fields,
+ double latitude,
+ double longitude,
+ double altitude,
+ GeoclueAccuracy *accuracy,
+ GError *error,
+ gpointer contact)
+{
+ EmpathyContactPriv *priv = GET_PRIV (contact);
+ GHashTable *new_location;
+
+ if (priv->location == NULL)
+ goto out;
+
+ if (error != NULL)
+ {
+ DEBUG ("Error geocoding location : %s", error->message);
+ goto out;
+ }
+
+ /* No need to change location if we didn't find the position */
+ if (!(fields & GEOCLUE_POSITION_FIELDS_LATITUDE))
+ goto out;
+
+ if (!(fields & GEOCLUE_POSITION_FIELDS_LONGITUDE))
+ goto out;
+
+ new_location = tp_asv_new (
+ EMPATHY_LOCATION_LAT, G_TYPE_DOUBLE, latitude,
+ EMPATHY_LOCATION_LON, G_TYPE_DOUBLE, longitude,
+ NULL);
+
+ DEBUG ("\t - Latitude: %f", latitude);
+ DEBUG ("\t - Longitude: %f", longitude);
+
+ /* Copy remaning fields. LAT and LON were not defined so we won't overwrite
+ * the values we just set. */
+ tp_g_hash_table_update (new_location, priv->location,
+ (GBoxedCopyFunc) g_strdup, (GBoxedCopyFunc) tp_g_value_slice_dup);
+
+ /* Set the altitude only if it wasn't defined before */
+ if (fields & GEOCLUE_POSITION_FIELDS_ALTITUDE &&
+ g_hash_table_lookup (new_location, EMPATHY_LOCATION_ALT) == NULL)
+ {
+ tp_asv_set_double (new_location, g_strdup (EMPATHY_LOCATION_ALT),
+ altitude);
+ DEBUG ("\t - Altitude: %f", altitude);
+ }
+
+ /* Don't change the accuracy as we used an address to get this position */
+ g_hash_table_unref (priv->location);
+ priv->location = new_location;
+ g_object_notify (contact, "location");
+out:
+ g_object_unref (geocode);
+ g_object_unref (contact);
+}
+
+static gchar *
+get_dup_string (GHashTable *location,
+ gchar *key)
+{
+ GValue *value;
+
+ value = g_hash_table_lookup (location, key);
+ if (value != NULL)
+ return g_value_dup_string (value);
+
+ return NULL;
+}
+
+static void
+update_geocode (EmpathyContact *contact)
+{
+ static GeoclueGeocode *geocode;
+ gchar *str;
+ GHashTable *address;
+ GHashTable *location;
+
+ location = empathy_contact_get_location (contact);
+ if (location == NULL)
+ return;
+
+ /* No need to search for position if contact published it */
+ if (g_hash_table_lookup (location, EMPATHY_LOCATION_LAT) != NULL ||
+ g_hash_table_lookup (location, EMPATHY_LOCATION_LON) != NULL)
+ return;
+
+ if (geocode == NULL)
+ {
+ geocode = geoclue_geocode_new (GEOCODE_SERVICE, GEOCODE_PATH);
+ g_object_add_weak_pointer (G_OBJECT (geocode), (gpointer *) &geocode);
+ }
+ else
+ {
+ g_object_ref (geocode);
+ }
+
+ address = geoclue_address_details_new ();
+
+ str = get_dup_string (location, EMPATHY_LOCATION_COUNTRY_CODE);
+ if (str != NULL)
+ {
+ g_hash_table_insert (address,
+ g_strdup (GEOCLUE_ADDRESS_KEY_COUNTRYCODE), str);
+ DEBUG ("\t - countrycode: %s", str);
+ }
+
+ str = get_dup_string (location, EMPATHY_LOCATION_COUNTRY);
+ if (str != NULL)
+ {
+ g_hash_table_insert (address,
+ g_strdup (GEOCLUE_ADDRESS_KEY_COUNTRY), str);
+ DEBUG ("\t - country: %s", str);
+ }
+
+ str = get_dup_string (location, EMPATHY_LOCATION_POSTAL_CODE);
+ if (str != NULL)
+ {
+ g_hash_table_insert (address,
+ g_strdup (GEOCLUE_ADDRESS_KEY_POSTALCODE), str);
+ DEBUG ("\t - postalcode: %s", str);
+ }
+
+ str = get_dup_string (location, EMPATHY_LOCATION_REGION);
+ if (str != NULL)
+ {
+ g_hash_table_insert (address,
+ g_strdup (GEOCLUE_ADDRESS_KEY_REGION), str);
+ DEBUG ("\t - region: %s", str);
+ }
+
+ str = get_dup_string (location, EMPATHY_LOCATION_LOCALITY);
+ if (str != NULL)
+ {
+ g_hash_table_insert (address,
+ g_strdup (GEOCLUE_ADDRESS_KEY_LOCALITY), str);
+ DEBUG ("\t - locality: %s", str);
+ }
+
+ str = get_dup_string (location, EMPATHY_LOCATION_STREET);
+ if (str != NULL)
+ {
+ g_hash_table_insert (address,
+ g_strdup (GEOCLUE_ADDRESS_KEY_STREET), str);
+ DEBUG ("\t - street: %s", str);
+ }
+
+ if (g_hash_table_size (address) > 0)
+ {
+ g_object_ref (contact);
+
+ geoclue_geocode_address_to_position_async (geocode, address,
+ geocode_cb, contact);
+ }
+
+ g_hash_table_unref (address);
+}
+#endif
+
+static EmpathyCapabilities
+tp_caps_to_capabilities (TpCapabilities *caps)
+{
+ EmpathyCapabilities capabilities = 0;
+ guint i;
+ GPtrArray *classes;
+
+ classes = tp_capabilities_get_channel_classes (caps);
+
+ for (i = 0; i < classes->len; i++)
+ {
+ GValueArray *class_struct;
+ GHashTable *fixed_prop;
+ GStrv allowed_prop;
+ TpHandleType handle_type;
+ const gchar *chan_type;
+
+ class_struct = g_ptr_array_index (classes, i);
+ tp_value_array_unpack (class_struct, 2,
+ &fixed_prop,
+ &allowed_prop);
+
+ handle_type = tp_asv_get_uint32 (fixed_prop,
+ TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, NULL);
+ if (handle_type != TP_HANDLE_TYPE_CONTACT)
+ continue;
+
+ chan_type = tp_asv_get_string (fixed_prop,
+ TP_PROP_CHANNEL_CHANNEL_TYPE);
+
+ if (!tp_strdiff (chan_type, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER))
+ {
+ capabilities |= EMPATHY_CAPABILITIES_FT;
+ }
+ else if (!tp_strdiff (chan_type, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE))
+ {
+ const gchar *service;
+
+ service = tp_asv_get_string (fixed_prop,
+ TP_PROP_CHANNEL_TYPE_STREAM_TUBE_SERVICE);
+
+ if (!tp_strdiff (service, "rfb"))
+ capabilities |= EMPATHY_CAPABILITIES_RFB_STREAM_TUBE;
+ }
+ else if (!tp_strdiff (chan_type,
+ TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA))
+ {
+ guint j;
+
+ for (j = 0; allowed_prop[j] != NULL; j++)
+ {
+ if (!tp_strdiff (allowed_prop[j],
+ TP_PROP_CHANNEL_TYPE_STREAMED_MEDIA_INITIAL_AUDIO))
+ capabilities |= EMPATHY_CAPABILITIES_AUDIO;
+ else if (!tp_strdiff (allowed_prop[j],
+ TP_PROP_CHANNEL_TYPE_STREAMED_MEDIA_INITIAL_VIDEO))
+ capabilities |= EMPATHY_CAPABILITIES_VIDEO;
+ }
+ }
+ }
+
+ return capabilities;
+}
+
+static void
+set_capabilities_from_tp_caps (EmpathyContact *self,
+ TpCapabilities *caps)
+{
+ EmpathyCapabilities capabilities;
+
+ if (caps == NULL)
+ return;
+
+ capabilities = tp_caps_to_capabilities (caps);
+ empathy_contact_set_capabilities (self, capabilities);
+}
+
+static void
+contact_set_avatar_from_tp_contact (EmpathyContact *contact)
+{
+ EmpathyContactPriv *priv = GET_PRIV (contact);
+ const gchar *mime;
+ const gchar *token;
+ GFile *file;
+
+ token = tp_contact_get_avatar_token (priv->tp_contact);
+ mime = tp_contact_get_avatar_mime_type (priv->tp_contact);
+ file = tp_contact_get_avatar_file (priv->tp_contact);
+
+ if (file != NULL)
+ {
+ EmpathyAvatar *avatar;
+ gchar *data;
+ gsize len;
+
+ g_file_load_contents (file, NULL, &data, &len, NULL, NULL);
+ avatar = empathy_avatar_new ((guchar *) data, len, g_strdup (mime), g_strdup (token),
+ g_file_get_path (file));
+ empathy_contact_set_avatar (contact, avatar);
+ empathy_avatar_unref (avatar);
+ }
+ else
+ {
+ empathy_contact_set_avatar (contact, NULL);
+ }
+}
+
+EmpathyContact *
+empathy_contact_dup_from_tp_contact (TpContact *tp_contact)
+{
+ EmpathyContact *contact = NULL;
+
+ g_return_val_if_fail (TP_IS_CONTACT (tp_contact), NULL);
+
+ if (contacts_table == NULL)
+ contacts_table = g_hash_table_new (g_direct_hash, g_direct_equal);
+ else
+ contact = g_hash_table_lookup (contacts_table, tp_contact);
+
+ if (contact == NULL)
+ {
+ contact = empathy_contact_new (tp_contact);
+
+ /* The hash table does not keep any ref.
+ * contact keeps a ref to tp_contact, and is removed from the table in
+ * contact_dispose() */
+ g_hash_table_insert (contacts_table, tp_contact, contact);
+ }
+ else
+ {
+ g_object_ref (contact);
+ }
+
+ return contact;
+}
+