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