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