]> git.0d.be Git - empathy.git/blob - libempathy/gossip-telepathy-group.c
sv.po: Updated Swedish translation
[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 GList *
318 gossip_telepathy_group_get_local_pending_members_with_info (GossipTelepathyGroup *group)
319 {
320         GossipTelepathyGroupPriv *priv;
321         GPtrArray                *array;
322         guint                     i;
323         GList                    *infos = NULL;
324         GError                   *error = NULL;
325
326         g_return_val_if_fail (GOSSIP_IS_TELEPATHY_GROUP (group), NULL);
327
328         priv = GET_PRIV (group);
329
330         if (!tp_chan_iface_group_get_local_pending_members_with_info (priv->group_iface,
331                                                                       &array,
332                                                                       &error)) {
333                 gossip_debug (DEBUG_DOMAIN, 
334                               "GetLocalPendingMembersWithInfo failed: %s",
335                               error ? error->message : "No error given");
336                 g_clear_error (&error);
337
338                 return NULL;
339         }
340
341         if (!array) {
342                 /* This happens with butterfly because
343                  * GetLocalPendingMembersWithInfo is not 
344                  * implemented */
345                 return NULL;
346         }
347
348         for (i = 0; array->len > i; i++) {
349                 GValueArray       *pending_struct;
350                 GossipTpGroupInfo *info;
351                 const gchar       *message;
352
353                 info = g_slice_new (GossipTpGroupInfo);
354
355                 pending_struct = g_ptr_array_index (array, i);
356                 info->member = g_value_get_uint (g_value_array_get_nth (pending_struct, 0));
357                 info->actor = g_value_get_uint (g_value_array_get_nth (pending_struct, 1));
358                 info->reason = g_value_get_uint (g_value_array_get_nth (pending_struct, 2));
359                 message = g_value_get_string (g_value_array_get_nth (pending_struct, 3));
360                 info->message = g_strdup (message);
361                 g_value_array_free (pending_struct);
362
363                 infos = g_list_prepend (infos, info);
364         }
365         g_ptr_array_free (array, TRUE);
366
367         return infos;
368 }
369
370 void
371 gossip_telepathy_group_info_list_free (GList *infos)
372 {
373         GList *l;
374
375         for (l = infos; l; l = l->next) {
376                 GossipTpGroupInfo *info;
377
378                 info = l->data;
379
380                 g_free (info->message);
381                 g_slice_free (GossipTpGroupInfo, info);
382         }
383         g_list_free (infos);
384 }
385
386
387 static void
388 telepathy_group_destroy_cb (DBusGProxy           *proxy,
389                             GossipTelepathyGroup *group)
390 {
391         GossipTelepathyGroupPriv *priv;
392
393         priv = GET_PRIV (group);
394
395         g_object_unref (priv->group_iface);
396         g_object_unref (priv->tp_conn);
397         g_object_unref (priv->tp_chan);
398         priv->group_iface = NULL;
399         priv->tp_chan = NULL;
400         priv->tp_conn = NULL;
401 }
402
403 static void
404 telepathy_group_members_changed_cb (DBusGProxy           *group_iface,
405                                     gchar                *message,
406                                     GArray               *added,
407                                     GArray               *removed,
408                                     GArray               *local_pending,
409                                     GArray               *remote_pending,
410                                     guint                 actor,
411                                     guint                 reason,
412                                     GossipTelepathyGroup *group)
413 {
414         GossipTelepathyGroupPriv *priv;
415
416         priv = GET_PRIV (group);
417
418         /* emit signals */
419         if (added->len > 0) {
420                 g_signal_emit (group, signals[MEMBERS_ADDED], 0, 
421                                added, actor, reason, message);
422         }
423         if (removed->len > 0) {
424                 g_signal_emit (group, signals[MEMBERS_REMOVED], 0, 
425                                removed, actor, reason, message);
426         }
427         if (local_pending->len > 0) {
428                 g_signal_emit (group, signals[LOCAL_PENDING], 0,
429                                local_pending, actor, reason, message);
430         }
431         if (remote_pending->len > 0) {
432                 g_signal_emit (group, signals[REMOTE_PENDING], 0,
433                                remote_pending, actor, reason, message);
434         }
435 }
436
437 const gchar *
438 gossip_telepathy_group_get_name (GossipTelepathyGroup *group)
439 {
440         TelepathyHandleType  handle_type;
441         guint                channel_handle;
442         GArray              *group_handles;
443         gchar              **group_names;
444         GError              *error = NULL;
445
446         GossipTelepathyGroupPriv *priv;
447
448         g_return_val_if_fail (GOSSIP_IS_TELEPATHY_GROUP (group), NULL);
449
450         priv = GET_PRIV (group);
451
452         /* Lazy initialisation */
453         if (priv->group_name) {
454                 return priv->group_name;
455         }
456
457         if (!tp_chan_get_handle (DBUS_G_PROXY (priv->tp_chan),
458                                  &handle_type,
459                                  &channel_handle,
460                                  &error)) {
461                 gossip_debug (DEBUG_DOMAIN, 
462                               "Couldn't retreive channel handle for group: %s",
463                               error ? error->message : "No error given");
464                 g_clear_error (&error);
465                 return NULL;
466         }
467
468         group_handles = g_array_new (FALSE, FALSE, sizeof (guint));
469         g_array_append_val (group_handles, channel_handle);
470         if (!tp_conn_inspect_handles (DBUS_G_PROXY (priv->tp_conn),
471                                       handle_type,
472                                       group_handles,
473                                       &group_names,
474                                       &error)) {
475                 gossip_debug (DEBUG_DOMAIN, 
476                               "Couldn't get group name: %s",
477                               error ? error->message : "No error given");
478                 g_clear_error (&error);
479                 g_array_free (group_handles, TRUE);
480                 return NULL;
481         }
482
483         priv->group_name = *group_names;
484         g_array_free (group_handles, TRUE);
485         g_free (group_names);
486
487         return priv->group_name;
488 }
489
490 guint 
491 gossip_telepathy_group_get_self_handle (GossipTelepathyGroup *group)
492 {
493         GossipTelepathyGroupPriv *priv;
494         guint                     handle;
495         GError                   *error = NULL;
496
497         g_return_val_if_fail (GOSSIP_IS_TELEPATHY_GROUP (group), 0 );
498
499         priv = GET_PRIV (group);
500
501         if (!tp_chan_iface_group_get_self_handle (priv->group_iface, &handle, &error)) {
502                 gossip_debug (DEBUG_DOMAIN, 
503                               "Failed to get self handle: %s",
504                               error ? error->message : "No error given");
505                 g_clear_error (&error);
506                 return 0;
507         }
508
509         return handle;
510 }
511
512 const gchar *
513 gossip_telepathy_group_get_object_path (GossipTelepathyGroup *group)
514 {
515         GossipTelepathyGroupPriv *priv;
516
517         g_return_val_if_fail (GOSSIP_IS_TELEPATHY_GROUP (group), NULL);
518
519         priv = GET_PRIV (group);
520
521         return dbus_g_proxy_get_path (DBUS_G_PROXY (priv->tp_chan));
522 }
523
524 gboolean
525 gossip_telepathy_group_is_member (GossipTelepathyGroup *group,
526                                   guint                 handle)
527 {
528         GArray   *members;
529         guint     i;
530         gboolean  found = FALSE;
531
532         members = gossip_telepathy_group_get_members (group);
533         for (i = 0; i < members->len; i++) {
534                 if (g_array_index (members, guint, i) == handle) {
535                         found = TRUE;
536                         break;
537                 }
538         }
539         g_array_free (members, TRUE);
540         
541         return found;
542 }
543