1 /* vi: set et sw=4 ts=8 cino=t0,(0: */
2 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4; tab-width: 8 -*- */
3 /*
4 * This file is part of mission-control
5 *
6 * Copyright (C) 2007-2009 Nokia Corporation.
7 * Copyright (C) 2009 Collabora Ltd.
8 *
9 * Contact: Naba Kumar <naba.kumar@nokia.com>
10 *
11 * This library is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License
13 * version 2.1 as published by the Free Software Foundation.
14 *
15 * This library is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
23 * 02110-1301 USA
24 *
25 */
26
27 /**
28 * SECTION:mcd-manager
29 * @title: McdManager
30 * @short_description: Manager class representing Telepathy connection manager
31 * @see_also:
32 * @stability: Unstable
33 * @include: mcd-manager.h
34 *
35 * FIXME
36 */
37
38 #include "config.h"
39 #include "mcd-manager.h"
40 #include "mcd-manager-priv.h"
41 #include "mcd-misc.h"
42 #include "mcd-slacker.h"
43
44 #include <stdio.h>
45 #include <string.h>
46
47 #include <telepathy-glib/telepathy-glib.h>
48
49 #include "mcd-connection.h"
50
51 #define MANAGER_SUFFIX ".manager"
52
53 #define MCD_MANAGER_PRIV(manager) (MCD_MANAGER (manager)->priv)
54
55 G_DEFINE_TYPE (McdManager, mcd_manager, MCD_TYPE_OPERATION);
56
57 struct _McdManagerPrivate
58 {
59 gchar *name;
60 TpDBusDaemon *dbus_daemon;
61 TpSimpleClientFactory *client_factory;
62 McdDispatcher *dispatcher;
63
64 TpConnectionManager *tp_conn_mgr;
65
66 McdSlacker *slacker;
67
68 guint is_disposed : 1;
69 guint ready : 1;
70 };
71
72 enum
73 {
74 PROP_0,
75 PROP_NAME,
76 PROP_DISPATCHER,
77 PROP_CLIENT_FACTORY
78 };
79
80 static GQuark readiness_quark = 0;
81
82 static void
on_manager_ready(GObject * source_object,GAsyncResult * result,gpointer user_data)83 on_manager_ready (GObject *source_object,
84 GAsyncResult *result, gpointer user_data)
85 {
86 TpConnectionManager *tp_conn_mgr = TP_CONNECTION_MANAGER (source_object);
87 McdManager *manager = MCD_MANAGER (user_data);
88 McdManagerPrivate *priv;
89 GError *error = NULL;
90
91 tp_proxy_prepare_finish (tp_conn_mgr, result, &error);
92
93 priv = manager->priv;
94 DEBUG ("manager %s is ready", priv->name);
95 priv->ready = TRUE;
96 _mcd_object_ready (manager, readiness_quark, error);
97 g_clear_error (&error);
98 }
99
100 static void
_mcd_manager_finalize(GObject * object)101 _mcd_manager_finalize (GObject * object)
102 {
103 McdManagerPrivate *priv = MCD_MANAGER_PRIV (object);
104
105 g_free (priv->name);
106
107 G_OBJECT_CLASS (mcd_manager_parent_class)->finalize (object);
108 }
109
110 static void
_mcd_manager_dispose(GObject * object)111 _mcd_manager_dispose (GObject * object)
112 {
113 McdManagerPrivate *priv;
114
115 priv = MCD_MANAGER_PRIV (object);
116
117 if (priv->is_disposed)
118 {
119 return;
120 }
121
122 priv->is_disposed = TRUE;
123
124 tp_clear_object (&priv->dispatcher);
125 tp_clear_object (&priv->tp_conn_mgr);
126 tp_clear_object (&priv->client_factory);
127 tp_clear_object (&priv->dbus_daemon);
128 tp_clear_object (&priv->slacker);
129
130 G_OBJECT_CLASS (mcd_manager_parent_class)->dispose (object);
131 }
132
133 static void
_mcd_manager_connect(McdMission * mission)134 _mcd_manager_connect (McdMission * mission)
135 {
136 MCD_MISSION_CLASS (mcd_manager_parent_class)->connect (mission);
137 }
138
139 static void
_mcd_manager_disconnect(McdMission * mission)140 _mcd_manager_disconnect (McdMission * mission)
141 {
142 GList *connections;
143
144 DEBUG ("%p", mission);
145 MCD_MISSION_CLASS (mcd_manager_parent_class)->disconnect (mission);
146
147 /* We now call mcd_mission_abort() on all child connections; but since this
148 * could modify the list of the children, we cannot just use
149 * mcd_operation_foreach(). Instead, make a copy of the list and work on
150 * that. */
151 DEBUG("manager tree before abort:");
152 mcd_debug_print_tree(mission);
153 connections = g_list_copy ((GList *)mcd_operation_get_missions
154 (MCD_OPERATION (mission)));
155 g_list_foreach (connections, (GFunc) mcd_mission_abort, NULL);
156 g_list_free (connections);
157 DEBUG("manager tree after abort:");
158 mcd_debug_print_tree(mission);
159 }
160
161 static gboolean
mcd_manager_setup(McdManager * manager)162 mcd_manager_setup (McdManager *manager)
163 {
164 McdManagerPrivate *priv = manager->priv;
165 GError *error = NULL;
166
167 priv->slacker = mcd_slacker_new ();
168
169 priv->tp_conn_mgr =
170 tp_connection_manager_new (priv->dbus_daemon, priv->name,
171 NULL, &error);
172 if (error)
173 {
174 g_warning ("%s, cannot create manager %s: %s", G_STRFUNC,
175 priv->name, error->message);
176 goto error;
177 }
178
179 tp_proxy_prepare_async (priv->tp_conn_mgr, NULL, on_manager_ready, manager);
180
181 DEBUG ("Manager %s created", priv->name);
182 return TRUE;
183
184 error:
185 tp_clear_object (&priv->tp_conn_mgr);
186 g_clear_error (&error);
187
188 return FALSE;
189 }
190
191 static GObject *
_mcd_manager_constructor(GType type,guint n_params,GObjectConstructParam * params)192 _mcd_manager_constructor (GType type, guint n_params,
193 GObjectConstructParam *params)
194 {
195 GObjectClass *object_class = (GObjectClass *)mcd_manager_parent_class;
196 McdManager *manager;
197
198 manager = MCD_MANAGER (object_class->constructor (type, n_params, params));
199
200 g_return_val_if_fail (manager != NULL, NULL);
201
202 if (!mcd_manager_setup (manager))
203 {
204 g_object_unref (manager);
205 return NULL;
206 }
207
208 return (GObject *) manager;
209 }
210
211 static void
_mcd_manager_set_property(GObject * obj,guint prop_id,const GValue * val,GParamSpec * pspec)212 _mcd_manager_set_property (GObject * obj, guint prop_id,
213 const GValue * val, GParamSpec * pspec)
214 {
215 McdManagerPrivate *priv = MCD_MANAGER_PRIV (obj);
216 McdDispatcher *dispatcher;
217
218 switch (prop_id)
219 {
220 case PROP_NAME:
221 g_assert (priv->name == NULL);
222 priv->name = g_value_dup_string (val);
223 break;
224 case PROP_DISPATCHER:
225 dispatcher = g_value_get_object (val);
226 if (dispatcher)
227 {
228 g_return_if_fail (MCD_IS_DISPATCHER (dispatcher));
229 g_object_ref (dispatcher);
230 }
231 tp_clear_object (&priv->dispatcher);
232 priv->dispatcher = dispatcher;
233 break;
234
235 case PROP_CLIENT_FACTORY:
236 g_assert (priv->client_factory == NULL); /* construct-only */
237 priv->client_factory = g_value_dup_object (val);
238 priv->dbus_daemon = g_object_ref (
239 tp_simple_client_factory_get_dbus_daemon (priv->client_factory));
240 break;
241
242 default:
243 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
244 break;
245 }
246 }
247
248 static void
_mcd_manager_get_property(GObject * obj,guint prop_id,GValue * val,GParamSpec * pspec)249 _mcd_manager_get_property (GObject * obj, guint prop_id,
250 GValue * val, GParamSpec * pspec)
251 {
252 McdManagerPrivate *priv = MCD_MANAGER_PRIV (obj);
253
254 switch (prop_id)
255 {
256 case PROP_DISPATCHER:
257 g_value_set_object (val, priv->dispatcher);
258 break;
259 default:
260 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
261 break;
262 }
263 }
264
265 static void
mcd_manager_class_init(McdManagerClass * klass)266 mcd_manager_class_init (McdManagerClass * klass)
267 {
268 GObjectClass *object_class = G_OBJECT_CLASS (klass);
269 McdMissionClass *mission_class = MCD_MISSION_CLASS (klass);
270
271 g_type_class_add_private (object_class, sizeof (McdManagerPrivate));
272
273 object_class->constructor = _mcd_manager_constructor;
274 object_class->finalize = _mcd_manager_finalize;
275 object_class->dispose = _mcd_manager_dispose;
276 object_class->set_property = _mcd_manager_set_property;
277 object_class->get_property = _mcd_manager_get_property;
278
279 mission_class->connect = _mcd_manager_connect;
280 mission_class->disconnect = _mcd_manager_disconnect;
281
282 /* Properties */
283 g_object_class_install_property
284 (object_class, PROP_NAME,
285 g_param_spec_string ("name", "Name", "Name",
286 NULL,
287 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
288 g_object_class_install_property
289 (object_class, PROP_DISPATCHER,
290 g_param_spec_object ("dispatcher",
291 "Dispatcher",
292 "Dispatcher",
293 MCD_TYPE_DISPATCHER,
294 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
295
296 g_object_class_install_property (object_class, PROP_CLIENT_FACTORY,
297 g_param_spec_object ("client-factory", "Client factory",
298 "Client factory", TP_TYPE_SIMPLE_CLIENT_FACTORY,
299 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
300
301 readiness_quark = g_quark_from_static_string ("mcd_manager_got_info");
302 }
303
304 static void
mcd_manager_init(McdManager * manager)305 mcd_manager_init (McdManager *manager)
306 {
307 McdManagerPrivate *priv;
308
309 priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, MCD_TYPE_MANAGER,
310 McdManagerPrivate);
311 manager->priv = priv;
312 }
313
314 /* Public methods */
315
316 McdManager *
mcd_manager_new(const gchar * unique_name,McdDispatcher * dispatcher,TpSimpleClientFactory * client_factory)317 mcd_manager_new (const gchar *unique_name,
318 McdDispatcher *dispatcher,
319 TpSimpleClientFactory *client_factory)
320 {
321 McdManager *obj;
322 obj = MCD_MANAGER (g_object_new (MCD_TYPE_MANAGER,
323 "name", unique_name,
324 "dispatcher", dispatcher,
325 "client-factory", client_factory,
326 NULL));
327 return obj;
328 }
329
330 /**
331 * mcd_manager_get_unique_name:
332 * @manager: the #McdManager.
333 *
334 * Gets the unique name of the @manager.
335 *
336 * Returns: a const string with the unique name.
337 */
338 const gchar *
mcd_manager_get_name(McdManager * manager)339 mcd_manager_get_name (McdManager *manager)
340 {
341 McdManagerPrivate *priv = MCD_MANAGER_PRIV (manager);
342 return priv->name;
343 }
344
345 TpProtocol *
_mcd_manager_dup_protocol(McdManager * manager,const gchar * protocol)346 _mcd_manager_dup_protocol (McdManager *manager,
347 const gchar *protocol)
348 {
349 TpProtocol *p;
350 g_return_val_if_fail (MCD_IS_MANAGER (manager), NULL);
351 g_return_val_if_fail (protocol != NULL, NULL);
352
353 p = tp_connection_manager_get_protocol_object (manager->priv->tp_conn_mgr,
354 protocol);
355
356 if (p == NULL)
357 return NULL;
358 else
359 return g_object_ref (p);
360 }
361
362 const TpConnectionManagerParam *
mcd_manager_get_protocol_param(McdManager * manager,const gchar * protocol,const gchar * param)363 mcd_manager_get_protocol_param (McdManager *manager, const gchar *protocol,
364 const gchar *param)
365 {
366 McdManagerPrivate *priv;
367 TpProtocol *cm_protocol;
368
369 g_return_val_if_fail (MCD_IS_MANAGER (manager), NULL);
370 g_return_val_if_fail (protocol != NULL, NULL);
371 g_return_val_if_fail (param != NULL, NULL);
372
373 priv = manager->priv;
374
375 cm_protocol = tp_connection_manager_get_protocol_object (priv->tp_conn_mgr,
376 protocol);
377
378 if (cm_protocol == NULL)
379 return NULL;
380
381 return tp_protocol_get_param (cm_protocol, param);
382 }
383
384 McdConnection *
mcd_manager_create_connection(McdManager * manager,McdAccount * account)385 mcd_manager_create_connection (McdManager *manager, McdAccount *account)
386 {
387 McdConnection *connection;
388
389 g_return_val_if_fail (MCD_IS_MANAGER (manager), NULL);
390 g_return_val_if_fail (manager->priv->tp_conn_mgr != NULL, NULL);
391
392 connection = g_object_new (MCD_TYPE_CONNECTION,
393 "client-factory", manager->priv->client_factory,
394 "tp-manager", manager->priv->tp_conn_mgr,
395 "dispatcher", manager->priv->dispatcher,
396 "account", account,
397 "slacker", manager->priv->slacker,
398 NULL);
399
400 mcd_operation_take_mission (MCD_OPERATION (manager),
401 MCD_MISSION (connection));
402 DEBUG ("Created a connection %p for account: %s",
403 connection, mcd_account_get_unique_name (account));
404
405 return connection;
406 }
407
408 /**
409 * mcd_manager_get_tp_proxy:
410 * @manager: the #McdManager.
411 *
412 * Returns: the #TpConnectionManager proxy, or %NULL.
413 */
414 TpConnectionManager *
mcd_manager_get_tp_proxy(McdManager * manager)415 mcd_manager_get_tp_proxy (McdManager *manager)
416 {
417 g_return_val_if_fail (MCD_IS_MANAGER (manager), NULL);
418 return manager->priv->tp_conn_mgr;
419 }
420
421 /**
422 * mcd_manager_call_when_ready:
423 * @manager: the #McdManager.
424 * @callbacks: the #McdManagerReadyCb to invoke.
425 * @user_data: user data to be passed to the callback.
426 *
427 * Invoke @callback when @manager is ready, i.e. when its introspection has
428 * completed and all the manager protocols and parameter descriptions are
429 * available.
430 */
431 void
mcd_manager_call_when_ready(McdManager * manager,McdManagerReadyCb callback,gpointer user_data)432 mcd_manager_call_when_ready (McdManager *manager, McdManagerReadyCb callback,
433 gpointer user_data)
434 {
435 g_return_if_fail (MCD_IS_MANAGER (manager));
436 g_return_if_fail (callback != NULL);
437
438 if (manager->priv->ready)
439 callback (manager, NULL, user_data);
440 else
441 _mcd_object_call_when_ready (manager, readiness_quark,
442 (McdReadyCb)callback, user_data);
443 }
444
445