]> git.0d.be Git - empathy.git/blob - libempathy/empathy-tp-roomlist.c
Updated Basque language
[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 #include <telepathy-glib/interfaces.h>
30
31 #include "empathy-account.h"
32
33 #include "empathy-tp-roomlist.h"
34 #include "empathy-chatroom.h"
35 #include "empathy-utils.h"
36
37 #define DEBUG_FLAG EMPATHY_DEBUG_TP
38 #include "empathy-debug.h"
39
40 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyTpRoomlist)
41 typedef struct {
42         TpConnection *connection;
43         TpChannel    *channel;
44         EmpathyAccount    *account;
45         gboolean      is_listing;
46         gboolean      start_requested;
47 } EmpathyTpRoomlistPriv;
48
49 enum {
50         NEW_ROOM,
51         DESTROY,
52         ERROR,
53         LAST_SIGNAL
54 };
55
56 enum {
57         PROP_0,
58         PROP_ACCOUNT,
59         PROP_IS_LISTING,
60 };
61
62 static guint signals[LAST_SIGNAL];
63
64 G_DEFINE_TYPE (EmpathyTpRoomlist, empathy_tp_roomlist, G_TYPE_OBJECT);
65
66 static void
67 tp_roomlist_listing_cb (TpChannel *channel,
68                         gboolean   listing,
69                         gpointer   user_data,
70                         GObject   *list)
71 {
72         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
73
74         DEBUG ("Listing: %s", listing ? "Yes" : "No");
75         priv->is_listing = listing;
76         g_object_notify (list, "is-listing");
77 }
78
79 static void
80 tp_roomlist_chatrooms_free (gpointer data)
81 {
82         GSList *chatrooms = data;
83
84         g_slist_foreach (chatrooms, (GFunc) g_object_unref, NULL);
85         g_slist_free (chatrooms);
86 }
87
88 static void
89 tp_roomlist_inspect_handles_cb (TpConnection *connection,
90                                 const gchar **names,
91                                 const GError *error,
92                                 gpointer      user_data,
93                                 GObject      *list)
94 {
95         GSList *chatrooms = user_data;
96
97         if (error != NULL) {
98                 DEBUG ("Error: %s", error->message);
99                 return;
100         }
101
102         while (*names != NULL) {
103                 EmpathyChatroom *chatroom = chatrooms->data;
104
105                 empathy_chatroom_set_room (chatroom, *names);
106                 g_signal_emit (list, signals[NEW_ROOM], 0, chatroom);
107
108                 names++;
109                 chatrooms = chatrooms->next;
110         }
111 }
112
113 static void
114 tp_roomlist_got_rooms_cb (TpChannel       *channel,
115                           const GPtrArray *rooms,
116                           gpointer         user_data,
117                           GObject         *list)
118 {
119         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
120         EmpathyChatroom       *chatroom;
121         guint                  i;
122         GArray                *handles = NULL;
123         GSList                *chatrooms = NULL;
124
125         for (i = 0; i < rooms->len; i++) {
126                 const GValue *room_name_value;
127                 const GValue *handle_name_value;
128                 const GValue *room_members_value;
129                 const GValue *room_subject_value;
130                 const GValue *room_invite_value;
131                 const GValue *room_password_value;
132                 GValueArray  *room_struct;
133                 guint         handle;
134                 const gchar  *channel_type;
135                 GHashTable   *info;
136
137                 /* Get information */
138                 room_struct = g_ptr_array_index (rooms, i);
139                 handle = g_value_get_uint (g_value_array_get_nth (room_struct, 0));
140                 channel_type = g_value_get_string (g_value_array_get_nth (room_struct, 1));
141                 info = g_value_get_boxed (g_value_array_get_nth (room_struct, 2));
142                 room_name_value = g_hash_table_lookup (info, "name");
143                 handle_name_value = g_hash_table_lookup (info, "handle-name");
144                 room_subject_value = g_hash_table_lookup (info, "subject");
145                 room_members_value = g_hash_table_lookup (info, "members");
146                 room_invite_value = g_hash_table_lookup (info, "invite-only");
147                 room_password_value = g_hash_table_lookup (info, "password");
148
149                 if (tp_strdiff (channel_type, TP_IFACE_CHANNEL_TYPE_TEXT)) {
150                         continue;
151                 }
152
153                 chatroom = empathy_chatroom_new (priv->account);
154
155                 if (room_name_value != NULL) {
156                         empathy_chatroom_set_name (chatroom,
157                                                    g_value_get_string (room_name_value));
158                 }
159
160                 if (room_members_value != NULL) {
161                         empathy_chatroom_set_members_count (chatroom,
162                                                    g_value_get_uint (room_members_value));
163                 }
164
165                 if (room_subject_value != NULL) {
166                         empathy_chatroom_set_subject (chatroom,
167                                                    g_value_get_string (room_subject_value));
168                 }
169
170                 if (room_invite_value != NULL) {
171                         empathy_chatroom_set_invite_only (chatroom,
172                                                    g_value_get_boolean (room_invite_value));
173                 }
174
175                 if (room_password_value != NULL) {
176                         empathy_chatroom_set_need_password (chatroom,
177                                                    g_value_get_boolean (room_password_value));
178                 }
179
180                 if (handle_name_value != NULL) {
181                         empathy_chatroom_set_room (chatroom,
182                                                    g_value_get_string (handle_name_value));
183
184                         /* We have the room ID, we can directly emit it */
185                         g_signal_emit (list, signals[NEW_ROOM], 0, chatroom);
186                         g_object_unref (chatroom);
187                 } else {
188                         /* We don't have the room ID, we'll inspect all handles
189                          * at once and then emit rooms */
190                         if (handles == NULL) {
191                                 handles = g_array_new (FALSE, FALSE, sizeof (guint));
192                         }
193
194                         g_array_append_val (handles, handle);
195                         chatrooms = g_slist_prepend (chatrooms, chatroom);
196                 }
197         }
198
199         if (handles != NULL) {
200                 chatrooms = g_slist_reverse (chatrooms);
201                 tp_cli_connection_call_inspect_handles (priv->connection, -1,
202                                                        TP_HANDLE_TYPE_ROOM,
203                                                        handles,
204                                                        tp_roomlist_inspect_handles_cb,
205                                                        chatrooms,
206                                                        tp_roomlist_chatrooms_free,
207                                                        list);
208                 g_array_free (handles, TRUE);
209         }
210 }
211
212 static void
213 tp_roomlist_get_listing_rooms_cb (TpChannel    *channel,
214                                   gboolean      is_listing,
215                                   const GError *error,
216                                   gpointer      user_data,
217                                   GObject      *list)
218 {
219         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
220
221         if (error) {
222                 DEBUG ("Error geting listing rooms: %s", error->message);
223                 return;
224         }
225
226         priv->is_listing = is_listing;
227         g_object_notify (list, "is-listing");
228 }
229
230 static void
231 tp_roomlist_invalidated_cb (TpChannel         *channel,
232                             guint              domain,
233                             gint               code,
234                             gchar             *message,
235                             EmpathyTpRoomlist *list)
236 {
237         DEBUG ("Channel invalidated: %s", message);
238         g_signal_emit (list, signals[DESTROY], 0);
239 }
240
241 static void
242 call_list_rooms_cb (TpChannel *proxy,
243                     const GError *error,
244                     gpointer list,
245                     GObject *weak_object)
246 {
247         if (error != NULL) {
248                 DEBUG ("Error listing rooms: %s", error->message);
249                 g_signal_emit_by_name (list, "error::start", error);
250         }
251 }
252
253 static void
254 stop_listing_cb (TpChannel *proxy,
255                  const GError *error,
256                  gpointer list,
257                  GObject *weak_object)
258 {
259         if (error != NULL) {
260                 DEBUG ("Error on stop listing: %s", error->message);
261                 g_signal_emit_by_name (list, "error::stop", error);
262         }
263 }
264
265 static void
266 channel_ready_cb (TpChannel *channel,
267                   const GError *error,
268                   gpointer user_data)
269 {
270         EmpathyTpRoomlist *list = EMPATHY_TP_ROOMLIST (user_data);
271         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
272
273         if (error != NULL) {
274                 DEBUG ("Channel invalidated: %s", error->message);
275                 g_signal_emit (list, signals[DESTROY], 0);
276                 return;
277         }
278
279         g_signal_connect (priv->channel, "invalidated",
280                           G_CALLBACK (tp_roomlist_invalidated_cb),
281                           list);
282
283         tp_cli_channel_type_room_list_connect_to_listing_rooms (priv->channel,
284                                                                 tp_roomlist_listing_cb,
285                                                                 NULL, NULL,
286                                                                 G_OBJECT (list),
287                                                                 NULL);
288         tp_cli_channel_type_room_list_connect_to_got_rooms (priv->channel,
289                                                             tp_roomlist_got_rooms_cb,
290                                                             NULL, NULL,
291                                                             G_OBJECT (list),
292                                                             NULL);
293
294         tp_cli_channel_type_room_list_call_get_listing_rooms (priv->channel, -1,
295                                                               tp_roomlist_get_listing_rooms_cb,
296                                                               NULL, NULL,
297                                                               G_OBJECT (list));
298
299         if (priv->start_requested == TRUE) {
300                 tp_cli_channel_type_room_list_call_list_rooms (priv->channel, -1,
301                         call_list_rooms_cb, list, NULL, NULL);
302                 priv->start_requested = FALSE;
303         }
304 }
305
306 static void
307 tp_roomlist_request_channel_cb (TpConnection *connection,
308                                 const gchar  *object_path,
309                                 const GError *error,
310                                 gpointer      user_data,
311                                 GObject      *list)
312 {
313         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
314
315         if (error) {
316                 DEBUG ("Error requesting channel: %s", error->message);
317                 return;
318         }
319
320         priv->channel = tp_channel_new (priv->connection, object_path,
321                                         TP_IFACE_CHANNEL_TYPE_ROOM_LIST,
322                                         TP_HANDLE_TYPE_NONE,
323                                         0, NULL);
324         tp_channel_call_when_ready (priv->channel, channel_ready_cb, list);
325 }
326
327 static void
328 tp_roomlist_finalize (GObject *object)
329 {
330         EmpathyTpRoomlistPriv *priv = GET_PRIV (object);
331
332         if (priv->channel) {
333                 DEBUG ("Closing channel...");
334                 g_signal_handlers_disconnect_by_func (priv->channel,
335                                                       tp_roomlist_invalidated_cb,
336                                                       object);
337                 tp_cli_channel_call_close (priv->channel, -1,
338                                            NULL, NULL, NULL, NULL);
339                 g_object_unref (priv->channel);
340         }
341
342         if (priv->account) {
343                 g_object_unref (priv->account);
344         }
345         if (priv->connection) {
346                 g_object_unref (priv->connection);
347         }
348
349         G_OBJECT_CLASS (empathy_tp_roomlist_parent_class)->finalize (object);
350 }
351
352 static void
353 tp_roomlist_constructed (GObject *list)
354 {
355         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
356
357         priv->connection = empathy_account_get_connection (priv->account);
358         g_object_ref (priv->connection);
359
360         tp_cli_connection_call_request_channel (priv->connection, -1,
361                                                 TP_IFACE_CHANNEL_TYPE_ROOM_LIST,
362                                                 TP_HANDLE_TYPE_NONE,
363                                                 0,
364                                                 TRUE,
365                                                 tp_roomlist_request_channel_cb,
366                                                 NULL, NULL,
367                                                 list);
368 }
369
370 static void
371 tp_roomlist_get_property (GObject    *object,
372                           guint       param_id,
373                           GValue     *value,
374                           GParamSpec *pspec)
375 {
376         EmpathyTpRoomlistPriv *priv = GET_PRIV (object);
377
378         switch (param_id) {
379         case PROP_ACCOUNT:
380                 g_value_set_object (value, priv->account);
381                 break;
382         case PROP_IS_LISTING:
383                 g_value_set_boolean (value, priv->is_listing);
384                 break;
385         default:
386                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
387                 break;
388         };
389 }
390
391 static void
392 tp_roomlist_set_property (GObject      *object,
393                           guint         param_id,
394                           const GValue *value,
395                           GParamSpec   *pspec)
396 {
397         EmpathyTpRoomlistPriv *priv = GET_PRIV (object);
398
399         switch (param_id) {
400         case PROP_ACCOUNT:
401                 priv->account = g_value_dup_object (value);
402                 break;
403         default:
404                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
405                 break;
406         };
407 }
408
409 static void
410 empathy_tp_roomlist_class_init (EmpathyTpRoomlistClass *klass)
411 {
412         GObjectClass *object_class = G_OBJECT_CLASS (klass);
413
414         object_class->finalize = tp_roomlist_finalize;
415         object_class->constructed = tp_roomlist_constructed;
416         object_class->get_property = tp_roomlist_get_property;
417         object_class->set_property = tp_roomlist_set_property;
418
419         g_object_class_install_property (object_class,
420                                          PROP_ACCOUNT,
421                                          g_param_spec_object ("account",
422                                                               "The Account",
423                                                               "The account on which it lists rooms",
424                                                               EMPATHY_TYPE_ACCOUNT,
425                                                               G_PARAM_READWRITE |
426                                                               G_PARAM_CONSTRUCT_ONLY));
427         g_object_class_install_property (object_class,
428                                          PROP_IS_LISTING,
429                                          g_param_spec_boolean ("is-listing",
430                                                                "Is listing",
431                                                                "Are we listing rooms",
432                                                                FALSE,
433                                                                G_PARAM_READABLE));
434
435         signals[NEW_ROOM] =
436                 g_signal_new ("new-room",
437                               G_TYPE_FROM_CLASS (klass),
438                               G_SIGNAL_RUN_LAST,
439                               0,
440                               NULL, NULL,
441                               g_cclosure_marshal_VOID__OBJECT,
442                               G_TYPE_NONE,
443                               1, EMPATHY_TYPE_CHATROOM);
444
445         signals[DESTROY] =
446                 g_signal_new ("destroy",
447                               G_TYPE_FROM_CLASS (klass),
448                               G_SIGNAL_RUN_LAST,
449                               0,
450                               NULL, NULL,
451                               g_cclosure_marshal_VOID__VOID,
452                               G_TYPE_NONE,
453                               0);
454
455         signals[ERROR] =
456                 g_signal_new ("error",
457                               G_TYPE_FROM_CLASS (klass),
458                               G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
459                               0,
460                               NULL, NULL,
461                               g_cclosure_marshal_VOID__POINTER,
462                               G_TYPE_NONE,
463                               1, G_TYPE_POINTER);
464
465         g_type_class_add_private (object_class, sizeof (EmpathyTpRoomlistPriv));
466 }
467
468 static void
469 empathy_tp_roomlist_init (EmpathyTpRoomlist *list)
470 {
471         EmpathyTpRoomlistPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (list,
472                 EMPATHY_TYPE_TP_ROOMLIST, EmpathyTpRoomlistPriv);
473
474         list->priv = priv;
475         priv->start_requested = FALSE;
476         priv->is_listing = FALSE;
477 }
478
479 EmpathyTpRoomlist *
480 empathy_tp_roomlist_new (EmpathyAccount *account)
481 {
482         EmpathyTpRoomlist *list;
483
484         list = g_object_new (EMPATHY_TYPE_TP_ROOMLIST,
485                              "account", account,
486                              NULL);
487
488         return list;
489 }
490
491 gboolean
492 empathy_tp_roomlist_is_listing (EmpathyTpRoomlist *list)
493 {
494         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
495
496         g_return_val_if_fail (EMPATHY_IS_TP_ROOMLIST (list), FALSE);
497
498         return priv->is_listing;
499 }
500
501 void
502 empathy_tp_roomlist_start (EmpathyTpRoomlist *list)
503 {
504         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
505
506         g_return_if_fail (EMPATHY_IS_TP_ROOMLIST (list));
507         if (priv->channel != NULL) {
508                 tp_cli_channel_type_room_list_call_list_rooms (priv->channel, -1,
509                         call_list_rooms_cb, list, NULL, NULL);
510         } else {
511                 priv->start_requested = TRUE;
512         }
513 }
514
515 void
516 empathy_tp_roomlist_stop (EmpathyTpRoomlist *list)
517 {
518         EmpathyTpRoomlistPriv *priv = GET_PRIV (list);
519
520         g_return_if_fail (EMPATHY_IS_TP_ROOMLIST (list));
521
522         if (priv->channel == NULL)
523                 return;
524
525         g_return_if_fail (TP_IS_CHANNEL (priv->channel));
526
527         tp_cli_channel_type_room_list_call_stop_listing (priv->channel, -1,
528                                                          stop_listing_cb, list, NULL, NULL);
529 }
530