]> git.0d.be Git - empathy.git/blob - libempathy/empathy-tp-group.c
Rename all filenames starting with "gossip" by "empathy", change namespace
[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
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 (EMPATHY_TYPE_TP_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 (tp_group_members_changed_cb),
180                                      group, NULL);
181         g_signal_connect (group_iface, "destroy",
182                           G_CALLBACK (tp_group_destroy_cb),
183                           group);
184
185         return group;
186 }
187
188 void
189 empathy_tp_group_add_members (EmpathyTpGroup *group,
190                               GArray         *handles,
191                               const gchar    *message)
192 {
193         EmpathyTpGroupPriv *priv;
194         GError             *error = NULL;
195
196         g_return_if_fail (EMPATHY_IS_TP_GROUP (group));
197         g_return_if_fail (handles != NULL);
198
199         priv = GET_PRIV (group);
200
201         if (!tp_chan_iface_group_add_members (priv->group_iface,
202                                               handles,
203                                               message,
204                                               &error)) {
205                 empathy_debug (DEBUG_DOMAIN,
206                               "Failed to add members: %s",
207                               error ? error->message : "No error given");
208                 g_clear_error (&error);
209         }
210 }
211
212 void
213 empathy_tp_group_add_member (EmpathyTpGroup *group,
214                              guint           handle,
215                              const gchar    *message)
216 {
217         GArray *handles;
218
219         handles = g_array_new (FALSE, FALSE, sizeof (guint));
220         g_array_append_val (handles, handle);
221
222         empathy_tp_group_add_members (group, handles, message);
223
224         g_array_free (handles, TRUE);
225 }
226
227 void
228 empathy_tp_group_remove_members (EmpathyTpGroup *group,
229                                  GArray         *handles,
230                                  const gchar    *message)
231 {
232         EmpathyTpGroupPriv *priv;
233         GError             *error = NULL;
234
235         g_return_if_fail (EMPATHY_IS_TP_GROUP (group));
236
237         priv = GET_PRIV (group);
238
239         if (!tp_chan_iface_group_remove_members (priv->group_iface,
240                                                  handles,
241                                                  message,
242                                                  &error)) {
243                 empathy_debug (DEBUG_DOMAIN, 
244                               "Failed to remove members: %s",
245                               error ? error->message : "No error given");
246                 g_clear_error (&error);
247         }
248 }
249
250 void
251 empathy_tp_group_remove_member (EmpathyTpGroup *group,
252                                 guint           handle,
253                                 const gchar    *message)
254 {
255         GArray *handles;
256
257         g_return_if_fail (EMPATHY_IS_TP_GROUP (group));
258
259         handles = g_array_new (FALSE, FALSE, sizeof (guint));
260         g_array_append_val (handles, handle);
261
262         empathy_tp_group_remove_members (group, handles, message);
263
264         g_array_free (handles, TRUE);
265 }
266
267 GArray *
268 empathy_tp_group_get_members (EmpathyTpGroup *group)
269 {
270         EmpathyTpGroupPriv *priv;
271         GArray             *members;
272         GError             *error = NULL;
273
274         g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), NULL);
275
276         priv = GET_PRIV (group);
277
278         if (!tp_chan_iface_group_get_members (priv->group_iface,
279                                               &members,
280                                               &error)) {
281                 empathy_debug (DEBUG_DOMAIN, 
282                               "Couldn't get members: %s",
283                               error ? error->message : "No error given");
284                 g_clear_error (&error);
285                 return NULL;
286         }
287
288         return members;
289 }
290
291 void
292 empathy_tp_group_get_all_members (EmpathyTpGroup  *group,
293                                   GArray         **members,
294                                   GArray         **local_pending,
295                                   GArray         **remote_pending)
296 {
297         EmpathyTpGroupPriv *priv;
298         GError             *error = NULL;
299
300         g_return_if_fail (EMPATHY_IS_TP_GROUP (group));
301
302         priv = GET_PRIV (group);
303
304         if (!tp_chan_iface_group_get_all_members (priv->group_iface,
305                                                   members,
306                                                   local_pending,
307                                                   remote_pending,
308                                                   &error)) {
309                 empathy_debug (DEBUG_DOMAIN,
310                               "Couldn't get all members: %s",
311                               error ? error->message : "No error given");
312                 g_clear_error (&error);
313         }
314 }
315
316 GList *
317 empathy_tp_group_get_local_pending_members_with_info (EmpathyTpGroup *group)
318 {
319         EmpathyTpGroupPriv *priv;
320         GPtrArray          *array;
321         guint               i;
322         GList              *infos = NULL;
323         GError             *error = NULL;
324
325         g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), NULL);
326
327         priv = GET_PRIV (group);
328
329         if (!tp_chan_iface_group_get_local_pending_members_with_info (priv->group_iface,
330                                                                       &array,
331                                                                       &error)) {
332                 empathy_debug (DEBUG_DOMAIN, 
333                               "GetLocalPendingMembersWithInfo failed: %s",
334                               error ? error->message : "No error given");
335                 g_clear_error (&error);
336
337                 return NULL;
338         }
339
340         if (!array) {
341                 /* This happens with butterfly because
342                  * GetLocalPendingMembersWithInfo is not 
343                  * implemented */
344                 return NULL;
345         }
346
347         for (i = 0; array->len > i; i++) {
348                 GValueArray        *pending_struct;
349                 EmpathyTpGroupInfo *info;
350                 const gchar        *message;
351
352                 info = g_slice_new (EmpathyTpGroupInfo);
353
354                 pending_struct = g_ptr_array_index (array, i);
355                 info->member = g_value_get_uint (g_value_array_get_nth (pending_struct, 0));
356                 info->actor = g_value_get_uint (g_value_array_get_nth (pending_struct, 1));
357                 info->reason = g_value_get_uint (g_value_array_get_nth (pending_struct, 2));
358                 message = g_value_get_string (g_value_array_get_nth (pending_struct, 3));
359                 info->message = g_strdup (message);
360                 g_value_array_free (pending_struct);
361
362                 infos = g_list_prepend (infos, info);
363         }
364         g_ptr_array_free (array, TRUE);
365
366         return infos;
367 }
368
369 void
370 empathy_tp_group_info_list_free (GList *infos)
371 {
372         GList *l;
373
374         for (l = infos; l; l = l->next) {
375                 EmpathyTpGroupInfo *info;
376
377                 info = l->data;
378
379                 g_free (info->message);
380                 g_slice_free (EmpathyTpGroupInfo, info);
381         }
382         g_list_free (infos);
383 }
384
385
386 static void
387 tp_group_destroy_cb (DBusGProxy     *proxy,
388                      EmpathyTpGroup *group)
389 {
390         EmpathyTpGroupPriv *priv;
391
392         priv = GET_PRIV (group);
393
394         g_object_unref (priv->group_iface);
395         g_object_unref (priv->tp_conn);
396         g_object_unref (priv->tp_chan);
397         priv->group_iface = NULL;
398         priv->tp_chan = NULL;
399         priv->tp_conn = NULL;
400 }
401
402 static void
403 tp_group_members_changed_cb (DBusGProxy     *group_iface,
404                              gchar          *message,
405                              GArray         *added,
406                              GArray         *removed,
407                              GArray         *local_pending,
408                              GArray         *remote_pending,
409                              guint           actor,
410                              guint           reason,
411                              EmpathyTpGroup *group)
412 {
413         EmpathyTpGroupPriv *priv;
414
415         priv = GET_PRIV (group);
416
417         /* emit signals */
418         if (added->len > 0) {
419                 g_signal_emit (group, signals[MEMBERS_ADDED], 0, 
420                                added, actor, reason, message);
421         }
422         if (removed->len > 0) {
423                 g_signal_emit (group, signals[MEMBERS_REMOVED], 0, 
424                                removed, actor, reason, message);
425         }
426         if (local_pending->len > 0) {
427                 g_signal_emit (group, signals[LOCAL_PENDING], 0,
428                                local_pending, actor, reason, message);
429         }
430         if (remote_pending->len > 0) {
431                 g_signal_emit (group, signals[REMOTE_PENDING], 0,
432                                remote_pending, actor, reason, message);
433         }
434 }
435
436 const gchar *
437 empathy_tp_group_get_name (EmpathyTpGroup *group)
438 {
439         TelepathyHandleType  handle_type;
440         guint                channel_handle;
441         GArray              *group_handles;
442         gchar              **group_names;
443         GError              *error = NULL;
444
445         EmpathyTpGroupPriv *priv;
446
447         g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), NULL);
448
449         priv = GET_PRIV (group);
450
451         /* Lazy initialisation */
452         if (priv->group_name) {
453                 return priv->group_name;
454         }
455
456         if (!tp_chan_get_handle (DBUS_G_PROXY (priv->tp_chan),
457                                  &handle_type,
458                                  &channel_handle,
459                                  &error)) {
460                 empathy_debug (DEBUG_DOMAIN, 
461                               "Couldn't retreive channel handle for group: %s",
462                               error ? error->message : "No error given");
463                 g_clear_error (&error);
464                 return NULL;
465         }
466
467         group_handles = g_array_new (FALSE, FALSE, sizeof (guint));
468         g_array_append_val (group_handles, channel_handle);
469         if (!tp_conn_inspect_handles (DBUS_G_PROXY (priv->tp_conn),
470                                       handle_type,
471                                       group_handles,
472                                       &group_names,
473                                       &error)) {
474                 empathy_debug (DEBUG_DOMAIN, 
475                               "Couldn't get group name: %s",
476                               error ? error->message : "No error given");
477                 g_clear_error (&error);
478                 g_array_free (group_handles, TRUE);
479                 return NULL;
480         }
481
482         priv->group_name = *group_names;
483         g_array_free (group_handles, TRUE);
484         g_free (group_names);
485
486         return priv->group_name;
487 }
488
489 guint 
490 empathy_tp_group_get_self_handle (EmpathyTpGroup *group)
491 {
492         EmpathyTpGroupPriv *priv;
493         guint               handle;
494         GError             *error = NULL;
495
496         g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), 0 );
497
498         priv = GET_PRIV (group);
499
500         if (!tp_chan_iface_group_get_self_handle (priv->group_iface, &handle, &error)) {
501                 empathy_debug (DEBUG_DOMAIN, 
502                               "Failed to get self handle: %s",
503                               error ? error->message : "No error given");
504                 g_clear_error (&error);
505                 return 0;
506         }
507
508         return handle;
509 }
510
511 const gchar *
512 empathy_tp_group_get_object_path (EmpathyTpGroup *group)
513 {
514         EmpathyTpGroupPriv *priv;
515
516         g_return_val_if_fail (EMPATHY_IS_TP_GROUP (group), NULL);
517
518         priv = GET_PRIV (group);
519
520         return dbus_g_proxy_get_path (DBUS_G_PROXY (priv->tp_chan));
521 }
522
523 gboolean
524 empathy_tp_group_is_member (EmpathyTpGroup *group,
525                             guint           handle)
526 {
527         GArray   *members;
528         guint     i;
529         gboolean  found = FALSE;
530
531         members = empathy_tp_group_get_members (group);
532         for (i = 0; i < members->len; i++) {
533                 if (g_array_index (members, guint, i) == handle) {
534                         found = TRUE;
535                         break;
536                 }
537         }
538         g_array_free (members, TRUE);
539         
540         return found;
541 }
542