1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2  *
3  * Copyright (C) 2008 Red Hat, Inc.
4  * Copyright (C) 2012-2021 MATE Developers
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, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19  * 02110-1301, USA.
20  */
21 
22 #include "config.h"
23 
24 #include <fcntl.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <time.h>
28 #include <unistd.h>
29 
30 #include <dbus/dbus-glib.h>
31 
32 #include "gsm-inhibitor.h"
33 #include "gsm-inhibitor-glue.h"
34 #include "gsm-util.h"
35 
36 static guint32 inhibitor_serial = 1;
37 
38 struct _GsmInhibitor
39 {
40         GObject parent;
41         char *id;
42         char *bus_name;
43         char *app_id;
44         char *client_id;
45         char *reason;
46         guint flags;
47         guint toplevel_xid;
48         guint cookie;
49         DBusGConnection *connection;
50 };
51 
52 enum {
53         PROP_0,
54         PROP_BUS_NAME,
55         PROP_REASON,
56         PROP_APP_ID,
57         PROP_CLIENT_ID,
58         PROP_FLAGS,
59         PROP_TOPLEVEL_XID,
60         PROP_COOKIE
61 };
62 
G_DEFINE_TYPE(GsmInhibitor,gsm_inhibitor,G_TYPE_OBJECT)63 G_DEFINE_TYPE (GsmInhibitor, gsm_inhibitor, G_TYPE_OBJECT)
64 
65 GQuark
66 gsm_inhibitor_error_quark (void)
67 {
68         static GQuark ret = 0;
69         if (ret == 0) {
70                 ret = g_quark_from_static_string ("gsm_inhibitor_error");
71         }
72 
73         return ret;
74 }
75 
76 #define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
77 
78 GType
gsm_inhibitor_error_get_type(void)79 gsm_inhibitor_error_get_type (void)
80 {
81         static GType etype = 0;
82 
83         if (etype == 0) {
84                 static const GEnumValue values[] = {
85                         ENUM_ENTRY (GSM_INHIBITOR_ERROR_GENERAL, "GeneralError"),
86                         ENUM_ENTRY (GSM_INHIBITOR_ERROR_NOT_SET, "NotSet"),
87                         { 0, 0, 0 }
88                 };
89 
90                 g_assert (GSM_INHIBITOR_NUM_ERRORS == G_N_ELEMENTS (values) - 1);
91 
92                 etype = g_enum_register_static ("GsmInhibitorError", values);
93         }
94 
95         return etype;
96 }
97 
98 static guint32
get_next_inhibitor_serial(void)99 get_next_inhibitor_serial (void)
100 {
101         guint32 serial;
102 
103         serial = inhibitor_serial++;
104 
105         if ((gint32)inhibitor_serial < 0) {
106                 inhibitor_serial = 1;
107         }
108 
109         return serial;
110 }
111 
112 static gboolean
register_inhibitor(GsmInhibitor * inhibitor)113 register_inhibitor (GsmInhibitor *inhibitor)
114 {
115         GError *error;
116 
117         error = NULL;
118         inhibitor->connection = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
119         if (inhibitor->connection == NULL) {
120                 if (error != NULL) {
121                         g_critical ("error getting session bus: %s", error->message);
122                         g_error_free (error);
123                 }
124                 return FALSE;
125         }
126 
127         dbus_g_connection_register_g_object (inhibitor->connection, inhibitor->id, G_OBJECT (inhibitor));
128 
129         return TRUE;
130 }
131 
132 static GObject *
gsm_inhibitor_constructor(GType type,guint n_construct_properties,GObjectConstructParam * construct_properties)133 gsm_inhibitor_constructor (GType                  type,
134                            guint                  n_construct_properties,
135                            GObjectConstructParam *construct_properties)
136 {
137         GsmInhibitor *inhibitor;
138         gboolean      res;
139 
140         inhibitor = GSM_INHIBITOR (G_OBJECT_CLASS (gsm_inhibitor_parent_class)->constructor (type,
141                                                                                              n_construct_properties,
142                                                                                              construct_properties));
143 
144         g_free (inhibitor->id);
145         inhibitor->id = g_strdup_printf ("/org/gnome/SessionManager/Inhibitor%u", get_next_inhibitor_serial ());
146         res = register_inhibitor (inhibitor);
147         if (! res) {
148                 g_warning ("Unable to register inhibitor with session bus");
149         }
150 
151         return G_OBJECT (inhibitor);
152 }
153 
154 static void
gsm_inhibitor_init(GsmInhibitor * inhibitor)155 gsm_inhibitor_init (GsmInhibitor *inhibitor)
156 {
157 }
158 
159 static void
gsm_inhibitor_set_bus_name(GsmInhibitor * inhibitor,const char * bus_name)160 gsm_inhibitor_set_bus_name (GsmInhibitor  *inhibitor,
161                             const char    *bus_name)
162 {
163         g_return_if_fail (GSM_IS_INHIBITOR (inhibitor));
164 
165         g_free (inhibitor->bus_name);
166 
167         if (bus_name != NULL) {
168                 inhibitor->bus_name = g_strdup (bus_name);
169         } else {
170                 inhibitor->bus_name = g_strdup ("");
171         }
172         g_object_notify (G_OBJECT (inhibitor), "bus-name");
173 }
174 
175 static void
gsm_inhibitor_set_app_id(GsmInhibitor * inhibitor,const char * app_id)176 gsm_inhibitor_set_app_id (GsmInhibitor  *inhibitor,
177                           const char    *app_id)
178 {
179         g_return_if_fail (GSM_IS_INHIBITOR (inhibitor));
180 
181         g_free (inhibitor->app_id);
182 
183         inhibitor->app_id = g_strdup (app_id);
184         g_object_notify (G_OBJECT (inhibitor), "app-id");
185 }
186 
187 static void
gsm_inhibitor_set_client_id(GsmInhibitor * inhibitor,const char * client_id)188 gsm_inhibitor_set_client_id (GsmInhibitor  *inhibitor,
189                              const char    *client_id)
190 {
191         g_return_if_fail (GSM_IS_INHIBITOR (inhibitor));
192 
193         g_free (inhibitor->client_id);
194 
195         g_debug ("GsmInhibitor: setting client-id = %s", client_id);
196 
197         if (client_id != NULL) {
198                 inhibitor->client_id = g_strdup (client_id);
199         } else {
200                 inhibitor->client_id = g_strdup ("");
201         }
202         g_object_notify (G_OBJECT (inhibitor), "client-id");
203 }
204 
205 static void
gsm_inhibitor_set_reason(GsmInhibitor * inhibitor,const char * reason)206 gsm_inhibitor_set_reason (GsmInhibitor  *inhibitor,
207                           const char    *reason)
208 {
209         g_return_if_fail (GSM_IS_INHIBITOR (inhibitor));
210 
211         g_free (inhibitor->reason);
212 
213         if (reason != NULL) {
214                 inhibitor->reason = g_strdup (reason);
215         } else {
216                 inhibitor->reason = g_strdup ("");
217         }
218         g_object_notify (G_OBJECT (inhibitor), "reason");
219 }
220 
221 static void
gsm_inhibitor_set_cookie(GsmInhibitor * inhibitor,guint cookie)222 gsm_inhibitor_set_cookie (GsmInhibitor  *inhibitor,
223                           guint          cookie)
224 {
225         g_return_if_fail (GSM_IS_INHIBITOR (inhibitor));
226 
227         if (inhibitor->cookie != cookie) {
228                 inhibitor->cookie = cookie;
229                 g_object_notify (G_OBJECT (inhibitor), "cookie");
230         }
231 }
232 
233 static void
gsm_inhibitor_set_flags(GsmInhibitor * inhibitor,guint flags)234 gsm_inhibitor_set_flags (GsmInhibitor  *inhibitor,
235                          guint          flags)
236 {
237         g_return_if_fail (GSM_IS_INHIBITOR (inhibitor));
238 
239         if (inhibitor->flags != flags) {
240                 inhibitor->flags = flags;
241                 g_object_notify (G_OBJECT (inhibitor), "flags");
242         }
243 }
244 
245 static void
gsm_inhibitor_set_toplevel_xid(GsmInhibitor * inhibitor,guint xid)246 gsm_inhibitor_set_toplevel_xid (GsmInhibitor  *inhibitor,
247                                 guint          xid)
248 {
249         g_return_if_fail (GSM_IS_INHIBITOR (inhibitor));
250 
251         if (inhibitor->toplevel_xid != xid) {
252                 inhibitor->toplevel_xid = xid;
253                 g_object_notify (G_OBJECT (inhibitor), "toplevel-xid");
254         }
255 }
256 
257 const char *
gsm_inhibitor_peek_bus_name(GsmInhibitor * inhibitor)258 gsm_inhibitor_peek_bus_name (GsmInhibitor  *inhibitor)
259 {
260         g_return_val_if_fail (GSM_IS_INHIBITOR (inhibitor), NULL);
261 
262         return inhibitor->bus_name;
263 }
264 
265 gboolean
gsm_inhibitor_get_app_id(GsmInhibitor * inhibitor,char ** id,GError ** error)266 gsm_inhibitor_get_app_id (GsmInhibitor *inhibitor,
267                           char        **id,
268                           GError      **error)
269 {
270         g_return_val_if_fail (GSM_IS_INHIBITOR (inhibitor), FALSE);
271 
272         if (inhibitor->app_id != NULL) {
273                 *id = g_strdup (inhibitor->app_id);
274         } else {
275                 *id = g_strdup ("");
276         }
277 
278         return TRUE;
279 }
280 
281 gboolean
gsm_inhibitor_get_client_id(GsmInhibitor * inhibitor,char ** id,GError ** error)282 gsm_inhibitor_get_client_id (GsmInhibitor *inhibitor,
283                              char        **id,
284                              GError      **error)
285 {
286         g_return_val_if_fail (GSM_IS_INHIBITOR (inhibitor), FALSE);
287 
288         /* object paths are not allowed to be NULL or blank */
289         if (IS_STRING_EMPTY (inhibitor->client_id)) {
290                 g_set_error (error,
291                              GSM_INHIBITOR_ERROR,
292                              GSM_INHIBITOR_ERROR_NOT_SET,
293                              "Value is not set");
294                 return FALSE;
295         }
296 
297         *id = g_strdup (inhibitor->client_id);
298 
299         g_debug ("GsmInhibitor: getting client-id = '%s'", *id);
300 
301         return TRUE;
302 }
303 
304 gboolean
gsm_inhibitor_get_reason(GsmInhibitor * inhibitor,char ** reason,GError ** error)305 gsm_inhibitor_get_reason (GsmInhibitor *inhibitor,
306                           char        **reason,
307                           GError      **error)
308 {
309         g_return_val_if_fail (GSM_IS_INHIBITOR (inhibitor), FALSE);
310 
311         if (inhibitor->reason != NULL) {
312                 *reason = g_strdup (inhibitor->reason);
313         } else {
314                 *reason = g_strdup ("");
315         }
316 
317         return TRUE;
318 }
319 
320 gboolean
gsm_inhibitor_get_flags(GsmInhibitor * inhibitor,guint * flags,GError ** error)321 gsm_inhibitor_get_flags (GsmInhibitor *inhibitor,
322                          guint        *flags,
323                          GError      **error)
324 {
325         g_return_val_if_fail (GSM_IS_INHIBITOR (inhibitor), FALSE);
326 
327         *flags = inhibitor->flags;
328 
329         return TRUE;
330 }
331 
332 gboolean
gsm_inhibitor_get_toplevel_xid(GsmInhibitor * inhibitor,guint * xid,GError ** error)333 gsm_inhibitor_get_toplevel_xid (GsmInhibitor *inhibitor,
334                                 guint        *xid,
335                                 GError      **error)
336 {
337         g_return_val_if_fail (GSM_IS_INHIBITOR (inhibitor), FALSE);
338 
339         *xid = inhibitor->toplevel_xid;
340 
341         return TRUE;
342 }
343 
344 const char *
gsm_inhibitor_peek_id(GsmInhibitor * inhibitor)345 gsm_inhibitor_peek_id (GsmInhibitor *inhibitor)
346 {
347         g_return_val_if_fail (GSM_IS_INHIBITOR (inhibitor), NULL);
348 
349         return inhibitor->id;
350 }
351 
352 const char *
gsm_inhibitor_peek_app_id(GsmInhibitor * inhibitor)353 gsm_inhibitor_peek_app_id (GsmInhibitor  *inhibitor)
354 {
355         g_return_val_if_fail (GSM_IS_INHIBITOR (inhibitor), NULL);
356 
357         return inhibitor->app_id;
358 }
359 
360 const char *
gsm_inhibitor_peek_client_id(GsmInhibitor * inhibitor)361 gsm_inhibitor_peek_client_id (GsmInhibitor  *inhibitor)
362 {
363         g_return_val_if_fail (GSM_IS_INHIBITOR (inhibitor), NULL);
364 
365         return inhibitor->client_id;
366 }
367 
368 const char *
gsm_inhibitor_peek_reason(GsmInhibitor * inhibitor)369 gsm_inhibitor_peek_reason (GsmInhibitor  *inhibitor)
370 {
371         g_return_val_if_fail (GSM_IS_INHIBITOR (inhibitor), NULL);
372 
373         return inhibitor->reason;
374 }
375 
376 guint
gsm_inhibitor_peek_flags(GsmInhibitor * inhibitor)377 gsm_inhibitor_peek_flags (GsmInhibitor  *inhibitor)
378 {
379         g_return_val_if_fail (GSM_IS_INHIBITOR (inhibitor), 0);
380 
381         return inhibitor->flags;
382 }
383 
384 guint
gsm_inhibitor_peek_toplevel_xid(GsmInhibitor * inhibitor)385 gsm_inhibitor_peek_toplevel_xid (GsmInhibitor  *inhibitor)
386 {
387         g_return_val_if_fail (GSM_IS_INHIBITOR (inhibitor), 0);
388 
389         return inhibitor->toplevel_xid;
390 }
391 
392 guint
gsm_inhibitor_peek_cookie(GsmInhibitor * inhibitor)393 gsm_inhibitor_peek_cookie (GsmInhibitor  *inhibitor)
394 {
395         g_return_val_if_fail (GSM_IS_INHIBITOR (inhibitor), 0);
396 
397         return inhibitor->cookie;
398 }
399 
400 static void
gsm_inhibitor_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)401 gsm_inhibitor_set_property (GObject       *object,
402                             guint          prop_id,
403                             const GValue  *value,
404                             GParamSpec    *pspec)
405 {
406         GsmInhibitor *self;
407 
408         self = GSM_INHIBITOR (object);
409 
410         switch (prop_id) {
411         case PROP_BUS_NAME:
412                 gsm_inhibitor_set_bus_name (self, g_value_get_string (value));
413                 break;
414         case PROP_APP_ID:
415                 gsm_inhibitor_set_app_id (self, g_value_get_string (value));
416                 break;
417         case PROP_CLIENT_ID:
418                 gsm_inhibitor_set_client_id (self, g_value_get_string (value));
419                 break;
420         case PROP_REASON:
421                 gsm_inhibitor_set_reason (self, g_value_get_string (value));
422                 break;
423         case PROP_FLAGS:
424                 gsm_inhibitor_set_flags (self, g_value_get_uint (value));
425                 break;
426         case PROP_COOKIE:
427                 gsm_inhibitor_set_cookie (self, g_value_get_uint (value));
428                 break;
429         case PROP_TOPLEVEL_XID:
430                 gsm_inhibitor_set_toplevel_xid (self, g_value_get_uint (value));
431                 break;
432         default:
433                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
434                 break;
435         }
436 }
437 
438 static void
gsm_inhibitor_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)439 gsm_inhibitor_get_property (GObject    *object,
440                             guint       prop_id,
441                             GValue     *value,
442                             GParamSpec *pspec)
443 {
444         GsmInhibitor *self;
445 
446         self = GSM_INHIBITOR (object);
447 
448         switch (prop_id) {
449         case PROP_BUS_NAME:
450                 g_value_set_string (value, self->bus_name);
451                 break;
452         case PROP_APP_ID:
453                 g_value_set_string (value, self->app_id);
454                 break;
455         case PROP_CLIENT_ID:
456                 g_value_set_string (value, self->client_id);
457                 break;
458         case PROP_REASON:
459                 g_value_set_string (value, self->reason);
460                 break;
461         case PROP_FLAGS:
462                 g_value_set_uint (value, self->flags);
463                 break;
464         case PROP_COOKIE:
465                 g_value_set_uint (value, self->cookie);
466                 break;
467         case PROP_TOPLEVEL_XID:
468                 g_value_set_uint (value, self->toplevel_xid);
469                 break;
470         default:
471                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
472                 break;
473         }
474 }
475 
476 static void
gsm_inhibitor_finalize(GObject * object)477 gsm_inhibitor_finalize (GObject *object)
478 {
479         GsmInhibitor *inhibitor = (GsmInhibitor *) object;
480 
481         g_free (inhibitor->id);
482         g_free (inhibitor->bus_name);
483         g_free (inhibitor->app_id);
484         g_free (inhibitor->client_id);
485         g_free (inhibitor->reason);
486 
487         G_OBJECT_CLASS (gsm_inhibitor_parent_class)->finalize (object);
488 }
489 
490 static void
gsm_inhibitor_class_init(GsmInhibitorClass * klass)491 gsm_inhibitor_class_init (GsmInhibitorClass *klass)
492 {
493         GObjectClass *object_class = G_OBJECT_CLASS (klass);
494 
495         object_class->finalize             = gsm_inhibitor_finalize;
496         object_class->constructor          = gsm_inhibitor_constructor;
497         object_class->get_property         = gsm_inhibitor_get_property;
498         object_class->set_property         = gsm_inhibitor_set_property;
499 
500         g_object_class_install_property (object_class,
501                                          PROP_BUS_NAME,
502                                          g_param_spec_string ("bus-name",
503                                                               "bus-name",
504                                                               "bus-name",
505                                                               "",
506                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
507         g_object_class_install_property (object_class,
508                                          PROP_APP_ID,
509                                          g_param_spec_string ("app-id",
510                                                               "app-id",
511                                                               "app-id",
512                                                               "",
513                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
514         g_object_class_install_property (object_class,
515                                          PROP_CLIENT_ID,
516                                          g_param_spec_string ("client-id",
517                                                               "client-id",
518                                                               "client-id",
519                                                               "",
520                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
521         g_object_class_install_property (object_class,
522                                          PROP_REASON,
523                                          g_param_spec_string ("reason",
524                                                               "reason",
525                                                               "reason",
526                                                               "",
527                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
528         g_object_class_install_property (object_class,
529                                          PROP_FLAGS,
530                                          g_param_spec_uint ("flags",
531                                                             "flags",
532                                                             "flags",
533                                                             0,
534                                                             G_MAXINT,
535                                                             0,
536                                                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
537         g_object_class_install_property (object_class,
538                                          PROP_TOPLEVEL_XID,
539                                          g_param_spec_uint ("toplevel-xid",
540                                                             "toplevel-xid",
541                                                             "toplevel-xid",
542                                                             0,
543                                                             G_MAXINT,
544                                                             0,
545                                                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
546         g_object_class_install_property (object_class,
547                                          PROP_COOKIE,
548                                          g_param_spec_uint ("cookie",
549                                                             "cookie",
550                                                             "cookie",
551                                                             0,
552                                                             G_MAXINT,
553                                                             0,
554                                                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
555 
556         dbus_g_object_type_install_info (GSM_TYPE_INHIBITOR, &dbus_glib_gsm_inhibitor_object_info);
557         dbus_g_error_domain_register (GSM_INHIBITOR_ERROR, NULL, GSM_INHIBITOR_TYPE_ERROR);
558 }
559 
560 GsmInhibitor *
gsm_inhibitor_new(const char * app_id,guint toplevel_xid,guint flags,const char * reason,const char * bus_name,guint cookie)561 gsm_inhibitor_new (const char    *app_id,
562                    guint          toplevel_xid,
563                    guint          flags,
564                    const char    *reason,
565                    const char    *bus_name,
566                    guint          cookie)
567 {
568         GsmInhibitor *inhibitor;
569 
570         inhibitor = g_object_new (GSM_TYPE_INHIBITOR,
571                                   "app-id", app_id,
572                                   "reason", reason,
573                                   "bus-name", bus_name,
574                                   "flags", flags,
575                                   "toplevel-xid", toplevel_xid,
576                                   "cookie", cookie,
577                                   NULL);
578 
579         return inhibitor;
580 }
581 
582 GsmInhibitor *
gsm_inhibitor_new_for_client(const char * client_id,const char * app_id,guint flags,const char * reason,const char * bus_name,guint cookie)583 gsm_inhibitor_new_for_client (const char    *client_id,
584                               const char    *app_id,
585                               guint          flags,
586                               const char    *reason,
587                               const char    *bus_name,
588                               guint          cookie)
589 {
590         GsmInhibitor *inhibitor;
591 
592         inhibitor = g_object_new (GSM_TYPE_INHIBITOR,
593                                   "client-id", client_id,
594                                   "app-id", app_id,
595                                   "reason", reason,
596                                   "bus-name", bus_name,
597                                   "flags", flags,
598                                   "cookie", cookie,
599                                   NULL);
600 
601         return inhibitor;
602 }
603