1 /* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2; -*- */
3 * Copyright (C) 2007-2009 Collabora Ltd.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 * Authors: Xavier Claessens <xclaesse@gmail.com>
26 #include <glib/gi18n-lib.h>
28 #include <telepathy-glib/account-manager.h>
29 #include <telepathy-glib/interfaces.h>
30 #include <telepathy-glib/util.h>
32 #include <telepathy-logger/contact.h>
33 #endif /* ENABLE_TPL */
36 #include <geoclue/geoclue-geocode.h>
39 #include "empathy-contact.h"
40 #include "empathy-utils.h"
41 #include "empathy-enum-types.h"
42 #include "empathy-marshal.h"
43 #include "empathy-location.h"
45 #define DEBUG_FLAG EMPATHY_DEBUG_CONTACT
46 #include "empathy-debug.h"
48 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyContact)
50 TpContact *tp_contact;
54 EmpathyAvatar *avatar;
55 TpConnectionPresenceType presence;
56 gchar *presence_message;
58 EmpathyCapabilities capabilities;
61 /* Location is composed of string keys and GValues.
62 * Example: a "city" key would have "Helsinki" as string GValue,
63 * a "latitude" would have 65.0 as double GValue.
65 * This is a super set of the location stored in TpContact as we can try add
66 * more fields by searching the address using geoclue.
71 static void contact_finalize (GObject *object);
72 static void contact_get_property (GObject *object, guint param_id,
73 GValue *value, GParamSpec *pspec);
74 static void contact_set_property (GObject *object, guint param_id,
75 const GValue *value, GParamSpec *pspec);
78 static void update_geocode (EmpathyContact *contact);
81 static void empathy_contact_set_location (EmpathyContact *contact,
82 GHashTable *location);
84 static void set_capabilities_from_tp_caps (EmpathyContact *self,
85 TpCapabilities *caps);
87 static void contact_set_avatar_from_tp_contact (EmpathyContact *contact);
89 G_DEFINE_TYPE (EmpathyContact, empathy_contact, G_TYPE_OBJECT);
100 PROP_PRESENCE_MESSAGE,
112 static guint signals[LAST_SIGNAL];
115 tp_contact_notify_cb (TpContact *tp_contact,
119 EmpathyContactPriv *priv = GET_PRIV (contact);
121 /* Forward property notifications */
122 if (!tp_strdiff (param->name, "alias"))
123 g_object_notify (contact, "name");
124 else if (!tp_strdiff (param->name, "presence-type")) {
125 TpConnectionPresenceType presence;
127 presence = empathy_contact_get_presence (EMPATHY_CONTACT (contact));
128 g_signal_emit (contact, signals[PRESENCE_CHANGED], 0, presence,
130 priv->presence = presence;
131 g_object_notify (contact, "presence");
133 else if (!tp_strdiff (param->name, "presence-message"))
134 g_object_notify (contact, "presence-message");
135 else if (!tp_strdiff (param->name, "identifier"))
136 g_object_notify (contact, "id");
137 else if (!tp_strdiff (param->name, "handle"))
138 g_object_notify (contact, "handle");
139 else if (!tp_strdiff (param->name, "location"))
141 GHashTable *location;
143 location = tp_contact_get_location (tp_contact);
144 /* This will start a geoclue search to find the address if needed */
145 empathy_contact_set_location (EMPATHY_CONTACT (contact), location);
147 else if (!tp_strdiff (param->name, "capabilities"))
149 set_capabilities_from_tp_caps (EMPATHY_CONTACT (contact),
150 tp_contact_get_capabilities (tp_contact));
152 else if (!tp_strdiff (param->name, "avatar-file"))
154 contact_set_avatar_from_tp_contact (EMPATHY_CONTACT (contact));
159 contact_dispose (GObject *object)
161 EmpathyContactPriv *priv = GET_PRIV (object);
163 if (priv->tp_contact)
165 g_signal_handlers_disconnect_by_func (priv->tp_contact,
166 tp_contact_notify_cb, object);
167 g_object_unref (priv->tp_contact);
169 priv->tp_contact = NULL;
172 g_object_unref (priv->account);
173 priv->account = NULL;
175 if (priv->avatar != NULL)
177 empathy_avatar_unref (priv->avatar);
181 if (priv->location != NULL)
183 g_hash_table_unref (priv->location);
184 priv->location = NULL;
187 G_OBJECT_CLASS (empathy_contact_parent_class)->dispose (object);
191 empathy_contact_class_init (EmpathyContactClass *class)
193 GObjectClass *object_class;
195 object_class = G_OBJECT_CLASS (class);
197 object_class->finalize = contact_finalize;
198 object_class->dispose = contact_dispose;
199 object_class->get_property = contact_get_property;
200 object_class->set_property = contact_set_property;
202 g_object_class_install_property (object_class,
204 g_param_spec_object ("tp-contact",
206 "The TpContact associated with the contact",
208 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
210 g_object_class_install_property (object_class,
212 g_param_spec_object ("account",
214 "The account associated with the contact",
216 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
218 g_object_class_install_property (object_class,
220 g_param_spec_string ("id",
222 "String identifying contact",
224 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
226 g_object_class_install_property (object_class,
228 g_param_spec_string ("name",
230 "The name of the contact",
232 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
234 g_object_class_install_property (object_class,
236 g_param_spec_boxed ("avatar",
240 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
242 g_object_class_install_property (object_class,
244 g_param_spec_uint ("presence",
246 "Presence of contact",
247 TP_CONNECTION_PRESENCE_TYPE_UNSET,
248 NUM_TP_CONNECTION_PRESENCE_TYPES,
249 TP_CONNECTION_PRESENCE_TYPE_UNSET,
250 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
252 g_object_class_install_property (object_class,
253 PROP_PRESENCE_MESSAGE,
254 g_param_spec_string ("presence-message",
255 "Contact presence message",
256 "Presence message of contact",
258 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
260 g_object_class_install_property (object_class,
262 g_param_spec_uint ("handle",
264 "The handle of the contact",
268 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
270 g_object_class_install_property (object_class,
272 g_param_spec_flags ("capabilities",
273 "Contact Capabilities",
274 "Capabilities of the contact",
275 EMPATHY_TYPE_CAPABILITIES,
276 EMPATHY_CAPABILITIES_UNKNOWN,
277 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
279 g_object_class_install_property (object_class,
281 g_param_spec_boolean ("is-user",
283 "Is contact the user",
285 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
288 g_object_class_install_property (object_class,
290 g_param_spec_boxed ("location",
292 "Physical location of the contact",
294 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
296 signals[PRESENCE_CHANGED] =
297 g_signal_new ("presence-changed",
298 G_TYPE_FROM_CLASS (class),
302 _empathy_marshal_VOID__UINT_UINT,
307 g_type_class_add_private (object_class, sizeof (EmpathyContactPriv));
311 empathy_contact_init (EmpathyContact *contact)
313 EmpathyContactPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (contact,
314 EMPATHY_TYPE_CONTACT, EmpathyContactPriv);
316 contact->priv = priv;
318 priv->location = NULL;
322 contact_finalize (GObject *object)
324 EmpathyContactPriv *priv;
326 priv = GET_PRIV (object);
328 DEBUG ("finalize: %p", object);
332 g_free (priv->presence_message);
334 G_OBJECT_CLASS (empathy_contact_parent_class)->finalize (object);
338 set_tp_contact (EmpathyContact *contact,
339 TpContact *tp_contact)
341 EmpathyContactPriv *priv = GET_PRIV (contact);
342 GHashTable *location;
344 if (tp_contact == NULL)
347 g_assert (priv->tp_contact == NULL);
348 priv->tp_contact = g_object_ref (tp_contact);
349 priv->presence = empathy_contact_get_presence (contact);
351 location = tp_contact_get_location (tp_contact);
352 if (location != NULL)
353 empathy_contact_set_location (contact, location);
355 set_capabilities_from_tp_caps (contact,
356 tp_contact_get_capabilities (tp_contact));
358 contact_set_avatar_from_tp_contact (contact);
360 g_signal_connect (priv->tp_contact, "notify",
361 G_CALLBACK (tp_contact_notify_cb), contact);
365 contact_get_property (GObject *object,
370 EmpathyContact *contact = EMPATHY_CONTACT (object);
374 case PROP_TP_CONTACT:
375 g_value_set_object (value, empathy_contact_get_tp_contact (contact));
378 g_value_set_object (value, empathy_contact_get_account (contact));
381 g_value_set_string (value, empathy_contact_get_id (contact));
384 g_value_set_string (value, empathy_contact_get_name (contact));
387 g_value_set_boxed (value, empathy_contact_get_avatar (contact));
390 g_value_set_uint (value, empathy_contact_get_presence (contact));
392 case PROP_PRESENCE_MESSAGE:
393 g_value_set_string (value, empathy_contact_get_presence_message (contact));
396 g_value_set_uint (value, empathy_contact_get_handle (contact));
398 case PROP_CAPABILITIES:
399 g_value_set_flags (value, empathy_contact_get_capabilities (contact));
402 g_value_set_boolean (value, empathy_contact_is_user (contact));
405 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
411 contact_set_property (GObject *object,
416 EmpathyContact *contact = EMPATHY_CONTACT (object);
417 EmpathyContactPriv *priv = GET_PRIV (object);
421 case PROP_TP_CONTACT:
422 set_tp_contact (contact, g_value_get_object (value));
425 g_assert (priv->account == NULL);
426 priv->account = g_value_dup_object (value);
429 empathy_contact_set_id (contact, g_value_get_string (value));
432 empathy_contact_set_name (contact, g_value_get_string (value));
435 empathy_contact_set_avatar (contact, g_value_get_boxed (value));
438 empathy_contact_set_presence (contact, g_value_get_uint (value));
440 case PROP_PRESENCE_MESSAGE:
441 empathy_contact_set_presence_message (contact, g_value_get_string (value));
444 empathy_contact_set_handle (contact, g_value_get_uint (value));
446 case PROP_CAPABILITIES:
447 empathy_contact_set_capabilities (contact, g_value_get_flags (value));
450 empathy_contact_set_is_user (contact, g_value_get_boolean (value));
453 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
459 empathy_contact_new (TpContact *tp_contact)
461 g_return_val_if_fail (TP_IS_CONTACT (tp_contact), NULL);
463 return g_object_new (EMPATHY_TYPE_CONTACT,
464 "tp-contact", tp_contact,
470 empathy_contact_from_tpl_contact (TpAccount *account,
471 TplContact *tpl_contact)
473 EmpathyContact *retval;
476 g_return_val_if_fail (TPL_IS_CONTACT (tpl_contact), NULL);
478 is_user = (TPL_CONTACT_USER == tpl_contact_get_contact_type (tpl_contact));
480 retval = g_object_new (EMPATHY_TYPE_CONTACT,
481 "id", tpl_contact_get_alias (tpl_contact),
482 "name", tpl_contact_get_identifier (tpl_contact),
487 if (!EMP_STR_EMPTY (tpl_contact_get_avatar_token (tpl_contact)))
488 empathy_contact_load_avatar_cache (retval,
489 tpl_contact_get_avatar_token (tpl_contact));
493 #endif /* ENABLE_TPL */
496 empathy_contact_new_for_log (TpAccount *account,
501 g_return_val_if_fail (id != NULL, NULL);
502 g_assert (account != NULL);
504 return g_object_new (EMPATHY_TYPE_CONTACT,
513 empathy_contact_get_tp_contact (EmpathyContact *contact)
515 EmpathyContactPriv *priv;
517 g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
519 priv = GET_PRIV (contact);
521 return priv->tp_contact;
525 empathy_contact_get_id (EmpathyContact *contact)
527 EmpathyContactPriv *priv;
529 g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
531 priv = GET_PRIV (contact);
533 if (priv->tp_contact != NULL)
534 return tp_contact_get_identifier (priv->tp_contact);
540 empathy_contact_set_id (EmpathyContact *contact,
543 EmpathyContactPriv *priv;
545 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
546 g_return_if_fail (id != NULL);
548 priv = GET_PRIV (contact);
550 /* We temporally ref the contact because it could be destroyed
551 * during the signal emition */
552 g_object_ref (contact);
553 if (tp_strdiff (id, priv->id))
556 priv->id = g_strdup (id);
558 g_object_notify (G_OBJECT (contact), "id");
559 if (EMP_STR_EMPTY (priv->name))
560 g_object_notify (G_OBJECT (contact), "name");
563 g_object_unref (contact);
567 empathy_contact_get_name (EmpathyContact *contact)
569 EmpathyContactPriv *priv;
572 g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
574 priv = GET_PRIV (contact);
576 if (priv->tp_contact != NULL)
577 alias = tp_contact_get_alias (priv->tp_contact);
581 if (!EMP_STR_EMPTY (alias))
584 return empathy_contact_get_id (contact);
588 empathy_contact_set_name (EmpathyContact *contact,
591 EmpathyContactPriv *priv;
593 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
595 priv = GET_PRIV (contact);
597 g_object_ref (contact);
598 if (tp_strdiff (name, priv->name))
601 priv->name = g_strdup (name);
602 g_object_notify (G_OBJECT (contact), "name");
604 g_object_unref (contact);
608 empathy_contact_get_avatar (EmpathyContact *contact)
610 EmpathyContactPriv *priv;
612 g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
614 priv = GET_PRIV (contact);
620 empathy_contact_set_avatar (EmpathyContact *contact,
621 EmpathyAvatar *avatar)
623 EmpathyContactPriv *priv;
625 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
627 priv = GET_PRIV (contact);
629 if (priv->avatar == avatar)
634 empathy_avatar_unref (priv->avatar);
639 priv->avatar = empathy_avatar_ref (avatar);
641 g_object_notify (G_OBJECT (contact), "avatar");
645 empathy_contact_get_account (EmpathyContact *contact)
647 EmpathyContactPriv *priv;
649 g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
651 priv = GET_PRIV (contact);
653 if (priv->account == NULL && priv->tp_contact != NULL)
655 TpConnection *connection;
657 /* FIXME: This assume the account manager already exists */
658 connection = tp_contact_get_connection (priv->tp_contact);
660 g_object_ref (empathy_get_account_for_connection (connection));
663 return priv->account;
667 empathy_contact_get_connection (EmpathyContact *contact)
669 EmpathyContactPriv *priv;
671 g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
673 priv = GET_PRIV (contact);
675 if (priv->tp_contact != NULL)
676 return tp_contact_get_connection (priv->tp_contact);
681 TpConnectionPresenceType
682 empathy_contact_get_presence (EmpathyContact *contact)
684 EmpathyContactPriv *priv;
686 g_return_val_if_fail (EMPATHY_IS_CONTACT (contact),
687 TP_CONNECTION_PRESENCE_TYPE_UNSET);
689 priv = GET_PRIV (contact);
691 if (priv->tp_contact != NULL)
692 return tp_contact_get_presence_type (priv->tp_contact);
694 return priv->presence;
698 empathy_contact_set_presence (EmpathyContact *contact,
699 TpConnectionPresenceType presence)
701 EmpathyContactPriv *priv;
702 TpConnectionPresenceType old_presence;
704 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
706 priv = GET_PRIV (contact);
708 if (presence == priv->presence)
711 old_presence = priv->presence;
712 priv->presence = presence;
714 g_signal_emit (contact, signals[PRESENCE_CHANGED], 0, presence, old_presence);
716 g_object_notify (G_OBJECT (contact), "presence");
720 empathy_contact_get_presence_message (EmpathyContact *contact)
722 EmpathyContactPriv *priv;
724 g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
726 priv = GET_PRIV (contact);
728 if (priv->tp_contact != NULL)
729 return tp_contact_get_presence_message (priv->tp_contact);
731 return priv->presence_message;
735 empathy_contact_set_presence_message (EmpathyContact *contact,
736 const gchar *message)
738 EmpathyContactPriv *priv = GET_PRIV (contact);
740 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
742 if (!tp_strdiff (message, priv->presence_message))
745 g_free (priv->presence_message);
746 priv->presence_message = g_strdup (message);
748 g_object_notify (G_OBJECT (contact), "presence-message");
752 empathy_contact_get_handle (EmpathyContact *contact)
754 EmpathyContactPriv *priv;
756 g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), 0);
758 priv = GET_PRIV (contact);
760 if (priv->tp_contact != NULL)
761 return tp_contact_get_handle (priv->tp_contact);
767 empathy_contact_set_handle (EmpathyContact *contact,
770 EmpathyContactPriv *priv;
772 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
774 priv = GET_PRIV (contact);
776 g_object_ref (contact);
777 if (handle != priv->handle)
779 priv->handle = handle;
780 g_object_notify (G_OBJECT (contact), "handle");
782 g_object_unref (contact);
786 empathy_contact_get_capabilities (EmpathyContact *contact)
788 EmpathyContactPriv *priv;
790 g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), 0);
792 priv = GET_PRIV (contact);
794 return priv->capabilities;
798 empathy_contact_set_capabilities (EmpathyContact *contact,
799 EmpathyCapabilities capabilities)
801 EmpathyContactPriv *priv;
803 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
805 priv = GET_PRIV (contact);
807 if (priv->capabilities == capabilities)
810 priv->capabilities = capabilities;
812 g_object_notify (G_OBJECT (contact), "capabilities");
816 empathy_contact_is_user (EmpathyContact *contact)
818 EmpathyContactPriv *priv;
820 g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
822 priv = GET_PRIV (contact);
824 return priv->is_user;
828 empathy_contact_set_is_user (EmpathyContact *contact,
831 EmpathyContactPriv *priv;
833 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
835 priv = GET_PRIV (contact);
837 if (priv->is_user == is_user)
840 priv->is_user = is_user;
842 g_object_notify (G_OBJECT (contact), "is-user");
846 empathy_contact_is_online (EmpathyContact *contact)
848 g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
850 switch (empathy_contact_get_presence (contact))
852 case TP_CONNECTION_PRESENCE_TYPE_OFFLINE:
853 case TP_CONNECTION_PRESENCE_TYPE_UNKNOWN:
854 case TP_CONNECTION_PRESENCE_TYPE_ERROR:
862 empathy_contact_get_status (EmpathyContact *contact)
864 const gchar *message;
866 g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), "");
868 message = empathy_contact_get_presence_message (contact);
869 if (!EMP_STR_EMPTY (message))
872 return empathy_presence_get_default_message (
873 empathy_contact_get_presence (contact));
877 empathy_contact_can_voip (EmpathyContact *contact)
879 EmpathyContactPriv *priv;
881 g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
883 priv = GET_PRIV (contact);
885 return priv->capabilities & (EMPATHY_CAPABILITIES_AUDIO |
886 EMPATHY_CAPABILITIES_VIDEO);
890 empathy_contact_can_voip_audio (EmpathyContact *contact)
892 EmpathyContactPriv *priv;
894 g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
896 priv = GET_PRIV (contact);
898 return priv->capabilities & EMPATHY_CAPABILITIES_AUDIO;
902 empathy_contact_can_voip_video (EmpathyContact *contact)
904 EmpathyContactPriv *priv;
906 g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
908 priv = GET_PRIV (contact);
910 return priv->capabilities & EMPATHY_CAPABILITIES_VIDEO;
914 empathy_contact_can_send_files (EmpathyContact *contact)
916 EmpathyContactPriv *priv;
918 g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
920 priv = GET_PRIV (contact);
922 return priv->capabilities & EMPATHY_CAPABILITIES_FT;
926 empathy_contact_can_use_stream_tube (EmpathyContact *contact)
928 EmpathyContactPriv *priv;
930 g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
932 priv = GET_PRIV (contact);
934 return priv->capabilities & EMPATHY_CAPABILITIES_STREAM_TUBE;
938 contact_get_avatar_filename (EmpathyContact *contact,
944 gchar *token_escaped;
946 if (EMP_STR_EMPTY (empathy_contact_get_id (contact)))
949 token_escaped = tp_escape_as_identifier (token);
950 account = empathy_contact_get_account (contact);
952 avatar_path = g_build_filename (g_get_user_cache_dir (),
955 tp_account_get_connection_manager (account),
956 tp_account_get_protocol (account),
958 g_mkdir_with_parents (avatar_path, 0700);
960 avatar_file = g_build_filename (avatar_path, token_escaped, NULL);
962 g_free (token_escaped);
963 g_free (avatar_path);
969 empathy_contact_load_avatar_cache (EmpathyContact *contact,
972 EmpathyAvatar *avatar = NULL;
976 GError *error = NULL;
978 g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
979 g_return_val_if_fail (!EMP_STR_EMPTY (token), FALSE);
981 /* Load the avatar from file if it exists */
982 filename = contact_get_avatar_filename (contact, token);
983 if (filename && g_file_test (filename, G_FILE_TEST_EXISTS))
985 if (!g_file_get_contents (filename, &data, &len, &error))
987 DEBUG ("Failed to load avatar from cache: %s",
988 error ? error->message : "No error given");
989 g_clear_error (&error);
995 DEBUG ("Avatar loaded from %s", filename);
996 avatar = empathy_avatar_new ((guchar *) data, len, NULL, g_strdup (token),
998 empathy_contact_set_avatar (contact, avatar);
999 empathy_avatar_unref (avatar);
1006 return data != NULL;
1010 empathy_avatar_get_type (void)
1012 static GType type_id = 0;
1016 type_id = g_boxed_type_register_static ("EmpathyAvatar",
1017 (GBoxedCopyFunc) empathy_avatar_ref,
1018 (GBoxedFreeFunc) empathy_avatar_unref);
1025 * empathy_avatar_new:
1026 * @data: the avatar data
1027 * @len: the size of avatar data
1028 * @format: the mime type of the avatar image
1029 * @token: the token of the avatar
1030 * @filename: the filename where the avatar is stored in cache
1032 * Create a #EmpathyAvatar from the provided data. This function takes the
1033 * ownership of @data, @format, @token and @filename.
1035 * Returns: a new #EmpathyAvatar
1038 empathy_avatar_new (guchar *data,
1044 EmpathyAvatar *avatar;
1046 avatar = g_slice_new0 (EmpathyAvatar);
1047 avatar->data = data;
1049 avatar->format = format;
1050 avatar->token = token;
1051 avatar->filename = filename;
1052 avatar->refcount = 1;
1058 empathy_avatar_unref (EmpathyAvatar *avatar)
1060 g_return_if_fail (avatar != NULL);
1063 if (avatar->refcount == 0)
1065 g_free (avatar->data);
1066 g_free (avatar->format);
1067 g_free (avatar->token);
1068 g_slice_free (EmpathyAvatar, avatar);
1073 empathy_avatar_ref (EmpathyAvatar *avatar)
1075 g_return_val_if_fail (avatar != NULL, NULL);
1083 * empathy_avatar_save_to_file:
1084 * @avatar: the avatar
1085 * @filename: name of a file to write avatar to
1086 * @error: return location for a GError, or NULL
1088 * Save the avatar to a file named filename
1090 * Returns: %TRUE on success, %FALSE if an error occurred
1093 empathy_avatar_save_to_file (EmpathyAvatar *self,
1094 const gchar *filename,
1097 return g_file_set_contents (filename, (const gchar *) self->data, self->len,
1102 * empathy_contact_get_location:
1103 * @contact: an #EmpathyContact
1105 * Returns the user's location if available. The keys are defined in
1106 * empathy-location.h. If the contact doesn't have location
1107 * information, the GHashTable will be empthy. Use #g_hash_table_unref when
1108 * you are done with the #GHashTable.
1110 * It is composed of string keys and GValues. Keys are
1111 * defined in empathy-location.h such as #EMPATHY_LOCATION_COUNTRY.
1112 * Example: a "city" key would have "Helsinki" as string GValue,
1113 * a "latitude" would have 65.0 as double GValue.
1115 * Returns: a #GHashTable of location values
1118 empathy_contact_get_location (EmpathyContact *contact)
1120 EmpathyContactPriv *priv;
1122 g_return_val_if_fail (EMPATHY_CONTACT (contact), NULL);
1124 priv = GET_PRIV (contact);
1126 return priv->location;
1130 * empathy_contact_set_location:
1131 * @contact: an #EmpathyContact
1132 * @location: a #GHashTable of the location
1134 * Sets the user's location based on the location #GHashTable passed.
1135 * It is composed of string keys and GValues. Keys are
1136 * defined in empathy-location.h such as #EMPATHY_LOCATION_COUNTRY.
1137 * Example: a "city" key would have "Helsinki" as string GValue,
1138 * a "latitude" would have 65.0 as double GValue.
1141 empathy_contact_set_location (EmpathyContact *contact,
1142 GHashTable *location)
1144 EmpathyContactPriv *priv;
1146 g_return_if_fail (EMPATHY_CONTACT (contact));
1147 g_return_if_fail (location != NULL);
1149 priv = GET_PRIV (contact);
1151 if (priv->location != NULL)
1152 g_hash_table_unref (priv->location);
1154 priv->location = g_hash_table_ref (location);
1156 update_geocode (contact);
1158 g_object_notify (G_OBJECT (contact), "location");
1162 * empathy_contact_equal:
1163 * @contact1: an #EmpathyContact
1164 * @contact2: an #EmpathyContact
1166 * Returns FALSE if one of the contacts is NULL but the other is not.
1167 * Otherwise returns TRUE if both pointer are equal or if they bith
1168 * refer to the same id.
1169 * It's only necessary to call this function if your contact objects
1170 * come from logs where contacts are created dynamically and comparing
1171 * pointers is not enough.
1174 empathy_contact_equal (gconstpointer contact1,
1175 gconstpointer contact2)
1182 if ((contact1 == NULL) != (contact2 == NULL)) {
1185 if (contact1 == contact2) {
1188 c1 = EMPATHY_CONTACT (contact1);
1189 c2 = EMPATHY_CONTACT (contact2);
1190 id1 = empathy_contact_get_id (c1);
1191 id2 = empathy_contact_get_id (c2);
1192 if (!tp_strdiff (id1, id2)) {
1199 #define GEOCODE_SERVICE "org.freedesktop.Geoclue.Providers.Yahoo"
1200 #define GEOCODE_PATH "/org/freedesktop/Geoclue/Providers/Yahoo"
1202 /* This callback is called by geoclue when it found a position
1203 * for the given address. A position is necessary for a contact
1204 * to show up on the map
1207 geocode_cb (GeoclueGeocode *geocode,
1208 GeocluePositionFields fields,
1212 GeoclueAccuracy *accuracy,
1216 EmpathyContactPriv *priv = GET_PRIV (contact);
1217 GHashTable *new_location;
1219 if (priv->location == NULL)
1224 DEBUG ("Error geocoding location : %s", error->message);
1228 /* No need to change location if we didn't find the position */
1229 if (!(fields & GEOCLUE_POSITION_FIELDS_LATITUDE))
1232 if (!(fields & GEOCLUE_POSITION_FIELDS_LONGITUDE))
1235 new_location = tp_asv_new (
1236 EMPATHY_LOCATION_LAT, G_TYPE_DOUBLE, latitude,
1237 EMPATHY_LOCATION_LON, G_TYPE_DOUBLE, longitude,
1240 DEBUG ("\t - Latitude: %f", latitude);
1241 DEBUG ("\t - Longitude: %f", longitude);
1243 /* Copy remaning fields. LAT and LON were not defined so we won't overwrite
1244 * the values we just set. */
1245 tp_g_hash_table_update (new_location, priv->location,
1246 (GBoxedCopyFunc) g_strdup, (GBoxedCopyFunc) tp_g_value_slice_dup);
1248 /* Set the altitude only if it wasn't defined before */
1249 if (fields & GEOCLUE_POSITION_FIELDS_ALTITUDE &&
1250 g_hash_table_lookup (new_location, EMPATHY_LOCATION_ALT) == NULL)
1252 tp_asv_set_double (new_location, g_strdup (EMPATHY_LOCATION_ALT),
1254 DEBUG ("\t - Altitude: %f", altitude);
1257 /* Don't change the accuracy as we used an address to get this position */
1258 g_hash_table_unref (priv->location);
1259 priv->location = new_location;
1260 g_object_notify (contact, "location");
1262 g_object_unref (geocode);
1263 g_object_unref (contact);
1267 get_dup_string (GHashTable *location,
1272 value = g_hash_table_lookup (location, key);
1274 return g_value_dup_string (value);
1280 update_geocode (EmpathyContact *contact)
1282 static GeoclueGeocode *geocode;
1284 GHashTable *address;
1285 GHashTable *location;
1287 location = empathy_contact_get_location (contact);
1288 if (location == NULL)
1291 /* No need to search for position if contact published it */
1292 if (g_hash_table_lookup (location, EMPATHY_LOCATION_LAT) != NULL ||
1293 g_hash_table_lookup (location, EMPATHY_LOCATION_LON) != NULL)
1296 if (geocode == NULL)
1298 geocode = geoclue_geocode_new (GEOCODE_SERVICE, GEOCODE_PATH);
1299 g_object_add_weak_pointer (G_OBJECT (geocode), (gpointer *) &geocode);
1303 g_object_ref (geocode);
1306 address = geoclue_address_details_new ();
1308 str = get_dup_string (location, EMPATHY_LOCATION_COUNTRY_CODE);
1311 g_hash_table_insert (address,
1312 g_strdup (GEOCLUE_ADDRESS_KEY_COUNTRYCODE), str);
1313 DEBUG ("\t - countrycode: %s", str);
1316 str = get_dup_string (location, EMPATHY_LOCATION_COUNTRY);
1319 g_hash_table_insert (address,
1320 g_strdup (GEOCLUE_ADDRESS_KEY_COUNTRY), str);
1321 DEBUG ("\t - country: %s", str);
1324 str = get_dup_string (location, EMPATHY_LOCATION_POSTAL_CODE);
1327 g_hash_table_insert (address,
1328 g_strdup (GEOCLUE_ADDRESS_KEY_POSTALCODE), str);
1329 DEBUG ("\t - postalcode: %s", str);
1332 str = get_dup_string (location, EMPATHY_LOCATION_REGION);
1335 g_hash_table_insert (address,
1336 g_strdup (GEOCLUE_ADDRESS_KEY_REGION), str);
1337 DEBUG ("\t - region: %s", str);
1340 str = get_dup_string (location, EMPATHY_LOCATION_LOCALITY);
1343 g_hash_table_insert (address,
1344 g_strdup (GEOCLUE_ADDRESS_KEY_LOCALITY), str);
1345 DEBUG ("\t - locality: %s", str);
1348 str = get_dup_string (location, EMPATHY_LOCATION_STREET);
1351 g_hash_table_insert (address,
1352 g_strdup (GEOCLUE_ADDRESS_KEY_STREET), str);
1353 DEBUG ("\t - street: %s", str);
1356 if (g_hash_table_size (address) > 0)
1358 g_object_ref (contact);
1360 geoclue_geocode_address_to_position_async (geocode, address,
1361 geocode_cb, contact);
1364 g_hash_table_unref (address);
1368 static EmpathyCapabilities
1369 tp_caps_to_capabilities (TpCapabilities *caps)
1371 EmpathyCapabilities capabilities = 0;
1375 classes = tp_capabilities_get_channel_classes (caps);
1377 for (i = 0; i < classes->len; i++)
1379 GValueArray *class_struct;
1380 GHashTable *fixed_prop;
1382 TpHandleType handle_type;
1383 const gchar *chan_type;
1385 class_struct = g_ptr_array_index (classes, i);
1386 tp_value_array_unpack (class_struct, 2,
1390 handle_type = tp_asv_get_uint32 (fixed_prop,
1391 TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, NULL);
1392 if (handle_type != TP_HANDLE_TYPE_CONTACT)
1395 chan_type = tp_asv_get_string (fixed_prop,
1396 TP_PROP_CHANNEL_CHANNEL_TYPE);
1398 if (!tp_strdiff (chan_type, TP_IFACE_CHANNEL_TYPE_FILE_TRANSFER))
1400 capabilities |= EMPATHY_CAPABILITIES_FT;
1402 else if (!tp_strdiff (chan_type, TP_IFACE_CHANNEL_TYPE_STREAM_TUBE))
1404 capabilities |= EMPATHY_CAPABILITIES_STREAM_TUBE;
1406 else if (!tp_strdiff (chan_type,
1407 TP_IFACE_CHANNEL_TYPE_STREAMED_MEDIA))
1411 for (j = 0; allowed_prop[j] != NULL; j++)
1413 if (!tp_strdiff (allowed_prop[j],
1414 TP_PROP_CHANNEL_TYPE_STREAMED_MEDIA_INITIAL_AUDIO))
1415 capabilities |= EMPATHY_CAPABILITIES_AUDIO;
1416 else if (!tp_strdiff (allowed_prop[j],
1417 TP_PROP_CHANNEL_TYPE_STREAMED_MEDIA_INITIAL_VIDEO))
1418 capabilities |= EMPATHY_CAPABILITIES_VIDEO;
1423 return capabilities;
1427 set_capabilities_from_tp_caps (EmpathyContact *self,
1428 TpCapabilities *caps)
1430 EmpathyCapabilities capabilities;
1435 capabilities = tp_caps_to_capabilities (caps);
1436 empathy_contact_set_capabilities (self, capabilities);
1440 contact_set_avatar_from_tp_contact (EmpathyContact *contact)
1442 EmpathyContactPriv *priv = GET_PRIV (contact);
1447 token = tp_contact_get_avatar_token (priv->tp_contact);
1448 mime = tp_contact_get_avatar_mime_type (priv->tp_contact);
1449 file = tp_contact_get_avatar_file (priv->tp_contact);
1453 EmpathyAvatar *avatar;
1457 g_file_load_contents (file, NULL, &data, &len, NULL, NULL);
1458 avatar = empathy_avatar_new ((guchar *) data, len, g_strdup (mime), g_strdup (token),
1459 g_file_get_path (file));
1460 empathy_contact_set_avatar (contact, avatar);
1461 empathy_avatar_unref (avatar);
1465 empathy_contact_set_avatar (contact, NULL);