1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2  *
3  * Copyright (C) 2007 Novell, Inc.
4  * Copyright (C) 2008 Red Hat, Inc.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <config.h>
21 
22 #include <ctype.h>
23 #include <string.h>
24 #include <sys/wait.h>
25 #include <errno.h>
26 
27 #include <glib.h>
28 #include <gio/gio.h>
29 #include <gio/gdesktopappinfo.h>
30 
31 #define GNOME_DESKTOP_USE_UNSTABLE_API
32 #include <libgnome-desktop/gnome-systemd.h>
33 
34 #ifdef HAVE_SYSTEMD
35 #ifdef ENABLE_SYSTEMD_JOURNAL
36 #include <systemd/sd-journal.h>
37 #endif
38 #include <systemd/sd-daemon.h>
39 #endif
40 
41 #include "gsm-autostart-app.h"
42 #include "gsm-util.h"
43 
44 enum {
45         AUTOSTART_LAUNCH_SPAWN = 0,
46         AUTOSTART_LAUNCH_ACTIVATE
47 };
48 
49 enum {
50         GSM_CONDITION_NONE           = 0,
51         GSM_CONDITION_IF_EXISTS      = 1,
52         GSM_CONDITION_UNLESS_EXISTS  = 2,
53         GSM_CONDITION_GSETTINGS      = 3,
54         GSM_CONDITION_IF_SESSION     = 4,
55         GSM_CONDITION_UNLESS_SESSION = 5,
56         GSM_CONDITION_UNKNOWN        = 6
57 };
58 
59 #define GSM_SESSION_CLIENT_DBUS_INTERFACE "org.gnome.SessionClient"
60 
61 struct _GsmAutostartAppPrivate {
62         gboolean              mask_systemd;
63         char                 *desktop_filename;
64         char                 *desktop_id;
65         char                 *startup_id;
66 
67         GDesktopAppInfo      *app_info;
68         /* provides defined in session definition */
69         GSList               *session_provides;
70 
71         /* desktop file state */
72         char                 *condition_string;
73         gboolean              condition;
74         gboolean              autorestart;
75 
76         GFileMonitor         *condition_monitor;
77         guint                 condition_notify_id;
78         GSettings            *condition_settings;
79 
80         int                   launch_type;
81         GPid                  pid;
82         guint                 child_watch_id;
83 };
84 
85 enum {
86         CONDITION_CHANGED,
87         LAST_SIGNAL
88 };
89 
90 enum {
91         PROP_0,
92         PROP_DESKTOP_FILENAME,
93         PROP_MASK_SYSTEMD
94 };
95 
96 static guint signals[LAST_SIGNAL] = { 0 };
97 
98 #define GSM_AUTOSTART_APP_GET_PRIVATE(object) (G_TYPE_INSTANCE_GET_PRIVATE ((object), GSM_TYPE_AUTOSTART_APP, GsmAutostartAppPrivate))
99 
100 static void gsm_autostart_app_initable_iface_init (GInitableIface  *iface);
101 
G_DEFINE_TYPE_WITH_CODE(GsmAutostartApp,gsm_autostart_app,GSM_TYPE_APP,G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,gsm_autostart_app_initable_iface_init))102 G_DEFINE_TYPE_WITH_CODE (GsmAutostartApp, gsm_autostart_app, GSM_TYPE_APP,
103                          G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, gsm_autostart_app_initable_iface_init))
104 
105 static void
106 gsm_autostart_app_init (GsmAutostartApp *app)
107 {
108         app->priv = GSM_AUTOSTART_APP_GET_PRIVATE (app);
109 
110         app->priv->pid = -1;
111         app->priv->condition_monitor = NULL;
112         app->priv->condition = FALSE;
113 }
114 
115 static gboolean
is_disabled(GsmApp * app)116 is_disabled (GsmApp *app)
117 {
118         GsmAutostartAppPrivate *priv;
119 
120         priv = GSM_AUTOSTART_APP (app)->priv;
121 
122         /* GSM_AUTOSTART_APP_ENABLED_KEY key, used by old gnome-session */
123         if (g_desktop_app_info_has_key (priv->app_info,
124                                         GSM_AUTOSTART_APP_ENABLED_KEY) &&
125             !g_desktop_app_info_get_boolean (priv->app_info,
126                                              GSM_AUTOSTART_APP_ENABLED_KEY)) {
127                 g_debug ("app %s is disabled by " GSM_AUTOSTART_APP_ENABLED_KEY,
128                          gsm_app_peek_id (app));
129                 return TRUE;
130         }
131 
132         /* Hidden key, used by autostart spec */
133         if (g_desktop_app_info_get_is_hidden (priv->app_info)) {
134                 g_debug ("app %s is disabled by Hidden",
135                          gsm_app_peek_id (app));
136                 return TRUE;
137         }
138 
139         /* Check OnlyShowIn/NotShowIn/TryExec */
140         if (!g_desktop_app_info_get_show_in (priv->app_info, NULL)) {
141                 g_debug ("app %s is not for the current desktop",
142                          gsm_app_peek_id (app));
143                 return TRUE;
144         }
145 
146         /* Check if app is systemd enabled and mask-systemd is set. */
147         if (priv->mask_systemd &&
148             g_desktop_app_info_has_key (priv->app_info,
149                                         GSM_AUTOSTART_APP_SYSTEMD_KEY) &&
150             g_desktop_app_info_get_boolean (priv->app_info,
151                                             GSM_AUTOSTART_APP_SYSTEMD_KEY)) {
152                 g_debug ("app %s is disabled by " GSM_AUTOSTART_APP_SYSTEMD_KEY,
153                          gsm_app_peek_id (app));
154                 return TRUE;
155         }
156 
157         /* Do not check AutostartCondition - this method is only to determine
158          if the app is unconditionally disabled */
159 
160         return FALSE;
161 }
162 
163 static gboolean
parse_condition_string(const char * condition_string,guint * condition_kindp,char ** keyp)164 parse_condition_string (const char *condition_string,
165                         guint      *condition_kindp,
166                         char      **keyp)
167 {
168         const char *space;
169         const char *key;
170         int         len;
171         guint       kind;
172 
173         space = condition_string + strcspn (condition_string, " ");
174         len = space - condition_string;
175         key = space;
176         while (isspace ((unsigned char)*key)) {
177                 key++;
178         }
179 
180         kind = GSM_CONDITION_UNKNOWN;
181 
182         if (!g_ascii_strncasecmp (condition_string, "if-exists", len) && key) {
183                 kind = GSM_CONDITION_IF_EXISTS;
184         } else if (!g_ascii_strncasecmp (condition_string, "unless-exists", len) && key) {
185                 kind = GSM_CONDITION_UNLESS_EXISTS;
186         } else if (!g_ascii_strncasecmp (condition_string, "GSettings", len)) {
187                 kind = GSM_CONDITION_GSETTINGS;
188         } else if (!g_ascii_strncasecmp (condition_string, "GNOME3", len)) {
189                 condition_string = key;
190                 space = condition_string + strcspn (condition_string, " ");
191                 len = space - condition_string;
192                 key = space;
193                 while (isspace ((unsigned char)*key)) {
194                         key++;
195                 }
196                 if (!g_ascii_strncasecmp (condition_string, "if-session", len) && key) {
197                         kind = GSM_CONDITION_IF_SESSION;
198                 } else if (!g_ascii_strncasecmp (condition_string, "unless-session", len) && key) {
199                         kind = GSM_CONDITION_UNLESS_SESSION;
200                 }
201         }
202 
203         if (kind == GSM_CONDITION_UNKNOWN) {
204                 key = NULL;
205         }
206 
207         if (keyp != NULL) {
208                 *keyp = g_strdup (key);
209         }
210 
211         if (condition_kindp != NULL) {
212                 *condition_kindp = kind;
213         }
214 
215         return (kind != GSM_CONDITION_UNKNOWN);
216 }
217 
218 static void
if_exists_condition_cb(GFileMonitor * monitor,GFile * file,GFile * other_file,GFileMonitorEvent event,GsmApp * app)219 if_exists_condition_cb (GFileMonitor     *monitor,
220                         GFile            *file,
221                         GFile            *other_file,
222                         GFileMonitorEvent event,
223                         GsmApp           *app)
224 {
225         GsmAutostartAppPrivate *priv;
226         gboolean                condition = FALSE;
227 
228         priv = GSM_AUTOSTART_APP (app)->priv;
229 
230         switch (event) {
231         case G_FILE_MONITOR_EVENT_CREATED:
232                 condition = TRUE;
233                 break;
234         case G_FILE_MONITOR_EVENT_DELETED:
235                 condition = FALSE;
236                 break;
237         default:
238                 /* Ignore any other monitor event */
239                 return;
240         }
241 
242         /* Emit only if the condition actually changed */
243         if (condition != priv->condition) {
244                 priv->condition = condition;
245                 g_signal_emit (app, signals[CONDITION_CHANGED], 0, condition);
246         }
247 }
248 
249 static void
unless_exists_condition_cb(GFileMonitor * monitor,GFile * file,GFile * other_file,GFileMonitorEvent event,GsmApp * app)250 unless_exists_condition_cb (GFileMonitor     *monitor,
251                             GFile            *file,
252                             GFile            *other_file,
253                             GFileMonitorEvent event,
254                             GsmApp           *app)
255 {
256         GsmAutostartAppPrivate *priv;
257         gboolean                condition = FALSE;
258 
259         priv = GSM_AUTOSTART_APP (app)->priv;
260 
261         switch (event) {
262         case G_FILE_MONITOR_EVENT_CREATED:
263                 condition = FALSE;
264                 break;
265         case G_FILE_MONITOR_EVENT_DELETED:
266                 condition = TRUE;
267                 break;
268         default:
269                 /* Ignore any other monitor event */
270                 return;
271         }
272 
273         /* Emit only if the condition actually changed */
274         if (condition != priv->condition) {
275                 priv->condition = condition;
276                 g_signal_emit (app, signals[CONDITION_CHANGED], 0, condition);
277         }
278 }
279 
280 static void
gsettings_condition_cb(GSettings * settings,const char * key,gpointer user_data)281 gsettings_condition_cb (GSettings  *settings,
282                         const char *key,
283                         gpointer    user_data)
284 {
285         GsmApp                 *app;
286         GsmAutostartAppPrivate *priv;
287         gboolean                condition;
288 
289         g_return_if_fail (GSM_IS_APP (user_data));
290 
291         app = GSM_APP (user_data);
292 
293         priv = GSM_AUTOSTART_APP (app)->priv;
294 
295         condition = g_settings_get_boolean (settings, key);
296 
297         g_debug ("GsmAutostartApp: app:%s condition changed condition:%d",
298                  gsm_app_peek_id (app),
299                  condition);
300 
301         /* Emit only if the condition actually changed */
302         if (condition != priv->condition) {
303                 priv->condition = condition;
304                 g_signal_emit (app, signals[CONDITION_CHANGED], 0, condition);
305         }
306 }
307 
308 static gboolean
setup_gsettings_condition_monitor(GsmAutostartApp * app,const char * key)309 setup_gsettings_condition_monitor (GsmAutostartApp *app,
310                                    const char      *key)
311 {
312         GSettingsSchemaSource *source;
313         GSettingsSchema *schema;
314         GSettings *settings;
315         GSettingsSchemaKey *schema_key;
316         const GVariantType *key_type;
317         char **elems;
318         gboolean retval = FALSE;
319         char *signal;
320 
321         retval = FALSE;
322 
323         schema = NULL;
324 
325         elems = g_strsplit (key, " ", 2);
326 
327         if (elems == NULL)
328                 goto out;
329 
330         if (elems[0] == NULL || elems[1] == NULL)
331                 goto out;
332 
333         source = g_settings_schema_source_get_default ();
334 
335         schema = g_settings_schema_source_lookup (source, elems[0], TRUE);
336 
337         if (schema == NULL)
338                 goto out;
339 
340         if (!g_settings_schema_has_key (schema, elems[1]))
341                 goto out;
342 
343         schema_key = g_settings_schema_get_key (schema, elems[1]);
344 
345         g_assert (schema_key != NULL);
346 
347         key_type = g_settings_schema_key_get_value_type (schema_key);
348 
349         g_settings_schema_key_unref (schema_key);
350 
351         g_assert (key_type != NULL);
352 
353         if (!g_variant_type_equal (key_type, G_VARIANT_TYPE_BOOLEAN))
354                 goto out;
355 
356         settings = g_settings_new_full (schema, NULL, NULL);
357         retval = g_settings_get_boolean (settings, elems[1]);
358 
359         signal = g_strdup_printf ("changed::%s", elems[1]);
360         g_signal_connect (G_OBJECT (settings), signal,
361                           G_CALLBACK (gsettings_condition_cb), app);
362         g_free (signal);
363 
364         app->priv->condition_settings = settings;
365 
366 out:
367         if (schema)
368                 g_settings_schema_unref (schema);
369         g_strfreev (elems);
370 
371         return retval;
372 }
373 
374 static void
if_session_condition_cb(GObject * object,GParamSpec * pspec,gpointer user_data)375 if_session_condition_cb (GObject    *object,
376                          GParamSpec *pspec,
377                          gpointer    user_data)
378 {
379         GsmApp                 *app;
380         GsmAutostartAppPrivate *priv;
381         char                   *session_name;
382         char                   *key;
383         gboolean                condition;
384 
385         g_return_if_fail (GSM_IS_APP (user_data));
386 
387         app = GSM_APP (user_data);
388 
389         priv = GSM_AUTOSTART_APP (app)->priv;
390 
391         parse_condition_string (priv->condition_string, NULL, &key);
392 
393         g_object_get (object, "session-name", &session_name, NULL);
394         condition = strcmp (session_name, key) == 0;
395         g_free (session_name);
396 
397         g_free (key);
398 
399         g_debug ("GsmAutostartApp: app:%s condition changed condition:%d",
400                  gsm_app_peek_id (app),
401                  condition);
402 
403         /* Emit only if the condition actually changed */
404         if (condition != priv->condition) {
405                 priv->condition = condition;
406                 g_signal_emit (app, signals[CONDITION_CHANGED], 0, condition);
407         }
408 }
409 
410 static void
unless_session_condition_cb(GObject * object,GParamSpec * pspec,gpointer user_data)411 unless_session_condition_cb (GObject    *object,
412                              GParamSpec *pspec,
413                              gpointer    user_data)
414 {
415         GsmApp                 *app;
416         GsmAutostartAppPrivate *priv;
417         char                   *session_name;
418         char                   *key;
419         gboolean                condition;
420 
421         g_return_if_fail (GSM_IS_APP (user_data));
422 
423         app = GSM_APP (user_data);
424 
425         priv = GSM_AUTOSTART_APP (app)->priv;
426 
427         parse_condition_string (priv->condition_string, NULL, &key);
428 
429         g_object_get (object, "session-name", &session_name, NULL);
430         condition = strcmp (session_name, key) != 0;
431         g_free (session_name);
432 
433         g_free (key);
434 
435         g_debug ("GsmAutostartApp: app:%s condition changed condition:%d",
436                  gsm_app_peek_id (app),
437                  condition);
438 
439         /* Emit only if the condition actually changed */
440         if (condition != priv->condition) {
441                 priv->condition = condition;
442                 g_signal_emit (app, signals[CONDITION_CHANGED], 0, condition);
443         }
444 }
445 
446 static char *
resolve_conditional_file_path(const char * file)447 resolve_conditional_file_path (const char *file)
448 {
449         if (g_path_is_absolute (file))
450                 return g_strdup (file);
451         return g_build_filename (g_get_user_config_dir (), file, NULL);
452 }
453 
454 static void
setup_condition_monitor(GsmAutostartApp * app)455 setup_condition_monitor (GsmAutostartApp *app)
456 {
457         guint    kind;
458         char    *key;
459         gboolean res;
460         gboolean disabled;
461 
462         if (app->priv->condition_monitor != NULL) {
463                 g_file_monitor_cancel (app->priv->condition_monitor);
464         }
465 
466         if (app->priv->condition_string == NULL) {
467                 return;
468         }
469 
470         /* if it is disabled outright there is no point in monitoring */
471         if (is_disabled (GSM_APP (app))) {
472                 return;
473         }
474 
475         key = NULL;
476         res = parse_condition_string (app->priv->condition_string, &kind, &key);
477         if (! res) {
478                 g_free (key);
479                 return;
480         }
481 
482         if (key == NULL) {
483                 return;
484         }
485 
486         if (kind == GSM_CONDITION_IF_EXISTS) {
487                 char  *file_path;
488                 GFile *file;
489 
490                 file_path = resolve_conditional_file_path (key);
491                 disabled = !g_file_test (file_path, G_FILE_TEST_EXISTS);
492 
493                 file = g_file_new_for_path (file_path);
494                 app->priv->condition_monitor = g_file_monitor_file (file, 0, NULL, NULL);
495 
496                 g_signal_connect (app->priv->condition_monitor, "changed",
497                                   G_CALLBACK (if_exists_condition_cb),
498                                   app);
499 
500                 g_object_unref (file);
501                 g_free (file_path);
502         } else if (kind == GSM_CONDITION_UNLESS_EXISTS) {
503                 char  *file_path;
504                 GFile *file;
505 
506                 file_path = resolve_conditional_file_path (key);
507                 disabled = g_file_test (file_path, G_FILE_TEST_EXISTS);
508 
509                 file = g_file_new_for_path (file_path);
510                 app->priv->condition_monitor = g_file_monitor_file (file, 0, NULL, NULL);
511 
512                 g_signal_connect (app->priv->condition_monitor, "changed",
513                                   G_CALLBACK (unless_exists_condition_cb),
514                                   app);
515 
516                 g_object_unref (file);
517                 g_free (file_path);
518         } else if (kind == GSM_CONDITION_GSETTINGS) {
519                 disabled = !setup_gsettings_condition_monitor (app, key);
520         } else if (kind == GSM_CONDITION_IF_SESSION) {
521                 GsmManager *manager;
522                 char *session_name;
523 
524                 /* get the singleton */
525                 manager = gsm_manager_get ();
526 
527                 g_object_get (manager, "session-name", &session_name, NULL);
528                 disabled = strcmp (session_name, key) != 0;
529 
530                 g_signal_connect (manager, "notify::session-name",
531                                   G_CALLBACK (if_session_condition_cb), app);
532                 g_free (session_name);
533         } else if (kind == GSM_CONDITION_UNLESS_SESSION) {
534                 GsmManager *manager;
535                 char *session_name;
536 
537                 /* get the singleton */
538                 manager = gsm_manager_get ();
539 
540                 g_object_get (manager, "session-name", &session_name, NULL);
541                 disabled = strcmp (session_name, key) == 0;
542 
543                 g_signal_connect (manager, "notify::session-name",
544                                   G_CALLBACK (unless_session_condition_cb), app);
545                 g_free (session_name);
546         } else {
547                 disabled = TRUE;
548         }
549 
550         g_free (key);
551 
552         if (disabled) {
553                 /* FIXME: cache the disabled value? */
554         }
555 }
556 
557 static void
load_desktop_file(GsmAutostartApp * app)558 load_desktop_file (GsmAutostartApp  *app)
559 {
560         char    *dbus_name;
561         char    *startup_id;
562         char    *phase_str;
563         int      phase;
564         gboolean res;
565 
566         g_assert (app->priv->app_info != NULL);
567 
568         phase_str = g_desktop_app_info_get_string (app->priv->app_info,
569                                                    GSM_AUTOSTART_APP_PHASE_KEY);
570         if (phase_str != NULL) {
571                 if (strcmp (phase_str, "EarlyInitialization") == 0) {
572                         phase = GSM_MANAGER_PHASE_EARLY_INITIALIZATION;
573                 } else if (strcmp (phase_str, "PreDisplayServer") == 0) {
574                         phase = GSM_MANAGER_PHASE_PRE_DISPLAY_SERVER;
575                 } else if (strcmp (phase_str, "DisplayServer") == 0) {
576                         phase = GSM_MANAGER_PHASE_DISPLAY_SERVER;
577                 } else if (strcmp (phase_str, "Initialization") == 0) {
578                         phase = GSM_MANAGER_PHASE_INITIALIZATION;
579                 } else if (strcmp (phase_str, "WindowManager") == 0) {
580                         phase = GSM_MANAGER_PHASE_WINDOW_MANAGER;
581                 } else if (strcmp (phase_str, "Panel") == 0) {
582                         phase = GSM_MANAGER_PHASE_PANEL;
583                 } else if (strcmp (phase_str, "Desktop") == 0) {
584                         phase = GSM_MANAGER_PHASE_DESKTOP;
585                 } else {
586                         phase = GSM_MANAGER_PHASE_APPLICATION;
587                 }
588 
589                 g_free (phase_str);
590         } else {
591                 phase = GSM_MANAGER_PHASE_APPLICATION;
592         }
593 
594         dbus_name = g_desktop_app_info_get_string (app->priv->app_info,
595                                                    GSM_AUTOSTART_APP_DBUS_NAME_KEY);
596         if (dbus_name != NULL) {
597                 app->priv->launch_type = AUTOSTART_LAUNCH_ACTIVATE;
598         } else {
599                 app->priv->launch_type = AUTOSTART_LAUNCH_SPAWN;
600         }
601 
602         /* this must only be done on first load */
603         switch (app->priv->launch_type) {
604         case AUTOSTART_LAUNCH_SPAWN:
605                 startup_id =
606                         g_desktop_app_info_get_string (app->priv->app_info,
607                                                        GSM_AUTOSTART_APP_STARTUP_ID_KEY);
608 
609                 if (startup_id == NULL) {
610                         startup_id = gsm_util_generate_startup_id ();
611                 }
612                 break;
613         case AUTOSTART_LAUNCH_ACTIVATE:
614                 startup_id = g_strdup (dbus_name);
615                 break;
616         default:
617                 g_assert_not_reached ();
618         }
619 
620         res = g_desktop_app_info_has_key (app->priv->app_info,
621                                           GSM_AUTOSTART_APP_AUTORESTART_KEY);
622         if (res) {
623                 app->priv->autorestart = g_desktop_app_info_get_boolean (app->priv->app_info,
624                                                                          GSM_AUTOSTART_APP_AUTORESTART_KEY);
625         } else {
626                 app->priv->autorestart = FALSE;
627         }
628 
629         g_free (app->priv->condition_string);
630         app->priv->condition_string = g_desktop_app_info_get_string (app->priv->app_info,
631                                                                    "AutostartCondition");
632         setup_condition_monitor (app);
633 
634         g_object_set (app,
635                       "phase", phase,
636                       "startup-id", startup_id,
637                       NULL);
638 
639         g_free (startup_id);
640         g_free (dbus_name);
641 }
642 
643 static void
gsm_autostart_app_set_desktop_filename(GsmAutostartApp * app,const char * desktop_filename)644 gsm_autostart_app_set_desktop_filename (GsmAutostartApp *app,
645                                         const char      *desktop_filename)
646 {
647         if (app->priv->app_info != NULL) {
648                 g_clear_object (&app->priv->app_info);
649                 g_clear_pointer (&app->priv->desktop_filename, g_free);
650                 g_clear_pointer (&app->priv->desktop_id, g_free);
651         }
652 
653         if (desktop_filename == NULL) {
654                 return;
655         }
656 
657         app->priv->desktop_filename = g_strdup (desktop_filename);
658         app->priv->desktop_id = g_path_get_basename (desktop_filename);
659 }
660 
661 static void
gsm_autostart_app_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)662 gsm_autostart_app_set_property (GObject      *object,
663                                 guint         prop_id,
664                                 const GValue *value,
665                                 GParamSpec   *pspec)
666 {
667         GsmAutostartApp *self;
668 
669         self = GSM_AUTOSTART_APP (object);
670 
671         switch (prop_id) {
672         case PROP_DESKTOP_FILENAME:
673                 gsm_autostart_app_set_desktop_filename (self, g_value_get_string (value));
674                 break;
675         case PROP_MASK_SYSTEMD:
676                 self->priv->mask_systemd = g_value_get_boolean (value);
677                 break;
678         default:
679                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
680                 break;
681         }
682 }
683 
684 static void
gsm_autostart_app_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)685 gsm_autostart_app_get_property (GObject    *object,
686                                 guint       prop_id,
687                                 GValue     *value,
688                                 GParamSpec *pspec)
689 {
690         GsmAutostartApp *self;
691 
692         self = GSM_AUTOSTART_APP (object);
693 
694         switch (prop_id) {
695         case PROP_DESKTOP_FILENAME:
696                 if (self->priv->app_info != NULL) {
697                         g_value_set_string (value, g_desktop_app_info_get_filename (self->priv->app_info));
698                 } else {
699                         g_value_set_string (value, NULL);
700                 }
701                 break;
702         case PROP_MASK_SYSTEMD:
703                 g_value_set_boolean (value, self->priv->mask_systemd);
704                 break;
705         default:
706                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
707                 break;
708         }
709 }
710 
711 static void
gsm_autostart_app_dispose(GObject * object)712 gsm_autostart_app_dispose (GObject *object)
713 {
714         GsmAutostartAppPrivate *priv;
715 
716         priv = GSM_AUTOSTART_APP (object)->priv;
717 
718         g_clear_pointer (&priv->startup_id, g_free);
719 
720         if (priv->session_provides) {
721                 g_slist_free_full (priv->session_provides, g_free);
722                 priv->session_provides = NULL;
723         }
724 
725         g_clear_pointer (&priv->condition_string, g_free);
726         g_clear_object (&priv->condition_settings);
727         g_clear_object (&priv->app_info);
728         g_clear_pointer (&priv->desktop_filename, g_free);
729         g_clear_pointer (&priv->desktop_id, g_free);
730 
731         if (priv->child_watch_id > 0) {
732                 g_source_remove (priv->child_watch_id);
733                 priv->child_watch_id = 0;
734         }
735 
736         if (priv->condition_monitor) {
737                 g_file_monitor_cancel (priv->condition_monitor);
738         }
739 
740         G_OBJECT_CLASS (gsm_autostart_app_parent_class)->dispose (object);
741 }
742 
743 static gboolean
is_running(GsmApp * app)744 is_running (GsmApp *app)
745 {
746         GsmAutostartAppPrivate *priv;
747         gboolean                is;
748 
749         priv = GSM_AUTOSTART_APP (app)->priv;
750 
751         /* is running if pid is still valid or
752          * or a client is connected
753          */
754         /* FIXME: check client */
755         is = (priv->pid != -1);
756 
757         return is;
758 }
759 
760 static gboolean
is_conditionally_disabled(GsmApp * app)761 is_conditionally_disabled (GsmApp *app)
762 {
763         GsmAutostartAppPrivate *priv;
764         gboolean                res;
765         gboolean                disabled;
766         char                   *key;
767         guint                   kind;
768 
769         priv = GSM_AUTOSTART_APP (app)->priv;
770 
771         /* Check AutostartCondition */
772         if (priv->condition_string == NULL) {
773                 return FALSE;
774         }
775 
776         key = NULL;
777         res = parse_condition_string (priv->condition_string, &kind, &key);
778         if (! res) {
779                 g_free (key);
780                 return TRUE;
781         }
782 
783         if (key == NULL) {
784                 return TRUE;
785         }
786 
787         if (kind == GSM_CONDITION_IF_EXISTS) {
788                 char *file_path;
789 
790                 file_path = resolve_conditional_file_path (key);
791                 disabled = !g_file_test (file_path, G_FILE_TEST_EXISTS);
792                 g_free (file_path);
793         } else if (kind == GSM_CONDITION_UNLESS_EXISTS) {
794                 char *file_path;
795 
796                 file_path = resolve_conditional_file_path (key);
797                 disabled = g_file_test (file_path, G_FILE_TEST_EXISTS);
798                 g_free (file_path);
799         } else if (kind == GSM_CONDITION_GSETTINGS &&
800                    priv->condition_settings != NULL) {
801                 char **elems;
802                 elems = g_strsplit (key, " ", 2);
803                 disabled = !g_settings_get_boolean (priv->condition_settings, elems[1]);
804                 g_strfreev (elems);
805         } else if (kind == GSM_CONDITION_IF_SESSION) {
806                 GsmManager *manager;
807                 char *session_name;
808 
809                 /* get the singleton */
810                 manager = gsm_manager_get ();
811 
812                 g_object_get (manager, "session-name", &session_name, NULL);
813                 disabled = strcmp (session_name, key) != 0;
814                 g_free (session_name);
815         } else if (kind == GSM_CONDITION_UNLESS_SESSION) {
816                 GsmManager *manager;
817                 char *session_name;
818 
819                 /* get the singleton */
820                 manager = gsm_manager_get ();
821 
822                 g_object_get (manager, "session-name", &session_name, NULL);
823                 disabled = strcmp (session_name, key) == 0;
824                 g_free (session_name);
825         } else {
826                 disabled = TRUE;
827         }
828 
829         /* Set initial condition */
830         priv->condition = !disabled;
831 
832         g_free (key);
833 
834         return disabled;
835 }
836 
837 static void
app_exited(GPid pid,int status,GsmAutostartApp * app)838 app_exited (GPid             pid,
839             int              status,
840             GsmAutostartApp *app)
841 {
842         g_debug ("GsmAutostartApp: (pid:%d) done (%s:%d)",
843                  (int) pid,
844                  WIFEXITED (status) ? "status"
845                  : WIFSIGNALED (status) ? "signal"
846                  : "unknown",
847                  WIFEXITED (status) ? WEXITSTATUS (status)
848                  : WIFSIGNALED (status) ? WTERMSIG (status)
849                  : -1);
850 
851         g_spawn_close_pid (app->priv->pid);
852         app->priv->pid = -1;
853         app->priv->child_watch_id = 0;
854 
855         if (WIFEXITED (status)) {
856                 gsm_app_exited (GSM_APP (app), WEXITSTATUS (status));
857         } else if (WIFSIGNALED (status)) {
858                 gsm_app_died (GSM_APP (app), WTERMSIG (status));
859         }
860 }
861 
862 static int
_signal_pid(int pid,int signal)863 _signal_pid (int pid,
864              int signal)
865 {
866         int status;
867 
868         /* perhaps block sigchld */
869         g_debug ("GsmAutostartApp: sending signal %d to process %d", signal, pid);
870         errno = 0;
871         status = kill (pid, signal);
872 
873         if (status < 0) {
874                 if (errno == ESRCH) {
875                         g_warning ("Child process %d was already dead.",
876                                    (int)pid);
877                 } else {
878                         g_warning ("Couldn't kill child process %d: %s",
879                                    pid,
880                                    g_strerror (errno));
881                 }
882         }
883 
884         /* perhaps unblock sigchld */
885 
886         return status;
887 }
888 
889 static gboolean
autostart_app_stop_spawn(GsmAutostartApp * app,GError ** error)890 autostart_app_stop_spawn (GsmAutostartApp *app,
891                           GError         **error)
892 {
893         int res;
894 
895         if (app->priv->pid < 1) {
896                 g_set_error (error,
897                              GSM_APP_ERROR,
898                              GSM_APP_ERROR_STOP,
899                              "Not running");
900                 return FALSE;
901         }
902 
903         res = _signal_pid (app->priv->pid, SIGTERM);
904         if (res != 0) {
905                 g_set_error (error,
906                              GSM_APP_ERROR,
907                              GSM_APP_ERROR_STOP,
908                              "Unable to stop: %s",
909                              g_strerror (errno));
910                 return FALSE;
911         }
912 
913         return TRUE;
914 }
915 
916 static gboolean
autostart_app_stop_activate(GsmAutostartApp * app,GError ** error)917 autostart_app_stop_activate (GsmAutostartApp *app,
918                              GError         **error)
919 {
920         return TRUE;
921 }
922 
923 static gboolean
gsm_autostart_app_stop(GsmApp * app,GError ** error)924 gsm_autostart_app_stop (GsmApp  *app,
925                         GError **error)
926 {
927         GsmAutostartApp *aapp;
928         gboolean         ret;
929 
930         aapp = GSM_AUTOSTART_APP (app);
931 
932         g_return_val_if_fail (aapp->priv->app_info != NULL, FALSE);
933 
934         switch (aapp->priv->launch_type) {
935         case AUTOSTART_LAUNCH_SPAWN:
936                 ret = autostart_app_stop_spawn (aapp, error);
937                 break;
938         case AUTOSTART_LAUNCH_ACTIVATE:
939                 ret = autostart_app_stop_activate (aapp, error);
940                 break;
941         default:
942                 g_assert_not_reached ();
943                 break;
944         }
945 
946         return ret;
947 }
948 
949 static void
app_launched(GAppLaunchContext * ctx,GAppInfo * appinfo,GVariant * platform_data,gpointer data)950 app_launched (GAppLaunchContext *ctx,
951               GAppInfo    *appinfo,
952               GVariant    *platform_data,
953               gpointer     data)
954 {
955         GsmAutostartApp *app = data;
956         gint pid;
957         gchar *sn_id;
958 
959         pid = 0;
960         sn_id = NULL;
961 
962         g_variant_lookup (platform_data, "pid", "i", &pid);
963         g_variant_lookup (platform_data, "startup-notification-id", "s", &sn_id);
964         app->priv->pid = pid;
965         app->priv->startup_id = sn_id;
966 
967         /* We are not interested in the result. */
968         gnome_start_systemd_scope (app->priv->desktop_id,
969                                    pid,
970                                    NULL,
971                                    NULL,
972                                    NULL, NULL, NULL);
973 }
974 
975 #ifdef ENABLE_SYSTEMD_JOURNAL
976 static void
on_child_setup(GsmAutostartApp * app)977 on_child_setup (GsmAutostartApp *app)
978 {
979         int standard_output, standard_error;
980 
981         /* The FALSE means programs aren't expected to prefix each
982          * line with <n> prefix to specify priority.
983          */
984         standard_output = sd_journal_stream_fd (app->priv->desktop_id,
985                                                 LOG_INFO,
986                                                 FALSE);
987         standard_error = sd_journal_stream_fd (app->priv->desktop_id,
988                                                LOG_WARNING,
989                                                FALSE);
990 
991         if (standard_output >= 0) {
992                 dup2 (standard_output, STDOUT_FILENO);
993                 close (standard_output);
994         }
995 
996         if (standard_error >= 0) {
997                 dup2 (standard_error, STDERR_FILENO);
998                 close (standard_error);
999         }
1000 }
1001 #endif
1002 
1003 static gboolean
autostart_app_start_spawn(GsmAutostartApp * app,GError ** error)1004 autostart_app_start_spawn (GsmAutostartApp *app,
1005                            GError         **error)
1006 {
1007         gboolean         success;
1008         GError          *local_error;
1009         const char      *startup_id;
1010         const char * const *variable_blacklist;
1011         const char * const *child_environment;
1012         int i;
1013         GAppLaunchContext *ctx;
1014         GSpawnChildSetupFunc child_setup_func = NULL;
1015         gpointer             child_setup_data = NULL;
1016         guint handler;
1017 
1018         startup_id = gsm_app_peek_startup_id (GSM_APP (app));
1019         g_assert (startup_id != NULL);
1020 
1021         g_debug ("GsmAutostartApp: starting %s: command=%s startup-id=%s", app->priv->desktop_id, g_app_info_get_commandline (G_APP_INFO (app->priv->app_info)), startup_id);
1022 
1023         g_free (app->priv->startup_id);
1024         local_error = NULL;
1025         ctx = g_app_launch_context_new ();
1026 
1027         variable_blacklist = gsm_util_get_variable_blacklist ();
1028         for (i = 0; variable_blacklist[i] != NULL; i++)
1029                 g_app_launch_context_unsetenv (ctx, variable_blacklist[i]);
1030 
1031         child_environment = gsm_util_listenv ();
1032         for (i = 0; child_environment[i] != NULL; i++) {
1033                 char **environment_tuple;
1034                 const char *key;
1035                 const char *value;
1036 
1037                 environment_tuple = g_strsplit (child_environment[i], "=", 2);
1038                 key = environment_tuple[0];
1039                 value = environment_tuple[1];
1040 
1041                 if (value != NULL)
1042                         g_app_launch_context_setenv (ctx, key, value);
1043 
1044                 g_strfreev (environment_tuple);
1045         }
1046 
1047         if (startup_id != NULL) {
1048                 g_app_launch_context_setenv (ctx, "DESKTOP_AUTOSTART_ID", startup_id);
1049         }
1050 
1051 #ifdef ENABLE_SYSTEMD_JOURNAL
1052         if (sd_booted () > 0) {
1053                 child_setup_func = (GSpawnChildSetupFunc) on_child_setup;
1054                 child_setup_data = app;
1055         }
1056 #endif
1057 
1058         handler = g_signal_connect (ctx, "launched", G_CALLBACK (app_launched), app);
1059         success = g_desktop_app_info_launch_uris_as_manager (app->priv->app_info,
1060                                                              NULL,
1061                                                              ctx,
1062                                                              G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH,
1063                                                              child_setup_func, child_setup_data,
1064                                                              NULL, NULL,
1065                                                              &local_error);
1066         g_signal_handler_disconnect (ctx, handler);
1067 
1068         if (success) {
1069                 if (app->priv->pid > 0) {
1070                         g_debug ("GsmAutostartApp: started pid:%d", app->priv->pid);
1071                         app->priv->child_watch_id = g_child_watch_add (app->priv->pid,
1072                                                                        (GChildWatchFunc)app_exited,
1073                                                                        app);
1074                 }
1075         } else {
1076                 g_set_error (error,
1077                              GSM_APP_ERROR,
1078                              GSM_APP_ERROR_START,
1079                              "Unable to start application: %s", local_error->message);
1080                 g_error_free (local_error);
1081         }
1082 
1083         return success;
1084 }
1085 
1086 static void
start_notify(GObject * source,GAsyncResult * result,gpointer user_data)1087 start_notify (GObject      *source,
1088               GAsyncResult *result,
1089               gpointer      user_data)
1090 {
1091         GError          *error;
1092         GsmAutostartApp *app;
1093 
1094         app  = user_data;
1095         error = NULL;
1096 
1097         g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), result, &error);
1098 
1099         if (error != NULL) {
1100                 g_warning ("GsmAutostartApp: Error starting application: %s", error->message);
1101                 g_error_free (error);
1102         } else {
1103                 g_debug ("GsmAutostartApp: Started application %s", app->priv->desktop_id);
1104         }
1105 }
1106 
1107 static gboolean
autostart_app_start_activate(GsmAutostartApp * app,GError ** error)1108 autostart_app_start_activate (GsmAutostartApp  *app,
1109                               GError          **error)
1110 {
1111         const char      *name;
1112         char            *path;
1113         char            *arguments;
1114         GDBusConnection *bus;
1115         GError          *local_error;
1116 
1117         local_error = NULL;
1118         bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &local_error);
1119         if (local_error != NULL) {
1120                 g_warning ("error getting session bus: %s", local_error->message);
1121                 g_propagate_error (error, local_error);
1122                 return FALSE;
1123         }
1124 
1125         name = gsm_app_peek_startup_id (GSM_APP (app));
1126         g_assert (name != NULL);
1127 
1128         path = g_desktop_app_info_get_string (app->priv->app_info,
1129                                               GSM_AUTOSTART_APP_DBUS_PATH_KEY);
1130         if (path == NULL) {
1131                 /* just pick one? */
1132                 path = g_strdup ("/");
1133         }
1134 
1135         arguments = g_desktop_app_info_get_string (app->priv->app_info,
1136                                                    GSM_AUTOSTART_APP_DBUS_ARGS_KEY);
1137 
1138         g_dbus_connection_call (bus,
1139                                 name,
1140                                 path,
1141                                 GSM_SESSION_CLIENT_DBUS_INTERFACE,
1142                                 "Start",
1143                                 g_variant_new ("(s)", arguments),
1144                                 NULL,
1145                                 G_DBUS_CALL_FLAGS_NONE,
1146                                 -1, NULL,
1147                                 start_notify, app);
1148         g_object_unref (bus);
1149 
1150         return TRUE;
1151 }
1152 
1153 static gboolean
gsm_autostart_app_start(GsmApp * app,GError ** error)1154 gsm_autostart_app_start (GsmApp  *app,
1155                          GError **error)
1156 {
1157         GsmAutostartApp *aapp;
1158         gboolean         ret;
1159 
1160         aapp = GSM_AUTOSTART_APP (app);
1161 
1162         g_return_val_if_fail (aapp->priv->app_info != NULL, FALSE);
1163 
1164         switch (aapp->priv->launch_type) {
1165         case AUTOSTART_LAUNCH_SPAWN:
1166                 ret = autostart_app_start_spawn (aapp, error);
1167                 break;
1168         case AUTOSTART_LAUNCH_ACTIVATE:
1169                 ret = autostart_app_start_activate (aapp, error);
1170                 break;
1171         default:
1172                 g_assert_not_reached ();
1173                 break;
1174         }
1175 
1176         return ret;
1177 }
1178 
1179 static gboolean
gsm_autostart_app_restart(GsmApp * app,GError ** error)1180 gsm_autostart_app_restart (GsmApp  *app,
1181                            GError **error)
1182 {
1183         GError  *local_error;
1184         gboolean res;
1185 
1186         /* ignore stop errors - it is fine if it is already stopped */
1187         local_error = NULL;
1188         res = gsm_app_stop (app, &local_error);
1189         if (! res) {
1190                 g_debug ("GsmAutostartApp: Couldn't stop app: %s", local_error->message);
1191                 g_error_free (local_error);
1192         }
1193 
1194         res = gsm_app_start (app, &local_error);
1195         if (! res) {
1196                 g_propagate_error (error, local_error);
1197                 return FALSE;
1198         }
1199 
1200         return TRUE;
1201 }
1202 
1203 static gboolean
gsm_autostart_app_provides(GsmApp * app,const char * service)1204 gsm_autostart_app_provides (GsmApp     *app,
1205                             const char *service)
1206 {
1207         gchar           *provides_str;
1208         char           **provides;
1209         gsize            i;
1210         GSList          *l;
1211         GsmAutostartApp *aapp;
1212 
1213         g_return_val_if_fail (GSM_IS_APP (app), FALSE);
1214 
1215         aapp = GSM_AUTOSTART_APP (app);
1216 
1217         if (aapp->priv->app_info == NULL) {
1218                 return FALSE;
1219         }
1220 
1221         for (l = aapp->priv->session_provides; l != NULL; l = l->next) {
1222                 if (!strcmp (l->data, service))
1223                         return TRUE;
1224         }
1225 
1226         provides_str = g_desktop_app_info_get_string (aapp->priv->app_info,
1227                                                       GSM_AUTOSTART_APP_PROVIDES_KEY);
1228         if (!provides_str) {
1229                 return FALSE;
1230         }
1231         provides = g_strsplit (provides_str, ";", -1);
1232         g_free (provides_str);
1233 
1234         for (i = 0; provides[i]; i++) {
1235                 if (!strcmp (provides[i], service)) {
1236                         g_strfreev (provides);
1237                         return TRUE;
1238                 }
1239         }
1240 
1241         g_strfreev (provides);
1242 
1243         return FALSE;
1244 }
1245 
1246 static char **
gsm_autostart_app_get_provides(GsmApp * app)1247 gsm_autostart_app_get_provides (GsmApp *app)
1248 {
1249         GsmAutostartApp  *aapp;
1250         gchar            *provides_str;
1251         char            **provides;
1252         gsize             provides_len;
1253         char            **result;
1254         gsize             result_len;
1255         int               i;
1256         GSList           *l;
1257 
1258         g_return_val_if_fail (GSM_IS_APP (app), NULL);
1259 
1260         aapp = GSM_AUTOSTART_APP (app);
1261 
1262         if (aapp->priv->app_info == NULL) {
1263                 return NULL;
1264         }
1265 
1266         provides_str = g_desktop_app_info_get_string (aapp->priv->app_info,
1267                                                       GSM_AUTOSTART_APP_PROVIDES_KEY);
1268 
1269         if (provides_str == NULL) {
1270                 return NULL;
1271         }
1272 
1273         provides = g_strsplit (provides_str, ";", -1);
1274         provides_len = g_strv_length (provides);
1275         g_free (provides_str);
1276 
1277         if (!aapp->priv->session_provides) {
1278                 return provides;
1279         }
1280 
1281         result_len = provides_len + g_slist_length (aapp->priv->session_provides);
1282         result = g_new (char *, result_len + 1); /* including last NULL */
1283 
1284         for (i = 0; provides[i] != NULL; i++)
1285                 result[i] = provides[i];
1286         g_free (provides);
1287 
1288         for (l = aapp->priv->session_provides; l != NULL; l = l->next, i++)
1289                 result[i] = g_strdup (l->data);
1290 
1291         result[i] = NULL;
1292 
1293         g_assert (i == result_len);
1294 
1295         return result;
1296 }
1297 
1298 void
gsm_autostart_app_add_provides(GsmAutostartApp * aapp,const char * provides)1299 gsm_autostart_app_add_provides (GsmAutostartApp *aapp,
1300                                 const char      *provides)
1301 {
1302         g_return_if_fail (GSM_IS_AUTOSTART_APP (aapp));
1303 
1304         aapp->priv->session_provides = g_slist_prepend (aapp->priv->session_provides,
1305                                                         g_strdup (provides));
1306 }
1307 
1308 static gboolean
gsm_autostart_app_has_autostart_condition(GsmApp * app,const char * condition)1309 gsm_autostart_app_has_autostart_condition (GsmApp     *app,
1310                                            const char *condition)
1311 {
1312         GsmAutostartApp *aapp;
1313 
1314         g_return_val_if_fail (GSM_IS_APP (app), FALSE);
1315         g_return_val_if_fail (condition != NULL, FALSE);
1316 
1317         aapp = GSM_AUTOSTART_APP (app);
1318 
1319         if (aapp->priv->condition_string == NULL) {
1320                 return FALSE;
1321         }
1322 
1323         if (strcmp (aapp->priv->condition_string, condition) == 0) {
1324                 return TRUE;
1325         }
1326 
1327         return FALSE;
1328 }
1329 
1330 static gboolean
gsm_autostart_app_get_autorestart(GsmApp * app)1331 gsm_autostart_app_get_autorestart (GsmApp *app)
1332 {
1333         gboolean res;
1334         gboolean autorestart;
1335 
1336         if (GSM_AUTOSTART_APP (app)->priv->app_info == NULL) {
1337                 return FALSE;
1338         }
1339 
1340         autorestart = FALSE;
1341 
1342         res = g_desktop_app_info_has_key (GSM_AUTOSTART_APP (app)->priv->app_info,
1343                                           GSM_AUTOSTART_APP_AUTORESTART_KEY);
1344         if (res) {
1345                 autorestart = g_desktop_app_info_get_boolean (GSM_AUTOSTART_APP (app)->priv->app_info,
1346                                                               GSM_AUTOSTART_APP_AUTORESTART_KEY);
1347         }
1348 
1349         return autorestart;
1350 }
1351 
1352 static const char *
gsm_autostart_app_get_app_id(GsmApp * app)1353 gsm_autostart_app_get_app_id (GsmApp *app)
1354 {
1355         if (GSM_AUTOSTART_APP (app)->priv->app_info == NULL) {
1356                 return NULL;
1357         }
1358 
1359         return g_app_info_get_id (G_APP_INFO (GSM_AUTOSTART_APP (app)->priv->app_info));
1360 }
1361 
1362 static gboolean
gsm_autostart_app_initable_init(GInitable * initable,GCancellable * cancellable,GError ** error)1363 gsm_autostart_app_initable_init (GInitable *initable,
1364                                  GCancellable *cancellable,
1365                                  GError  **error)
1366 {
1367         GsmAutostartApp *app = GSM_AUTOSTART_APP (initable);
1368 
1369         g_assert (app->priv->desktop_filename != NULL);
1370         app->priv->app_info = g_desktop_app_info_new_from_filename (app->priv->desktop_filename);
1371         if (app->priv->app_info == NULL) {
1372                 g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
1373                              "Could not parse desktop file %s or it references a not found TryExec binary", app->priv->desktop_id);
1374                 return FALSE;
1375         }
1376 
1377         load_desktop_file (app);
1378 
1379         return TRUE;
1380 }
1381 
1382 static gboolean
gsm_autostart_app_save_to_keyfile(GsmApp * base_app,GKeyFile * keyfile,GError ** error)1383 gsm_autostart_app_save_to_keyfile (GsmApp    *base_app,
1384                                    GKeyFile  *keyfile,
1385                                    GError   **error)
1386 {
1387         GsmAutostartApp *app = GSM_AUTOSTART_APP (base_app);
1388         char   **provides = NULL;
1389         char    *dbus_name;
1390         char    *phase;
1391         gboolean res;
1392 
1393         provides = gsm_app_get_provides (base_app);
1394         if (provides != NULL) {
1395                 g_key_file_set_string_list (keyfile,
1396                                             G_KEY_FILE_DESKTOP_GROUP,
1397                                             GSM_AUTOSTART_APP_PROVIDES_KEY,
1398                                             (const char * const *)
1399                                             provides,
1400                                             g_strv_length (provides));
1401                 g_strfreev (provides);
1402         }
1403 
1404         phase = g_desktop_app_info_get_string (app->priv->app_info,
1405                                                    GSM_AUTOSTART_APP_PHASE_KEY);
1406         if (phase != NULL) {
1407                 g_key_file_set_string (keyfile,
1408                                        G_KEY_FILE_DESKTOP_GROUP,
1409                                        GSM_AUTOSTART_APP_PHASE_KEY,
1410                                        phase);
1411                 g_free (phase);
1412         }
1413 
1414         dbus_name = g_desktop_app_info_get_string (app->priv->app_info,
1415                                                    GSM_AUTOSTART_APP_DBUS_NAME_KEY);
1416         if (dbus_name != NULL) {
1417                 g_key_file_set_string (keyfile,
1418                                        G_KEY_FILE_DESKTOP_GROUP,
1419                                        GSM_AUTOSTART_APP_DBUS_NAME_KEY,
1420                                        dbus_name);
1421                 g_free (dbus_name);
1422         }
1423 
1424         res = g_desktop_app_info_has_key (app->priv->app_info,
1425                                           GSM_AUTOSTART_APP_AUTORESTART_KEY);
1426         if (res) {
1427                 g_key_file_set_boolean (keyfile,
1428                                         G_KEY_FILE_DESKTOP_GROUP,
1429                                         GSM_AUTOSTART_APP_AUTORESTART_KEY,
1430                                         g_desktop_app_info_get_boolean (app->priv->app_info,
1431                                                                         GSM_AUTOSTART_APP_AUTORESTART_KEY));
1432         }
1433 
1434         res = g_desktop_app_info_has_key (app->priv->app_info,
1435                                           GSM_AUTOSTART_APP_AUTORESTART_KEY);
1436         if (res) {
1437                 char *autostart_condition;
1438 
1439                 autostart_condition = g_desktop_app_info_get_string (app->priv->app_info, "AutostartCondition");
1440 
1441                 g_key_file_set_string (keyfile,
1442                                        G_KEY_FILE_DESKTOP_GROUP,
1443                                        "AutostartCondition",
1444                                        autostart_condition);
1445                 g_free (autostart_condition);
1446         }
1447 
1448         return TRUE;
1449 }
1450 
1451 static void
gsm_autostart_app_initable_iface_init(GInitableIface * iface)1452 gsm_autostart_app_initable_iface_init (GInitableIface  *iface)
1453 {
1454         iface->init = gsm_autostart_app_initable_init;
1455 }
1456 
1457 static void
gsm_autostart_app_class_init(GsmAutostartAppClass * klass)1458 gsm_autostart_app_class_init (GsmAutostartAppClass *klass)
1459 {
1460         GObjectClass *object_class = G_OBJECT_CLASS (klass);
1461         GsmAppClass  *app_class = GSM_APP_CLASS (klass);
1462 
1463         object_class->set_property = gsm_autostart_app_set_property;
1464         object_class->get_property = gsm_autostart_app_get_property;
1465         object_class->dispose = gsm_autostart_app_dispose;
1466 
1467         app_class->impl_is_disabled = is_disabled;
1468         app_class->impl_is_conditionally_disabled = is_conditionally_disabled;
1469         app_class->impl_is_running = is_running;
1470         app_class->impl_start = gsm_autostart_app_start;
1471         app_class->impl_restart = gsm_autostart_app_restart;
1472         app_class->impl_stop = gsm_autostart_app_stop;
1473         app_class->impl_provides = gsm_autostart_app_provides;
1474         app_class->impl_get_provides = gsm_autostart_app_get_provides;
1475         app_class->impl_has_autostart_condition = gsm_autostart_app_has_autostart_condition;
1476         app_class->impl_get_app_id = gsm_autostart_app_get_app_id;
1477         app_class->impl_get_autorestart = gsm_autostart_app_get_autorestart;
1478         app_class->impl_save_to_keyfile = gsm_autostart_app_save_to_keyfile;
1479 
1480         g_object_class_install_property (object_class,
1481                                          PROP_DESKTOP_FILENAME,
1482                                          g_param_spec_string ("desktop-filename",
1483                                                               "Desktop filename",
1484                                                               "Freedesktop .desktop file",
1485                                                               NULL,
1486                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
1487         g_object_class_install_property (object_class,
1488                                          PROP_MASK_SYSTEMD,
1489                                          g_param_spec_boolean ("mask-systemd",
1490                                                                "Mask if systemd started",
1491                                                                "Mask if GNOME systemd flag is set in desktop file",
1492                                                                FALSE,
1493                                                                G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
1494         signals[CONDITION_CHANGED] =
1495                 g_signal_new ("condition-changed",
1496                               G_OBJECT_CLASS_TYPE (object_class),
1497                               G_SIGNAL_RUN_LAST,
1498                               G_STRUCT_OFFSET (GsmAutostartAppClass, condition_changed),
1499                               NULL, NULL, NULL,
1500                               G_TYPE_NONE,
1501                               1,
1502                               G_TYPE_BOOLEAN);
1503 
1504         g_type_class_add_private (object_class, sizeof (GsmAutostartAppPrivate));
1505 }
1506 
1507 GsmApp *
gsm_autostart_app_new(const char * desktop_file,gboolean mask_systemd,GError ** error)1508 gsm_autostart_app_new (const char *desktop_file,
1509                        gboolean    mask_systemd,
1510                        GError    **error)
1511 {
1512         return (GsmApp*) g_initable_new (GSM_TYPE_AUTOSTART_APP, NULL, error,
1513                                          "desktop-filename", desktop_file,
1514                                          "mask-systemd", mask_systemd,
1515                                          NULL);
1516 }
1517