]> git.0d.be Git - empathy.git/blob - libempathy/empathy-contact.c
ref the contact temporally when setting properties because it could destroy the object.
[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-debug.h"
37 #include "empathy-enum-types.h"
38
39 #define DEBUG_DOMAIN "Contact"
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         empathy_debug (DEBUG_DOMAIN, "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                         gboolean             set)
320 {
321         EmpathyContactPriv *priv = GET_PRIV (contact);
322         EmpathyContactReady ready_old = priv->ready;
323
324         if (set) {
325                 priv->ready |= flag;
326         } else {
327                 priv->ready &= ~flag;
328         }
329
330         if (priv->ready != ready_old) {
331                 g_object_notify (G_OBJECT (contact), "ready");
332         }
333 }
334
335 EmpathyContact *
336 empathy_contact_new (McAccount *account)
337 {
338         return g_object_new (EMPATHY_TYPE_CONTACT,
339                              "account", account,
340                              NULL);
341 }
342
343 EmpathyContact *
344 empathy_contact_new_full (McAccount   *account,
345                           const gchar *id,
346                           const gchar *name)
347 {
348         return g_object_new (EMPATHY_TYPE_CONTACT,
349                              "account", account,
350                              "name", name,
351                              "id", id,
352                              NULL);
353 }
354
355 const gchar *
356 empathy_contact_get_id (EmpathyContact *contact)
357 {
358         EmpathyContactPriv *priv;
359
360         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
361
362         priv = GET_PRIV (contact);
363
364         return priv->id;
365 }
366
367 void
368 empathy_contact_set_id (EmpathyContact *contact,
369                        const gchar   *id)
370 {
371         EmpathyContactPriv *priv;
372
373         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
374         g_return_if_fail (id != NULL);
375
376         priv = GET_PRIV (contact);
377
378         if (!tp_strdiff (id, priv->id)) {
379                 return;
380         }
381
382         g_free (priv->id);
383         priv->id = g_strdup (id);
384         g_object_ref (contact);
385         contact_set_ready_flag (contact, EMPATHY_CONTACT_READY_ID,
386                                 !G_STR_EMPTY (id));
387         g_object_notify (G_OBJECT (contact), "id");
388         if (G_STR_EMPTY (priv->name)) {
389                 g_object_notify (G_OBJECT (contact), "name");
390         }
391         g_object_unref (contact);
392 }
393
394 const gchar *
395 empathy_contact_get_name (EmpathyContact *contact)
396 {
397         EmpathyContactPriv *priv;
398
399         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
400
401         priv = GET_PRIV (contact);
402
403         if (G_STR_EMPTY (priv->name)) {
404                 return empathy_contact_get_id (contact);
405         }
406
407         return priv->name;
408 }
409
410 void
411 empathy_contact_set_name (EmpathyContact *contact,
412                          const gchar   *name)
413 {
414         EmpathyContactPriv *priv;
415
416         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
417
418         priv = GET_PRIV (contact);
419
420         if (!tp_strdiff (name, priv->name)) {
421                 return;
422         }
423
424         g_free (priv->name);
425         priv->name = g_strdup (name);
426
427         g_object_ref (contact);
428         contact_set_ready_flag (contact, EMPATHY_CONTACT_READY_NAME,
429                                 name != NULL);
430         g_object_notify (G_OBJECT (contact), "name");
431         g_object_unref (contact);
432 }
433
434 EmpathyAvatar *
435 empathy_contact_get_avatar (EmpathyContact *contact)
436 {
437         EmpathyContactPriv *priv;
438
439         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
440
441         priv = GET_PRIV (contact);
442
443         return priv->avatar;
444 }
445
446 void
447 empathy_contact_set_avatar (EmpathyContact *contact,
448                            EmpathyAvatar  *avatar)
449 {
450         EmpathyContactPriv *priv;
451
452         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
453
454         priv = GET_PRIV (contact);
455
456         if (priv->avatar == avatar) {
457                 return;
458         }
459
460         if (priv->avatar) {
461                 empathy_avatar_unref (priv->avatar);
462                 priv->avatar = NULL;
463         }
464
465         if (avatar) {
466                 priv->avatar = empathy_avatar_ref (avatar);
467         }
468
469         g_object_notify (G_OBJECT (contact), "avatar");
470 }
471
472 McAccount *
473 empathy_contact_get_account (EmpathyContact *contact)
474 {
475         EmpathyContactPriv *priv;
476
477         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
478
479         priv = GET_PRIV (contact);
480
481         return priv->account;
482 }
483
484 void
485 empathy_contact_set_account (EmpathyContact *contact,
486                              McAccount      *account)
487 {
488         EmpathyContactPriv *priv;
489
490         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
491         g_return_if_fail (MC_IS_ACCOUNT (account));
492
493         priv = GET_PRIV (contact);
494
495         if (account == priv->account) {
496                 return;
497         }
498
499         if (priv->account) {
500                 g_object_unref (priv->account);
501         }
502         priv->account = g_object_ref (account);
503
504         g_object_notify (G_OBJECT (contact), "account");
505 }
506
507 McPresence
508 empathy_contact_get_presence (EmpathyContact *contact)
509 {
510         EmpathyContactPriv *priv;
511
512         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), MC_PRESENCE_UNSET);
513
514         priv = GET_PRIV (contact);
515
516         return priv->presence;
517 }
518
519 void
520 empathy_contact_set_presence (EmpathyContact *contact,
521                               McPresence      presence)
522 {
523         EmpathyContactPriv *priv;
524
525         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
526
527         priv = GET_PRIV (contact);
528
529         if (presence == priv->presence) {
530                 return;
531         }
532
533         priv->presence = presence;
534
535         g_object_notify (G_OBJECT (contact), "presence");
536 }
537
538 const gchar *
539 empathy_contact_get_presence_message (EmpathyContact *contact)
540 {
541         EmpathyContactPriv *priv;
542
543         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), NULL);
544
545         priv = GET_PRIV (contact);
546
547         return priv->presence_message;
548 }
549
550 void
551 empathy_contact_set_presence_message (EmpathyContact *contact,
552                                       const gchar    *message)
553 {
554         EmpathyContactPriv *priv = GET_PRIV (contact);
555
556         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
557
558         if (!tp_strdiff (message, priv->presence_message)) {
559                 return;
560         }
561
562         g_free (priv->presence_message);
563         priv->presence_message = g_strdup (message);
564
565         g_object_notify (G_OBJECT (contact), "presence-message");
566 }
567
568 guint
569 empathy_contact_get_handle (EmpathyContact *contact)
570 {
571         EmpathyContactPriv *priv;
572
573         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), 0);
574
575         priv = GET_PRIV (contact);
576
577         return priv->handle;
578 }
579
580 void
581 empathy_contact_set_handle (EmpathyContact *contact,
582                             guint           handle)
583 {
584         EmpathyContactPriv *priv;
585
586         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
587
588         priv = GET_PRIV (contact);
589
590         if (priv->handle == handle) {
591                 return;
592         }
593
594         priv->handle = handle;
595
596         g_object_ref (contact);
597         contact_set_ready_flag (contact, EMPATHY_CONTACT_READY_HANDLE,
598                                 handle != 0);
599         g_object_notify (G_OBJECT (contact), "handle");
600         g_object_unref (contact);
601 }
602
603 EmpathyCapabilities
604 empathy_contact_get_capabilities (EmpathyContact *contact)
605 {
606         EmpathyContactPriv *priv;
607
608         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), 0);
609
610         priv = GET_PRIV (contact);
611
612         return priv->capabilities;
613 }
614
615 void
616 empathy_contact_set_capabilities (EmpathyContact      *contact,
617                                   EmpathyCapabilities  capabilities)
618 {
619         EmpathyContactPriv *priv;
620
621         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
622
623         priv = GET_PRIV (contact);
624
625         if (priv->capabilities == capabilities) {
626                 return;
627         }
628
629         priv->capabilities = capabilities;
630
631         g_object_notify (G_OBJECT (contact), "capabilities");
632 }
633
634 gboolean
635 empathy_contact_is_user (EmpathyContact *contact)
636 {
637         EmpathyContactPriv *priv;
638
639         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
640
641         priv = GET_PRIV (contact);
642
643         return priv->is_user;
644 }
645
646 void
647 empathy_contact_set_is_user (EmpathyContact *contact,
648                             gboolean       is_user)
649 {
650         EmpathyContactPriv *priv;
651
652         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
653
654         priv = GET_PRIV (contact);
655
656         if (priv->is_user == is_user) {
657                 return;
658         }
659
660         priv->is_user = is_user;
661
662         g_object_notify (G_OBJECT (contact), "is-user");
663 }
664
665 gboolean
666 empathy_contact_is_online (EmpathyContact *contact)
667 {
668         EmpathyContactPriv *priv;
669
670         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
671
672         priv = GET_PRIV (contact);
673
674         return (priv->presence > MC_PRESENCE_OFFLINE);
675 }
676
677 const gchar *
678 empathy_contact_get_status (EmpathyContact *contact)
679 {
680         EmpathyContactPriv *priv;
681
682         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), "");
683
684         priv = GET_PRIV (contact);
685
686         if (priv->presence_message) {
687                 return priv->presence_message;
688         }
689
690         return empathy_presence_get_default_message (priv->presence);
691 }
692
693 gboolean
694 empathy_contact_can_voip (EmpathyContact *contact)
695 {
696         EmpathyContactPriv *priv;
697
698         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
699
700         priv = GET_PRIV (contact);
701
702         return priv->capabilities & (EMPATHY_CAPABILITIES_AUDIO |
703                                      EMPATHY_CAPABILITIES_VIDEO);
704 }
705
706 EmpathyContactReady
707 empathy_contact_get_ready (EmpathyContact *contact)
708 {
709         EmpathyContactPriv *priv;
710
711         g_return_val_if_fail (EMPATHY_IS_CONTACT (contact), FALSE);
712
713         priv = GET_PRIV (contact);
714
715         return priv->ready;
716 }
717
718 gboolean
719 empathy_contact_equal (gconstpointer v1,
720                       gconstpointer v2)
721 {
722         McAccount   *account_a;
723         McAccount   *account_b;
724         const gchar *id_a;
725         const gchar *id_b;
726
727         g_return_val_if_fail (EMPATHY_IS_CONTACT (v1), FALSE);
728         g_return_val_if_fail (EMPATHY_IS_CONTACT (v2), FALSE);
729
730         account_a = empathy_contact_get_account (EMPATHY_CONTACT (v1));
731         account_b = empathy_contact_get_account (EMPATHY_CONTACT (v2));
732
733         id_a = empathy_contact_get_id (EMPATHY_CONTACT (v1));
734         id_b = empathy_contact_get_id (EMPATHY_CONTACT (v2));
735
736         return empathy_account_equal (account_a, account_b) && g_str_equal (id_a, id_b);
737 }
738
739 guint
740 empathy_contact_hash (gconstpointer key)
741 {
742         EmpathyContactPriv *priv;
743
744         g_return_val_if_fail (EMPATHY_IS_CONTACT (key), +1);
745
746         priv = GET_PRIV (EMPATHY_CONTACT (key));
747
748         if (priv->hash == 0) {
749                 priv->hash = empathy_account_hash (priv->account) + g_str_hash (priv->id);
750         }
751
752         return priv->hash;
753 }
754
755 typedef struct {
756         EmpathyContactReady  ready;
757         GMainLoop           *loop;
758 } RunUntilReadyData;
759
760 static void
761 contact_ready_notify_cb (EmpathyContact    *contact,
762                          GParamSpec        *param,
763                          RunUntilReadyData *data)
764 {
765         EmpathyContactPriv *priv = GET_PRIV (contact);
766
767         if ((priv->ready & data->ready) == data->ready) {
768                 empathy_debug (DEBUG_DOMAIN, "contact %s (%d) ready %d",
769                                priv->id, priv->handle, priv->ready);
770                 g_main_loop_quit (data->loop);
771         }
772 }
773
774 void
775 empathy_contact_run_until_ready (EmpathyContact      *contact,
776                                  EmpathyContactReady  ready,
777                                  GMainLoop          **loop)
778 {
779         EmpathyContactPriv *priv = GET_PRIV (contact);
780         RunUntilReadyData   data;
781         gulong              signal_id;
782
783         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
784
785         if ((priv->ready & ready) == ready) {
786                 return;
787         }
788
789         empathy_debug (DEBUG_DOMAIN, "Run until ready=%d for contact %s (%d)",
790                        ready, priv->id, priv->handle);
791
792         data.ready = ready;
793         data.loop = g_main_loop_new (NULL, FALSE);
794
795         signal_id = g_signal_connect (contact, "notify::ready",
796                                       G_CALLBACK (contact_ready_notify_cb),
797                                       &data);
798         if (loop != NULL) {
799                 *loop = data.loop;
800         }
801
802         g_main_loop_run (data.loop);
803
804         if (loop != NULL) {
805                 *loop = NULL;
806         }
807
808         g_signal_handler_disconnect (contact, signal_id);
809         g_main_loop_unref (data.loop);
810 }
811