]> git.0d.be Git - empathy.git/blob - libempathy/empathy-contact.c
Completely reworked ContactList API. Fixes bug #471611, bug #467280, bug #459540...
[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 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 "empathy-contact.h"
33 #include "empathy-utils.h"
34 #include "empathy-debug.h"
35 #include "empathy-enum-types.h"
36
37 #define DEBUG_DOMAIN "Contact"
38
39 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), EMPATHY_TYPE_CONTACT, EmpathyContactPriv))
40
41 typedef struct _EmpathyContactPriv EmpathyContactPriv;
42
43 struct _EmpathyContactPriv {
44         gchar              *id;
45         gchar              *name;
46         EmpathyAvatar      *avatar;
47         McAccount          *account;
48         EmpathyPresence    *presence;
49         guint               handle;
50         gboolean            is_user;
51 };
52
53 static void empathy_contact_class_init (EmpathyContactClass *class);
54 static void empathy_contact_init       (EmpathyContact      *contact);
55 static void contact_finalize           (GObject             *object);
56 static void contact_get_property       (GObject             *object,
57                                         guint                param_id,
58                                         GValue              *value,
59                                         GParamSpec          *pspec);
60 static void contact_set_property       (GObject             *object,
61                                         guint                param_id,
62                                         const GValue        *value,
63                                         GParamSpec          *pspec);
64
65 G_DEFINE_TYPE (EmpathyContact, empathy_contact, G_TYPE_OBJECT);
66
67 enum {
68         PROP_0,
69         PROP_ID,
70         PROP_NAME,
71         PROP_AVATAR,
72         PROP_ACCOUNT,
73         PROP_PRESENCE,
74         PROP_GROUPS,
75         PROP_SUBSCRIPTION,
76         PROP_HANDLE,
77         PROP_IS_USER
78 };
79
80 static void
81 empathy_contact_class_init (EmpathyContactClass *class)
82 {
83         GObjectClass *object_class;
84
85         object_class = G_OBJECT_CLASS (class);
86
87         object_class->finalize     = contact_finalize;
88         object_class->get_property = contact_get_property;
89         object_class->set_property = contact_set_property;
90
91         g_object_class_install_property (object_class,
92                                          PROP_ID,
93                                          g_param_spec_string ("id",
94                                                               "Contact id",
95                                                               "String identifying contact",
96                                                               NULL,
97                                                               G_PARAM_READWRITE));
98
99         g_object_class_install_property (object_class,
100                                          PROP_NAME,
101                                          g_param_spec_string ("name",
102                                                               "Contact Name",
103                                                               "The name of the contact",
104                                                               NULL,
105                                                               G_PARAM_READWRITE));
106
107         g_object_class_install_property (object_class,
108                                          PROP_AVATAR,
109                                          g_param_spec_boxed ("avatar",
110                                                              "Avatar image",
111                                                              "The avatar image",
112                                                              EMPATHY_TYPE_AVATAR,
113                                                              G_PARAM_READWRITE));
114
115         g_object_class_install_property (object_class,
116                                          PROP_ACCOUNT,
117                                          g_param_spec_object ("account",
118                                                               "Contact Account",
119                                                               "The account associated with the contact",
120                                                               MC_TYPE_ACCOUNT,
121                                                               G_PARAM_READWRITE));
122
123         g_object_class_install_property (object_class,
124                                          PROP_PRESENCE,
125                                          g_param_spec_object ("presence",
126                                                               "Contact presence",
127                                                               "Presence of contact",
128                                                               EMPATHY_TYPE_PRESENCE,
129                                                               G_PARAM_READWRITE));
130
131         g_object_class_install_property (object_class,
132                                          PROP_HANDLE,
133                                          g_param_spec_uint ("handle",
134                                                             "Contact Handle",
135                                                             "The handle of the contact",
136                                                             0,
137                                                             G_MAXUINT,
138                                                             0,
139                                                             G_PARAM_READWRITE));
140         g_object_class_install_property (object_class,
141                                          PROP_IS_USER,
142                                          g_param_spec_boolean ("is-user",
143                                                                "Contact is-user",
144                                                                "Is contact the user",
145                                                                FALSE,
146                                                                G_PARAM_READWRITE));
147
148         g_type_class_add_private (object_class, sizeof (EmpathyContactPriv));
149 }
150
151 static void
152 empathy_contact_init (EmpathyContact *contact)
153 {
154 }
155
156 static void
157 contact_finalize (GObject *object)
158 {
159         EmpathyContactPriv *priv;
160
161         priv = GET_PRIV (object);
162
163         empathy_debug (DEBUG_DOMAIN, "finalize: %p", object);
164
165         g_free (priv->name);
166         g_free (priv->id);
167
168         if (priv->avatar) {
169                 empathy_avatar_unref (priv->avatar);
170         }
171
172         if (priv->presence) {
173                 g_object_unref (priv->presence);
174         }
175
176         if (priv->account) {
177                 g_object_unref (priv->account);
178         }
179
180         G_OBJECT_CLASS (empathy_contact_parent_class)->finalize (object);
181 }
182
183 static void
184 contact_get_property (GObject    *object,
185                       guint       param_id,
186                       GValue     *value,
187                       GParamSpec *pspec)
188 {
189         EmpathyContactPriv *priv;
190
191         priv = GET_PRIV (object);
192
193         switch (param_id) {
194         case PROP_ID:
195                 g_value_set_string (value,
196                                     empathy_contact_get_id (EMPATHY_CONTACT (object)));
197                 break;
198         case PROP_NAME:
199                 g_value_set_string (value,
200                                     empathy_contact_get_name (EMPATHY_CONTACT (object)));
201                 break;
202         case PROP_AVATAR:
203                 g_value_set_boxed (value, priv->avatar);
204                 break;
205         case PROP_ACCOUNT:
206                 g_value_set_object (value, priv->account);
207                 break;
208         case PROP_PRESENCE:
209                 g_value_set_object (value, priv->presence);
210                 break;
211         case PROP_HANDLE:
212                 g_value_set_uint (value, priv->handle);
213                 break;
214         case PROP_IS_USER:
215                 g_value_set_boolean (value, priv->is_user);
216                 break;
217         default:
218                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
219                 break;
220         };
221 }
222
223 static void
224 contact_set_property (GObject      *object,
225                       guint         param_id,
226                       const GValue *value,
227                       GParamSpec   *pspec)
228 {
229         EmpathyContactPriv *priv;
230
231         priv = GET_PRIV (object);
232
233         switch (param_id) {
234         case PROP_ID:
235                 empathy_contact_set_id (EMPATHY_CONTACT (object),
236                                        g_value_get_string (value));
237                 break;
238         case PROP_NAME:
239                 empathy_contact_set_name (EMPATHY_CONTACT (object),
240                                          g_value_get_string (value));
241                 break;
242         case PROP_AVATAR:
243                 empathy_contact_set_avatar (EMPATHY_CONTACT (object),
244                                            g_value_get_boxed (value));
245                 break;
246         case PROP_ACCOUNT:
247                 empathy_contact_set_account (EMPATHY_CONTACT (object),
248                                             MC_ACCOUNT (g_value_get_object (value)));
249                 break;
250         case PROP_PRESENCE:
251                 empathy_contact_set_presence (EMPATHY_CONTACT (object),
252                                              EMPATHY_PRESENCE (g_value_get_object (value)));
253                 break;
254         case PROP_HANDLE:
255                 empathy_contact_set_handle (EMPATHY_CONTACT (object),
256                                            g_value_get_uint (value));
257                 break;
258         case PROP_IS_USER:
259                 empathy_contact_set_is_user (EMPATHY_CONTACT (object),
260                                             g_value_get_boolean (value));
261                 break;
262         default:
263                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
264                 break;
265         };
266 }
267
268 EmpathyContact *
269 empathy_contact_new (McAccount *account)
270 {
271         return g_object_new (EMPATHY_TYPE_CONTACT,
272                              "account", account,
273                              NULL);
274 }
275
276 EmpathyContact *
277 empathy_contact_new_full (McAccount   *account,
278                           const gchar *id,
279                           const gchar *name)
280 {
281         return g_object_new (EMPATHY_TYPE_CONTACT,
282                              "account", account,
283                              "name", name,
284                              "id", id,
285                              NULL);
286 }
287
288 const gchar *
289 empathy_contact_get_id (EmpathyContact *contact)
290 {
291         EmpathyContactPriv *priv;
292
293         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), "");
294
295         priv = GET_PRIV (contact);
296
297         if (priv->id) {
298                 return priv->id;
299         }
300
301         return "";
302 }
303
304 void
305 empathy_contact_set_id (EmpathyContact *contact,
306                        const gchar   *id)
307 {
308         EmpathyContactPriv *priv;
309
310         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
311         g_return_if_fail (id != NULL);
312
313         priv = GET_PRIV (contact);
314
315         if (priv->id && strcmp (id, priv->id) == 0) {
316                 return;
317         }
318
319         g_free (priv->id);
320         priv->id = g_strdup (id);
321
322         g_object_notify (G_OBJECT (contact), "id");
323 }
324
325 const gchar *
326 empathy_contact_get_name (EmpathyContact *contact)
327 {
328         EmpathyContactPriv *priv;
329
330         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), "");
331
332         priv = GET_PRIV (contact);
333
334         if (G_STR_EMPTY (priv->name)) {
335                 return empathy_contact_get_id (contact);
336         }
337
338         return priv->name;
339 }
340
341 void
342 empathy_contact_set_name (EmpathyContact *contact,
343                          const gchar   *name)
344 {
345         EmpathyContactPriv *priv;
346
347         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
348         g_return_if_fail (name != NULL);
349
350         priv = GET_PRIV (contact);
351
352         if (priv->name && strcmp (name, priv->name) == 0) {
353                 return;
354         }
355
356         g_free (priv->name);
357         priv->name = g_strdup (name);
358
359         g_object_notify (G_OBJECT (contact), "name");
360 }
361
362 EmpathyAvatar *
363 empathy_contact_get_avatar (EmpathyContact *contact)
364 {
365         EmpathyContactPriv *priv;
366
367         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
368
369         priv = GET_PRIV (contact);
370
371         return priv->avatar;
372 }
373
374 void
375 empathy_contact_set_avatar (EmpathyContact *contact,
376                            EmpathyAvatar  *avatar)
377 {
378         EmpathyContactPriv *priv;
379
380         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
381
382         priv = GET_PRIV (contact);
383
384         if (priv->avatar == avatar) {
385                 return;
386         }
387
388         if (priv->avatar) {
389                 empathy_avatar_unref (priv->avatar);
390                 priv->avatar = NULL;
391         }
392
393         if (avatar) {
394                 priv->avatar = empathy_avatar_ref (avatar);
395         }
396
397         g_object_notify (G_OBJECT (contact), "avatar");
398 }
399
400 McAccount *
401 empathy_contact_get_account (EmpathyContact *contact)
402 {
403         EmpathyContactPriv *priv;
404
405         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
406
407         priv = GET_PRIV (contact);
408
409         return priv->account;
410 }
411
412 void
413 empathy_contact_set_account (EmpathyContact *contact,
414                              McAccount      *account)
415 {
416         EmpathyContactPriv *priv;
417
418         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
419         g_return_if_fail (MC_IS_ACCOUNT (account));
420
421         priv = GET_PRIV (contact);
422
423         if (account == priv->account) {
424                 return;
425         }
426
427         if (priv->account) {
428                 g_object_unref (priv->account);
429         }
430         priv->account = g_object_ref (account);
431
432         g_object_notify (G_OBJECT (contact), "account");
433 }
434
435 EmpathyPresence *
436 empathy_contact_get_presence (EmpathyContact *contact)
437 {
438         EmpathyContactPriv *priv;
439
440         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
441
442         priv = GET_PRIV (contact);
443
444         return priv->presence;
445 }
446
447 void
448 empathy_contact_set_presence (EmpathyContact  *contact,
449                               EmpathyPresence *presence)
450 {
451         EmpathyContactPriv *priv;
452
453         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
454
455         priv = GET_PRIV (contact);
456
457         if (presence == priv->presence) {
458                 return;
459         }
460
461         if (priv->presence) {
462                 g_object_unref (priv->presence);
463                 priv->presence = NULL;
464         }
465
466         if (presence) {
467                 priv->presence = g_object_ref (presence);
468         }
469
470         g_object_notify (G_OBJECT (contact), "presence");
471 }
472
473 guint
474 empathy_contact_get_handle (EmpathyContact *contact)
475 {
476         EmpathyContactPriv *priv;
477
478         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), 0);
479
480         priv = GET_PRIV (contact);
481
482         return priv->handle;
483 }
484
485 void
486 empathy_contact_set_handle (EmpathyContact *contact,
487                            guint          handle)
488 {
489         EmpathyContactPriv *priv;
490
491         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
492
493         priv = GET_PRIV (contact);
494
495         if (priv->handle == handle) {
496                 return;
497         }
498
499         priv->handle = handle;
500
501         g_object_notify (G_OBJECT (contact), "handle");
502 }
503
504 gboolean
505 empathy_contact_is_user (EmpathyContact *contact)
506 {
507         EmpathyContactPriv *priv;
508
509         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
510
511         priv = GET_PRIV (contact);
512
513         return priv->is_user;
514 }
515
516 void
517 empathy_contact_set_is_user (EmpathyContact *contact,
518                             gboolean       is_user)
519 {
520         EmpathyContactPriv *priv;
521
522         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
523
524         priv = GET_PRIV (contact);
525
526         if (priv->is_user == is_user) {
527                 return;
528         }
529
530         priv->is_user = is_user;
531
532         g_object_notify (G_OBJECT (contact), "is-user");
533 }
534
535 gboolean
536 empathy_contact_is_online (EmpathyContact *contact)
537 {
538         EmpathyContactPriv *priv;
539
540         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
541
542         priv = GET_PRIV (contact);
543
544         if (!priv->presence) {
545                 return FALSE;
546         }
547
548         return (empathy_presence_get_state (priv->presence) > MC_PRESENCE_OFFLINE);
549 }
550
551 const gchar *
552 empathy_contact_get_status (EmpathyContact *contact)
553 {
554         EmpathyContactPriv *priv;
555
556         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), "");
557
558         priv = GET_PRIV (contact);
559
560         if (priv->presence) {
561                 const gchar *status;
562
563                 status = empathy_presence_get_status (priv->presence);
564                 if (!status) {
565                         McPresence state;
566
567                         state = empathy_presence_get_state (priv->presence);
568                         status = empathy_presence_state_get_default_status (state);
569                 }
570
571                 return status;
572         }
573
574         return empathy_presence_state_get_default_status (MC_PRESENCE_OFFLINE);
575 }
576
577 gboolean
578 empathy_contact_equal (gconstpointer v1,
579                       gconstpointer v2)
580 {
581         McAccount   *account_a;
582         McAccount   *account_b;
583         const gchar *id_a;
584         const gchar *id_b;
585
586         g_return_val_if_fail (EMPATHY_IS_CONTACT (v1), FALSE);
587         g_return_val_if_fail (EMPATHY_IS_CONTACT (v2), FALSE);
588
589         account_a = empathy_contact_get_account (EMPATHY_CONTACT (v1));
590         account_b = empathy_contact_get_account (EMPATHY_CONTACT (v2));
591
592         id_a = empathy_contact_get_id (EMPATHY_CONTACT (v1));
593         id_b = empathy_contact_get_id (EMPATHY_CONTACT (v2));
594
595         return empathy_account_equal (account_a, account_b) && g_str_equal (id_a, id_b);
596 }
597
598 guint
599 empathy_contact_hash (gconstpointer key)
600 {
601         EmpathyContactPriv *priv;
602         guint              hash;
603
604         g_return_val_if_fail (EMPATHY_IS_CONTACT (key), +1);
605
606         priv = GET_PRIV (EMPATHY_CONTACT (key));
607
608         hash = empathy_account_hash (empathy_contact_get_account (EMPATHY_CONTACT (key)));
609         hash += g_str_hash (empathy_contact_get_id (EMPATHY_CONTACT (key)));
610
611         return hash;
612 }
613