]> git.0d.be Git - empathy.git/blob - libempathy/gossip-telepathy-group.c
4b04ac42f161e04d5f44ff1e375d7f3e0a68945c
[empathy.git] / libempathy / gossip-telepathy-group.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2006 Xavier Claessens <xclaesse@gmail.com>
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
21 #include <config.h>
22
23 #include <dbus/dbus-glib.h>
24 #include <libtelepathy/tp-chan.h>
25 #include <libtelepathy/tp-chan-iface-group-gen.h>
26 #include <libtelepathy/tp-constants.h>
27 #include <libtelepathy/tp-conn.h>
28
29 #include "gossip-debug.h"
30 #include "gossip-telepathy-group.h"
31 #include "empathy-marshal.h"
32
33 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
34                        GOSSIP_TYPE_TELEPATHY_GROUP, GossipTelepathyGroupPriv))
35
36 #define DEBUG_DOMAIN "TelepathyGroup"
37
38 struct _GossipTelepathyGroupPriv {
39         DBusGProxy *group_iface;
40         TpConn     *tp_conn;
41         TpChan     *tp_chan;
42         gchar      *group_name;
43 };
44
45 static void gossip_telepathy_group_class_init    (GossipTelepathyGroupClass *klass);
46 static void gossip_telepathy_group_init          (GossipTelepathyGroup      *group);
47 static void telepathy_group_finalize             (GObject                   *object);
48 static void telepathy_group_destroy_cb           (DBusGProxy                *proxy,
49                                                   GossipTelepathyGroup      *group);
50 static void telepathy_group_members_changed_cb   (DBusGProxy                *group_iface,
51                                                   gchar                     *message,
52                                                   GArray                    *added,
53                                                   GArray                    *removed,
54                                                   GArray                    *local_pending,
55                                                   GArray                    *remote_pending,
56                                                   guint                      actor,
57                                                   guint                      reason,
58                                                   GossipTelepathyGroup      *group);
59
60 enum {
61         MEMBERS_ADDED,
62         MEMBERS_REMOVED,
63         LOCAL_PENDING,
64         REMOTE_PENDING,
65         LAST_SIGNAL
66 };
67
68 static guint signals[LAST_SIGNAL];
69
70 G_DEFINE_TYPE (GossipTelepathyGroup, gossip_telepathy_group, G_TYPE_OBJECT);
71
72 static void
73 gossip_telepathy_group_class_init (GossipTelepathyGroupClass *klass)
74 {
75         GObjectClass *object_class = G_OBJECT_CLASS (klass);
76
77         object_class->finalize = telepathy_group_finalize;
78
79         signals[MEMBERS_ADDED] =
80                 g_signal_new ("members-added",
81                               G_TYPE_FROM_CLASS (klass),
82                               G_SIGNAL_RUN_LAST,
83                               0,
84                               NULL, NULL,
85                               empathy_marshal_VOID__POINTER_UINT_UINT_STRING,
86                               G_TYPE_NONE,
87                               4, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING);
88
89         signals[MEMBERS_REMOVED] =
90                 g_signal_new ("members-removed",
91                               G_TYPE_FROM_CLASS (klass),
92                               G_SIGNAL_RUN_LAST,
93                               0,
94                               NULL, NULL,
95                               empathy_marshal_VOID__POINTER_UINT_UINT_STRING,
96                               G_TYPE_NONE,
97                               4, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING);
98
99         signals[LOCAL_PENDING] =
100                 g_signal_new ("local-pending",
101                               G_TYPE_FROM_CLASS (klass),
102                               G_SIGNAL_RUN_LAST,
103                               0,
104                               NULL, NULL,
105                               empathy_marshal_VOID__POINTER_UINT_UINT_STRING,
106                               G_TYPE_NONE,
107                               4, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING);
108
109         signals[REMOTE_PENDING] =
110                 g_signal_new ("remote-pending",
111                               G_TYPE_FROM_CLASS (klass),
112                               G_SIGNAL_RUN_LAST,
113                               0,
114                               NULL, NULL,
115                               empathy_marshal_VOID__POINTER_UINT_UINT_STRING,
116                               G_TYPE_NONE,
117                               4, G_TYPE_POINTER, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_STRING);
118
119         g_type_class_add_private (object_class, sizeof (GossipTelepathyGroupPriv));
120 }
121
122 static void
123 gossip_telepathy_group_init (GossipTelepathyGroup *group)
124 {
125 }
126
127 static void
128 telepathy_group_finalize (GObject *object)
129 {
130         GossipTelepathyGroupPriv *priv;
131
132         priv = GET_PRIV (object);
133
134         if (priv->group_iface) {
135                 g_signal_handlers_disconnect_by_func (priv->group_iface,
136                                                       telepathy_group_destroy_cb,
137                                                       object);
138                 dbus_g_proxy_disconnect_signal (priv->group_iface, "MembersChanged",
139                                                 G_CALLBACK (telepathy_group_members_changed_cb),
140                                                 object);
141                 g_object_unref (priv->group_iface);
142         }
143
144         if (priv->tp_conn) {
145                 g_object_unref (priv->tp_conn);
146         }
147
148         if (priv->tp_chan) {
149                 g_object_unref (priv->tp_chan);
150         }
151
152         g_free (priv->group_name);
153
154         G_OBJECT_CLASS (gossip_telepathy_group_parent_class)->finalize (object);
155 }
156
157 GossipTelepathyGroup *
158 gossip_telepathy_group_new (TpChan *tp_chan,
159                             TpConn *tp_conn)
160 {
161         GossipTelepathyGroup     *group;
162         GossipTelepathyGroupPriv *priv;
163         DBusGProxy               *group_iface;
164
165         g_return_val_if_fail (TELEPATHY_IS_CHAN (tp_chan), NULL);
166
167         group_iface = tp_chan_get_interface (tp_chan,
168                                              TELEPATHY_CHAN_IFACE_GROUP_QUARK);
169         g_return_val_if_fail (group_iface != NULL, NULL);
170
171         group = g_object_new (GOSSIP_TYPE_TELEPATHY_GROUP, NULL);
172         priv = GET_PRIV (group);
173
174         priv->tp_conn = g_object_ref (tp_conn);
175         priv->tp_chan = g_object_ref (tp_chan);
176         priv->group_iface = g_object_ref (group_iface);
177
178         dbus_g_proxy_connect_signal (priv->group_iface, "MembersChanged",
179                                      G_CALLBACK (telepathy_group_members_changed_cb),
180                                      group, NULL);
181         g_signal_connect (group_iface, "destroy",
182                           G_CALLBACK (telepathy_group_destroy_cb),
183                           group);
184
185
186         return group;
187 }
188
189 void
190 gossip_telepathy_group_add_members (GossipTelepathyGroup *group,
191                                     GArray               *handles,
192                                     const gchar          *message)
193 {
194         GossipTelepathyGroupPriv *priv;
195         GError                   *error = NULL;
196
197         g_return_if_fail (GOSSIP_IS_TELEPATHY_GROUP (group));
198         g_return_if_fail (handles != NULL);
199
200         priv = GET_PRIV (group);
201
202         if (!tp_chan_iface_group_add_members (priv->group_iface,
203                                               handles,
204                                               message,
205                                               &error)) {
206                 gossip_debug (DEBUG_DOMAIN,
207                               "Failed to add members: %s",
208                               error ? error->message : "No error given");
209                 g_clear_error (&error);
210         }
211 }
212
213 void
214 gossip_telepathy_group_add_member (GossipTelepathyGroup *group,
215                                    guint                 handle,
216                                    const gchar          *message)
217 {
218         GArray *handles;
219
220         handles = g_array_new (FALSE, FALSE, sizeof (guint));
221         g_array_append_val (handles, handle);
222
223         gossip_telepathy_group_add_members (group, handles, message);
224
225         g_array_free (handles, TRUE);
226 }
227
228 void
229 gossip_telepathy_group_remove_members (GossipTelepathyGroup *group,
230                                        GArray               *handles,
231                                        const gchar          *message)
232 {
233         GossipTelepathyGroupPriv *priv;
234         GError                   *error = NULL;
235
236         g_return_if_fail (GOSSIP_IS_TELEPATHY_GROUP (group));
237
238         priv = GET_PRIV (group);
239
240         if (!tp_chan_iface_group_remove_members (priv->group_iface,
241                                                  handles,
242                                                  message,
243                                                  &error)) {
244                 gossip_debug (DEBUG_DOMAIN, 
245                               "Failed to remove members: %s",
246                               error ? error->message : "No error given");
247                 g_clear_error (&error);
248         }
249 }
250
251 void
252 gossip_telepathy_group_remove_member (GossipTelepathyGroup *group,
253                                       guint                 handle,
254                                       const gchar          *message)
255 {
256         GArray *handles;
257
258         g_return_if_fail (GOSSIP_IS_TELEPATHY_GROUP (group));
259
260         handles = g_array_new (FALSE, FALSE, sizeof (guint));
261         g_array_append_val (handles, handle);
262
263         gossip_telepathy_group_remove_members (group, handles, message);
264
265         g_array_free (handles, TRUE);
266 }
267
268 GArray *
269 gossip_telepathy_group_get_members (GossipTelepathyGroup *group)
270 {
271         GossipTelepathyGroupPriv *priv;
272         GArray                   *members;
273         GError                   *error = NULL;
274
275         g_return_val_if_fail (GOSSIP_IS_TELEPATHY_GROUP (group), NULL);
276
277         priv = GET_PRIV (group);
278
279         if (!tp_chan_iface_group_get_members (priv->group_iface,
280                                               &members,
281                                               &error)) {
282                 gossip_debug (DEBUG_DOMAIN, 
283                               "Couldn't get members: %s",
284                               error ? error->message : "No error given");
285                 g_clear_error (&error);
286                 return NULL;
287         }
288
289         return members;
290 }
291
292 void
293 gossip_telepathy_group_get_all_members (GossipTelepathyGroup  *group,
294                                         GArray               **members,
295                                         GArray               **local_pending,
296                                         GArray               **remote_pending)
297 {
298         GossipTelepathyGroupPriv *priv;
299         GError                   *error = NULL;
300
301         g_return_if_fail (GOSSIP_IS_TELEPATHY_GROUP (group));
302
303         priv = GET_PRIV (group);
304
305         if (!tp_chan_iface_group_get_all_members (priv->group_iface,
306                                                   members,
307                                                   local_pending,
308                                                   remote_pending,
309                                                   &error)) {
310                 gossip_debug (DEBUG_DOMAIN,
311                               "Couldn't get all members: %s",
312                               error ? error->message : "No error given");
313                 g_clear_error (&error);
314         }
315 }
316
317 GPtrArray *
318 gossip_telepathy_group_get_local_pending_members_with_info (GossipTelepathyGroup  *group)
319 {
320         GossipTelepathyGroupPriv *priv;
321         GPtrArray                *info = NULL;
322         GError                   *error = NULL;
323
324         g_return_val_if_fail (GOSSIP_IS_TELEPATHY_GROUP (group), NULL);
325
326         priv = GET_PRIV (group);
327
328         if (!tp_chan_iface_group_get_local_pending_members_with_info (priv->group_iface,
329                                                                       &info,
330                                                                       &error)) {
331                 gossip_debug (DEBUG_DOMAIN, 
332                               "GetLocalPendingMembersWithInfo failed: %s",
333                               error ? error->message : "No error given");
334                 g_clear_error (&error);
335         }
336
337         return info;
338 }
339
340 static void
341 telepathy_group_destroy_cb (DBusGProxy           *proxy,
342                             GossipTelepathyGroup *group)
343 {
344         GossipTelepathyGroupPriv *priv;
345
346         priv = GET_PRIV (group);
347
348         g_object_unref (priv->group_iface);
349         g_object_unref (priv->tp_conn);
350         g_object_unref (priv->tp_chan);
351         priv->group_iface = NULL;
352         priv->tp_chan = NULL;
353         priv->tp_conn = NULL;
354 }
355
356 static void
357 telepathy_group_members_changed_cb (DBusGProxy           *group_iface,
358                                     gchar                *message,
359                                     GArray               *added,
360                                     GArray               *removed,
361                                     GArray               *local_pending,
362                                     GArray               *remote_pending,
363                                     guint                 actor,
364                                     guint                 reason,
365                                     GossipTelepathyGroup *group)
366 {
367         GossipTelepathyGroupPriv *priv;
368
369         priv = GET_PRIV (group);
370
371         /* emit signals */
372         if (added->len > 0) {
373                 g_signal_emit (group, signals[MEMBERS_ADDED], 0, 
374                                added, actor, reason, message);
375         }
376         if (removed->len > 0) {
377                 g_signal_emit (group, signals[MEMBERS_REMOVED], 0, 
378                                removed, actor, reason, message);
379         }
380         if (local_pending->len > 0) {
381                 g_signal_emit (group, signals[LOCAL_PENDING], 0,
382                                local_pending, actor, reason, message);
383         }
384         if (remote_pending->len > 0) {
385                 g_signal_emit (group, signals[REMOTE_PENDING], 0,
386                                remote_pending, actor, reason, message);
387         }
388 }
389
390 const gchar *
391 gossip_telepathy_group_get_name (GossipTelepathyGroup *group)
392 {
393         TelepathyHandleType  handle_type;
394         guint                channel_handle;
395         GArray              *group_handles;
396         gchar              **group_names;
397         GError              *error = NULL;
398
399         GossipTelepathyGroupPriv *priv;
400
401         g_return_val_if_fail (GOSSIP_IS_TELEPATHY_GROUP (group), NULL);
402
403         priv = GET_PRIV (group);
404
405         /* Lazy initialisation */
406         if (priv->group_name) {
407                 return priv->group_name;
408         }
409
410         if (!tp_chan_get_handle (DBUS_G_PROXY (priv->tp_chan),
411                                  &handle_type,
412                                  &channel_handle,
413                                  &error)) {
414                 gossip_debug (DEBUG_DOMAIN, 
415                               "Couldn't retreive channel handle for group: %s",
416                               error ? error->message : "No error given");
417                 g_clear_error (&error);
418                 return NULL;
419         }
420
421         group_handles = g_array_new (FALSE, FALSE, sizeof (gint));
422         g_array_append_val (group_handles, channel_handle);
423         if (!tp_conn_inspect_handles (DBUS_G_PROXY (priv->tp_conn),
424                                       handle_type,
425                                       group_handles,
426                                       &group_names,
427                                       &error)) {
428                 gossip_debug (DEBUG_DOMAIN, 
429                               "Couldn't get group name: %s",
430                               error ? error->message : "No error given");
431                 g_clear_error (&error);
432                 g_array_free (group_handles, TRUE);
433                 return NULL;
434         }
435
436         priv->group_name = *group_names;
437         g_array_free (group_handles, TRUE);
438         g_free (group_names);
439
440         return priv->group_name;
441 }
442
443 guint 
444 gossip_telepathy_group_get_self_handle (GossipTelepathyGroup *group)
445 {
446         GossipTelepathyGroupPriv *priv;
447         guint                     handle;
448         GError                   *error = NULL;
449
450         g_return_val_if_fail (GOSSIP_IS_TELEPATHY_GROUP (group), 0 );
451
452         priv = GET_PRIV (group);
453
454         if (!tp_chan_iface_group_get_self_handle (priv->group_iface, &handle, &error)) {
455                 gossip_debug (DEBUG_DOMAIN, 
456                               "Failed to get self handle: %s",
457                               error ? error->message : "No error given");
458                 g_clear_error (&error);
459                 return 0;
460         }
461
462         return handle;
463 }
464
465 const gchar *
466 gossip_telepathy_group_get_object_path (GossipTelepathyGroup *group)
467 {
468         GossipTelepathyGroupPriv *priv;
469
470         g_return_val_if_fail (GOSSIP_IS_TELEPATHY_GROUP (group), NULL);
471
472         priv = GET_PRIV (group);
473
474         return dbus_g_proxy_get_path (DBUS_G_PROXY (priv->tp_chan));
475 }
476
477 gboolean
478 gossip_telepathy_group_is_member (GossipTelepathyGroup *group,
479                                   guint                 handle)
480 {
481         GArray   *members;
482         guint     i;
483         gboolean  found = FALSE;
484
485         members = gossip_telepathy_group_get_members (group);
486         for (i = 0; i < members->len; i++) {
487                 if (g_array_index (members, guint, i) == handle) {
488                         found = TRUE;
489                         break;
490                 }
491         }
492         g_array_free (members, TRUE);
493         
494         return found;
495 }
496