]> git.0d.be Git - empathy.git/blob - libempathy/empathy-tp-roomlist.c
4193685dc994236cb9dc9094f63e4087bb126326
[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
29 #include <libmissioncontrol/mission-control.h>
30
31 #include "empathy-tp-roomlist.h"
32 #include "empathy-chatroom.h"
33 #include "empathy-utils.h"
34 #include "empathy-debug.h"
35
36 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
37                        EMPATHY_TYPE_TP_ROOMLIST, EmpathyTpRoomlistPriv))
38
39 #define DEBUG_DOMAIN "TpRoomlist"
40
41 struct _EmpathyTpRoomlistPriv {
42         TpConnection *connection;
43         TpChannel    *channel;
44         McAccount    *account;
45         gboolean      is_listing;
46 };
47
48 static void empathy_tp_roomlist_class_init (EmpathyTpRoomlistClass *klass);
49 static void empathy_tp_roomlist_init       (EmpathyTpRoomlist      *chat);
50
51 enum {
52         NEW_ROOM,
53         DESTROY,
54         LAST_SIGNAL
55 };
56
57 enum {
58         PROP_0,
59         PROP_CONNECTION,
60         PROP_IS_LISTING,
61 };
62
63 static guint signals[LAST_SIGNAL];
64
65 G_DEFINE_TYPE (EmpathyTpRoomlist, empathy_tp_roomlist, G_TYPE_OBJECT);
66
67 static void
68 tp_roomlist_listing_cb (TpChannel *channel,
69                         gboolean   listing,
70                         gpointer   user_data,
71                         GObject   *list)
72 {
73         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
74
75         empathy_debug (DEBUG_DOMAIN, "Listing: %s", listing ? "Yes" : "No");
76         priv->is_listing = listing;
77         g_object_notify (list, "is-listing");
78 }
79
80 static void
81 tp_roomlist_got_rooms_cb (TpChannel       *channel,
82                           const GPtrArray *rooms,
83                           gpointer         user_data,
84                           GObject         *list)
85 {
86         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
87         guint                  i;
88         const gchar          **names;
89         gchar                **room_ids;
90         GArray                *handles;
91
92         names = g_new0 (const gchar*, rooms->len + 1);
93         handles = g_array_sized_new (FALSE, FALSE, sizeof (guint), rooms->len);
94         for (i = 0; i < rooms->len; i++) {
95                 const GValue *room_name_value;
96                 GValueArray  *room_struct;
97                 guint         handle;
98                 GHashTable   *info;
99
100                 /* Get information */
101                 room_struct = g_ptr_array_index (rooms, i);
102                 handle = g_value_get_uint (g_value_array_get_nth (room_struct, 0));
103                 info = g_value_get_boxed (g_value_array_get_nth (room_struct, 2));
104                 room_name_value = g_hash_table_lookup (info, "name");
105
106                 names[i] = g_value_get_string (room_name_value);
107                 g_array_append_val (handles, handle);
108         }
109                 
110         tp_cli_connection_run_inspect_handles (priv->connection, -1,
111                                                TP_HANDLE_TYPE_ROOM,
112                                                handles,
113                                                &room_ids,
114                                                NULL, NULL);
115         for (i = 0; i < handles->len; i++) {
116                 EmpathyChatroom *chatroom;
117
118                 chatroom = empathy_chatroom_new_full (priv->account,
119                                                       room_ids[i],
120                                                       names[i],
121                                                       FALSE);
122                 g_signal_emit (list, signals[NEW_ROOM], 0, chatroom);
123                 g_object_unref (chatroom);
124                 g_free (room_ids[i]);
125         }
126
127         g_free (names);
128         g_free (room_ids);
129         g_array_free (handles, TRUE);
130 }
131
132 static void
133 tp_roomlist_get_listing_rooms_cb (TpChannel    *channel,
134                                   gboolean      is_listing,
135                                   const GError *error,
136                                   gpointer      user_data,
137                                   GObject      *list)
138 {
139         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
140
141         if (error) {
142                 empathy_debug (DEBUG_DOMAIN, "Error geting listing rooms: %s",
143                                error->message);
144                 return;
145         }
146
147         priv->is_listing = is_listing;
148         g_object_notify (list, "is-listing");
149 }
150
151 static void
152 tp_roomlist_invalidated_cb (TpChannel         *channel,
153                             guint              domain,
154                             gint               code,
155                             gchar             *message,
156                             EmpathyTpRoomlist *list)
157 {
158         empathy_debug (DEBUG_DOMAIN, "Channel invalidated: %s", message);
159         g_signal_emit (list, signals[DESTROY], 0);
160 }
161
162 static void
163 tp_roomlist_request_channel_cb (TpConnection *connection,
164                                 const gchar  *object_path,
165                                 const GError *error,
166                                 gpointer      user_data,
167                                 GObject      *list)
168 {
169         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
170
171         if (error) {
172                 empathy_debug (DEBUG_DOMAIN, "Error requesting channel: %s",
173                                error->message);
174                 return;
175         }
176
177         priv->channel = tp_channel_new (priv->connection, object_path,
178                                         TP_IFACE_CHANNEL_TYPE_ROOM_LIST,
179                                         TP_HANDLE_TYPE_NONE,
180                                         0, NULL);
181         tp_channel_run_until_ready (priv->channel, NULL, NULL);
182
183         g_signal_connect (priv->channel, "invalidated",
184                           G_CALLBACK (tp_roomlist_invalidated_cb),
185                           list);
186
187         tp_cli_channel_type_room_list_connect_to_listing_rooms (priv->channel,
188                                                                 tp_roomlist_listing_cb,
189                                                                 NULL, NULL,
190                                                                 G_OBJECT (list),
191                                                                 NULL);
192         tp_cli_channel_type_room_list_connect_to_got_rooms (priv->channel,
193                                                             tp_roomlist_got_rooms_cb,
194                                                             NULL, NULL,
195                                                             G_OBJECT (list),
196                                                             NULL);
197
198         tp_cli_channel_type_room_list_call_get_listing_rooms (priv->channel, -1,
199                                                               tp_roomlist_get_listing_rooms_cb,
200                                                               NULL, NULL,
201                                                               G_OBJECT (list));
202 }
203
204 static void
205 tp_roomlist_finalize (GObject *object)
206 {
207         EmpathyTpRoomlistPriv *priv = GET_PRIV (object);
208
209         if (priv->channel) {
210                 empathy_debug (DEBUG_DOMAIN, "Closing channel...");
211                 g_signal_handlers_disconnect_by_func (priv->channel,
212                                                       tp_roomlist_invalidated_cb,
213                                                       object);
214                 tp_cli_channel_call_close (priv->channel, -1,
215                                            NULL, NULL, NULL, NULL);
216                 g_object_unref (priv->channel);
217         }
218
219         if (priv->account) {
220                 g_object_unref (priv->account);
221         }
222         if (priv->connection) {
223                 g_object_unref (priv->connection);
224         }
225
226         G_OBJECT_CLASS (empathy_tp_roomlist_parent_class)->finalize (object);
227 }
228
229 static void
230 tp_roomlist_constructed (GObject *list)
231 {
232         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
233         MissionControl        *mc;
234
235         mc = empathy_mission_control_new ();
236         priv->account = mission_control_get_account_for_tpconnection (mc,
237                                                                       priv->connection,
238                                                                       NULL);
239         g_object_unref (mc);
240
241         tp_cli_connection_call_request_channel (priv->connection, -1,
242                                                 TP_IFACE_CHANNEL_TYPE_ROOM_LIST,
243                                                 TP_HANDLE_TYPE_NONE,
244                                                 0,
245                                                 TRUE,
246                                                 tp_roomlist_request_channel_cb,
247                                                 NULL, NULL,
248                                                 list);
249 }
250
251 static void
252 tp_roomlist_get_property (GObject    *object,
253                           guint       param_id,
254                           GValue     *value,
255                           GParamSpec *pspec)
256 {
257         EmpathyTpRoomlistPriv *priv = GET_PRIV (object);
258
259         switch (param_id) {
260         case PROP_CONNECTION:
261                 g_value_set_object (value, priv->connection);
262                 break;
263         case PROP_IS_LISTING:
264                 g_value_set_boolean (value, priv->is_listing);
265                 break;
266         default:
267                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
268                 break;
269         };
270 }
271
272 static void
273 tp_roomlist_set_property (GObject      *object,
274                           guint         param_id,
275                           const GValue *value,
276                           GParamSpec   *pspec)
277 {
278         EmpathyTpRoomlistPriv *priv = GET_PRIV (object);
279
280         switch (param_id) {
281         case PROP_CONNECTION:
282                 priv->connection = g_object_ref (g_value_get_object (value));
283                 break;
284         default:
285                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
286                 break;
287         };
288 }
289
290 static void
291 empathy_tp_roomlist_class_init (EmpathyTpRoomlistClass *klass)
292 {
293         GObjectClass *object_class = G_OBJECT_CLASS (klass);
294
295         object_class->finalize = tp_roomlist_finalize;
296         object_class->constructed = tp_roomlist_constructed;
297         object_class->get_property = tp_roomlist_get_property;
298         object_class->set_property = tp_roomlist_set_property;
299
300         g_object_class_install_property (object_class,
301                                          PROP_CONNECTION,
302                                          g_param_spec_object ("connection",
303                                                               "The Connection",
304                                                               "The connection on which it lists rooms",
305                                                               TP_TYPE_CONNECTION,
306                                                               G_PARAM_READWRITE |
307                                                               G_PARAM_CONSTRUCT_ONLY));
308         g_object_class_install_property (object_class,
309                                          PROP_IS_LISTING,
310                                          g_param_spec_boolean ("is-listing",
311                                                                "Is listing",
312                                                                "Are we listing rooms",
313                                                                FALSE,
314                                                                G_PARAM_READABLE));
315
316         signals[NEW_ROOM] =
317                 g_signal_new ("new-room",
318                               G_TYPE_FROM_CLASS (klass),
319                               G_SIGNAL_RUN_LAST,
320                               0,
321                               NULL, NULL,
322                               g_cclosure_marshal_VOID__OBJECT,
323                               G_TYPE_NONE,
324                               1, EMPATHY_TYPE_CHATROOM);
325
326         signals[DESTROY] =
327                 g_signal_new ("destroy",
328                               G_TYPE_FROM_CLASS (klass),
329                               G_SIGNAL_RUN_LAST,
330                               0,
331                               NULL, NULL,
332                               g_cclosure_marshal_VOID__VOID,
333                               G_TYPE_NONE,
334                               0);
335
336         g_type_class_add_private (object_class, sizeof (EmpathyTpRoomlistPriv));
337 }
338
339 static void
340 empathy_tp_roomlist_init (EmpathyTpRoomlist *list)
341 {
342 }
343
344 EmpathyTpRoomlist *
345 empathy_tp_roomlist_new (McAccount *account)
346 {
347         EmpathyTpRoomlist *list;
348         MissionControl    *mc;
349         TpConnection      *connection;
350
351         g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
352
353         mc = empathy_mission_control_new ();
354         connection = mission_control_get_tpconnection (mc, account, NULL);
355
356         list = g_object_new (EMPATHY_TYPE_TP_ROOMLIST,
357                              "connection", connection,
358                              NULL);
359
360         g_object_unref (mc);
361         g_object_unref (connection);
362
363         return list;
364 }
365
366 gboolean
367 empathy_tp_roomlist_is_listing (EmpathyTpRoomlist *list)
368 {
369         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
370
371         g_return_val_if_fail (EMPATHY_IS_TP_ROOMLIST (list), FALSE);
372
373         return priv->is_listing;
374 }
375
376 void
377 empathy_tp_roomlist_start (EmpathyTpRoomlist *list)
378 {
379         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
380
381         g_return_if_fail (EMPATHY_IS_TP_ROOMLIST (list));
382         g_return_if_fail (TP_IS_CHANNEL (priv->channel));
383
384         tp_cli_channel_type_room_list_call_list_rooms (priv->channel, -1,
385                                                        NULL, NULL, NULL,
386                                                        G_OBJECT (list));
387 }
388
389 void
390 empathy_tp_roomlist_stop (EmpathyTpRoomlist *list)
391 {
392         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
393
394         g_return_if_fail (EMPATHY_IS_TP_ROOMLIST (list));
395         g_return_if_fail (TP_IS_CHANNEL (priv->channel));
396
397         tp_cli_channel_type_room_list_call_stop_listing (priv->channel, -1,
398                                                          NULL, NULL, NULL,
399                                                          G_OBJECT (list));
400 }
401