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