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-master
29 * @title: McdMaster
30 * @short_description: Server master class
31 * @see_also:
32 * @stability: Unstable
33 * @include: mcd-master.h
34 *
35 * This class implements actual mission-control. It keeps track of
36 * individual account presence and connection states in a McdPresenceFrame
37 * member object, which is available as a property.
38 *
39 * The McdPresenceFrame object could be easily utilized for
40 * any presence releated events and actions, either within this class or
41 * any other class subclassing it or using it.
42 *
43 * It is basically a container for all McdManager objects and
44 * takes care of their management. It also takes care of sleep and awake
45 * cycles (e.g. translates to auto away somewhere down the hierarchy).
46 */
47
48 #include <config.h>
49
50 #ifdef HAVE_SYS_STAT_H
51 #include <sys/stat.h>
52 #endif
53 #ifdef HAVE_SYS_TYPES_H
54 #include <sys/types.h>
55 #endif
56
57 #include <gmodule.h>
58 #include <string.h>
59 #include <dbus/dbus.h>
60 #include <dbus/dbus-glib.h>
61 #include <dbus/dbus-glib-lowlevel.h>
62 #include <telepathy-glib/telepathy-glib.h>
63
64 #ifdef G_OS_WIN32
65 #include <io.h>
66 #endif
67
68 #include "mcd-master.h"
69 #include "mcd-master-priv.h"
70 #include "mcd-manager.h"
71 #include "mcd-dispatcher.h"
72 #include "mcd-account-manager.h"
73 #include "mcd-account-manager-priv.h"
74 #include "mcd-account-conditions.h"
75 #include "mcd-account-priv.h"
76 #include "plugin-loader.h"
77
78 #ifdef G_OS_UNIX
79 # ifndef HAVE_UMASK
80 # error On Unix, MC relies on umask() for account privacy
81 # endif
82 #endif
83
84 G_DEFINE_TYPE (McdMaster, mcd_master, MCD_TYPE_OPERATION);
85
86 struct _McdMasterPrivate
87 {
88 McdAccountManager *account_manager;
89 McdDispatcher *dispatcher;
90
91 /* We create these for our member objects */
92 TpDBusDaemon *dbus_daemon;
93 TpSimpleClientFactory *client_factory;
94
95 /* Current pending sleep timer */
96 gint shutdown_timeout_id;
97
98 gboolean is_disposed;
99 gboolean low_memory;
100 gboolean idle;
101 };
102
103 enum
104 {
105 PROP_0,
106 PROP_PRESENCE_FRAME,
107 PROP_DBUS_CONNECTION,
108 PROP_DBUS_DAEMON,
109 PROP_DISPATCHER,
110 PROP_ACCOUNT_MANAGER,
111 };
112
113 /* Used to poison 'default_master' when the object it points to is disposed.
114 * The default_master should basically be alive for the duration of the MC run.
115 */
116 #define POISONED_MASTER ((McdMaster *) 0xdeadbeef)
117 static McdMaster *default_master = NULL;
118
119 static void
_mcd_master_get_property(GObject * obj,guint prop_id,GValue * val,GParamSpec * pspec)120 _mcd_master_get_property (GObject * obj, guint prop_id,
121 GValue * val, GParamSpec * pspec)
122 {
123 McdMasterPrivate *priv = MCD_MASTER (obj)->priv;
124
125 switch (prop_id)
126 {
127 case PROP_DISPATCHER:
128 g_value_set_object (val, priv->dispatcher);
129 break;
130 case PROP_DBUS_DAEMON:
131 g_value_set_object (val, priv->dbus_daemon);
132 break;
133 case PROP_DBUS_CONNECTION:
134 g_value_set_pointer (val, tp_proxy_get_dbus_connection (
135 TP_PROXY (priv->dbus_daemon)));
136 break;
137 case PROP_ACCOUNT_MANAGER:
138 g_value_set_object (val, priv->account_manager);
139 break;
140 default:
141 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
142 break;
143 }
144 }
145
146 static void
_mcd_master_set_property(GObject * obj,guint prop_id,const GValue * val,GParamSpec * pspec)147 _mcd_master_set_property (GObject *obj, guint prop_id,
148 const GValue *val, GParamSpec *pspec)
149 {
150 McdMasterPrivate *priv = MCD_MASTER (obj)->priv;
151
152 switch (prop_id)
153 {
154 case PROP_DBUS_DAEMON:
155 g_assert (priv->dbus_daemon == NULL);
156 priv->dbus_daemon = g_value_dup_object (val);
157 break;
158 default:
159 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, prop_id, pspec);
160 break;
161 }
162 }
163
164 static void
_mcd_master_dispose(GObject * object)165 _mcd_master_dispose (GObject * object)
166 {
167 McdMasterPrivate *priv = MCD_MASTER (object)->priv;
168
169 if (priv->is_disposed)
170 {
171 return;
172 }
173 priv->is_disposed = TRUE;
174
175 tp_clear_object (&priv->account_manager);
176 tp_clear_object (&priv->dbus_daemon);
177 tp_clear_object (&priv->dispatcher);
178 tp_clear_object (&priv->client_factory);
179
180 if (default_master == (McdMaster *) object)
181 {
182 default_master = POISONED_MASTER;
183 }
184
185 G_OBJECT_CLASS (mcd_master_parent_class)->dispose (object);
186 }
187
188 static GObject *
mcd_master_constructor(GType type,guint n_params,GObjectConstructParam * params)189 mcd_master_constructor (GType type, guint n_params,
190 GObjectConstructParam *params)
191 {
192 GObjectClass *object_class = (GObjectClass *)mcd_master_parent_class;
193 McdMaster *master;
194 McdMasterPrivate *priv;
195
196 master = MCD_MASTER (object_class->constructor (type, n_params, params));
197 priv = master->priv;
198
199 g_return_val_if_fail (master != NULL, NULL);
200
201 #ifdef HAVE_UMASK
202 /* mask out group and other rwx bits when creating files */
203 umask (0077);
204 #endif
205
206 priv->client_factory = tp_simple_client_factory_new (priv->dbus_daemon);
207 priv->account_manager = mcd_account_manager_new (priv->client_factory);
208
209 priv->dispatcher = mcd_dispatcher_new (priv->dbus_daemon, master);
210 g_assert (MCD_IS_DISPATCHER (priv->dispatcher));
211
212 _mcd_account_manager_setup (priv->account_manager);
213
214 dbus_connection_set_exit_on_disconnect (
215 dbus_g_connection_get_connection (
216 tp_proxy_get_dbus_connection (TP_PROXY (priv->dbus_daemon))),
217 TRUE);
218
219 return (GObject *) master;
220 }
221
222 static void
mcd_master_class_init(McdMasterClass * klass)223 mcd_master_class_init (McdMasterClass * klass)
224 {
225 GObjectClass *object_class = G_OBJECT_CLASS (klass);
226 g_type_class_add_private (object_class, sizeof (McdMasterPrivate));
227
228 object_class->constructor = mcd_master_constructor;
229 object_class->get_property = _mcd_master_get_property;
230 object_class->set_property = _mcd_master_set_property;
231 object_class->dispose = _mcd_master_dispose;
232
233 /* Properties */
234 g_object_class_install_property
235 (object_class, PROP_DISPATCHER,
236 g_param_spec_object ("dispatcher",
237 "Dispatcher",
238 "Dispatcher",
239 MCD_TYPE_DISPATCHER,
240 G_PARAM_READABLE));
241
242 g_object_class_install_property
243 (object_class, PROP_DBUS_DAEMON,
244 g_param_spec_object ("dbus-daemon", "DBus daemon", "DBus daemon",
245 TP_TYPE_DBUS_DAEMON,
246 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
247
248 g_object_class_install_property
249 (object_class, PROP_DBUS_CONNECTION,
250 g_param_spec_pointer ("dbus-connection",
251 "D-Bus Connection",
252 "D-Bus Connection",
253 G_PARAM_READABLE));
254
255 g_object_class_install_property
256 (object_class, PROP_ACCOUNT_MANAGER,
257 g_param_spec_object ("account-manager",
258 "AccountManager", "AccountManager",
259 MCD_TYPE_ACCOUNT_MANAGER,
260 G_PARAM_READABLE));
261 }
262
263 static void
mcd_master_init(McdMaster * master)264 mcd_master_init (McdMaster * master)
265 {
266 master->priv = G_TYPE_INSTANCE_GET_PRIVATE (master,
267 MCD_TYPE_MASTER, McdMasterPrivate);
268
269 if (!default_master)
270 default_master = master;
271
272 /* This newer plugin API is currently always enabled */
273 /* .... and is enabled before anything else as potentially *
274 * any mcd component could have a new-API style plugin */
275 _mcd_plugin_loader_init ();
276 }
277
278 McdMaster *
mcd_master_get_default(void)279 mcd_master_get_default (void)
280 {
281 if (!default_master)
282 default_master = MCD_MASTER (g_object_new (MCD_TYPE_MASTER, NULL));
283
284 g_return_val_if_fail (default_master != POISONED_MASTER, NULL);
285
286 return default_master;
287 }
288
289 /*
290 * _mcd_master_lookup_manager:
291 * @master: the #McdMaster.
292 * @unique_name: the name of the manager.
293 *
294 * Gets the manager whose name is @unique_name. If the manager object doesn't
295 * exists yet, it is created.
296 *
297 * Returns: a #McdManager. Caller must call g_object_ref() on it to ensure it
298 * will stay alive as long as needed.
299 */
300 McdManager *
_mcd_master_lookup_manager(McdMaster * master,const gchar * unique_name)301 _mcd_master_lookup_manager (McdMaster *master,
302 const gchar *unique_name)
303 {
304 const GList *managers, *list;
305 McdManager *manager;
306
307 managers = mcd_operation_get_missions (MCD_OPERATION (master));
308 for (list = managers; list; list = list->next)
309 {
310 manager = MCD_MANAGER (list->data);
311 if (strcmp (unique_name,
312 mcd_manager_get_name (manager)) == 0)
313 return manager;
314 }
315
316 manager = mcd_manager_new (unique_name,
317 master->priv->dispatcher,
318 master->priv->client_factory);
319 if (G_UNLIKELY (!manager))
320 g_warning ("Manager %s not created", unique_name);
321 else
322 mcd_operation_take_mission (MCD_OPERATION (master),
323 MCD_MISSION (manager));
324
325 return manager;
326 }
327
328 /**
329 * mcd_master_get_dbus_daemon:
330 * @master: the #McdMaster.
331 *
332 * Returns: the #TpDBusDaemon.
333 */
334 TpDBusDaemon *
mcd_master_get_dbus_daemon(McdMaster * master)335 mcd_master_get_dbus_daemon (McdMaster *master)
336 {
337 g_return_val_if_fail (MCD_IS_MASTER (master), NULL);
338 return master->priv->dbus_daemon;
339 }
340
341 /* Milliseconds to wait for Connectivity coming back up before exiting MC */
342 #define EXIT_COUNTDOWN_TIME 5000
343
344 static gboolean
_mcd_master_exit_by_timeout(gpointer data)345 _mcd_master_exit_by_timeout (gpointer data)
346 {
347 McdMaster *self = MCD_MASTER (data);
348
349 self->priv->shutdown_timeout_id = 0;
350
351 /* Notify sucide */
352 mcd_mission_abort (MCD_MISSION (self));
353 return FALSE;
354 }
355
356 void
mcd_master_shutdown(McdMaster * self,const gchar * reason)357 mcd_master_shutdown (McdMaster *self,
358 const gchar *reason)
359 {
360 McdMasterPrivate *priv;
361
362 g_return_if_fail (MCD_IS_MASTER (self));
363 priv = self->priv;
364
365 if(!priv->shutdown_timeout_id)
366 {
367 DEBUG ("MC will bail out because of \"%s\" out exit after %i",
368 reason ? reason : "No reason specified",
369 EXIT_COUNTDOWN_TIME);
370
371 priv->shutdown_timeout_id = g_timeout_add (EXIT_COUNTDOWN_TIME,
372 _mcd_master_exit_by_timeout,
373 self);
374 }
375 else
376 {
377 DEBUG ("Already shutting down. This one has the reason %s",
378 reason ? reason : "No reason specified");
379 }
380 mcd_debug_print_tree (self);
381 }
382