]> git.0d.be Git - empathy.git/blob - libempathy/empathy-tp-roomlist.c
04984096d98451d830a5464da00a752488aa2092
[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_got_rooms_cb (TpChannel       *channel,
78                           const GPtrArray *rooms,
79                           gpointer         user_data,
80                           GObject         *list)
81 {
82         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
83         EmpathyChatroom       *chatroom;
84         guint                  i;
85         gchar                **room_ids;
86         GArray                *handles = NULL;
87         GSList                *chatrooms = NULL, *l;
88         const gchar           *str;
89
90         for (i = 0; i < rooms->len; i++) {
91                 const GValue *room_name_value;
92                 const GValue *handle_name_value;
93                 GValueArray  *room_struct;
94                 guint         handle;
95                 const gchar  *channel_type;
96                 GHashTable   *info;
97
98                 /* Get information */
99                 room_struct = g_ptr_array_index (rooms, i);
100                 handle = g_value_get_uint (g_value_array_get_nth (room_struct, 0));
101                 channel_type = g_value_get_string (g_value_array_get_nth (room_struct, 1));
102                 info = g_value_get_boxed (g_value_array_get_nth (room_struct, 2));
103                 room_name_value = g_hash_table_lookup (info, "name");
104                 handle_name_value = g_hash_table_lookup (info, "handle-name");
105
106                 if (tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TEXT)) {
107                         continue;
108                 }
109
110                 chatroom = g_object_new (EMPATHY_TYPE_CHATROOM,
111                                          "account", priv->account,
112                                          NULL);
113
114                 if (room_name_value) {
115                         str = g_value_get_string (room_name_value);
116                         empathy_chatroom_set_name (chatroom, str);
117                 }
118
119                 if (handle_name_value) {
120                         str = g_value_get_string (handle_name_value);
121                         empathy_chatroom_set_room (chatroom, str);
122
123                         /* Room is ready, emit it */
124                         g_signal_emit (list, signals[NEW_ROOM], 0, chatroom);
125                         g_object_unref (chatroom);
126                 } else {
127                         /* We first need to inspect the handle */
128                         if (!handles) {
129                                 handles = g_array_new (FALSE, FALSE, sizeof (guint));
130                         }
131
132                         g_array_append_val (handles, handle);
133                         chatrooms = g_slist_prepend (chatrooms, chatroom);
134                 }
135         }
136
137         if (!handles) {
138                 /* All rooms were ready, we are done */
139                 return;
140         }
141
142         tp_cli_connection_run_inspect_handles (priv->connection, -1,
143                                                TP_HANDLE_TYPE_ROOM,
144                                                handles,
145                                                &room_ids,
146                                                NULL, NULL);
147
148         l = chatrooms = g_slist_reverse (chatrooms);
149         for (i = 0; i < handles->len; i++) {
150                 EmpathyChatroom *chatroom = l->data;
151
152                 empathy_chatroom_set_room (chatroom, room_ids[i]);
153                 g_signal_emit (list, signals[NEW_ROOM], 0, chatroom);
154
155                 g_object_unref (chatroom);
156                 g_free (room_ids[i]);
157         }
158
159         g_free (room_ids);
160         g_array_free (handles, TRUE);
161         g_slist_free (chatrooms);
162 }
163
164 static void
165 tp_roomlist_get_listing_rooms_cb (TpChannel    *channel,
166                                   gboolean      is_listing,
167                                   const GError *error,
168                                   gpointer      user_data,
169                                   GObject      *list)
170 {
171         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
172
173         if (error) {
174                 DEBUG ("Error geting listing rooms: %s", error->message);
175                 return;
176         }
177
178         priv->is_listing = is_listing;
179         g_object_notify (list, "is-listing");
180 }
181
182 static void
183 tp_roomlist_invalidated_cb (TpChannel         *channel,
184                             guint              domain,
185                             gint               code,
186                             gchar             *message,
187                             EmpathyTpRoomlist *list)
188 {
189         DEBUG ("Channel invalidated: %s", message);
190         g_signal_emit (list, signals[DESTROY], 0);
191 }
192
193 static void
194 tp_roomlist_request_channel_cb (TpConnection *connection,
195                                 const gchar  *object_path,
196                                 const GError *error,
197                                 gpointer      user_data,
198                                 GObject      *list)
199 {
200         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
201
202         if (error) {
203                 DEBUG ("Error requesting channel: %s", error->message);
204                 return;
205         }
206
207         priv->channel = tp_channel_new (priv->connection, object_path,
208                                         TP_IFACE_CHANNEL_TYPE_ROOM_LIST,
209                                         TP_HANDLE_TYPE_NONE,
210                                         0, NULL);
211         tp_channel_run_until_ready (priv->channel, NULL, NULL);
212
213         g_signal_connect (priv->channel, "invalidated",
214                           G_CALLBACK (tp_roomlist_invalidated_cb),
215                           list);
216
217         tp_cli_channel_type_room_list_connect_to_listing_rooms (priv->channel,
218                                                                 tp_roomlist_listing_cb,
219                                                                 NULL, NULL,
220                                                                 G_OBJECT (list),
221                                                                 NULL);
222         tp_cli_channel_type_room_list_connect_to_got_rooms (priv->channel,
223                                                             tp_roomlist_got_rooms_cb,
224                                                             NULL, NULL,
225                                                             G_OBJECT (list),
226                                                             NULL);
227
228         tp_cli_channel_type_room_list_call_get_listing_rooms (priv->channel, -1,
229                                                               tp_roomlist_get_listing_rooms_cb,
230                                                               NULL, NULL,
231                                                               G_OBJECT (list));
232 }
233
234 static void
235 tp_roomlist_finalize (GObject *object)
236 {
237         EmpathyTpRoomlistPriv *priv = GET_PRIV (object);
238
239         if (priv->channel) {
240                 DEBUG ("Closing channel...");
241                 g_signal_handlers_disconnect_by_func (priv->channel,
242                                                       tp_roomlist_invalidated_cb,
243                                                       object);
244                 tp_cli_channel_call_close (priv->channel, -1,
245                                            NULL, NULL, NULL, NULL);
246                 g_object_unref (priv->channel);
247         }
248
249         if (priv->account) {
250                 g_object_unref (priv->account);
251         }
252         if (priv->connection) {
253                 g_object_unref (priv->connection);
254         }
255
256         G_OBJECT_CLASS (empathy_tp_roomlist_parent_class)->finalize (object);
257 }
258
259 static void
260 tp_roomlist_constructed (GObject *list)
261 {
262         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
263         MissionControl        *mc;
264
265         mc = empathy_mission_control_new ();
266         priv->account = mission_control_get_account_for_tpconnection (mc,
267                                                                       priv->connection,
268                                                                       NULL);
269         g_object_unref (mc);
270
271         tp_cli_connection_call_request_channel (priv->connection, -1,
272                                                 TP_IFACE_CHANNEL_TYPE_ROOM_LIST,
273                                                 TP_HANDLE_TYPE_NONE,
274                                                 0,
275                                                 TRUE,
276                                                 tp_roomlist_request_channel_cb,
277                                                 NULL, NULL,
278                                                 list);
279 }
280
281 static void
282 tp_roomlist_get_property (GObject    *object,
283                           guint       param_id,
284                           GValue     *value,
285                           GParamSpec *pspec)
286 {
287         EmpathyTpRoomlistPriv *priv = GET_PRIV (object);
288
289         switch (param_id) {
290         case PROP_CONNECTION:
291                 g_value_set_object (value, priv->connection);
292                 break;
293         case PROP_IS_LISTING:
294                 g_value_set_boolean (value, priv->is_listing);
295                 break;
296         default:
297                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
298                 break;
299         };
300 }
301
302 static void
303 tp_roomlist_set_property (GObject      *object,
304                           guint         param_id,
305                           const GValue *value,
306                           GParamSpec   *pspec)
307 {
308         EmpathyTpRoomlistPriv *priv = GET_PRIV (object);
309
310         switch (param_id) {
311         case PROP_CONNECTION:
312                 priv->connection = g_object_ref (g_value_get_object (value));
313                 break;
314         default:
315                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
316                 break;
317         };
318 }
319
320 static void
321 empathy_tp_roomlist_class_init (EmpathyTpRoomlistClass *klass)
322 {
323         GObjectClass *object_class = G_OBJECT_CLASS (klass);
324
325         object_class->finalize = tp_roomlist_finalize;
326         object_class->constructed = tp_roomlist_constructed;
327         object_class->get_property = tp_roomlist_get_property;
328         object_class->set_property = tp_roomlist_set_property;
329
330         g_object_class_install_property (object_class,
331                                          PROP_CONNECTION,
332                                          g_param_spec_object ("connection",
333                                                               "The Connection",
334                                                               "The connection on which it lists rooms",
335                                                               TP_TYPE_CONNECTION,
336                                                               G_PARAM_READWRITE |
337                                                               G_PARAM_CONSTRUCT_ONLY));
338         g_object_class_install_property (object_class,
339                                          PROP_IS_LISTING,
340                                          g_param_spec_boolean ("is-listing",
341                                                                "Is listing",
342                                                                "Are we listing rooms",
343                                                                FALSE,
344                                                                G_PARAM_READABLE));
345
346         signals[NEW_ROOM] =
347                 g_signal_new ("new-room",
348                               G_TYPE_FROM_CLASS (klass),
349                               G_SIGNAL_RUN_LAST,
350                               0,
351                               NULL, NULL,
352                               g_cclosure_marshal_VOID__OBJECT,
353                               G_TYPE_NONE,
354                               1, EMPATHY_TYPE_CHATROOM);
355
356         signals[DESTROY] =
357                 g_signal_new ("destroy",
358                               G_TYPE_FROM_CLASS (klass),
359                               G_SIGNAL_RUN_LAST,
360                               0,
361                               NULL, NULL,
362                               g_cclosure_marshal_VOID__VOID,
363                               G_TYPE_NONE,
364                               0);
365
366         g_type_class_add_private (object_class, sizeof (EmpathyTpRoomlistPriv));
367 }
368
369 static void
370 empathy_tp_roomlist_init (EmpathyTpRoomlist *list)
371 {
372         EmpathyTpRoomlistPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (list,
373                 EMPATHY_TYPE_TP_ROOMLIST, EmpathyTpRoomlistPriv);
374
375         list->priv = priv;
376 }
377
378 EmpathyTpRoomlist *
379 empathy_tp_roomlist_new (McAccount *account)
380 {
381         EmpathyTpRoomlist *list;
382         MissionControl    *mc;
383         TpConnection      *connection;
384
385         g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
386
387         mc = empathy_mission_control_new ();
388         connection = mission_control_get_tpconnection (mc, account, NULL);
389
390         list = g_object_new (EMPATHY_TYPE_TP_ROOMLIST,
391                              "connection", connection,
392                              NULL);
393
394         g_object_unref (mc);
395         g_object_unref (connection);
396
397         return list;
398 }
399
400 gboolean
401 empathy_tp_roomlist_is_listing (EmpathyTpRoomlist *list)
402 {
403         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
404
405         g_return_val_if_fail (EMPATHY_IS_TP_ROOMLIST (list), FALSE);
406
407         return priv->is_listing;
408 }
409
410 void
411 empathy_tp_roomlist_start (EmpathyTpRoomlist *list)
412 {
413         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
414
415         g_return_if_fail (EMPATHY_IS_TP_ROOMLIST (list));
416         g_return_if_fail (TP_IS_CHANNEL (priv->channel));
417
418         tp_cli_channel_type_room_list_call_list_rooms (priv->channel, -1,
419                                                        NULL, NULL, NULL, NULL);
420 }
421
422 void
423 empathy_tp_roomlist_stop (EmpathyTpRoomlist *list)
424 {
425         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
426
427         g_return_if_fail (EMPATHY_IS_TP_ROOMLIST (list));
428         g_return_if_fail (TP_IS_CHANNEL (priv->channel));
429
430         tp_cli_channel_type_room_list_call_stop_listing (priv->channel, -1,
431                                                          NULL, NULL, NULL, NULL);
432 }
433