[darcs-to-svn @ Syncing new contact list stuff from gossip]
[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
34 #define DEBUG_DOMAIN "Contact"
35
36 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_CONTACT, GossipContactPriv))
37
38 typedef struct _GossipContactPriv GossipContactPriv;
39
40 struct _GossipContactPriv {
41         gchar              *id;
42         gchar              *name;
43         GossipAvatar       *avatar;
44         McAccount          *account;
45         GossipPresence     *presence;
46         GList              *groups;
47         GossipSubscription  subscription;
48         guint               handle;
49 };
50
51 static void contact_class_init    (GossipContactClass *class);
52 static void contact_init          (GossipContact      *contact);
53 static void contact_finalize      (GObject            *object);
54 static void contact_get_property  (GObject            *object,
55                                    guint               param_id,
56                                    GValue             *value,
57                                    GParamSpec         *pspec);
58 static void contact_set_property  (GObject            *object,
59                                    guint               param_id,
60                                    const GValue       *value,
61                                    GParamSpec         *pspec);
62
63 enum {
64         PROP_0,
65         PROP_ID,
66         PROP_NAME,
67         PROP_AVATAR,
68         PROP_ACCOUNT,
69         PROP_PRESENCE,
70         PROP_GROUPS,
71         PROP_SUBSCRIPTION,
72         PROP_HANDLE
73 };
74
75 static gpointer parent_class = NULL;
76
77 GType
78 gossip_contact_get_gtype (void)
79 {
80         static GType type = 0;
81
82         if (!type) {
83                 static const GTypeInfo info = {
84                         sizeof (GossipContactClass),
85                         NULL, /* base_init */
86                         NULL, /* base_finalize */
87                         (GClassInitFunc) contact_class_init,
88                         NULL, /* class_finalize */
89                         NULL, /* class_data */
90                         sizeof (GossipContact),
91                         0,    /* n_preallocs */
92                         (GInstanceInitFunc) contact_init
93                 };
94
95                 type = g_type_register_static (G_TYPE_OBJECT,
96                                                "GossipContact",
97                                                &info, 0);
98         }
99
100         return type;
101 }
102
103 static void
104 contact_class_init (GossipContactClass *class)
105 {
106         GObjectClass *object_class;
107
108         object_class = G_OBJECT_CLASS (class);
109         parent_class = g_type_class_peek_parent (class);
110
111         object_class->finalize     = contact_finalize;
112         object_class->get_property = contact_get_property;
113         object_class->set_property = contact_set_property;
114
115         g_object_class_install_property (object_class,
116                                          PROP_ID,
117                                          g_param_spec_string ("id",
118                                                               "Contact id",
119                                                               "String identifying contact",
120                                                               NULL,
121                                                               G_PARAM_READWRITE));
122
123         g_object_class_install_property (object_class,
124                                          PROP_NAME,
125                                          g_param_spec_string ("name",
126                                                               "Contact Name",
127                                                               "The name of the contact",
128                                                               NULL,
129                                                               G_PARAM_READWRITE));
130
131         g_object_class_install_property (object_class,
132                                          PROP_AVATAR,
133                                          g_param_spec_boxed ("avatar",
134                                                              "Avatar image",
135                                                              "The avatar image",
136                                                              GOSSIP_TYPE_AVATAR,
137                                                              G_PARAM_READWRITE));
138
139         g_object_class_install_property (object_class,
140                                          PROP_ACCOUNT,
141                                          g_param_spec_object ("account",
142                                                               "Contact Account",
143                                                               "The account associated with the contact",
144                                                               MC_TYPE_ACCOUNT,
145                                                               G_PARAM_READWRITE));
146
147         g_object_class_install_property (object_class,
148                                          PROP_PRESENCE,
149                                          g_param_spec_object ("presence",
150                                                               "Contact presence",
151                                                               "Presence of contact",
152                                                               GOSSIP_TYPE_PRESENCE,
153                                                               G_PARAM_READWRITE));
154
155         g_object_class_install_property (object_class,
156                                          PROP_GROUPS,
157                                          g_param_spec_pointer ("groups",
158                                                                "Contact groups",
159                                                                "Groups of contact",
160                                                                G_PARAM_READWRITE));
161
162         g_object_class_install_property (object_class,
163                                          PROP_SUBSCRIPTION,
164                                          g_param_spec_int ("subscription",
165                                                            "Contact Subscription",
166                                                            "The subscription status of the contact",
167                                                            GOSSIP_SUBSCRIPTION_NONE,
168                                                            GOSSIP_SUBSCRIPTION_BOTH,
169                                                            GOSSIP_SUBSCRIPTION_NONE,
170                                                            G_PARAM_READWRITE));
171
172
173         g_object_class_install_property (object_class,
174                                          PROP_HANDLE,
175                                          g_param_spec_uint ("handle",
176                                                             "Contact Handle",
177                                                             "The handle of the contact",
178                                                             0,
179                                                             G_MAXUINT,
180                                                             0,
181                                                             G_PARAM_READWRITE));
182
183         g_type_class_add_private (object_class, sizeof (GossipContactPriv));
184 }
185
186 static void
187 contact_init (GossipContact *contact)
188 {
189         GossipContactPriv *priv;
190
191         priv = GET_PRIV (contact);
192
193         priv->id       = NULL;
194         priv->name     = NULL;
195         priv->avatar   = NULL;
196         priv->account  = NULL;
197         priv->presence = NULL;
198         priv->groups   = NULL;
199         priv->handle   = 0;
200 }
201
202 static void
203 contact_finalize (GObject *object)
204 {
205         GossipContactPriv *priv;
206
207         priv = GET_PRIV (object);
208
209         gossip_debug (DEBUG_DOMAIN, "finalize: %p", object);
210
211         g_free (priv->name);
212         g_free (priv->id);
213
214         if (priv->avatar) {
215                 gossip_avatar_unref (priv->avatar);
216         }
217
218         if (priv->presence) {
219                 g_object_unref (priv->presence);
220         }
221
222         if (priv->groups) {
223                 g_list_foreach (priv->groups, (GFunc) g_free, NULL);
224                 g_list_free (priv->groups);
225         }
226
227         if (priv->account) {
228                 g_object_unref (priv->account);
229         }
230
231         (G_OBJECT_CLASS (parent_class)->finalize) (object);
232 }
233
234 static void
235 contact_get_property (GObject    *object,
236                       guint       param_id,
237                       GValue     *value,
238                       GParamSpec *pspec)
239 {
240         GossipContactPriv *priv;
241
242         priv = GET_PRIV (object);
243
244         switch (param_id) {
245         case PROP_ID:
246                 g_value_set_string (value,
247                                     gossip_contact_get_id (GOSSIP_CONTACT (object)));
248                 break;
249         case PROP_NAME:
250                 g_value_set_string (value,
251                                     gossip_contact_get_name (GOSSIP_CONTACT (object)));
252                 break;
253         case PROP_AVATAR:
254                 g_value_set_boxed (value, priv->avatar);
255                 break;
256         case PROP_ACCOUNT:
257                 g_value_set_object (value, priv->account);
258                 break;
259         case PROP_PRESENCE:
260                 g_value_set_object (value, priv->presence);
261                 break;
262         case PROP_GROUPS:
263                 g_value_set_pointer (value, priv->groups);
264                 break;
265         case PROP_SUBSCRIPTION:
266                 g_value_set_int (value, priv->subscription);
267                 break;
268         case PROP_HANDLE:
269                 g_value_set_uint (value, priv->handle);
270                 break;
271         default:
272                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
273                 break;
274         };
275 }
276
277 static void
278 contact_set_property (GObject      *object,
279                       guint         param_id,
280                       const GValue *value,
281                       GParamSpec   *pspec)
282 {
283         GossipContactPriv *priv;
284
285         priv = GET_PRIV (object);
286
287         switch (param_id) {
288         case PROP_ID:
289                 gossip_contact_set_id (GOSSIP_CONTACT (object),
290                                        g_value_get_string (value));
291                 break;
292         case PROP_NAME:
293                 gossip_contact_set_name (GOSSIP_CONTACT (object),
294                                          g_value_get_string (value));
295                 break;
296         case PROP_AVATAR:
297                 gossip_contact_set_avatar (GOSSIP_CONTACT (object),
298                                            g_value_get_boxed (value));
299                 break;
300         case PROP_ACCOUNT:
301                 gossip_contact_set_account (GOSSIP_CONTACT (object),
302                                             MC_ACCOUNT (g_value_get_object (value)));
303                 break;
304         case PROP_PRESENCE:
305                 gossip_contact_set_presence (GOSSIP_CONTACT (object),
306                                              GOSSIP_PRESENCE (g_value_get_object (value)));
307                 break;
308         case PROP_GROUPS:
309                 gossip_contact_set_groups (GOSSIP_CONTACT (object),
310                                            g_value_get_pointer (value));
311                 break;
312         case PROP_SUBSCRIPTION:
313                 gossip_contact_set_subscription (GOSSIP_CONTACT (object),
314                                                  g_value_get_int (value));
315                 break;
316         case PROP_HANDLE:
317                 gossip_contact_set_handle (GOSSIP_CONTACT (object),
318                                            g_value_get_uint (value));
319                 break;
320         default:
321                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
322                 break;
323         };
324 }
325
326 GossipContact *
327 gossip_contact_new (McAccount *account)
328 {
329         return g_object_new (GOSSIP_TYPE_CONTACT,
330                              "account", account,
331                              NULL);
332 }
333
334 GossipContact *
335 gossip_contact_new_full (McAccount *account,
336                          const gchar   *id,
337                          const gchar   *name)
338 {
339         return g_object_new (GOSSIP_TYPE_CONTACT,
340                              "account", account,
341                              "name", name,
342                              "id", id,
343                              NULL);
344 }
345
346 const gchar *
347 gossip_contact_get_id (GossipContact *contact)
348 {
349         GossipContactPriv *priv;
350
351         g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), "");
352
353         priv = GET_PRIV (contact);
354
355         if (priv->id) {
356                 return priv->id;
357         }
358
359         return "";
360 }
361
362 const gchar *
363 gossip_contact_get_name (GossipContact *contact)
364 {
365         GossipContactPriv *priv;
366
367         g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), "");
368
369         priv = GET_PRIV (contact);
370
371         if (priv->name == NULL) {
372                 return gossip_contact_get_id (contact);
373         }
374
375         return priv->name;
376 }
377
378 GossipAvatar *
379 gossip_contact_get_avatar (GossipContact *contact)
380 {
381         GossipContactPriv *priv;
382
383         g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), NULL);
384
385         priv = GET_PRIV (contact);
386
387         return priv->avatar;
388 }
389
390 McAccount *
391 gossip_contact_get_account (GossipContact *contact)
392 {
393         GossipContactPriv *priv;
394
395         g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), NULL);
396
397         priv = GET_PRIV (contact);
398
399         return priv->account;
400 }
401
402 GossipPresence *
403 gossip_contact_get_presence (GossipContact *contact)
404 {
405         GossipContactPriv *priv;
406
407         g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), NULL);
408
409         priv = GET_PRIV (contact);
410
411         return priv->presence;
412 }
413
414 GList *
415 gossip_contact_get_groups (GossipContact *contact)
416 {
417         GossipContactPriv *priv;
418
419         g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), NULL);
420
421         priv = GET_PRIV (contact);
422
423         return priv->groups;
424 }
425
426 GossipSubscription
427 gossip_contact_get_subscription (GossipContact *contact)
428 {
429         GossipContactPriv *priv;
430
431         g_return_val_if_fail (GOSSIP_IS_CONTACT (contact),
432                               GOSSIP_SUBSCRIPTION_NONE);
433
434         priv = GET_PRIV (contact);
435
436         return priv->subscription;
437 }
438
439 guint
440 gossip_contact_get_handle (GossipContact *contact)
441 {
442         GossipContactPriv *priv;
443
444         g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), 0);
445
446         priv = GET_PRIV (contact);
447
448         return priv->handle;
449 }
450
451 void
452 gossip_contact_set_id (GossipContact *contact,
453                        const gchar   *id)
454 {
455         GossipContactPriv *priv;
456
457         g_return_if_fail (GOSSIP_IS_CONTACT (contact));
458         g_return_if_fail (id != NULL);
459
460         priv = GET_PRIV (contact);
461
462         g_free (priv->id);
463         priv->id = g_strdup (id);
464
465         g_object_notify (G_OBJECT (contact), "id");
466 }
467
468 void
469 gossip_contact_set_name (GossipContact *contact,
470                          const gchar   *name)
471 {
472         GossipContactPriv *priv;
473
474         g_return_if_fail (GOSSIP_IS_CONTACT (contact));
475         g_return_if_fail (name != NULL);
476
477         priv = GET_PRIV (contact);
478
479         g_free (priv->name);
480         priv->name = g_strdup (name);
481
482         g_object_notify (G_OBJECT (contact), "name");
483 }
484
485 void
486 gossip_contact_set_avatar (GossipContact *contact,
487                            GossipAvatar  *avatar)
488 {
489         GossipContactPriv *priv;
490
491         g_return_if_fail (GOSSIP_IS_CONTACT (contact));
492
493         priv = GET_PRIV (contact);
494
495         if (priv->avatar) {
496                 gossip_avatar_unref (priv->avatar);
497                 priv->avatar = NULL;
498         }
499
500         if (avatar) {
501                 priv->avatar = gossip_avatar_ref (avatar);
502         }
503
504         g_object_notify (G_OBJECT (contact), "avatar");
505 }
506
507 void
508 gossip_contact_set_account (GossipContact *contact,
509                             McAccount     *account)
510 {
511         GossipContactPriv *priv;
512
513         g_return_if_fail (GOSSIP_IS_CONTACT (contact));
514         g_return_if_fail (MC_IS_ACCOUNT (account));
515
516         priv = GET_PRIV (contact);
517
518         if (priv->account) {
519                 g_object_unref (priv->account);
520         }
521         priv->account = g_object_ref (account);
522
523         g_object_notify (G_OBJECT (contact), "account");
524 }
525
526 void
527 gossip_contact_set_presence (GossipContact  *contact,
528                              GossipPresence *presence)
529 {
530         GossipContactPriv *priv;
531
532         g_return_if_fail (GOSSIP_IS_CONTACT (contact));
533
534         priv = GET_PRIV (contact);
535
536         if (priv->presence) {
537                 g_object_unref (priv->presence);
538                 priv->presence = NULL;
539         }
540
541         if (presence) {
542                 priv->presence = g_object_ref (presence);
543         }
544
545         g_object_notify (G_OBJECT (contact), "presence");
546 }
547
548 void
549 gossip_contact_set_groups (GossipContact *contact,
550                            GList         *groups)
551 {
552         GossipContactPriv *priv;
553         GList             *old_groups, *l;
554
555         g_return_if_fail (GOSSIP_IS_CONTACT (contact));
556
557         priv = GET_PRIV (contact);
558
559         old_groups = priv->groups;
560         priv->groups = NULL;
561
562         for (l = groups; l; l = l->next) {
563                 priv->groups = g_list_append (priv->groups,
564                                               g_strdup (l->data));
565         }
566
567         g_list_foreach (old_groups, (GFunc) g_free, NULL);
568         g_list_free (old_groups);
569
570         g_object_notify (G_OBJECT (contact), "groups");
571 }
572
573 void
574 gossip_contact_set_subscription (GossipContact      *contact,
575                                  GossipSubscription  subscription)
576 {
577         GossipContactPriv *priv;
578
579         g_return_if_fail (GOSSIP_IS_CONTACT (contact));
580
581         priv = GET_PRIV (contact);
582
583         priv->subscription = subscription;
584
585         g_object_notify (G_OBJECT (contact), "subscription");
586 }
587
588 void
589 gossip_contact_set_handle (GossipContact *contact,
590                            guint          handle)
591 {
592         GossipContactPriv *priv;
593
594         priv = GET_PRIV (contact);
595
596         priv->handle = handle;
597
598         g_object_notify (G_OBJECT (contact), "handle");
599 }
600
601 gboolean
602 gossip_contact_is_online (GossipContact *contact)
603 {
604         GossipContactPriv *priv;
605
606         g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), FALSE);
607
608         priv = GET_PRIV (contact);
609
610         return (priv->presence != NULL);
611 }
612
613 gboolean
614 gossip_contact_is_in_group (GossipContact *contact,
615                             const gchar   *group)
616 {
617         GossipContactPriv *priv;
618
619         g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), FALSE);
620         g_return_val_if_fail (!G_STR_EMPTY (group), FALSE);
621
622         priv = GET_PRIV (contact);
623
624         if (g_list_find_custom (priv->groups, group, (GCompareFunc) strcmp)) {
625                 return TRUE;
626         }
627
628         return FALSE;
629 }
630
631 const gchar *
632 gossip_contact_get_status (GossipContact *contact)
633 {
634         GossipContactPriv *priv;
635
636         g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), "");
637
638         priv = GET_PRIV (contact);
639
640         if (priv->presence) {
641                 const gchar *status;
642
643                 status = gossip_presence_get_status (priv->presence);
644                 if (!status) {
645                         GossipPresenceState state;
646
647                         state = gossip_presence_get_state (priv->presence);
648                         status = gossip_presence_state_get_default_status (state);
649                 }
650
651                 return status;
652         }
653
654         return _("Offline");
655 }
656
657 gboolean
658 gossip_contact_equal (gconstpointer v1,
659                       gconstpointer v2)
660 {
661         McAccount   *account_a;
662         McAccount   *account_b;
663         const gchar *id_a;
664         const gchar *id_b;
665
666         g_return_val_if_fail (GOSSIP_IS_CONTACT (v1), FALSE);
667         g_return_val_if_fail (GOSSIP_IS_CONTACT (v2), FALSE);
668
669         account_a = gossip_contact_get_account (GOSSIP_CONTACT (v1));
670         account_b = gossip_contact_get_account (GOSSIP_CONTACT (v2));
671
672         id_a = gossip_contact_get_id (GOSSIP_CONTACT (v1));
673         id_b = gossip_contact_get_id (GOSSIP_CONTACT (v2));
674
675         return gossip_account_equal (account_a, account_b) && g_str_equal (id_a, id_b);
676 }
677
678 guint
679 gossip_contact_hash (gconstpointer key)
680 {
681         GossipContactPriv *priv;
682         guint              hash;
683
684         g_return_val_if_fail (GOSSIP_IS_CONTACT (key), +1);
685
686         priv = GET_PRIV (GOSSIP_CONTACT (key));
687
688         hash = gossip_account_hash (gossip_contact_get_account (GOSSIP_CONTACT (key)));
689         hash += g_str_hash (gossip_contact_get_id (GOSSIP_CONTACT (key)));
690
691         return hash;
692 }
693