]> git.0d.be Git - empathy.git/blob - libempathy/gossip-contact.c
82147f67e848d774e3eeaf021636224480338138
[empathy.git] / libempathy / gossip-contact.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2004-2007 Imendio AB
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Authors: Mikael Hallendal <micke@imendio.com>
21  *          Martyn Russell <martyn@imendio.com>
22  */
23
24 #include "config.h"
25
26 #include <string.h>
27
28 #include <glib/gi18n.h>
29
30 #include "gossip-contact.h"
31 #include "gossip-utils.h"
32 #include "gossip-debug.h"
33 #include "empathy-contact-manager.h"
34
35 #define DEBUG_DOMAIN "Contact"
36
37 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_CONTACT, GossipContactPriv))
38
39 typedef struct _GossipContactPriv GossipContactPriv;
40
41 struct _GossipContactPriv {
42         gchar              *id;
43         gchar              *name;
44         GossipAvatar       *avatar;
45         McAccount          *account;
46         GossipPresence     *presence;
47         GList              *groups;
48         GossipSubscription  subscription;
49         guint               handle;
50 };
51
52 static void contact_class_init    (GossipContactClass *class);
53 static void contact_init          (GossipContact      *contact);
54 static void contact_finalize      (GObject            *object);
55 static void contact_get_property  (GObject            *object,
56                                    guint               param_id,
57                                    GValue             *value,
58                                    GParamSpec         *pspec);
59 static void contact_set_property  (GObject            *object,
60                                    guint               param_id,
61                                    const GValue       *value,
62                                    GParamSpec         *pspec);
63
64 enum {
65         PROP_0,
66         PROP_ID,
67         PROP_NAME,
68         PROP_AVATAR,
69         PROP_ACCOUNT,
70         PROP_PRESENCE,
71         PROP_GROUPS,
72         PROP_SUBSCRIPTION,
73         PROP_HANDLE
74 };
75
76 static gpointer parent_class = NULL;
77
78 GType
79 gossip_contact_get_gtype (void)
80 {
81         static GType type = 0;
82
83         if (!type) {
84                 static const GTypeInfo info = {
85                         sizeof (GossipContactClass),
86                         NULL, /* base_init */
87                         NULL, /* base_finalize */
88                         (GClassInitFunc) contact_class_init,
89                         NULL, /* class_finalize */
90                         NULL, /* class_data */
91                         sizeof (GossipContact),
92                         0,    /* n_preallocs */
93                         (GInstanceInitFunc) contact_init
94                 };
95
96                 type = g_type_register_static (G_TYPE_OBJECT,
97                                                "GossipContact",
98                                                &info, 0);
99         }
100
101         return type;
102 }
103
104 static void
105 contact_class_init (GossipContactClass *class)
106 {
107         GObjectClass *object_class;
108
109         object_class = G_OBJECT_CLASS (class);
110         parent_class = g_type_class_peek_parent (class);
111
112         object_class->finalize     = contact_finalize;
113         object_class->get_property = contact_get_property;
114         object_class->set_property = contact_set_property;
115
116         g_object_class_install_property (object_class,
117                                          PROP_ID,
118                                          g_param_spec_string ("id",
119                                                               "Contact id",
120                                                               "String identifying contact",
121                                                               NULL,
122                                                               G_PARAM_READWRITE));
123
124         g_object_class_install_property (object_class,
125                                          PROP_NAME,
126                                          g_param_spec_string ("name",
127                                                               "Contact Name",
128                                                               "The name of the contact",
129                                                               NULL,
130                                                               G_PARAM_READWRITE));
131
132         g_object_class_install_property (object_class,
133                                          PROP_AVATAR,
134                                          g_param_spec_boxed ("avatar",
135                                                              "Avatar image",
136                                                              "The avatar image",
137                                                              GOSSIP_TYPE_AVATAR,
138                                                              G_PARAM_READWRITE));
139
140         g_object_class_install_property (object_class,
141                                          PROP_ACCOUNT,
142                                          g_param_spec_object ("account",
143                                                               "Contact Account",
144                                                               "The account associated with the contact",
145                                                               MC_TYPE_ACCOUNT,
146                                                               G_PARAM_READWRITE));
147
148         g_object_class_install_property (object_class,
149                                          PROP_PRESENCE,
150                                          g_param_spec_object ("presence",
151                                                               "Contact presence",
152                                                               "Presence of contact",
153                                                               GOSSIP_TYPE_PRESENCE,
154                                                               G_PARAM_READWRITE));
155
156         g_object_class_install_property (object_class,
157                                          PROP_GROUPS,
158                                          g_param_spec_pointer ("groups",
159                                                                "Contact groups",
160                                                                "Groups of contact",
161                                                                G_PARAM_READWRITE));
162
163         g_object_class_install_property (object_class,
164                                          PROP_SUBSCRIPTION,
165                                          g_param_spec_int ("subscription",
166                                                            "Contact Subscription",
167                                                            "The subscription status of the contact",
168                                                            GOSSIP_SUBSCRIPTION_NONE,
169                                                            GOSSIP_SUBSCRIPTION_BOTH,
170                                                            GOSSIP_SUBSCRIPTION_NONE,
171                                                            G_PARAM_READWRITE));
172
173
174         g_object_class_install_property (object_class,
175                                          PROP_HANDLE,
176                                          g_param_spec_uint ("handle",
177                                                             "Contact Handle",
178                                                             "The handle of the contact",
179                                                             0,
180                                                             G_MAXUINT,
181                                                             0,
182                                                             G_PARAM_READWRITE));
183
184         g_type_class_add_private (object_class, sizeof (GossipContactPriv));
185 }
186
187 static void
188 contact_init (GossipContact *contact)
189 {
190         GossipContactPriv *priv;
191
192         priv = GET_PRIV (contact);
193
194         priv->id       = NULL;
195         priv->name     = NULL;
196         priv->avatar   = NULL;
197         priv->account  = NULL;
198         priv->presence = NULL;
199         priv->groups   = NULL;
200         priv->handle   = 0;
201 }
202
203 static void
204 contact_finalize (GObject *object)
205 {
206         GossipContactPriv *priv;
207
208         priv = GET_PRIV (object);
209
210         gossip_debug (DEBUG_DOMAIN, "finalize: %p", object);
211
212         g_free (priv->name);
213         g_free (priv->id);
214
215         if (priv->avatar) {
216                 gossip_avatar_unref (priv->avatar);
217         }
218
219         if (priv->presence) {
220                 g_object_unref (priv->presence);
221         }
222
223         if (priv->groups) {
224                 g_list_foreach (priv->groups, (GFunc) g_free, NULL);
225                 g_list_free (priv->groups);
226         }
227
228         if (priv->account) {
229                 g_object_unref (priv->account);
230         }
231
232         (G_OBJECT_CLASS (parent_class)->finalize) (object);
233 }
234
235 static void
236 contact_get_property (GObject    *object,
237                       guint       param_id,
238                       GValue     *value,
239                       GParamSpec *pspec)
240 {
241         GossipContactPriv *priv;
242
243         priv = GET_PRIV (object);
244
245         switch (param_id) {
246         case PROP_ID:
247                 g_value_set_string (value,
248                                     gossip_contact_get_id (GOSSIP_CONTACT (object)));
249                 break;
250         case PROP_NAME:
251                 g_value_set_string (value,
252                                     gossip_contact_get_name (GOSSIP_CONTACT (object)));
253                 break;
254         case PROP_AVATAR:
255                 g_value_set_boxed (value, priv->avatar);
256                 break;
257         case PROP_ACCOUNT:
258                 g_value_set_object (value, priv->account);
259                 break;
260         case PROP_PRESENCE:
261                 g_value_set_object (value, priv->presence);
262                 break;
263         case PROP_GROUPS:
264                 g_value_set_pointer (value, priv->groups);
265                 break;
266         case PROP_SUBSCRIPTION:
267                 g_value_set_int (value, priv->subscription);
268                 break;
269         case PROP_HANDLE:
270                 g_value_set_uint (value, priv->handle);
271                 break;
272         default:
273                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
274                 break;
275         };
276 }
277
278 static void
279 contact_set_property (GObject      *object,
280                       guint         param_id,
281                       const GValue *value,
282                       GParamSpec   *pspec)
283 {
284         GossipContactPriv *priv;
285
286         priv = GET_PRIV (object);
287
288         switch (param_id) {
289         case PROP_ID:
290                 gossip_contact_set_id (GOSSIP_CONTACT (object),
291                                        g_value_get_string (value));
292                 break;
293         case PROP_NAME:
294                 gossip_contact_set_name (GOSSIP_CONTACT (object),
295                                          g_value_get_string (value));
296                 break;
297         case PROP_AVATAR:
298                 gossip_contact_set_avatar (GOSSIP_CONTACT (object),
299                                            g_value_get_boxed (value));
300                 break;
301         case PROP_ACCOUNT:
302                 gossip_contact_set_account (GOSSIP_CONTACT (object),
303                                             MC_ACCOUNT (g_value_get_object (value)));
304                 break;
305         case PROP_PRESENCE:
306                 gossip_contact_set_presence (GOSSIP_CONTACT (object),
307                                              GOSSIP_PRESENCE (g_value_get_object (value)));
308                 break;
309         case PROP_GROUPS:
310                 gossip_contact_set_groups (GOSSIP_CONTACT (object),
311                                            g_value_get_pointer (value));
312                 break;
313         case PROP_SUBSCRIPTION:
314                 gossip_contact_set_subscription (GOSSIP_CONTACT (object),
315                                                  g_value_get_int (value));
316                 break;
317         case PROP_HANDLE:
318                 gossip_contact_set_handle (GOSSIP_CONTACT (object),
319                                            g_value_get_uint (value));
320                 break;
321         default:
322                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
323                 break;
324         };
325 }
326
327 GossipContact *
328 gossip_contact_new (McAccount *account)
329 {
330         return g_object_new (GOSSIP_TYPE_CONTACT,
331                              "account", account,
332                              NULL);
333 }
334
335 GossipContact *
336 gossip_contact_new_full (McAccount   *account,
337                          const gchar *id,
338                          const gchar *name)
339 {
340         return g_object_new (GOSSIP_TYPE_CONTACT,
341                              "account", account,
342                              "name", name,
343                              "id", id,
344                              NULL);
345 }
346
347 const gchar *
348 gossip_contact_get_id (GossipContact *contact)
349 {
350         GossipContactPriv *priv;
351
352         g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), "");
353
354         priv = GET_PRIV (contact);
355
356         if (priv->id) {
357                 return priv->id;
358         }
359
360         return "";
361 }
362
363 const gchar *
364 gossip_contact_get_name (GossipContact *contact)
365 {
366         GossipContactPriv *priv;
367
368         g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), "");
369
370         priv = GET_PRIV (contact);
371
372         if (priv->name == NULL) {
373                 return gossip_contact_get_id (contact);
374         }
375
376         return priv->name;
377 }
378
379 GossipAvatar *
380 gossip_contact_get_avatar (GossipContact *contact)
381 {
382         GossipContactPriv *priv;
383
384         g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), NULL);
385
386         priv = GET_PRIV (contact);
387
388         return priv->avatar;
389 }
390
391 McAccount *
392 gossip_contact_get_account (GossipContact *contact)
393 {
394         GossipContactPriv *priv;
395
396         g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), NULL);
397
398         priv = GET_PRIV (contact);
399
400         return priv->account;
401 }
402
403 GossipPresence *
404 gossip_contact_get_presence (GossipContact *contact)
405 {
406         GossipContactPriv *priv;
407
408         g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), NULL);
409
410         priv = GET_PRIV (contact);
411
412         return priv->presence;
413 }
414
415 GList *
416 gossip_contact_get_groups (GossipContact *contact)
417 {
418         GossipContactPriv *priv;
419
420         g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), NULL);
421
422         priv = GET_PRIV (contact);
423
424         return priv->groups;
425 }
426
427 GossipSubscription
428 gossip_contact_get_subscription (GossipContact *contact)
429 {
430         GossipContactPriv *priv;
431
432         g_return_val_if_fail (GOSSIP_IS_CONTACT (contact),
433                               GOSSIP_SUBSCRIPTION_NONE);
434
435         priv = GET_PRIV (contact);
436
437         return priv->subscription;
438 }
439
440 guint
441 gossip_contact_get_handle (GossipContact *contact)
442 {
443         GossipContactPriv *priv;
444
445         g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), 0);
446
447         priv = GET_PRIV (contact);
448
449         return priv->handle;
450 }
451
452 void
453 gossip_contact_set_id (GossipContact *contact,
454                        const gchar   *id)
455 {
456         GossipContactPriv *priv;
457
458         g_return_if_fail (GOSSIP_IS_CONTACT (contact));
459         g_return_if_fail (id != NULL);
460
461         priv = GET_PRIV (contact);
462
463         if (priv->id && strcmp (id, priv->id) == 0) {
464                 return;
465         }
466
467         g_free (priv->id);
468         priv->id = g_strdup (id);
469
470         g_object_notify (G_OBJECT (contact), "id");
471 }
472
473 void
474 gossip_contact_set_name (GossipContact *contact,
475                          const gchar   *name)
476 {
477         GossipContactPriv *priv;
478
479         g_return_if_fail (GOSSIP_IS_CONTACT (contact));
480         g_return_if_fail (name != NULL);
481
482         priv = GET_PRIV (contact);
483
484         if (priv->name && strcmp (name, priv->name) == 0) {
485                 return;
486         }
487
488         g_free (priv->name);
489         priv->name = g_strdup (name);
490
491         g_object_notify (G_OBJECT (contact), "name");
492 }
493
494 void
495 gossip_contact_set_avatar (GossipContact *contact,
496                            GossipAvatar  *avatar)
497 {
498         GossipContactPriv *priv;
499
500         g_return_if_fail (GOSSIP_IS_CONTACT (contact));
501
502         priv = GET_PRIV (contact);
503
504         if (priv->avatar == avatar) {
505                 return;
506         }
507
508         if (priv->avatar) {
509                 gossip_avatar_unref (priv->avatar);
510                 priv->avatar = NULL;
511         }
512
513         if (avatar) {
514                 priv->avatar = gossip_avatar_ref (avatar);
515         }
516
517         g_object_notify (G_OBJECT (contact), "avatar");
518 }
519
520 void
521 gossip_contact_set_account (GossipContact *contact,
522                             McAccount     *account)
523 {
524         GossipContactPriv *priv;
525
526         g_return_if_fail (GOSSIP_IS_CONTACT (contact));
527         g_return_if_fail (MC_IS_ACCOUNT (account));
528
529         priv = GET_PRIV (contact);
530
531         if (account == priv->account) {
532                 return;
533         }
534
535         if (priv->account) {
536                 g_object_unref (priv->account);
537         }
538         priv->account = g_object_ref (account);
539
540         g_object_notify (G_OBJECT (contact), "account");
541 }
542
543 void
544 gossip_contact_set_presence (GossipContact  *contact,
545                              GossipPresence *presence)
546 {
547         GossipContactPriv *priv;
548
549         g_return_if_fail (GOSSIP_IS_CONTACT (contact));
550
551         priv = GET_PRIV (contact);
552
553         if (presence == priv->presence) {
554                 return;
555         }
556
557         if (priv->presence) {
558                 g_object_unref (priv->presence);
559                 priv->presence = NULL;
560         }
561
562         if (presence) {
563                 priv->presence = g_object_ref (presence);
564         }
565
566         g_object_notify (G_OBJECT (contact), "presence");
567 }
568
569 void
570 gossip_contact_set_groups (GossipContact *contact,
571                            GList         *groups)
572 {
573         GossipContactPriv *priv;
574         GList             *old_groups, *l;
575
576         g_return_if_fail (GOSSIP_IS_CONTACT (contact));
577
578         priv = GET_PRIV (contact);
579
580         old_groups = priv->groups;
581         priv->groups = NULL;
582
583         for (l = groups; l; l = l->next) {
584                 priv->groups = g_list_append (priv->groups,
585                                               g_strdup (l->data));
586         }
587
588         g_list_foreach (old_groups, (GFunc) g_free, NULL);
589         g_list_free (old_groups);
590
591         g_object_notify (G_OBJECT (contact), "groups");
592 }
593
594 void
595 gossip_contact_set_subscription (GossipContact      *contact,
596                                  GossipSubscription  subscription)
597 {
598         GossipContactPriv *priv;
599
600         g_return_if_fail (GOSSIP_IS_CONTACT (contact));
601
602         priv = GET_PRIV (contact);
603
604         if (priv->subscription == subscription) {
605                 return;
606         }
607
608         priv->subscription = subscription;
609
610         g_object_notify (G_OBJECT (contact), "subscription");
611 }
612
613 void
614 gossip_contact_set_handle (GossipContact *contact,
615                            guint          handle)
616 {
617         GossipContactPriv *priv;
618
619         g_return_if_fail (GOSSIP_IS_CONTACT (contact));
620
621         priv = GET_PRIV (contact);
622
623         if (priv->handle == handle) {
624                 return;
625         }
626
627         priv->handle = handle;
628
629         g_object_notify (G_OBJECT (contact), "handle");
630 }
631
632 void
633 gossip_contact_add_group (GossipContact *contact,
634                           const gchar   *group)
635 {
636         GossipContactPriv *priv;
637
638         g_return_if_fail (GOSSIP_IS_CONTACT (contact));
639         g_return_if_fail (group != NULL);
640
641         priv = GET_PRIV (contact);
642
643         if (!g_list_find_custom (priv->groups, group, (GCompareFunc) strcmp)) {
644                 priv->groups = g_list_prepend (priv->groups, g_strdup (group));
645                 g_object_notify (G_OBJECT (contact), "groups");
646         }
647 }
648
649 void
650 gossip_contact_remove_group (GossipContact *contact,
651                              const gchar   *group)
652 {
653         GossipContactPriv *priv;
654         GList             *l;
655
656         g_return_if_fail (GOSSIP_IS_CONTACT (contact));
657         g_return_if_fail (group != NULL);
658
659         priv = GET_PRIV (contact);
660
661         l = g_list_find_custom (priv->groups, group, (GCompareFunc) strcmp);
662         if (l) {
663                 g_free (l->data);
664                 priv->groups = g_list_delete_link (priv->groups, l);
665                 g_object_notify (G_OBJECT (contact), "groups");
666         }
667 }
668
669 gboolean
670 gossip_contact_is_online (GossipContact *contact)
671 {
672         GossipContactPriv *priv;
673
674         g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), FALSE);
675
676         priv = GET_PRIV (contact);
677
678         return (priv->presence != NULL);
679 }
680
681 gboolean
682 gossip_contact_is_in_group (GossipContact *contact,
683                             const gchar   *group)
684 {
685         GossipContactPriv *priv;
686
687         g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), FALSE);
688         g_return_val_if_fail (!G_STR_EMPTY (group), FALSE);
689
690         priv = GET_PRIV (contact);
691
692         if (g_list_find_custom (priv->groups, group, (GCompareFunc) strcmp)) {
693                 return TRUE;
694         }
695
696         return FALSE;
697 }
698
699 const gchar *
700 gossip_contact_get_status (GossipContact *contact)
701 {
702         GossipContactPriv *priv;
703
704         g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), "");
705
706         priv = GET_PRIV (contact);
707
708         if (priv->presence) {
709                 const gchar *status;
710
711                 status = gossip_presence_get_status (priv->presence);
712                 if (!status) {
713                         McPresence state;
714
715                         state = gossip_presence_get_state (priv->presence);
716                         status = gossip_presence_state_get_default_status (state);
717                 }
718
719                 return status;
720         }
721
722         return gossip_presence_state_get_default_status (MC_PRESENCE_OFFLINE);
723 }
724
725 GossipContact *
726 gossip_contact_get_user (GossipContact *contact)
727 {
728         GossipContactPriv     *priv;
729         EmpathyContactManager *manager;
730         GossipContact         *user_contact;
731
732         g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), NULL);
733
734         priv = GET_PRIV (contact);
735
736         manager = empathy_contact_manager_new ();
737         user_contact = empathy_contact_manager_get_user (manager, priv->account);
738         g_object_unref (manager);
739
740         return user_contact;
741 }
742
743 gboolean
744 gossip_contact_equal (gconstpointer v1,
745                       gconstpointer v2)
746 {
747         McAccount   *account_a;
748         McAccount   *account_b;
749         const gchar *id_a;
750         const gchar *id_b;
751
752         g_return_val_if_fail (GOSSIP_IS_CONTACT (v1), FALSE);
753         g_return_val_if_fail (GOSSIP_IS_CONTACT (v2), FALSE);
754
755         account_a = gossip_contact_get_account (GOSSIP_CONTACT (v1));
756         account_b = gossip_contact_get_account (GOSSIP_CONTACT (v2));
757
758         id_a = gossip_contact_get_id (GOSSIP_CONTACT (v1));
759         id_b = gossip_contact_get_id (GOSSIP_CONTACT (v2));
760
761         return gossip_account_equal (account_a, account_b) && g_str_equal (id_a, id_b);
762 }
763
764 guint
765 gossip_contact_hash (gconstpointer key)
766 {
767         GossipContactPriv *priv;
768         guint              hash;
769
770         g_return_val_if_fail (GOSSIP_IS_CONTACT (key), +1);
771
772         priv = GET_PRIV (GOSSIP_CONTACT (key));
773
774         hash = gossip_account_hash (gossip_contact_get_account (GOSSIP_CONTACT (key)));
775         hash += g_str_hash (gossip_contact_get_id (GOSSIP_CONTACT (key)));
776
777         return hash;
778 }
779