]> git.0d.be Git - empathy.git/blob - libempathy/empathy-tp-roomlist.c
Merge branch 'master' into tp-tube
[empathy.git] / libempathy / empathy-tp-roomlist.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2007-2008 Collabora Ltd.
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library 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  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18  * 
19  * Authors: Xavier Claessens <xclaesse@gmail.com>
20  */
21
22 #include <config.h>
23
24 #include <string.h>
25
26 #include <telepathy-glib/channel.h>
27 #include <telepathy-glib/dbus.h>
28 #include <telepathy-glib/util.h>
29
30 #include <libmissioncontrol/mission-control.h>
31
32 #include "empathy-tp-roomlist.h"
33 #include "empathy-chatroom.h"
34 #include "empathy-utils.h"
35
36 #define DEBUG_FLAG EMPATHY_DEBUG_TP
37 #include "empathy-debug.h"
38
39 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyTpRoomlist)
40 typedef struct {
41         TpConnection *connection;
42         TpChannel    *channel;
43         McAccount    *account;
44         gboolean      is_listing;
45 } EmpathyTpRoomlistPriv;
46
47 enum {
48         NEW_ROOM,
49         DESTROY,
50         LAST_SIGNAL
51 };
52
53 enum {
54         PROP_0,
55         PROP_CONNECTION,
56         PROP_IS_LISTING,
57 };
58
59 static guint signals[LAST_SIGNAL];
60
61 G_DEFINE_TYPE (EmpathyTpRoomlist, empathy_tp_roomlist, G_TYPE_OBJECT);
62
63 static void
64 tp_roomlist_listing_cb (TpChannel *channel,
65                         gboolean   listing,
66                         gpointer   user_data,
67                         GObject   *list)
68 {
69         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
70
71         DEBUG ("Listing: %s", listing ? "Yes" : "No");
72         priv->is_listing = listing;
73         g_object_notify (list, "is-listing");
74 }
75
76 static void
77 tp_roomlist_chatrooms_free (gpointer data)
78 {
79         GSList *chatrooms = data;
80
81         g_slist_foreach (chatrooms, (GFunc) g_object_unref, NULL);
82         g_slist_free (chatrooms);
83 }
84
85 static void
86 tp_roomlist_inspect_handles_cb (TpConnection *connection,
87                                 const gchar **names,
88                                 const GError *error,
89                                 gpointer      user_data,
90                                 GObject      *list)
91 {
92         GSList *chatrooms = user_data;
93
94         if (error != NULL) {
95                 DEBUG ("Error: %s", error->message);
96                 return;
97         }
98
99         while (*names != NULL) {
100                 EmpathyChatroom *chatroom = chatrooms->data;
101
102                 empathy_chatroom_set_room (chatroom, *names);
103                 g_signal_emit (list, signals[NEW_ROOM], 0, chatroom);
104
105                 names++;
106                 chatrooms = chatrooms->next;
107         }
108 }
109
110 static void
111 tp_roomlist_got_rooms_cb (TpChannel       *channel,
112                           const GPtrArray *rooms,
113                           gpointer         user_data,
114                           GObject         *list)
115 {
116         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
117         EmpathyChatroom       *chatroom;
118         guint                  i;
119         GArray                *handles = NULL;
120         GSList                *chatrooms = NULL;
121
122         for (i = 0; i < rooms->len; i++) {
123                 const GValue *room_name_value;
124                 const GValue *handle_name_value;
125                 const GValue *room_members_value;
126                 const GValue *room_subject_value;
127                 const GValue *room_invite_value;
128                 const GValue *room_password_value;
129                 GValueArray  *room_struct;
130                 guint         handle;
131                 const gchar  *channel_type;
132                 GHashTable   *info;
133
134                 /* Get information */
135                 room_struct = g_ptr_array_index (rooms, i);
136                 handle = g_value_get_uint (g_value_array_get_nth (room_struct, 0));
137                 channel_type = g_value_get_string (g_value_array_get_nth (room_struct, 1));
138                 info = g_value_get_boxed (g_value_array_get_nth (room_struct, 2));
139                 room_name_value = g_hash_table_lookup (info, "name");
140                 handle_name_value = g_hash_table_lookup (info, "handle-name");
141                 room_subject_value = g_hash_table_lookup (info, "subject");
142                 room_members_value = g_hash_table_lookup (info, "members");
143                 room_invite_value = g_hash_table_lookup (info, "invite-only");
144                 room_password_value = g_hash_table_lookup (info, "password");
145
146                 if (tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TEXT)) {
147                         continue;
148                 }
149
150                 chatroom = empathy_chatroom_new (priv->account);
151
152                 if (room_name_value != NULL) {
153                         empathy_chatroom_set_name (chatroom,
154                                                    g_value_get_string (room_name_value));
155                 }
156
157                 if (room_members_value != NULL) {
158                         empathy_chatroom_set_members_count (chatroom,
159                                                    g_value_get_uint (room_members_value));
160                 }
161
162                 if (room_subject_value != NULL) {
163                         empathy_chatroom_set_subject (chatroom,
164                                                    g_value_get_string (room_subject_value));
165                 }
166
167                 if (room_invite_value != NULL) {
168                         empathy_chatroom_set_invite_only (chatroom,
169                                                    g_value_get_boolean (room_invite_value));
170                 }
171
172                 if (room_password_value != NULL) {
173                         empathy_chatroom_set_need_password (chatroom,
174                                                    g_value_get_boolean (room_password_value));
175                 }
176
177                 if (handle_name_value != NULL) {
178                         empathy_chatroom_set_room (chatroom,
179                                                    g_value_get_string (handle_name_value));
180
181                         /* We have the room ID, we can directly emit it */
182                         g_signal_emit (list, signals[NEW_ROOM], 0, chatroom);
183                         g_object_unref (chatroom);
184                 } else {
185                         /* We don't have the room ID, we'll inspect all handles
186                          * at once and then emit rooms */
187                         if (handles == NULL) {
188                                 handles = g_array_new (FALSE, FALSE, sizeof (guint));
189                         }
190
191                         g_array_append_val (handles, handle);
192                         chatrooms = g_slist_prepend (chatrooms, chatroom);
193                 }
194         }
195
196         if (handles != NULL) {
197                 chatrooms = g_slist_reverse (chatrooms);
198                 tp_cli_connection_call_inspect_handles (priv->connection, -1,
199                                                        TP_HANDLE_TYPE_ROOM,
200                                                        handles,
201                                                        tp_roomlist_inspect_handles_cb,
202                                                        chatrooms,
203                                                        tp_roomlist_chatrooms_free,
204                                                        list);
205                 g_array_free (handles, TRUE);
206         }
207 }
208
209 static void
210 tp_roomlist_get_listing_rooms_cb (TpChannel    *channel,
211                                   gboolean      is_listing,
212                                   const GError *error,
213                                   gpointer      user_data,
214                                   GObject      *list)
215 {
216         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
217
218         if (error) {
219                 DEBUG ("Error geting listing rooms: %s", error->message);
220                 return;
221         }
222
223         priv->is_listing = is_listing;
224         g_object_notify (list, "is-listing");
225 }
226
227 static void
228 tp_roomlist_invalidated_cb (TpChannel         *channel,
229                             guint              domain,
230                             gint               code,
231                             gchar             *message,
232                             EmpathyTpRoomlist *list)
233 {
234         DEBUG ("Channel invalidated: %s", message);
235         g_signal_emit (list, signals[DESTROY], 0);
236 }
237
238 static void
239 tp_roomlist_request_channel_cb (TpConnection *connection,
240                                 const gchar  *object_path,
241                                 const GError *error,
242                                 gpointer      user_data,
243                                 GObject      *list)
244 {
245         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
246
247         if (error) {
248                 DEBUG ("Error requesting channel: %s", error->message);
249                 return;
250         }
251
252         priv->channel = tp_channel_new (priv->connection, object_path,
253                                         TP_IFACE_CHANNEL_TYPE_ROOM_LIST,
254                                         TP_HANDLE_TYPE_NONE,
255                                         0, NULL);
256         tp_channel_run_until_ready (priv->channel, NULL, NULL);
257
258         g_signal_connect (priv->channel, "invalidated",
259                           G_CALLBACK (tp_roomlist_invalidated_cb),
260                           list);
261
262         tp_cli_channel_type_room_list_connect_to_listing_rooms (priv->channel,
263                                                                 tp_roomlist_listing_cb,
264                                                                 NULL, NULL,
265                                                                 G_OBJECT (list),
266                                                                 NULL);
267         tp_cli_channel_type_room_list_connect_to_got_rooms (priv->channel,
268                                                             tp_roomlist_got_rooms_cb,
269                                                             NULL, NULL,
270                                                             G_OBJECT (list),
271                                                             NULL);
272
273         tp_cli_channel_type_room_list_call_get_listing_rooms (priv->channel, -1,
274                                                               tp_roomlist_get_listing_rooms_cb,
275                                                               NULL, NULL,
276                                                               G_OBJECT (list));
277 }
278
279 static void
280 tp_roomlist_finalize (GObject *object)
281 {
282         EmpathyTpRoomlistPriv *priv = GET_PRIV (object);
283
284         if (priv->channel) {
285                 DEBUG ("Closing channel...");
286                 g_signal_handlers_disconnect_by_func (priv->channel,
287                                                       tp_roomlist_invalidated_cb,
288                                                       object);
289                 tp_cli_channel_call_close (priv->channel, -1,
290                                            NULL, NULL, NULL, NULL);
291                 g_object_unref (priv->channel);
292         }
293
294         if (priv->account) {
295                 g_object_unref (priv->account);
296         }
297         if (priv->connection) {
298                 g_object_unref (priv->connection);
299         }
300
301         G_OBJECT_CLASS (empathy_tp_roomlist_parent_class)->finalize (object);
302 }
303
304 static void
305 tp_roomlist_constructed (GObject *list)
306 {
307         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
308         MissionControl        *mc;
309
310         mc = empathy_mission_control_dup_singleton ();
311         priv->account = mission_control_get_account_for_tpconnection (mc,
312                                                                       priv->connection,
313                                                                       NULL);
314         g_object_unref (mc);
315
316         tp_cli_connection_call_request_channel (priv->connection, -1,
317                                                 TP_IFACE_CHANNEL_TYPE_ROOM_LIST,
318                                                 TP_HANDLE_TYPE_NONE,
319                                                 0,
320                                                 TRUE,
321                                                 tp_roomlist_request_channel_cb,
322                                                 NULL, NULL,
323                                                 list);
324 }
325
326 static void
327 tp_roomlist_get_property (GObject    *object,
328                           guint       param_id,
329                           GValue     *value,
330                           GParamSpec *pspec)
331 {
332         EmpathyTpRoomlistPriv *priv = GET_PRIV (object);
333
334         switch (param_id) {
335         case PROP_CONNECTION:
336                 g_value_set_object (value, priv->connection);
337                 break;
338         case PROP_IS_LISTING:
339                 g_value_set_boolean (value, priv->is_listing);
340                 break;
341         default:
342                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
343                 break;
344         };
345 }
346
347 static void
348 tp_roomlist_set_property (GObject      *object,
349                           guint         param_id,
350                           const GValue *value,
351                           GParamSpec   *pspec)
352 {
353         EmpathyTpRoomlistPriv *priv = GET_PRIV (object);
354
355         switch (param_id) {
356         case PROP_CONNECTION:
357                 priv->connection = g_object_ref (g_value_get_object (value));
358                 break;
359         default:
360                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
361                 break;
362         };
363 }
364
365 static void
366 empathy_tp_roomlist_class_init (EmpathyTpRoomlistClass *klass)
367 {
368         GObjectClass *object_class = G_OBJECT_CLASS (klass);
369
370         object_class->finalize = tp_roomlist_finalize;
371         object_class->constructed = tp_roomlist_constructed;
372         object_class->get_property = tp_roomlist_get_property;
373         object_class->set_property = tp_roomlist_set_property;
374
375         g_object_class_install_property (object_class,
376                                          PROP_CONNECTION,
377                                          g_param_spec_object ("connection",
378                                                               "The Connection",
379                                                               "The connection on which it lists rooms",
380                                                               TP_TYPE_CONNECTION,
381                                                               G_PARAM_READWRITE |
382                                                               G_PARAM_CONSTRUCT_ONLY));
383         g_object_class_install_property (object_class,
384                                          PROP_IS_LISTING,
385                                          g_param_spec_boolean ("is-listing",
386                                                                "Is listing",
387                                                                "Are we listing rooms",
388                                                                FALSE,
389                                                                G_PARAM_READABLE));
390
391         signals[NEW_ROOM] =
392                 g_signal_new ("new-room",
393                               G_TYPE_FROM_CLASS (klass),
394                               G_SIGNAL_RUN_LAST,
395                               0,
396                               NULL, NULL,
397                               g_cclosure_marshal_VOID__OBJECT,
398                               G_TYPE_NONE,
399                               1, EMPATHY_TYPE_CHATROOM);
400
401         signals[DESTROY] =
402                 g_signal_new ("destroy",
403                               G_TYPE_FROM_CLASS (klass),
404                               G_SIGNAL_RUN_LAST,
405                               0,
406                               NULL, NULL,
407                               g_cclosure_marshal_VOID__VOID,
408                               G_TYPE_NONE,
409                               0);
410
411         g_type_class_add_private (object_class, sizeof (EmpathyTpRoomlistPriv));
412 }
413
414 static void
415 empathy_tp_roomlist_init (EmpathyTpRoomlist *list)
416 {
417         EmpathyTpRoomlistPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (list,
418                 EMPATHY_TYPE_TP_ROOMLIST, EmpathyTpRoomlistPriv);
419
420         list->priv = priv;
421 }
422
423 EmpathyTpRoomlist *
424 empathy_tp_roomlist_new (McAccount *account)
425 {
426         EmpathyTpRoomlist *list;
427         MissionControl    *mc;
428         TpConnection      *connection;
429
430         g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
431
432         mc = empathy_mission_control_dup_singleton ();
433         connection = mission_control_get_tpconnection (mc, account, NULL);
434
435         list = g_object_new (EMPATHY_TYPE_TP_ROOMLIST,
436                              "connection", connection,
437                              NULL);
438
439         g_object_unref (mc);
440         g_object_unref (connection);
441
442         return list;
443 }
444
445 gboolean
446 empathy_tp_roomlist_is_listing (EmpathyTpRoomlist *list)
447 {
448         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
449
450         g_return_val_if_fail (EMPATHY_IS_TP_ROOMLIST (list), FALSE);
451
452         return priv->is_listing;
453 }
454
455 void
456 empathy_tp_roomlist_start (EmpathyTpRoomlist *list)
457 {
458         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
459
460         g_return_if_fail (EMPATHY_IS_TP_ROOMLIST (list));
461         g_return_if_fail (TP_IS_CHANNEL (priv->channel));
462
463         tp_cli_channel_type_room_list_call_list_rooms (priv->channel, -1,
464                                                        NULL, NULL, NULL, NULL);
465 }
466
467 void
468 empathy_tp_roomlist_stop (EmpathyTpRoomlist *list)
469 {
470         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
471
472         g_return_if_fail (EMPATHY_IS_TP_ROOMLIST (list));
473         g_return_if_fail (TP_IS_CHANNEL (priv->channel));
474
475         tp_cli_channel_type_room_list_call_stop_listing (priv->channel, -1,
476                                                          NULL, NULL, NULL, NULL);
477 }
478