]> git.0d.be Git - empathy.git/blob - libempathy/empathy-tp-group.c
65e52f091a4f6da0e226ff639e2c3ae7e52768ad
[empathy.git] / libempathy / empathy-tp-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 "empathy-debug.h"
30 #include "empathy-tp-group.h"
31 #include "empathy-marshal.h"
32
33 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
34                        EMPATHY_TYPE_TP_GROUP, EmpathyTpGroupPriv))
35
36 #define DEBUG_DOMAIN "TpGroup"
37
38 struct _EmpathyTpGroupPriv {
39         DBusGProxy *group_iface;
40         TpConn     *tp_conn;
41         TpChan     *tp_chan;
42         gchar      *group_name;
43 };
44
45 static void empathy_tp_group_class_init (EmpathyTpGroupClass *klass);
46 static void empathy_tp_group_init       (EmpathyTpGroup      *group);
47 static void tp_group_finalize           (GObject             *object);
48 static void tp_group_destroy_cb         (DBusGProxy          *proxy,
49                                          EmpathyTpGroup      *group);
50 static void tp_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                                          EmpathyTpGroup      *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 (EmpathyTpGroup, empathy_tp_group, G_TYPE_OBJECT);
71
72 static void
73 empathy_tp_group_class_init (EmpathyTpGroupClass *klass)
74 {
75         GObjectClass *object_class = G_OBJECT_CLASS (klass);
76
77         object_class->finalize = tp_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 (EmpathyTpGroupPriv));
120 }
121
122 static void
123 empathy_tp_group_init (EmpathyTpGroup *group)
124 {
125 }
126
127 static void
128 tp_group_finalize (GObject *object)
129 {
130         EmpathyTpGroupPriv *priv;
131
132         priv = GET_PRIV (object);
133
134         if (priv->group_iface) {
135                 g_signal_handlers_disconnect_by_func (priv->group_iface,
136                                                       tp_group_destroy_cb,
137                                                       object);
138                 dbus_g_proxy_disconnect_signal (priv->group_iface, "MembersChanged",
139                                                 G_CALLBACK (tp_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 (empathy_tp_group_parent_class)->finalize (object);
155 }
156
157 EmpathyTpGroup *
158 empathy_tp_group_new (TpChan *tp_chan,
159                       TpConn *tp_conn)
160 {
161         EmpathyTpGroup     *group;
162         EmpathyTpGroupPriv *priv;
163         DBusGProxy         *group_iface;
164
165         g_return_val_if_fail (TELEPATHY_IS_CHAN (tp_chan), NULL);
166         g_return_val_if_fail (TELEPATHY_IS_CONN (tp_conn), NULL);
167
168         group_iface = tp_chan_get_interface (tp_chan,
169                                              TELEPATHY_CHAN_IFACE_GROUP_QUARK);
170         g_return_val_if_fail (group_iface != NULL, NULL);
171
172         group = g_object_new (EMPATHY_TYPE_TP_GROUP, NULL);
173         priv = GET_PRIV (group);
174
175         priv->tp_conn = g_object_ref (tp_conn);
176         priv->tp_chan = g_object_ref (tp_chan);
177         priv->group_iface = g_object_ref (group_iface);
178
179         dbus_g_proxy_connect_signal (priv->group_iface, "MembersChanged",
180                                      G_CALLBACK (tp_group_members_changed_cb),
181                                      group, NULL);
182         g_signal_connect (group_iface, "destroy",
183                           G_CALLBACK (tp_group_destroy_cb),
184                           group);
185
186         return group;
187 }
188
189 void
190 empathy_tp_group_add_members (EmpathyTpGroup *group,
191                               GArray         *handles,
192                               const gchar    *message)
193 {
194         EmpathyTpGroupPriv *priv;
195         GError             *error = NULL;
196
197         g_return_if_fail (EMPATHY_IS_TP_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                 empathy_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 empathy_tp_group_add_member (EmpathyTpGroup *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         empathy_tp_group_add_members (group, handles, message);
224
225         g_array_free (handles, TRUE);
226 }
227
228 void
229 empathy_tp_group_remove_members (EmpathyTpGroup *group,
230                                  GArray         *handles,
231                                  const gchar    *message)
232 {
233         EmpathyTpGroupPriv *priv;
234         GError             *error = NULL;
235
236         g_return_if_fail (EMPATHY_IS_TP_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                 empathy_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 empathy_tp_group_remove_member (EmpathyTpGroup *group,
253                                 guint           handle,
254                                 const gchar    *message)
255 {
256         GArray *handles;
257
258         g_return_if_fail (EMPATHY_IS_TP_GROUP (group));
259
260         handles = g_array_new (FALSE, FALSE, sizeof (guint));
261         g_array_append_val (handles, handle);
262
263         empathy_tp_group_remove_members (group, handles, message);
264
265         g_array_free (handles, TRUE);
266 }
267
268 GArray *
269 empathy_tp_group_get_members (EmpathyTpGroup *group)
270 {
271         EmpathyTpGroupPriv *priv;
272         GArray             *members;
273         GError             *error = NULL;
274
275         g_return_val_if_fail (EMPATHY_IS_TP_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                 empathy_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 empathy_tp_group_get_all_members (EmpathyTpGroup  *group,
294                                   GArray         **members,
295                                   GArray         **local_pending,
296                                   GArray         **remote_pending)
297 {
298         EmpathyTpGroupPriv *priv;
299         GError             *error = NULL;
300
301         g_return_if_fail (EMPATHY_IS_TP_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                 empathy_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 empathy_tp_group_get_local_pending_members_with_info (EmpathyTpGroup *group)
319 {
320         EmpathyTpGroupPriv *priv;
321         GPtrArray          *array;
322         guint               i;
323         GList              *infos = NULL;
324         GError             *error = NULL;
325
326         g_return_val_if_fail (EMPATHY_IS_TP_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                 empathy_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                 EmpathyTpGroupInfo *info;
351                 const gchar        *message;
352
353                 info = g_slice_new (EmpathyTpGroupInfo);
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 empathy_tp_group_info_list_free (GList *infos)
372 {
373         GList *l;
374
375         for (l = infos; l; l = l->next) {
376                 EmpathyTpGroupInfo *info;
377
378                 info = l->data;
379
380                 g_free (info->message);
381                 g_slice_free (EmpathyTpGroupInfo, info);
382         }
383         g_list_free (infos);
384 }
385
386
387 static void
388 tp_group_destroy_cb (DBusGProxy     *proxy,
389                      EmpathyTpGroup *group)
390 {
391         EmpathyTpGroupPriv *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 tp_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                              EmpathyTpGroup *group)
413 {
414         EmpathyTpGroupPriv *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 empathy_tp_group_get_name (EmpathyTpGroup *group)
439 {
440         TelepathyHandleType  handle_type;
441         guint                channel_handle;
442         GArray              *group_handles;
443         gchar              **group_names;
444         GError              *error = NULL;
445
446         EmpathyTpGroupPriv *priv;
447
448         g_return_val_if_fail (EMPATHY_IS_TP_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                 empathy_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                 empathy_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 empathy_tp_group_get_self_handle (EmpathyTpGroup *group)
492 {
493         EmpathyTpGroupPriv *priv;
494         guint               handle;
495         GError             *error = NULL;
496
497         g_return_val_if_fail (EMPATHY_IS_TP_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                 empathy_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 empathy_tp_group_get_object_path (EmpathyTpGroup *group)
514 {
515         EmpathyTpGroupPriv *priv;
516
517         g_return_val_if_fail (EMPATHY_IS_TP_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 empathy_tp_group_is_member (EmpathyTpGroup *group,
526                             guint           handle)
527 {
528         GArray   *members;
529         guint     i;
530         gboolean  found = FALSE;
531
532         members = empathy_tp_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