]> git.0d.be Git - empathy.git/blob - libempathy/empathy-contact.c
Make use of tp-glib debug system.
[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) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_CONTACT, EmpathyContactPriv))
42
43 typedef struct _EmpathyContactPriv EmpathyContactPriv;
44
45 struct _EmpathyContactPriv {
46         gchar              *id;
47         gchar              *name;
48         EmpathyAvatar      *avatar;
49         McAccount          *account;
50         McPresence          presence;
51         gchar              *presence_message;
52         guint               handle;
53         EmpathyCapabilities capabilities;
54         gboolean            is_user;
55         guint               hash;
56         EmpathyContactReady ready;
57 };
58
59 static void empathy_contact_class_init (EmpathyContactClass *class);
60 static void empathy_contact_init       (EmpathyContact      *contact);
61 static void contact_finalize           (GObject             *object);
62 static void contact_get_property       (GObject             *object,
63                                         guint                param_id,
64                                         GValue              *value,
65                                         GParamSpec          *pspec);
66 static void contact_set_property       (GObject             *object,
67                                         guint                param_id,
68                                         const GValue        *value,
69                                         GParamSpec          *pspec);
70
71 G_DEFINE_TYPE (EmpathyContact, empathy_contact, G_TYPE_OBJECT);
72
73 enum {
74         PROP_0,
75         PROP_ID,
76         PROP_NAME,
77         PROP_AVATAR,
78         PROP_ACCOUNT,
79         PROP_PRESENCE,
80         PROP_PRESENCE_MESSAGE,
81         PROP_HANDLE,
82         PROP_CAPABILITIES,
83         PROP_IS_USER,
84         PROP_READY
85 };
86
87 static void
88 empathy_contact_class_init (EmpathyContactClass *class)
89 {
90         GObjectClass *object_class;
91
92         object_class = G_OBJECT_CLASS (class);
93
94         object_class->finalize     = contact_finalize;
95         object_class->get_property = contact_get_property;
96         object_class->set_property = contact_set_property;
97
98         g_object_class_install_property (object_class,
99                                          PROP_ID,
100                                          g_param_spec_string ("id",
101                                                               "Contact id",
102                                                               "String identifying contact",
103                                                               NULL,
104                                                               G_PARAM_READWRITE));
105
106         g_object_class_install_property (object_class,
107                                          PROP_NAME,
108                                          g_param_spec_string ("name",
109                                                               "Contact Name",
110                                                               "The name of the contact",
111                                                               NULL,
112                                                               G_PARAM_READWRITE));
113
114         g_object_class_install_property (object_class,
115                                          PROP_AVATAR,
116                                          g_param_spec_boxed ("avatar",
117                                                              "Avatar image",
118                                                              "The avatar image",
119                                                              EMPATHY_TYPE_AVATAR,
120                                                              G_PARAM_READWRITE));
121
122         g_object_class_install_property (object_class,
123                                          PROP_ACCOUNT,
124                                          g_param_spec_object ("account",
125                                                               "Contact Account",
126                                                               "The account associated with the contact",
127                                                               MC_TYPE_ACCOUNT,
128                                                               G_PARAM_READWRITE));
129
130         g_object_class_install_property (object_class,
131                                          PROP_PRESENCE,
132                                          g_param_spec_uint ("presence",
133                                                             "Contact presence",
134                                                             "Presence of contact",
135                                                             MC_PRESENCE_UNSET,
136                                                             LAST_MC_PRESENCE,
137                                                             MC_PRESENCE_UNSET,
138                                                             G_PARAM_READWRITE));
139
140         g_object_class_install_property (object_class,
141                                          PROP_PRESENCE_MESSAGE,
142                                          g_param_spec_string ("presence-message",
143                                                               "Contact presence message",
144                                                               "Presence message of contact",
145                                                               NULL,
146                                                               G_PARAM_READWRITE));
147         g_object_class_install_property (object_class,
148                                          PROP_HANDLE,
149                                          g_param_spec_uint ("handle",
150                                                             "Contact Handle",
151                                                             "The handle of the contact",
152                                                             0,
153                                                             G_MAXUINT,
154                                                             0,
155                                                             G_PARAM_READWRITE));
156
157         g_object_class_install_property (object_class,
158                                          PROP_CAPABILITIES,
159                                          g_param_spec_flags ("capabilities",
160                                                              "Contact Capabilities",
161                                                              "Capabilities of the contact",
162                                                              EMPATHY_TYPE_CAPABILITIES,
163                                                              EMPATHY_CAPABILITIES_UNKNOWN,
164                                                              G_PARAM_CONSTRUCT | G_PARAM_READWRITE));
165
166         g_object_class_install_property (object_class,
167                                          PROP_IS_USER,
168                                          g_param_spec_boolean ("is-user",
169                                                                "Contact is-user",
170                                                                "Is contact the user",
171                                                                FALSE,
172                                                                G_PARAM_READWRITE));
173
174         g_object_class_install_property (object_class,
175                                          PROP_READY,
176                                          g_param_spec_flags ("ready",
177                                                              "Contact ready flags",
178                                                              "Flags for ready properties",
179                                                              EMPATHY_TYPE_CONTACT_READY,
180                                                              EMPATHY_CONTACT_READY_NONE,
181                                                              G_PARAM_READABLE));
182
183         g_type_class_add_private (object_class, sizeof (EmpathyContactPriv));
184 }
185
186 static void
187 empathy_contact_init (EmpathyContact *contact)
188 {
189 }
190
191 static void
192 contact_finalize (GObject *object)
193 {
194         EmpathyContactPriv *priv;
195
196         priv = GET_PRIV (object);
197
198         DEBUG ("finalize: %p", object);
199
200         g_free (priv->name);
201         g_free (priv->id);
202         g_free (priv->presence_message);
203
204         if (priv->avatar) {
205                 empathy_avatar_unref (priv->avatar);
206         }
207
208         if (priv->account) {
209                 g_object_unref (priv->account);
210         }
211
212         G_OBJECT_CLASS (empathy_contact_parent_class)->finalize (object);
213 }
214
215 static void
216 contact_get_property (GObject    *object,
217                       guint       param_id,
218                       GValue     *value,
219                       GParamSpec *pspec)
220 {
221         EmpathyContactPriv *priv;
222
223         priv = GET_PRIV (object);
224
225         switch (param_id) {
226         case PROP_ID:
227                 g_value_set_string (value, priv->id);
228                 break;
229         case PROP_NAME:
230                 g_value_set_string (value,
231                                     empathy_contact_get_name (EMPATHY_CONTACT (object)));
232                 break;
233         case PROP_AVATAR:
234                 g_value_set_boxed (value, priv->avatar);
235                 break;
236         case PROP_ACCOUNT:
237                 g_value_set_object (value, priv->account);
238                 break;
239         case PROP_PRESENCE:
240                 g_value_set_uint (value, priv->presence);
241                 break;
242         case PROP_PRESENCE_MESSAGE:
243                 g_value_set_string (value, priv->presence_message);
244                 break;
245         case PROP_HANDLE:
246                 g_value_set_uint (value, priv->handle);
247                 break;
248         case PROP_CAPABILITIES:
249                 g_value_set_flags (value, priv->capabilities);
250                 break;
251         case PROP_IS_USER:
252                 g_value_set_boolean (value, priv->is_user);
253                 break;
254         case PROP_READY:
255                 g_value_set_flags (value, priv->ready);
256                 break;
257         default:
258                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
259                 break;
260         };
261 }
262
263 static void
264 contact_set_property (GObject      *object,
265                       guint         param_id,
266                       const GValue *value,
267                       GParamSpec   *pspec)
268 {
269         EmpathyContactPriv *priv;
270
271         priv = GET_PRIV (object);
272
273         switch (param_id) {
274         case PROP_ID:
275                 empathy_contact_set_id (EMPATHY_CONTACT (object),
276                                        g_value_get_string (value));
277                 break;
278         case PROP_NAME:
279                 empathy_contact_set_name (EMPATHY_CONTACT (object),
280                                          g_value_get_string (value));
281                 break;
282         case PROP_AVATAR:
283                 empathy_contact_set_avatar (EMPATHY_CONTACT (object),
284                                            g_value_get_boxed (value));
285                 break;
286         case PROP_ACCOUNT:
287                 empathy_contact_set_account (EMPATHY_CONTACT (object),
288                                             MC_ACCOUNT (g_value_get_object (value)));
289                 break;
290         case PROP_PRESENCE:
291                 empathy_contact_set_presence (EMPATHY_CONTACT (object),
292                                               g_value_get_uint (value));
293                 break;
294         case PROP_PRESENCE_MESSAGE:
295                 empathy_contact_set_presence_message (EMPATHY_CONTACT (object),
296                                                       g_value_get_string (value));
297                 break;
298         case PROP_HANDLE:
299                 empathy_contact_set_handle (EMPATHY_CONTACT (object),
300                                            g_value_get_uint (value));
301                 break;
302         case PROP_CAPABILITIES:
303                 empathy_contact_set_capabilities (EMPATHY_CONTACT (object),
304                                                   g_value_get_flags (value));
305                 break;
306         case PROP_IS_USER:
307                 empathy_contact_set_is_user (EMPATHY_CONTACT (object),
308                                             g_value_get_boolean (value));
309                 break;
310         default:
311                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
312                 break;
313         };
314 }
315
316 static void
317 contact_set_ready_flag (EmpathyContact      *contact,
318                         EmpathyContactReady  flag)
319 {
320         EmpathyContactPriv *priv = GET_PRIV (contact);
321
322         if (!(priv->ready & flag)) {
323                 priv->ready |= flag;
324                 g_object_notify (G_OBJECT (contact), "ready");
325         }
326 }
327
328 EmpathyContact *
329 empathy_contact_new (McAccount *account)
330 {
331         return g_object_new (EMPATHY_TYPE_CONTACT,
332                              "account", account,
333                              NULL);
334 }
335
336 EmpathyContact *
337 empathy_contact_new_full (McAccount   *account,
338                           const gchar *id,
339                           const gchar *name)
340 {
341         return g_object_new (EMPATHY_TYPE_CONTACT,
342                              "account", account,
343                              "name", name,
344                              "id", id,
345                              NULL);
346 }
347
348 const gchar *
349 empathy_contact_get_id (EmpathyContact *contact)
350 {
351         EmpathyContactPriv *priv;
352
353         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
354
355         priv = GET_PRIV (contact);
356
357         return priv->id;
358 }
359
360 void
361 empathy_contact_set_id (EmpathyContact *contact,
362                        const gchar   *id)
363 {
364         EmpathyContactPriv *priv;
365
366         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
367         g_return_if_fail (id != NULL);
368
369         priv = GET_PRIV (contact);
370
371         /* We temporally ref the contact because it could be destroyed
372          * during the signal emition */
373         g_object_ref (contact);
374         contact_set_ready_flag (contact, EMPATHY_CONTACT_READY_ID);
375         if (tp_strdiff (id, priv->id)) {
376                 g_free (priv->id);
377                 priv->id = g_strdup (id);
378
379                 g_object_notify (G_OBJECT (contact), "id");
380                 if (G_STR_EMPTY (priv->name)) {
381                         g_object_notify (G_OBJECT (contact), "name");
382                 }
383         }
384
385         g_object_unref (contact);
386 }
387
388 const gchar *
389 empathy_contact_get_name (EmpathyContact *contact)
390 {
391         EmpathyContactPriv *priv;
392
393         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
394
395         priv = GET_PRIV (contact);
396
397         if (G_STR_EMPTY (priv->name)) {
398                 return empathy_contact_get_id (contact);
399         }
400
401         return priv->name;
402 }
403
404 void
405 empathy_contact_set_name (EmpathyContact *contact,
406                          const gchar   *name)
407 {
408         EmpathyContactPriv *priv;
409
410         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
411
412         priv = GET_PRIV (contact);
413
414         g_object_ref (contact);
415         contact_set_ready_flag (contact, EMPATHY_CONTACT_READY_NAME);
416         if (tp_strdiff (name, priv->name)) {
417                 g_free (priv->name);
418                 priv->name = g_strdup (name);
419                 g_object_notify (G_OBJECT (contact), "name");
420         }
421         g_object_unref (contact);
422 }
423
424 EmpathyAvatar *
425 empathy_contact_get_avatar (EmpathyContact *contact)
426 {
427         EmpathyContactPriv *priv;
428
429         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
430
431         priv = GET_PRIV (contact);
432
433         return priv->avatar;
434 }
435
436 void
437 empathy_contact_set_avatar (EmpathyContact *contact,
438                            EmpathyAvatar  *avatar)
439 {
440         EmpathyContactPriv *priv;
441
442         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
443
444         priv = GET_PRIV (contact);
445
446         if (priv->avatar == avatar) {
447                 return;
448         }
449
450         if (priv->avatar) {
451                 empathy_avatar_unref (priv->avatar);
452                 priv->avatar = NULL;
453         }
454
455         if (avatar) {
456                 priv->avatar = empathy_avatar_ref (avatar);
457         }
458
459         g_object_notify (G_OBJECT (contact), "avatar");
460 }
461
462 McAccount *
463 empathy_contact_get_account (EmpathyContact *contact)
464 {
465         EmpathyContactPriv *priv;
466
467         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
468
469         priv = GET_PRIV (contact);
470
471         return priv->account;
472 }
473
474 void
475 empathy_contact_set_account (EmpathyContact *contact,
476                              McAccount      *account)
477 {
478         EmpathyContactPriv *priv;
479
480         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
481         g_return_if_fail (MC_IS_ACCOUNT (account));
482
483         priv = GET_PRIV (contact);
484
485         if (account == priv->account) {
486                 return;
487         }
488
489         if (priv->account) {
490                 g_object_unref (priv->account);
491         }
492         priv->account = g_object_ref (account);
493
494         g_object_notify (G_OBJECT (contact), "account");
495 }
496
497 McPresence
498 empathy_contact_get_presence (EmpathyContact *contact)
499 {
500         EmpathyContactPriv *priv;
501
502         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), MC_PRESENCE_UNSET);
503
504         priv = GET_PRIV (contact);
505
506         return priv->presence;
507 }
508
509 void
510 empathy_contact_set_presence (EmpathyContact *contact,
511                               McPresence      presence)
512 {
513         EmpathyContactPriv *priv;
514
515         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
516
517         priv = GET_PRIV (contact);
518
519         if (presence == priv->presence) {
520                 return;
521         }
522
523         priv->presence = presence;
524
525         g_object_notify (G_OBJECT (contact), "presence");
526 }
527
528 const gchar *
529 empathy_contact_get_presence_message (EmpathyContact *contact)
530 {
531         EmpathyContactPriv *priv;
532
533         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
534
535         priv = GET_PRIV (contact);
536
537         return priv->presence_message;
538 }
539
540 void
541 empathy_contact_set_presence_message (EmpathyContact *contact,
542                                       const gchar    *message)
543 {
544         EmpathyContactPriv *priv = GET_PRIV (contact);
545
546         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
547
548         if (!tp_strdiff (message, priv->presence_message)) {
549                 return;
550         }
551
552         g_free (priv->presence_message);
553         priv->presence_message = g_strdup (message);
554
555         g_object_notify (G_OBJECT (contact), "presence-message");
556 }
557
558 guint
559 empathy_contact_get_handle (EmpathyContact *contact)
560 {
561         EmpathyContactPriv *priv;
562
563         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), 0);
564
565         priv = GET_PRIV (contact);
566
567         return priv->handle;
568 }
569
570 void
571 empathy_contact_set_handle (EmpathyContact *contact,
572                             guint           handle)
573 {
574         EmpathyContactPriv *priv;
575
576         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
577
578         priv = GET_PRIV (contact);
579
580         g_object_ref (contact);
581         contact_set_ready_flag (contact, EMPATHY_CONTACT_READY_HANDLE);
582         if (handle != priv->handle) {
583                 priv->handle = handle;
584                 g_object_notify (G_OBJECT (contact), "handle");
585         }
586         g_object_unref (contact);
587 }
588
589 EmpathyCapabilities
590 empathy_contact_get_capabilities (EmpathyContact *contact)
591 {
592         EmpathyContactPriv *priv;
593
594         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), 0);
595
596         priv = GET_PRIV (contact);
597
598         return priv->capabilities;
599 }
600
601 void
602 empathy_contact_set_capabilities (EmpathyContact      *contact,
603                                   EmpathyCapabilities  capabilities)
604 {
605         EmpathyContactPriv *priv;
606
607         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
608
609         priv = GET_PRIV (contact);
610
611         if (priv->capabilities == capabilities) {
612                 return;
613         }
614
615         priv->capabilities = capabilities;
616
617         g_object_notify (G_OBJECT (contact), "capabilities");
618 }
619
620 gboolean
621 empathy_contact_is_user (EmpathyContact *contact)
622 {
623         EmpathyContactPriv *priv;
624
625         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
626
627         priv = GET_PRIV (contact);
628
629         return priv->is_user;
630 }
631
632 void
633 empathy_contact_set_is_user (EmpathyContact *contact,
634                             gboolean       is_user)
635 {
636         EmpathyContactPriv *priv;
637
638         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
639
640         priv = GET_PRIV (contact);
641
642         if (priv->is_user == is_user) {
643                 return;
644         }
645
646         priv->is_user = is_user;
647
648         g_object_notify (G_OBJECT (contact), "is-user");
649 }
650
651 gboolean
652 empathy_contact_is_online (EmpathyContact *contact)
653 {
654         EmpathyContactPriv *priv;
655
656         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
657
658         priv = GET_PRIV (contact);
659
660         return (priv->presence > MC_PRESENCE_OFFLINE);
661 }
662
663 const gchar *
664 empathy_contact_get_status (EmpathyContact *contact)
665 {
666         EmpathyContactPriv *priv;
667
668         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), "");
669
670         priv = GET_PRIV (contact);
671
672         if (priv->presence_message) {
673                 return priv->presence_message;
674         }
675
676         return empathy_presence_get_default_message (priv->presence);
677 }
678
679 gboolean
680 empathy_contact_can_voip (EmpathyContact *contact)
681 {
682         EmpathyContactPriv *priv;
683
684         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
685
686         priv = GET_PRIV (contact);
687
688         return priv->capabilities & (EMPATHY_CAPABILITIES_AUDIO |
689                                      EMPATHY_CAPABILITIES_VIDEO);
690 }
691
692 EmpathyContactReady
693 empathy_contact_get_ready (EmpathyContact *contact)
694 {
695         EmpathyContactPriv *priv;
696
697         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
698
699         priv = GET_PRIV (contact);
700
701         return priv->ready;
702 }
703
704 gboolean
705 empathy_contact_equal (gconstpointer v1,
706                       gconstpointer v2)
707 {
708         McAccount   *account_a;
709         McAccount   *account_b;
710         const gchar *id_a;
711         const gchar *id_b;
712
713         g_return_val_if_fail (EMPATHY_IS_CONTACT (v1), FALSE);
714         g_return_val_if_fail (EMPATHY_IS_CONTACT (v2), FALSE);
715
716         account_a = empathy_contact_get_account (EMPATHY_CONTACT (v1));
717         account_b = empathy_contact_get_account (EMPATHY_CONTACT (v2));
718
719         id_a = empathy_contact_get_id (EMPATHY_CONTACT (v1));
720         id_b = empathy_contact_get_id (EMPATHY_CONTACT (v2));
721
722         return empathy_account_equal (account_a, account_b) && g_str_equal (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) + g_str_hash (priv->id);
736         }
737
738         return priv->hash;
739 }
740
741 static gboolean
742 contact_is_ready_func (GObject  *contact,
743                        gpointer  user_data)
744 {
745         EmpathyContactPriv *priv = GET_PRIV (contact);
746         EmpathyContactReady ready;
747
748         ready = GPOINTER_TO_UINT (user_data);
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