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