Use help:empathy to open the help
[empathy-mirror.git] / libempathy / empathy-tp-roomlist.c
blob93e28d3d3b150a48b8a48151e33c55bb9241190c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * Copyright (C) 2007-2008 Collabora Ltd.
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.
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.
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
19 * Authors: Xavier Claessens <xclaesse@gmail.com>
22 #include <config.h>
24 #include <string.h>
26 #include <telepathy-glib/channel.h>
27 #include <telepathy-glib/dbus.h>
28 #include <telepathy-glib/util.h>
29 #include <telepathy-glib/interfaces.h>
31 #include "empathy-tp-roomlist.h"
32 #include "empathy-chatroom.h"
33 #include "empathy-utils.h"
35 #define DEBUG_FLAG EMPATHY_DEBUG_TP
36 #include "empathy-debug.h"
38 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyTpRoomlist)
39 typedef struct {
40 TpConnection *connection;
41 TpChannel *channel;
42 TpAccount *account;
43 gboolean is_listing;
44 gboolean start_requested;
45 } EmpathyTpRoomlistPriv;
47 enum {
48 NEW_ROOM,
49 DESTROY,
50 ERROR,
51 LAST_SIGNAL
54 enum {
55 PROP_0,
56 PROP_ACCOUNT,
57 PROP_IS_LISTING,
60 static guint signals[LAST_SIGNAL];
62 G_DEFINE_TYPE (EmpathyTpRoomlist, empathy_tp_roomlist, G_TYPE_OBJECT);
64 static void
65 tp_roomlist_listing_cb (TpChannel *channel,
66 gboolean listing,
67 gpointer user_data,
68 GObject *list)
70 EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
72 DEBUG ("Listing: %s", listing ? "Yes" : "No");
73 priv->is_listing = listing;
74 g_object_notify (list, "is-listing");
77 static void
78 tp_roomlist_chatrooms_free (gpointer data)
80 GSList *chatrooms = data;
82 g_slist_foreach (chatrooms, (GFunc) g_object_unref, NULL);
83 g_slist_free (chatrooms);
86 static void
87 tp_roomlist_inspect_handles_cb (TpConnection *connection,
88 const gchar **names,
89 const GError *error,
90 gpointer user_data,
91 GObject *list)
93 GSList *chatrooms = user_data;
95 if (error != NULL) {
96 DEBUG ("Error: %s", error->message);
97 return;
100 while (*names != NULL) {
101 EmpathyChatroom *chatroom = chatrooms->data;
103 empathy_chatroom_set_room (chatroom, *names);
104 g_signal_emit (list, signals[NEW_ROOM], 0, chatroom);
106 names++;
107 chatrooms = chatrooms->next;
111 static void
112 tp_roomlist_got_rooms_cb (TpChannel *channel,
113 const GPtrArray *rooms,
114 gpointer user_data,
115 GObject *list)
117 EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
118 EmpathyChatroom *chatroom;
119 guint i;
120 GArray *handles = NULL;
121 GSList *chatrooms = NULL;
123 for (i = 0; i < rooms->len; i++) {
124 const GValue *room_name_value;
125 const GValue *handle_name_value;
126 const GValue *room_members_value;
127 const GValue *room_subject_value;
128 const GValue *room_invite_value;
129 const GValue *room_password_value;
130 GValueArray *room_struct;
131 guint handle;
132 const gchar *channel_type;
133 GHashTable *info;
135 /* Get information */
136 room_struct = g_ptr_array_index (rooms, i);
137 handle = g_value_get_uint (g_value_array_get_nth (room_struct, 0));
138 channel_type = g_value_get_string (g_value_array_get_nth (room_struct, 1));
139 info = g_value_get_boxed (g_value_array_get_nth (room_struct, 2));
140 room_name_value = g_hash_table_lookup (info, "name");
141 handle_name_value = g_hash_table_lookup (info, "handle-name");
142 room_subject_value = g_hash_table_lookup (info, "subject");
143 room_members_value = g_hash_table_lookup (info, "members");
144 room_invite_value = g_hash_table_lookup (info, "invite-only");
145 room_password_value = g_hash_table_lookup (info, "password");
147 if (tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TEXT)) {
148 continue;
151 chatroom = empathy_chatroom_new (priv->account);
153 if (room_name_value != NULL) {
154 empathy_chatroom_set_name (chatroom,
155 g_value_get_string (room_name_value));
158 if (room_members_value != NULL) {
159 empathy_chatroom_set_members_count (chatroom,
160 g_value_get_uint (room_members_value));
163 if (room_subject_value != NULL) {
164 empathy_chatroom_set_subject (chatroom,
165 g_value_get_string (room_subject_value));
168 if (room_invite_value != NULL) {
169 empathy_chatroom_set_invite_only (chatroom,
170 g_value_get_boolean (room_invite_value));
173 if (room_password_value != NULL) {
174 empathy_chatroom_set_need_password (chatroom,
175 g_value_get_boolean (room_password_value));
178 if (handle_name_value != NULL) {
179 empathy_chatroom_set_room (chatroom,
180 g_value_get_string (handle_name_value));
182 /* We have the room ID, we can directly emit it */
183 g_signal_emit (list, signals[NEW_ROOM], 0, chatroom);
184 g_object_unref (chatroom);
185 } else {
186 /* We don't have the room ID, we'll inspect all handles
187 * at once and then emit rooms */
188 if (handles == NULL) {
189 handles = g_array_new (FALSE, FALSE, sizeof (guint));
192 g_array_append_val (handles, handle);
193 chatrooms = g_slist_prepend (chatrooms, chatroom);
197 if (handles != NULL) {
198 chatrooms = g_slist_reverse (chatrooms);
199 tp_cli_connection_call_inspect_handles (priv->connection, -1,
200 TP_HANDLE_TYPE_ROOM,
201 handles,
202 tp_roomlist_inspect_handles_cb,
203 chatrooms,
204 tp_roomlist_chatrooms_free,
205 list);
206 g_array_unref (handles);
210 static void
211 tp_roomlist_get_listing_rooms_cb (TpChannel *channel,
212 gboolean is_listing,
213 const GError *error,
214 gpointer user_data,
215 GObject *list)
217 EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
219 if (error) {
220 DEBUG ("Error geting listing rooms: %s", error->message);
221 return;
224 priv->is_listing = is_listing;
225 g_object_notify (list, "is-listing");
228 static void
229 tp_roomlist_invalidated_cb (TpChannel *channel,
230 guint domain,
231 gint code,
232 gchar *message,
233 EmpathyTpRoomlist *list)
235 DEBUG ("Channel invalidated: %s", message);
236 g_signal_emit (list, signals[DESTROY], 0);
239 static void
240 call_list_rooms_cb (TpChannel *proxy,
241 const GError *error,
242 gpointer list,
243 GObject *weak_object)
245 if (error != NULL) {
246 DEBUG ("Error listing rooms: %s", error->message);
247 g_signal_emit_by_name (list, "error::start", error);
251 static void
252 stop_listing_cb (TpChannel *proxy,
253 const GError *error,
254 gpointer list,
255 GObject *weak_object)
257 if (error != NULL) {
258 DEBUG ("Error on stop listing: %s", error->message);
259 g_signal_emit_by_name (list, "error::stop", error);
263 static void
264 tp_roomlist_create_channel_cb (GObject *source,
265 GAsyncResult *result,
266 gpointer user_data)
268 EmpathyTpRoomlist *self = user_data;
269 EmpathyTpRoomlistPriv *priv = GET_PRIV (self);
270 GError *error = NULL;
272 priv->channel = tp_account_channel_request_create_and_handle_channel_finish (
273 TP_ACCOUNT_CHANNEL_REQUEST (source), result, NULL, &error);
275 if (priv->channel == NULL) {
276 DEBUG ("Error creating channel: %s", error->message);
277 g_error_free (error);
278 goto out;
281 g_signal_connect (priv->channel, "invalidated",
282 G_CALLBACK (tp_roomlist_invalidated_cb), self);
284 tp_cli_channel_type_room_list_connect_to_listing_rooms (priv->channel,
285 tp_roomlist_listing_cb,
286 NULL, NULL,
287 G_OBJECT (self),
288 NULL);
289 tp_cli_channel_type_room_list_connect_to_got_rooms (priv->channel,
290 tp_roomlist_got_rooms_cb,
291 NULL, NULL,
292 G_OBJECT (self),
293 NULL);
295 tp_cli_channel_type_room_list_call_get_listing_rooms (priv->channel, -1,
296 tp_roomlist_get_listing_rooms_cb,
297 NULL, NULL,
298 G_OBJECT (self));
300 if (priv->start_requested == TRUE) {
301 tp_cli_channel_type_room_list_call_list_rooms (priv->channel, -1,
302 call_list_rooms_cb, self, NULL, G_OBJECT (self));
303 priv->start_requested = FALSE;
306 out:
307 g_object_unref (self);
310 static void
311 tp_roomlist_finalize (GObject *object)
313 EmpathyTpRoomlistPriv *priv = GET_PRIV (object);
315 if (priv->channel) {
316 DEBUG ("Closing channel...");
317 g_signal_handlers_disconnect_by_func (priv->channel,
318 tp_roomlist_invalidated_cb,
319 object);
320 tp_cli_channel_call_close (priv->channel, -1,
321 NULL, NULL, NULL, NULL);
322 g_object_unref (priv->channel);
325 if (priv->account) {
326 g_object_unref (priv->account);
328 if (priv->connection) {
329 g_object_unref (priv->connection);
332 G_OBJECT_CLASS (empathy_tp_roomlist_parent_class)->finalize (object);
335 static void
336 tp_roomlist_constructed (GObject *list)
338 EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
339 GHashTable *request;
340 TpAccountChannelRequest *req;
342 request = tp_asv_new (
343 TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
344 TP_IFACE_CHANNEL_TYPE_ROOM_LIST,
345 TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT, TP_HANDLE_TYPE_NONE,
346 NULL);
348 priv->connection = tp_account_get_connection (priv->account);
349 g_object_ref (priv->connection);
351 req = tp_account_channel_request_new (priv->account, request,
352 TP_USER_ACTION_TIME_CURRENT_TIME);
354 /* Ensure we stay alive during the async call */
355 g_object_ref (list);
357 tp_account_channel_request_create_and_handle_channel_async (req, NULL,
358 tp_roomlist_create_channel_cb, list);
360 g_hash_table_unref (request);
361 g_object_unref (req);
364 static void
365 tp_roomlist_get_property (GObject *object,
366 guint param_id,
367 GValue *value,
368 GParamSpec *pspec)
370 EmpathyTpRoomlistPriv *priv = GET_PRIV (object);
372 switch (param_id) {
373 case PROP_ACCOUNT:
374 g_value_set_object (value, priv->account);
375 break;
376 case PROP_IS_LISTING:
377 g_value_set_boolean (value, priv->is_listing);
378 break;
379 default:
380 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
381 break;
385 static void
386 tp_roomlist_set_property (GObject *object,
387 guint param_id,
388 const GValue *value,
389 GParamSpec *pspec)
391 EmpathyTpRoomlistPriv *priv = GET_PRIV (object);
393 switch (param_id) {
394 case PROP_ACCOUNT:
395 priv->account = g_value_dup_object (value);
396 break;
397 default:
398 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
399 break;
403 static void
404 empathy_tp_roomlist_class_init (EmpathyTpRoomlistClass *klass)
406 GObjectClass *object_class = G_OBJECT_CLASS (klass);
408 object_class->finalize = tp_roomlist_finalize;
409 object_class->constructed = tp_roomlist_constructed;
410 object_class->get_property = tp_roomlist_get_property;
411 object_class->set_property = tp_roomlist_set_property;
413 g_object_class_install_property (object_class,
414 PROP_ACCOUNT,
415 g_param_spec_object ("account",
416 "The Account",
417 "The account on which it lists rooms",
418 TP_TYPE_ACCOUNT,
419 G_PARAM_READWRITE |
420 G_PARAM_CONSTRUCT_ONLY));
421 g_object_class_install_property (object_class,
422 PROP_IS_LISTING,
423 g_param_spec_boolean ("is-listing",
424 "Is listing",
425 "Are we listing rooms",
426 FALSE,
427 G_PARAM_READABLE));
429 signals[NEW_ROOM] =
430 g_signal_new ("new-room",
431 G_TYPE_FROM_CLASS (klass),
432 G_SIGNAL_RUN_LAST,
434 NULL, NULL,
435 g_cclosure_marshal_generic,
436 G_TYPE_NONE,
437 1, EMPATHY_TYPE_CHATROOM);
439 signals[DESTROY] =
440 g_signal_new ("destroy",
441 G_TYPE_FROM_CLASS (klass),
442 G_SIGNAL_RUN_LAST,
444 NULL, NULL,
445 g_cclosure_marshal_generic,
446 G_TYPE_NONE,
449 signals[ERROR] =
450 g_signal_new ("error",
451 G_TYPE_FROM_CLASS (klass),
452 G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
454 NULL, NULL,
455 g_cclosure_marshal_generic,
456 G_TYPE_NONE,
457 1, G_TYPE_POINTER);
459 g_type_class_add_private (object_class, sizeof (EmpathyTpRoomlistPriv));
462 static void
463 empathy_tp_roomlist_init (EmpathyTpRoomlist *list)
465 EmpathyTpRoomlistPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (list,
466 EMPATHY_TYPE_TP_ROOMLIST, EmpathyTpRoomlistPriv);
468 list->priv = priv;
469 priv->start_requested = FALSE;
470 priv->is_listing = FALSE;
473 EmpathyTpRoomlist *
474 empathy_tp_roomlist_new (TpAccount *account)
476 EmpathyTpRoomlist *list;
478 list = g_object_new (EMPATHY_TYPE_TP_ROOMLIST,
479 "account", account,
480 NULL);
482 return list;
485 gboolean
486 empathy_tp_roomlist_is_listing (EmpathyTpRoomlist *list)
488 EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
490 g_return_val_if_fail (EMPATHY_IS_TP_ROOMLIST (list), FALSE);
492 return priv->is_listing;
495 void
496 empathy_tp_roomlist_start (EmpathyTpRoomlist *list)
498 EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
500 g_return_if_fail (EMPATHY_IS_TP_ROOMLIST (list));
501 if (priv->channel != NULL) {
502 tp_cli_channel_type_room_list_call_list_rooms (priv->channel, -1,
503 call_list_rooms_cb, list, NULL, NULL);
504 } else {
505 priv->start_requested = TRUE;
509 void
510 empathy_tp_roomlist_stop (EmpathyTpRoomlist *list)
512 EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
514 g_return_if_fail (EMPATHY_IS_TP_ROOMLIST (list));
516 if (priv->channel == NULL)
517 return;
519 g_return_if_fail (TP_IS_CHANNEL (priv->channel));
521 tp_cli_channel_type_room_list_call_stop_listing (priv->channel, -1,
522 stop_listing_cb, list, NULL, NULL);