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