]> git.0d.be Git - empathy.git/blob - libempathy/empathy-contact.c
Fix some coding style
[empathy.git] / libempathy / empathy-contact.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2004 Imendio AB
4  * Copyright (C) 2007-2008 Collabora Ltd.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this program; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  *
21  * Authors: Mikael Hallendal <micke@imendio.com>
22  *          Martyn Russell <martyn@imendio.com>
23  *          Xavier Claessens <xclaesse@gmail.com>
24  */
25
26 #include "config.h"
27
28 #include <string.h>
29
30 #include <glib/gi18n.h>
31
32 #include <telepathy-glib/util.h>
33
34 #include "empathy-contact.h"
35 #include "empathy-utils.h"
36 #include "empathy-enum-types.h"
37
38 #define DEBUG_FLAG EMPATHY_DEBUG_CONTACT
39 #include "empathy-debug.h"
40
41 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyContact)
42 typedef struct {
43   gchar *id;
44   gchar *name;
45   EmpathyAvatar *avatar;
46   McAccount *account;
47   McPresence presence;
48   gchar *presence_message;
49   guint handle;
50   EmpathyCapabilities capabilities;
51   gboolean is_user;
52   guint hash;
53   EmpathyContactReady ready;
54 } EmpathyContactPriv;
55
56 static void contact_finalize (GObject *object);
57 static void contact_get_property (GObject *object, guint param_id,
58     GValue *value, GParamSpec *pspec);
59 static void contact_set_property (GObject *object, guint param_id,
60     const GValue *value, GParamSpec *pspec);
61
62 G_DEFINE_TYPE (EmpathyContact, empathy_contact, G_TYPE_OBJECT);
63
64 enum
65 {
66   PROP_0,
67   PROP_ID,
68   PROP_NAME,
69   PROP_AVATAR,
70   PROP_ACCOUNT,
71   PROP_PRESENCE,
72   PROP_PRESENCE_MESSAGE,
73   PROP_HANDLE,
74   PROP_CAPABILITIES,
75   PROP_IS_USER,
76   PROP_READY
77 };
78
79 static void
80 empathy_contact_class_init (EmpathyContactClass *class)
81 {
82   GObjectClass *object_class;
83
84   object_class = G_OBJECT_CLASS (class);
85
86   object_class->finalize = contact_finalize;
87   object_class->get_property = contact_get_property;
88   object_class->set_property = contact_set_property;
89
90   g_object_class_install_property (object_class,
91       PROP_ID,
92       g_param_spec_string ("id",
93         "Contact id",
94         "String identifying contact",
95         NULL,
96         G_PARAM_READWRITE));
97
98   g_object_class_install_property (object_class,
99       PROP_NAME,
100       g_param_spec_string ("name",
101         "Contact Name",
102         "The name of the contact",
103         NULL,
104         G_PARAM_READWRITE));
105
106   g_object_class_install_property (object_class,
107       PROP_AVATAR,
108       g_param_spec_boxed ("avatar",
109         "Avatar image",
110         "The avatar image",
111         EMPATHY_TYPE_AVATAR,
112         G_PARAM_READWRITE));
113
114   g_object_class_install_property (object_class,
115       PROP_ACCOUNT,
116       g_param_spec_object ("account",
117         "Contact Account",
118         "The account associated with the contact",
119         MC_TYPE_ACCOUNT,
120         G_PARAM_READWRITE));
121
122   g_object_class_install_property (object_class,
123       PROP_PRESENCE,
124       g_param_spec_uint ("presence",
125         "Contact presence",
126         "Presence of contact",
127         MC_PRESENCE_UNSET,
128         LAST_MC_PRESENCE,
129         MC_PRESENCE_UNSET,
130         G_PARAM_READWRITE));
131
132   g_object_class_install_property (object_class,
133       PROP_PRESENCE_MESSAGE,
134       g_param_spec_string ("presence-message",
135         "Contact presence message",
136         "Presence message of contact",
137         NULL,
138         G_PARAM_READWRITE));
139
140   g_object_class_install_property (object_class,
141       PROP_HANDLE,
142       g_param_spec_uint ("handle",
143         "Contact Handle",
144         "The handle of the contact",
145         0,
146         G_MAXUINT,
147         0,
148         G_PARAM_READWRITE));
149
150   g_object_class_install_property (object_class,
151       PROP_CAPABILITIES,
152       g_param_spec_flags ("capabilities",
153         "Contact Capabilities",
154         "Capabilities of the contact",
155         EMPATHY_TYPE_CAPABILITIES,
156         EMPATHY_CAPABILITIES_UNKNOWN,
157         G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
158
159   g_object_class_install_property (object_class,
160       PROP_IS_USER,
161       g_param_spec_boolean ("is-user",
162         "Contact is-user",
163         "Is contact the user",
164         FALSE,
165         G_PARAM_READWRITE));
166
167   g_object_class_install_property (object_class,
168       PROP_READY,
169       g_param_spec_flags ("ready",
170         "Contact ready flags",
171         "Flags for ready properties",
172         EMPATHY_TYPE_CONTACT_READY,
173         EMPATHY_CONTACT_READY_NONE,
174         G_PARAM_READABLE));
175
176   g_type_class_add_private (object_class, sizeof (EmpathyContactPriv));
177 }
178
179 static void
180 empathy_contact_init (EmpathyContact *contact)
181 {
182   EmpathyContactPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (contact,
183     EMPATHY_TYPE_CONTACT, EmpathyContactPriv);
184
185   contact->priv = priv;
186 }
187
188 static void
189 contact_finalize (GObject *object)
190 {
191   EmpathyContactPriv *priv;
192
193   priv = GET_PRIV (object);
194
195   DEBUG ("finalize: %p", object);
196
197   g_free (priv->name);
198   g_free (priv->id);
199   g_free (priv->presence_message);
200
201   if (priv->avatar)
202       empathy_avatar_unref (priv->avatar);
203
204   if (priv->account)
205       g_object_unref (priv->account);
206
207   G_OBJECT_CLASS (empathy_contact_parent_class)->finalize (object);
208 }
209
210 static void
211 contact_get_property (GObject *object,
212                       guint param_id,
213                       GValue *value,
214                       GParamSpec *pspec)
215 {
216   EmpathyContactPriv *priv;
217
218   priv = GET_PRIV (object);
219
220   switch (param_id)
221     {
222       case PROP_ID:
223         g_value_set_string (value, priv->id);
224         break;
225       case PROP_NAME:
226         g_value_set_string (value,
227             empathy_contact_get_name (EMPATHY_CONTACT (object)));
228         break;
229       case PROP_AVATAR:
230         g_value_set_boxed (value, priv->avatar);
231         break;
232       case PROP_ACCOUNT:
233         g_value_set_object (value, priv->account);
234         break;
235       case PROP_PRESENCE:
236         g_value_set_uint (value, priv->presence);
237         break;
238       case PROP_PRESENCE_MESSAGE:
239         g_value_set_string (value, priv->presence_message);
240         break;
241       case PROP_HANDLE:
242         g_value_set_uint (value, priv->handle);
243         break;
244       case PROP_CAPABILITIES:
245         g_value_set_flags (value, priv->capabilities);
246         break;
247       case PROP_IS_USER:
248         g_value_set_boolean (value, priv->is_user);
249         break;
250       case PROP_READY:
251         g_value_set_flags (value, priv->ready);
252         break;
253       default:
254         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
255         break;
256     };
257 }
258
259 static void
260 contact_set_property (GObject *object,
261                       guint param_id,
262                       const GValue *value,
263                       GParamSpec *pspec)
264 {
265   EmpathyContactPriv *priv;
266
267   priv = GET_PRIV (object);
268
269   switch (param_id)
270     {
271       case PROP_ID:
272         empathy_contact_set_id (EMPATHY_CONTACT (object),
273         g_value_get_string (value));
274         break;
275       case PROP_NAME:
276         empathy_contact_set_name (EMPATHY_CONTACT (object),
277         g_value_get_string (value));
278         break;
279       case PROP_AVATAR:
280         empathy_contact_set_avatar (EMPATHY_CONTACT (object),
281         g_value_get_boxed (value));
282         break;
283       case PROP_ACCOUNT:
284         empathy_contact_set_account (EMPATHY_CONTACT (object),
285         MC_ACCOUNT (g_value_get_object (value)));
286         break;
287       case PROP_PRESENCE:
288         empathy_contact_set_presence (EMPATHY_CONTACT (object),
289         g_value_get_uint (value));
290         break;
291       case PROP_PRESENCE_MESSAGE:
292         empathy_contact_set_presence_message (EMPATHY_CONTACT (object),
293         g_value_get_string (value));
294         break;
295       case PROP_HANDLE:
296         empathy_contact_set_handle (EMPATHY_CONTACT (object),
297         g_value_get_uint (value));
298         break;
299       case PROP_CAPABILITIES:
300         empathy_contact_set_capabilities (EMPATHY_CONTACT (object),
301         g_value_get_flags (value));
302         break;
303       case PROP_IS_USER:
304         empathy_contact_set_is_user (EMPATHY_CONTACT (object),
305         g_value_get_boolean (value));
306         break;
307       default:
308         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
309         break;
310     };
311 }
312
313 static void
314 contact_set_ready_flag (EmpathyContact *contact,
315                         EmpathyContactReady flag)
316 {
317   EmpathyContactPriv *priv = GET_PRIV (contact);
318
319   if (!(priv->ready & flag))
320     {
321       priv->ready |= flag;
322       g_object_notify (G_OBJECT (contact), "ready");
323     }
324 }
325
326 EmpathyContact *
327 empathy_contact_new (McAccount *account)
328 {
329   return g_object_new (EMPATHY_TYPE_CONTACT,
330       "account", account,
331       NULL);
332 }
333
334 EmpathyContact *
335 empathy_contact_new_full (McAccount  *account,
336                           const gchar *id,
337                           const gchar *name)
338 {
339   return g_object_new (EMPATHY_TYPE_CONTACT,
340       "account", account,
341        "name", name,
342        "id", id,
343        NULL);
344 }
345
346 const gchar *
347 empathy_contact_get_id (EmpathyContact *contact)
348 {
349   EmpathyContactPriv *priv;
350
351   g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
352
353   priv = GET_PRIV (contact);
354
355   return priv->id;
356 }
357
358 void
359 empathy_contact_set_id (EmpathyContact *contact,
360                         const gchar *id)
361 {
362   EmpathyContactPriv *priv;
363
364   g_return_if_fail (EMPATHY_IS_CONTACT (contact));
365   g_return_if_fail (id != NULL);
366
367   priv = GET_PRIV (contact);
368
369   /* We temporally ref the contact because it could be destroyed
370    * during the signal emition */
371   g_object_ref (contact);
372   if (tp_strdiff (id, priv->id))
373     {
374       g_free (priv->id);
375       priv->id = g_strdup (id);
376
377       g_object_notify (G_OBJECT (contact), "id");
378       if (G_STR_EMPTY (priv->name))
379           g_object_notify (G_OBJECT (contact), "name");
380     }
381   contact_set_ready_flag (contact, EMPATHY_CONTACT_READY_ID);
382
383   g_object_unref (contact);
384 }
385
386 const gchar *
387 empathy_contact_get_name (EmpathyContact *contact)
388 {
389   EmpathyContactPriv *priv;
390
391   g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
392
393   priv = GET_PRIV (contact);
394
395   if (G_STR_EMPTY (priv->name))
396       return empathy_contact_get_id (contact);
397
398   return priv->name;
399 }
400
401 void
402 empathy_contact_set_name (EmpathyContact *contact,
403                           const gchar *name)
404 {
405   EmpathyContactPriv *priv;
406
407   g_return_if_fail (EMPATHY_IS_CONTACT (contact));
408
409   priv = GET_PRIV (contact);
410
411   g_object_ref (contact);
412   if (tp_strdiff (name, priv->name))
413     {
414       g_free (priv->name);
415       priv->name = g_strdup (name);
416       g_object_notify (G_OBJECT (contact), "name");
417     }
418   contact_set_ready_flag (contact, EMPATHY_CONTACT_READY_NAME);
419   g_object_unref (contact);
420 }
421
422 EmpathyAvatar *
423 empathy_contact_get_avatar (EmpathyContact *contact)
424 {
425   EmpathyContactPriv *priv;
426
427   g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
428
429   priv = GET_PRIV (contact);
430
431   return priv->avatar;
432 }
433
434 void
435 empathy_contact_set_avatar (EmpathyContact *contact,
436                             EmpathyAvatar *avatar)
437 {
438   EmpathyContactPriv *priv;
439
440   g_return_if_fail (EMPATHY_IS_CONTACT (contact));
441
442   priv = GET_PRIV (contact);
443
444   if (priv->avatar == avatar)
445     return;
446
447   if (priv->avatar)
448     {
449       empathy_avatar_unref (priv->avatar);
450       priv->avatar = NULL;
451     }
452
453   if (avatar)
454       priv->avatar = empathy_avatar_ref (avatar);
455
456   g_object_notify (G_OBJECT (contact), "avatar");
457 }
458
459 McAccount *
460 empathy_contact_get_account (EmpathyContact *contact)
461 {
462   EmpathyContactPriv *priv;
463
464   g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
465
466   priv = GET_PRIV (contact);
467
468   return priv->account;
469 }
470
471 void
472 empathy_contact_set_account (EmpathyContact *contact,
473                              McAccount *account)
474 {
475   EmpathyContactPriv *priv;
476
477   g_return_if_fail (EMPATHY_IS_CONTACT (contact));
478   g_return_if_fail (MC_IS_ACCOUNT (account));
479
480   priv = GET_PRIV (contact);
481
482   if (account == priv->account)
483     return;
484
485   if (priv->account)
486       g_object_unref (priv->account);
487   priv->account = g_object_ref (account);
488
489   g_object_notify (G_OBJECT (contact), "account");
490 }
491
492 McPresence
493 empathy_contact_get_presence (EmpathyContact *contact)
494 {
495   EmpathyContactPriv *priv;
496
497   g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), MC_PRESENCE_UNSET);
498
499   priv = GET_PRIV (contact);
500
501   return priv->presence;
502 }
503
504 void
505 empathy_contact_set_presence (EmpathyContact *contact,
506                               McPresence presence)
507 {
508   EmpathyContactPriv *priv;
509
510   g_return_if_fail (EMPATHY_IS_CONTACT (contact));
511
512   priv = GET_PRIV (contact);
513
514   if (presence == priv->presence)
515     return;
516
517   priv->presence = presence;
518
519   g_object_notify (G_OBJECT (contact), "presence");
520 }
521
522 const gchar *
523 empathy_contact_get_presence_message (EmpathyContact *contact)
524 {
525   EmpathyContactPriv *priv;
526
527   g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
528
529   priv = GET_PRIV (contact);
530
531   return priv->presence_message;
532 }
533
534 void
535 empathy_contact_set_presence_message (EmpathyContact *contact,
536                                       const gchar *message)
537 {
538   EmpathyContactPriv *priv = GET_PRIV (contact);
539
540   g_return_if_fail (EMPATHY_IS_CONTACT (contact));
541
542   if (!tp_strdiff (message, priv->presence_message))
543     return;
544
545   g_free (priv->presence_message);
546   priv->presence_message = g_strdup (message);
547
548   g_object_notify (G_OBJECT (contact), "presence-message");
549 }
550
551 guint
552 empathy_contact_get_handle (EmpathyContact *contact)
553 {
554   EmpathyContactPriv *priv;
555
556   g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), 0);
557
558   priv = GET_PRIV (contact);
559
560   return priv->handle;
561 }
562
563 void
564 empathy_contact_set_handle (EmpathyContact *contact,
565                             guint handle)
566 {
567   EmpathyContactPriv *priv;
568
569   g_return_if_fail (EMPATHY_IS_CONTACT (contact));
570
571   priv = GET_PRIV (contact);
572
573   g_object_ref (contact);
574   if (handle != priv->handle)
575     {
576       priv->handle = handle;
577       g_object_notify (G_OBJECT (contact), "handle");
578     }
579   contact_set_ready_flag (contact, EMPATHY_CONTACT_READY_HANDLE);
580   g_object_unref (contact);
581 }
582
583 EmpathyCapabilities
584 empathy_contact_get_capabilities (EmpathyContact *contact)
585 {
586   EmpathyContactPriv *priv;
587
588   g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), 0);
589
590   priv = GET_PRIV (contact);
591
592   return priv->capabilities;
593 }
594
595 void
596 empathy_contact_set_capabilities (EmpathyContact *contact,
597                                   EmpathyCapabilities capabilities)
598 {
599   EmpathyContactPriv *priv;
600
601   g_return_if_fail (EMPATHY_IS_CONTACT (contact));
602
603   priv = GET_PRIV (contact);
604
605   if (priv->capabilities == capabilities)
606     return;
607
608   priv->capabilities = capabilities;
609
610   g_object_notify (G_OBJECT (contact), "capabilities");
611 }
612
613 gboolean
614 empathy_contact_is_user (EmpathyContact *contact)
615 {
616   EmpathyContactPriv *priv;
617
618   g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
619
620   priv = GET_PRIV (contact);
621
622   return priv->is_user;
623 }
624
625 void
626 empathy_contact_set_is_user (EmpathyContact *contact,
627                              gboolean is_user)
628 {
629   EmpathyContactPriv *priv;
630
631   g_return_if_fail (EMPATHY_IS_CONTACT (contact));
632
633   priv = GET_PRIV (contact);
634
635   if (priv->is_user == is_user)
636     return;
637
638   priv->is_user = is_user;
639
640   g_object_notify (G_OBJECT (contact), "is-user");
641 }
642
643 gboolean
644 empathy_contact_is_online (EmpathyContact *contact)
645 {
646   EmpathyContactPriv *priv;
647
648   g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
649
650   priv = GET_PRIV (contact);
651
652   return (priv->presence > MC_PRESENCE_OFFLINE);
653 }
654
655 const gchar *
656 empathy_contact_get_status (EmpathyContact *contact)
657 {
658   EmpathyContactPriv *priv;
659
660   g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), "");
661
662   priv = GET_PRIV (contact);
663
664   if (priv->presence_message)
665     return priv->presence_message;
666
667   return empathy_presence_get_default_message (priv->presence);
668 }
669
670 gboolean
671 empathy_contact_can_voip (EmpathyContact *contact)
672 {
673   EmpathyContactPriv *priv;
674
675   g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
676
677   priv = GET_PRIV (contact);
678
679   return priv->capabilities & (EMPATHY_CAPABILITIES_AUDIO |
680       EMPATHY_CAPABILITIES_VIDEO);
681 }
682
683 EmpathyContactReady
684 empathy_contact_get_ready (EmpathyContact *contact)
685 {
686   EmpathyContactPriv *priv;
687
688   g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
689
690   priv = GET_PRIV (contact);
691
692   return priv->ready;
693 }
694
695 gboolean
696 empathy_contact_equal (gconstpointer v1,
697                        gconstpointer v2)
698 {
699   McAccount *account_a;
700   McAccount *account_b;
701   const gchar *id_a;
702   const gchar *id_b;
703
704   g_return_val_if_fail (EMPATHY_IS_CONTACT (v1), FALSE);
705   g_return_val_if_fail (EMPATHY_IS_CONTACT (v2), FALSE);
706
707   account_a = empathy_contact_get_account (EMPATHY_CONTACT (v1));
708   account_b = empathy_contact_get_account (EMPATHY_CONTACT (v2));
709
710   id_a = empathy_contact_get_id (EMPATHY_CONTACT (v1));
711   id_b = empathy_contact_get_id (EMPATHY_CONTACT (v2));
712
713   return empathy_account_equal (account_a, account_b) &&
714       !tp_strdiff (id_a, id_b);
715 }
716
717 guint
718 empathy_contact_hash (gconstpointer key)
719 {
720   EmpathyContactPriv *priv;
721
722   g_return_val_if_fail (EMPATHY_IS_CONTACT (key), +1);
723
724   priv = GET_PRIV (EMPATHY_CONTACT (key));
725
726   if (priv->hash == 0)
727     {
728       priv->hash = empathy_account_hash (priv->account) ^
729           g_str_hash (priv->id);
730     }
731
732   return priv->hash;
733 }
734
735 static gboolean
736 contact_is_ready_func (GObject *contact,
737                        gpointer user_data)
738 {
739   EmpathyContactPriv *priv = GET_PRIV (contact);
740   EmpathyContactReady ready;
741
742   ready = GPOINTER_TO_UINT (user_data);
743
744   /* When the name is NULL, empathy_contact_get_name() fallback to the id.
745    * When the caller want to wait the name to be ready, it also want to wait
746    * the id to be ready in case of fallback. */
747   if ((ready & EMPATHY_CONTACT_READY_NAME) && G_STR_EMPTY (priv->name))
748       ready |= EMPATHY_CONTACT_READY_ID;
749
750   return (priv->ready & ready) == ready;
751 }
752
753 void
754 empathy_contact_run_until_ready (EmpathyContact *contact,
755                                  EmpathyContactReady ready,
756                                  GMainLoop **loop)
757 {
758   empathy_run_until_ready_full (contact, "notify::ready",
759       contact_is_ready_func, GUINT_TO_POINTER (ready),
760       loop);
761 }
762
763 static gchar *
764 contact_get_avatar_filename (EmpathyContact *contact,
765                              const gchar *token)
766 {
767   EmpathyContactPriv *priv = GET_PRIV (contact);
768   gchar *avatar_path;
769   gchar *avatar_file;
770   gchar *token_escaped;
771   gchar *contact_escaped;
772
773   if (G_STR_EMPTY (priv->id))
774     return NULL;
775
776   contact_escaped = tp_escape_as_identifier (priv->id);
777   token_escaped = tp_escape_as_identifier (token);
778
779   avatar_path = g_build_filename (g_get_user_cache_dir (),
780       PACKAGE_NAME,
781       "avatars",
782       mc_account_get_unique_name (priv->account),
783       contact_escaped,
784       NULL);
785   g_mkdir_with_parents (avatar_path, 0700);
786
787   avatar_file = g_build_filename (avatar_path, token_escaped, NULL);
788
789   g_free (contact_escaped);
790   g_free (token_escaped);
791   g_free (avatar_path);
792
793   return avatar_file;
794 }
795
796 void
797 empathy_contact_load_avatar_data (EmpathyContact *contact,
798                                   const guchar  *data,
799                                   const gsize len,
800                                   const gchar *format,
801                                   const gchar *token)
802 {
803   EmpathyAvatar *avatar;
804   gchar *filename;
805   GError *error = NULL;
806
807   g_return_if_fail (EMPATHY_IS_CONTACT (contact));
808   g_return_if_fail (data != NULL);
809   g_return_if_fail (len > 0);
810   g_return_if_fail (format != NULL);
811   g_return_if_fail (!G_STR_EMPTY (token));
812
813   /* Load and set the avatar */
814   avatar = empathy_avatar_new (g_memdup (data, len), len, g_strdup (format),
815       g_strdup (token));
816   empathy_contact_set_avatar (contact, avatar);
817   empathy_avatar_unref (avatar);
818
819   /* Save to cache if not yet in it */
820   filename = contact_get_avatar_filename (contact, token);
821   if (filename && !g_file_test (filename, G_FILE_TEST_EXISTS))
822     {
823       if (!empathy_avatar_save_to_file (avatar, filename, &error))
824         {
825           DEBUG ("Failed to save avatar in cache: %s",
826             error ? error->message : "No error given");
827           g_clear_error (&error);
828         }
829       else
830           DEBUG ("Avatar saved to %s", filename);
831     }
832   g_free (filename);
833 }
834
835 gboolean
836 empathy_contact_load_avatar_cache (EmpathyContact *contact,
837                                    const gchar *token)
838 {
839   EmpathyAvatar *avatar = NULL;
840   gchar *filename;
841   gchar *data = NULL;
842   gsize len;
843   GError *error = NULL;
844
845   g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
846   g_return_val_if_fail (!G_STR_EMPTY (token), FALSE);
847
848   /* Load the avatar from file if it exists */
849   filename = contact_get_avatar_filename (contact, token);
850   if (filename && g_file_test (filename, G_FILE_TEST_EXISTS))
851     {
852       if (!g_file_get_contents (filename, &data, &len, &error))
853         {
854           DEBUG ("Failed to load avatar from cache: %s",
855             error ? error->message : "No error given");
856           g_clear_error (&error);
857         }
858     }
859
860   if (data)
861     {
862       DEBUG ("Avatar loaded from %s", filename);
863       avatar = empathy_avatar_new (data, len, NULL, g_strdup (token));
864       empathy_contact_set_avatar (contact, avatar);
865       empathy_avatar_unref (avatar);
866     }
867
868   g_free (filename);
869
870   return data != NULL;
871 }
872
873 GType
874 empathy_avatar_get_type (void)
875 {
876   static GType type_id = 0;
877
878   if (!type_id)
879     {
880       type_id = g_boxed_type_register_static ("EmpathyAvatar",
881           (GBoxedCopyFunc) empathy_avatar_ref,
882           (GBoxedFreeFunc) empathy_avatar_unref);
883     }
884
885   return type_id;
886 }
887
888 EmpathyAvatar *
889 empathy_avatar_new (guchar *data,
890                     gsize len,
891                     gchar *format,
892                     gchar *token)
893 {
894   EmpathyAvatar *avatar;
895
896   avatar = g_slice_new0 (EmpathyAvatar);
897   avatar->data = data;
898   avatar->len = len;
899   avatar->format = format;
900   avatar->token = token;
901   avatar->refcount = 1;
902
903   return avatar;
904 }
905
906 void
907 empathy_avatar_unref (EmpathyAvatar *avatar)
908 {
909   g_return_if_fail (avatar != NULL);
910
911   avatar->refcount--;
912   if (avatar->refcount == 0)
913     {
914       g_free (avatar->data);
915       g_free (avatar->format);
916       g_free (avatar->token);
917       g_slice_free (EmpathyAvatar, avatar);
918     }
919 }
920
921 EmpathyAvatar *
922 empathy_avatar_ref (EmpathyAvatar *avatar)
923 {
924   g_return_val_if_fail (avatar != NULL, NULL);
925
926   avatar->refcount++;
927
928   return avatar;
929 }
930
931 /**
932  * empathy_avatar_save_to_file:
933  * @avatar: the avatar
934  * @filename: name of a file to write avatar to
935  * @error: return location for a GError, or NULL
936  *
937  * Save the avatar to a file named filename
938  *
939  * Returns: %TRUE on success, %FALSE if an error occurred 
940  */
941 gboolean
942 empathy_avatar_save_to_file (EmpathyAvatar *self,
943                              const gchar *filename,
944                              GError **error)
945 {
946   return g_file_set_contents (filename, self->data, self->len, error);
947 }
948