]> git.0d.be Git - empathy.git/blob - libempathy/empathy-contact.c
Use gi18n-lib.h instead of gi18n.h for libraries.
[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-lib.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 gboolean
684 empathy_contact_can_send_files (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->capabilities & EMPATHY_CAPABILITIES_FT;
693 }
694
695 EmpathyContactReady
696 empathy_contact_get_ready (EmpathyContact *contact)
697 {
698   EmpathyContactPriv *priv;
699
700   g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
701
702   priv = GET_PRIV (contact);
703
704   return priv->ready;
705 }
706
707 gboolean
708 empathy_contact_equal (gconstpointer v1,
709                        gconstpointer v2)
710 {
711   McAccount *account_a;
712   McAccount *account_b;
713   const gchar *id_a;
714   const gchar *id_b;
715
716   g_return_val_if_fail (EMPATHY_IS_CONTACT (v1), FALSE);
717   g_return_val_if_fail (EMPATHY_IS_CONTACT (v2), FALSE);
718
719   account_a = empathy_contact_get_account (EMPATHY_CONTACT (v1));
720   account_b = empathy_contact_get_account (EMPATHY_CONTACT (v2));
721
722   id_a = empathy_contact_get_id (EMPATHY_CONTACT (v1));
723   id_b = empathy_contact_get_id (EMPATHY_CONTACT (v2));
724
725   return empathy_account_equal (account_a, account_b) &&
726       !tp_strdiff (id_a, id_b);
727 }
728
729 guint
730 empathy_contact_hash (gconstpointer key)
731 {
732   EmpathyContactPriv *priv;
733
734   g_return_val_if_fail (EMPATHY_IS_CONTACT (key), +1);
735
736   priv = GET_PRIV (EMPATHY_CONTACT (key));
737
738   if (priv->hash == 0)
739     {
740       priv->hash = empathy_account_hash (priv->account) ^
741           g_str_hash (priv->id);
742     }
743
744   return priv->hash;
745 }
746
747 static gboolean
748 contact_is_ready_func (GObject *contact,
749                        gpointer user_data)
750 {
751   EmpathyContactPriv *priv = GET_PRIV (contact);
752   EmpathyContactReady ready;
753
754   ready = GPOINTER_TO_UINT (user_data);
755
756   /* When the name is NULL, empathy_contact_get_name() fallback to the id.
757    * When the caller want to wait the name to be ready, it also want to wait
758    * the id to be ready in case of fallback. */
759   if ((ready & EMPATHY_CONTACT_READY_NAME) && G_STR_EMPTY (priv->name))
760       ready |= EMPATHY_CONTACT_READY_ID;
761
762   return (priv->ready & ready) == ready;
763 }
764
765 void
766 empathy_contact_run_until_ready (EmpathyContact *contact,
767                                  EmpathyContactReady ready,
768                                  GMainLoop **loop)
769 {
770   empathy_run_until_ready_full (contact, "notify::ready",
771       contact_is_ready_func, GUINT_TO_POINTER (ready),
772       loop);
773 }
774
775 static gchar *
776 contact_get_avatar_filename (EmpathyContact *contact,
777                              const gchar *token)
778 {
779   EmpathyContactPriv *priv = GET_PRIV (contact);
780   gchar *avatar_path;
781   gchar *avatar_file;
782   gchar *token_escaped;
783   gchar *contact_escaped;
784
785   if (G_STR_EMPTY (priv->id))
786     return NULL;
787
788   contact_escaped = tp_escape_as_identifier (priv->id);
789   token_escaped = tp_escape_as_identifier (token);
790
791   avatar_path = g_build_filename (g_get_user_cache_dir (),
792       PACKAGE_NAME,
793       "avatars",
794       mc_account_get_unique_name (priv->account),
795       contact_escaped,
796       NULL);
797   g_mkdir_with_parents (avatar_path, 0700);
798
799   avatar_file = g_build_filename (avatar_path, token_escaped, NULL);
800
801   g_free (contact_escaped);
802   g_free (token_escaped);
803   g_free (avatar_path);
804
805   return avatar_file;
806 }
807
808 void
809 empathy_contact_load_avatar_data (EmpathyContact *contact,
810                                   const guchar  *data,
811                                   const gsize len,
812                                   const gchar *format,
813                                   const gchar *token)
814 {
815   EmpathyAvatar *avatar;
816   gchar *filename;
817   GError *error = NULL;
818
819   g_return_if_fail (EMPATHY_IS_CONTACT (contact));
820   g_return_if_fail (data != NULL);
821   g_return_if_fail (len > 0);
822   g_return_if_fail (format != NULL);
823   g_return_if_fail (!G_STR_EMPTY (token));
824
825   /* Load and set the avatar */
826   avatar = empathy_avatar_new (g_memdup (data, len), len, g_strdup (format),
827       g_strdup (token));
828   empathy_contact_set_avatar (contact, avatar);
829   empathy_avatar_unref (avatar);
830
831   /* Save to cache if not yet in it */
832   filename = contact_get_avatar_filename (contact, token);
833   if (filename && !g_file_test (filename, G_FILE_TEST_EXISTS))
834     {
835       if (!empathy_avatar_save_to_file (avatar, filename, &error))
836         {
837           DEBUG ("Failed to save avatar in cache: %s",
838             error ? error->message : "No error given");
839           g_clear_error (&error);
840         }
841       else
842           DEBUG ("Avatar saved to %s", filename);
843     }
844   g_free (filename);
845 }
846
847 gboolean
848 empathy_contact_load_avatar_cache (EmpathyContact *contact,
849                                    const gchar *token)
850 {
851   EmpathyAvatar *avatar = NULL;
852   gchar *filename;
853   gchar *data = NULL;
854   gsize len;
855   GError *error = NULL;
856
857   g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
858   g_return_val_if_fail (!G_STR_EMPTY (token), FALSE);
859
860   /* Load the avatar from file if it exists */
861   filename = contact_get_avatar_filename (contact, token);
862   if (filename && g_file_test (filename, G_FILE_TEST_EXISTS))
863     {
864       if (!g_file_get_contents (filename, &data, &len, &error))
865         {
866           DEBUG ("Failed to load avatar from cache: %s",
867             error ? error->message : "No error given");
868           g_clear_error (&error);
869         }
870     }
871
872   if (data)
873     {
874       DEBUG ("Avatar loaded from %s", filename);
875       avatar = empathy_avatar_new (data, len, NULL, g_strdup (token));
876       empathy_contact_set_avatar (contact, avatar);
877       empathy_avatar_unref (avatar);
878     }
879
880   g_free (filename);
881
882   return data != NULL;
883 }
884
885 GType
886 empathy_avatar_get_type (void)
887 {
888   static GType type_id = 0;
889
890   if (!type_id)
891     {
892       type_id = g_boxed_type_register_static ("EmpathyAvatar",
893           (GBoxedCopyFunc) empathy_avatar_ref,
894           (GBoxedFreeFunc) empathy_avatar_unref);
895     }
896
897   return type_id;
898 }
899
900 EmpathyAvatar *
901 empathy_avatar_new (guchar *data,
902                     gsize len,
903                     gchar *format,
904                     gchar *token)
905 {
906   EmpathyAvatar *avatar;
907
908   avatar = g_slice_new0 (EmpathyAvatar);
909   avatar->data = data;
910   avatar->len = len;
911   avatar->format = format;
912   avatar->token = token;
913   avatar->refcount = 1;
914
915   return avatar;
916 }
917
918 void
919 empathy_avatar_unref (EmpathyAvatar *avatar)
920 {
921   g_return_if_fail (avatar != NULL);
922
923   avatar->refcount--;
924   if (avatar->refcount == 0)
925     {
926       g_free (avatar->data);
927       g_free (avatar->format);
928       g_free (avatar->token);
929       g_slice_free (EmpathyAvatar, avatar);
930     }
931 }
932
933 EmpathyAvatar *
934 empathy_avatar_ref (EmpathyAvatar *avatar)
935 {
936   g_return_val_if_fail (avatar != NULL, NULL);
937
938   avatar->refcount++;
939
940   return avatar;
941 }
942
943 /**
944  * empathy_avatar_save_to_file:
945  * @avatar: the avatar
946  * @filename: name of a file to write avatar to
947  * @error: return location for a GError, or NULL
948  *
949  * Save the avatar to a file named filename
950  *
951  * Returns: %TRUE on success, %FALSE if an error occurred 
952  */
953 gboolean
954 empathy_avatar_save_to_file (EmpathyAvatar *self,
955                              const gchar *filename,
956                              GError **error)
957 {
958   return g_file_set_contents (filename, self->data, self->len, error);
959 }
960