1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2  *
3  * Copyright (C) 2008 Red Hat, Inc.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street - Suite 500, Boston, MA
18  * 02110-1335, USA.
19  */
20 
21 #include "config.h"
22 
23 #include <fcntl.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <time.h>
27 #include <unistd.h>
28 
29 #include "csm-inhibitor.h"
30 #include "csm-exported-inhibitor.h"
31 
32 #include "csm-util.h"
33 
34 static guint32 inhibitor_serial = 1;
35 
36 #define CSM_INHIBITOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CSM_TYPE_INHIBITOR, CsmInhibitorPrivate))
37 
38 struct CsmInhibitorPrivate
39 {
40         char *id;
41         char *bus_name;
42         char *app_id;
43         char *client_id;
44         char *reason;
45         guint flags;
46         guint toplevel_xid;
47         guint cookie;
48         GDBusConnection *connection;
49         CsmExportedInhibitor *skeleton;
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 
63 G_DEFINE_TYPE (CsmInhibitor, csm_inhibitor, G_TYPE_OBJECT)
64 
65 #define CSM_INHIBITOR_DBUS_IFACE "org.gnome.SessionManager.Inhibitor"
66 
67 static const GDBusErrorEntry csm_inhibitor_error_entries[] = {
68         { CSM_INHIBITOR_ERROR_GENERAL, CSM_INHIBITOR_DBUS_IFACE ".GeneralError" },
69         { CSM_INHIBITOR_ERROR_NOT_SET, CSM_INHIBITOR_DBUS_IFACE ".NotSet" }
70 };
71 
72 GQuark
csm_inhibitor_error_quark(void)73 csm_inhibitor_error_quark (void)
74 {
75         static volatile gsize quark_volatile = 0;
76 
77         g_dbus_error_register_error_domain ("csm_inhibitor_error",
78                                             &quark_volatile,
79                                             csm_inhibitor_error_entries,
80                                             G_N_ELEMENTS (csm_inhibitor_error_entries));
81 
82         return quark_volatile;
83 }
84 
85 static gboolean
csm_inhibitor_get_app_id(CsmExportedInhibitor * skeleton,GDBusMethodInvocation * invocation,CsmInhibitor * inhibitor)86 csm_inhibitor_get_app_id (CsmExportedInhibitor  *skeleton,
87                           GDBusMethodInvocation *invocation,
88                           CsmInhibitor          *inhibitor)
89 {
90         const gchar *id;
91 
92         if (inhibitor->priv->app_id != NULL) {
93                 id = inhibitor->priv->app_id;
94         } else {
95                 id = "";
96         }
97 
98         csm_exported_inhibitor_complete_get_app_id (skeleton, invocation, id);
99 
100         return TRUE;
101 }
102 
103 static gboolean
csm_inhibitor_get_client_id(CsmExportedInhibitor * skeleton,GDBusMethodInvocation * invocation,CsmInhibitor * inhibitor)104 csm_inhibitor_get_client_id (CsmExportedInhibitor  *skeleton,
105                              GDBusMethodInvocation *invocation,
106                              CsmInhibitor          *inhibitor)
107 {
108         /* object paths are not allowed to be NULL or blank */
109         if (IS_STRING_EMPTY (inhibitor->priv->client_id)) {
110                 g_dbus_method_invocation_return_error (invocation,
111                                                        CSM_INHIBITOR_ERROR,
112                                                        CSM_INHIBITOR_ERROR_NOT_SET,
113                                                        "Value is not set");
114 
115                 return TRUE;
116         }
117 
118         csm_exported_inhibitor_complete_get_client_id (skeleton, invocation, inhibitor->priv->client_id);
119 
120         g_debug ("CsmInhibitor: getting client-id = '%s'", inhibitor->priv->client_id);
121 
122         return TRUE;
123 }
124 
125 static gboolean
csm_inhibitor_get_reason(CsmExportedInhibitor * skeleton,GDBusMethodInvocation * invocation,CsmInhibitor * inhibitor)126 csm_inhibitor_get_reason (CsmExportedInhibitor  *skeleton,
127                           GDBusMethodInvocation *invocation,
128                           CsmInhibitor          *inhibitor)
129 {
130         const gchar *reason;
131 
132         if (inhibitor->priv->reason != NULL) {
133                 reason = inhibitor->priv->reason;
134         } else {
135                 reason = "";
136         }
137 
138         csm_exported_inhibitor_complete_get_reason (skeleton, invocation, reason);
139 
140         return TRUE;
141 }
142 
143 static gboolean
csm_inhibitor_get_flags(CsmExportedInhibitor * skeleton,GDBusMethodInvocation * invocation,CsmInhibitor * inhibitor)144 csm_inhibitor_get_flags (CsmExportedInhibitor  *skeleton,
145                          GDBusMethodInvocation *invocation,
146                          CsmInhibitor          *inhibitor)
147 {
148         csm_exported_inhibitor_complete_get_flags (skeleton, invocation, inhibitor->priv->flags);
149 
150         return TRUE;
151 }
152 
153 static gboolean
csm_inhibitor_get_toplevel_xid(CsmExportedInhibitor * skeleton,GDBusMethodInvocation * invocation,CsmInhibitor * inhibitor)154 csm_inhibitor_get_toplevel_xid (CsmExportedInhibitor  *skeleton,
155                                 GDBusMethodInvocation *invocation,
156                                 CsmInhibitor          *inhibitor)
157 {
158 
159         csm_exported_inhibitor_complete_get_toplevel_xid (skeleton, invocation, inhibitor->priv->toplevel_xid);
160 
161         return TRUE;
162 }
163 
164 static guint32
get_next_inhibitor_serial(void)165 get_next_inhibitor_serial (void)
166 {
167         guint32 serial;
168 
169         serial = inhibitor_serial++;
170 
171         if ((gint32)inhibitor_serial < 0) {
172                 inhibitor_serial = 1;
173         }
174 
175         return serial;
176 }
177 
178 static gboolean
register_inhibitor(CsmInhibitor * inhibitor)179 register_inhibitor (CsmInhibitor *inhibitor)
180 {
181         GError *error;
182         CsmExportedInhibitor *skeleton;
183 
184         error = NULL;
185         inhibitor->priv->connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
186 
187         if (error != NULL) {
188                 g_critical ("error getting session bus: %s", error->message);
189                 g_error_free (error);
190                 return FALSE;
191         }
192 
193         skeleton = csm_exported_inhibitor_skeleton_new ();
194         inhibitor->priv->skeleton = skeleton;
195         g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (skeleton),
196                                           inhibitor->priv->connection,
197                                           inhibitor->priv->id, &error);
198 
199         if (error != NULL) {
200                 g_critical ("error exporting inhibitor on session bus: %s", error->message);
201                 g_error_free (error);
202                 return FALSE;
203         }
204 
205         g_signal_connect (skeleton, "handle-get-app-id",
206                           G_CALLBACK (csm_inhibitor_get_app_id), inhibitor);
207         g_signal_connect (skeleton, "handle-get-client-id",
208                           G_CALLBACK (csm_inhibitor_get_client_id), inhibitor);
209         g_signal_connect (skeleton, "handle-get-flags",
210                           G_CALLBACK (csm_inhibitor_get_flags), inhibitor);
211         g_signal_connect (skeleton, "handle-get-reason",
212                           G_CALLBACK (csm_inhibitor_get_reason), inhibitor);
213         g_signal_connect (skeleton, "handle-get-toplevel-xid",
214                           G_CALLBACK (csm_inhibitor_get_toplevel_xid), inhibitor);
215 
216         return TRUE;
217 }
218 
219 static GObject *
csm_inhibitor_constructor(GType type,guint n_construct_properties,GObjectConstructParam * construct_properties)220 csm_inhibitor_constructor (GType                  type,
221                            guint                  n_construct_properties,
222                            GObjectConstructParam *construct_properties)
223 {
224         CsmInhibitor *inhibitor;
225         gboolean      res;
226 
227         inhibitor = CSM_INHIBITOR (G_OBJECT_CLASS (csm_inhibitor_parent_class)->constructor (type,
228                                                                                              n_construct_properties,
229                                                                                              construct_properties));
230 
231         g_free (inhibitor->priv->id);
232         inhibitor->priv->id = g_strdup_printf ("/org/gnome/SessionManager/Inhibitor%u", get_next_inhibitor_serial ());
233         res = register_inhibitor (inhibitor);
234         if (! res) {
235                 g_warning ("Unable to register inhibitor with session bus");
236         }
237 
238         return G_OBJECT (inhibitor);
239 }
240 
241 static void
csm_inhibitor_init(CsmInhibitor * inhibitor)242 csm_inhibitor_init (CsmInhibitor *inhibitor)
243 {
244         inhibitor->priv = CSM_INHIBITOR_GET_PRIVATE (inhibitor);
245 }
246 
247 static void
csm_inhibitor_set_bus_name(CsmInhibitor * inhibitor,const char * bus_name)248 csm_inhibitor_set_bus_name (CsmInhibitor  *inhibitor,
249                             const char    *bus_name)
250 {
251         g_return_if_fail (CSM_IS_INHIBITOR (inhibitor));
252 
253         g_free (inhibitor->priv->bus_name);
254 
255         if (bus_name != NULL) {
256                 inhibitor->priv->bus_name = g_strdup (bus_name);
257         } else {
258                 inhibitor->priv->bus_name = g_strdup ("");
259         }
260         g_object_notify (G_OBJECT (inhibitor), "bus-name");
261 }
262 
263 static void
csm_inhibitor_set_app_id(CsmInhibitor * inhibitor,const char * app_id)264 csm_inhibitor_set_app_id (CsmInhibitor  *inhibitor,
265                           const char    *app_id)
266 {
267         g_return_if_fail (CSM_IS_INHIBITOR (inhibitor));
268 
269         g_free (inhibitor->priv->app_id);
270 
271         inhibitor->priv->app_id = g_strdup (app_id);
272         g_object_notify (G_OBJECT (inhibitor), "app-id");
273 }
274 
275 static void
csm_inhibitor_set_client_id(CsmInhibitor * inhibitor,const char * client_id)276 csm_inhibitor_set_client_id (CsmInhibitor  *inhibitor,
277                              const char    *client_id)
278 {
279         g_return_if_fail (CSM_IS_INHIBITOR (inhibitor));
280 
281         g_free (inhibitor->priv->client_id);
282 
283         g_debug ("CsmInhibitor: setting client-id = %s", client_id);
284 
285         if (client_id != NULL) {
286                 inhibitor->priv->client_id = g_strdup (client_id);
287         } else {
288                 inhibitor->priv->client_id = g_strdup ("");
289         }
290         g_object_notify (G_OBJECT (inhibitor), "client-id");
291 }
292 
293 static void
csm_inhibitor_set_reason(CsmInhibitor * inhibitor,const char * reason)294 csm_inhibitor_set_reason (CsmInhibitor  *inhibitor,
295                           const char    *reason)
296 {
297         g_return_if_fail (CSM_IS_INHIBITOR (inhibitor));
298 
299         g_free (inhibitor->priv->reason);
300 
301         if (reason != NULL) {
302                 inhibitor->priv->reason = g_strdup (reason);
303         } else {
304                 inhibitor->priv->reason = g_strdup ("");
305         }
306         g_object_notify (G_OBJECT (inhibitor), "reason");
307 }
308 
309 static void
csm_inhibitor_set_cookie(CsmInhibitor * inhibitor,guint cookie)310 csm_inhibitor_set_cookie (CsmInhibitor  *inhibitor,
311                           guint          cookie)
312 {
313         g_return_if_fail (CSM_IS_INHIBITOR (inhibitor));
314 
315         if (inhibitor->priv->cookie != cookie) {
316                 inhibitor->priv->cookie = cookie;
317                 g_object_notify (G_OBJECT (inhibitor), "cookie");
318         }
319 }
320 
321 static void
csm_inhibitor_set_flags(CsmInhibitor * inhibitor,guint flags)322 csm_inhibitor_set_flags (CsmInhibitor  *inhibitor,
323                          guint          flags)
324 {
325         g_return_if_fail (CSM_IS_INHIBITOR (inhibitor));
326 
327         if (inhibitor->priv->flags != flags) {
328                 inhibitor->priv->flags = flags;
329                 g_object_notify (G_OBJECT (inhibitor), "flags");
330         }
331 }
332 
333 static void
csm_inhibitor_set_toplevel_xid(CsmInhibitor * inhibitor,guint xid)334 csm_inhibitor_set_toplevel_xid (CsmInhibitor  *inhibitor,
335                                 guint          xid)
336 {
337         g_return_if_fail (CSM_IS_INHIBITOR (inhibitor));
338 
339         if (inhibitor->priv->toplevel_xid != xid) {
340                 inhibitor->priv->toplevel_xid = xid;
341                 g_object_notify (G_OBJECT (inhibitor), "toplevel-xid");
342         }
343 }
344 
345 const char *
csm_inhibitor_peek_bus_name(CsmInhibitor * inhibitor)346 csm_inhibitor_peek_bus_name (CsmInhibitor  *inhibitor)
347 {
348         g_return_val_if_fail (CSM_IS_INHIBITOR (inhibitor), NULL);
349 
350         return inhibitor->priv->bus_name;
351 }
352 
353 const char *
csm_inhibitor_peek_id(CsmInhibitor * inhibitor)354 csm_inhibitor_peek_id (CsmInhibitor *inhibitor)
355 {
356         g_return_val_if_fail (CSM_IS_INHIBITOR (inhibitor), NULL);
357 
358         return inhibitor->priv->id;
359 }
360 
361 const char *
csm_inhibitor_peek_app_id(CsmInhibitor * inhibitor)362 csm_inhibitor_peek_app_id (CsmInhibitor  *inhibitor)
363 {
364         g_return_val_if_fail (CSM_IS_INHIBITOR (inhibitor), NULL);
365 
366         return inhibitor->priv->app_id;
367 }
368 
369 const char *
csm_inhibitor_peek_client_id(CsmInhibitor * inhibitor)370 csm_inhibitor_peek_client_id (CsmInhibitor  *inhibitor)
371 {
372         g_return_val_if_fail (CSM_IS_INHIBITOR (inhibitor), NULL);
373 
374         return inhibitor->priv->client_id;
375 }
376 
377 const char *
csm_inhibitor_peek_reason(CsmInhibitor * inhibitor)378 csm_inhibitor_peek_reason (CsmInhibitor  *inhibitor)
379 {
380         g_return_val_if_fail (CSM_IS_INHIBITOR (inhibitor), NULL);
381 
382         return inhibitor->priv->reason;
383 }
384 
385 guint
csm_inhibitor_peek_flags(CsmInhibitor * inhibitor)386 csm_inhibitor_peek_flags (CsmInhibitor  *inhibitor)
387 {
388         g_return_val_if_fail (CSM_IS_INHIBITOR (inhibitor), 0);
389 
390         return inhibitor->priv->flags;
391 }
392 
393 guint
csm_inhibitor_peek_toplevel_xid(CsmInhibitor * inhibitor)394 csm_inhibitor_peek_toplevel_xid (CsmInhibitor  *inhibitor)
395 {
396         g_return_val_if_fail (CSM_IS_INHIBITOR (inhibitor), 0);
397 
398         return inhibitor->priv->toplevel_xid;
399 }
400 
401 guint
csm_inhibitor_peek_cookie(CsmInhibitor * inhibitor)402 csm_inhibitor_peek_cookie (CsmInhibitor  *inhibitor)
403 {
404         g_return_val_if_fail (CSM_IS_INHIBITOR (inhibitor), 0);
405 
406         return inhibitor->priv->cookie;
407 }
408 
409 static void
csm_inhibitor_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)410 csm_inhibitor_set_property (GObject       *object,
411                             guint          prop_id,
412                             const GValue  *value,
413                             GParamSpec    *pspec)
414 {
415         CsmInhibitor *self;
416 
417         self = CSM_INHIBITOR (object);
418 
419         switch (prop_id) {
420         case PROP_BUS_NAME:
421                 csm_inhibitor_set_bus_name (self, g_value_get_string (value));
422                 break;
423         case PROP_APP_ID:
424                 csm_inhibitor_set_app_id (self, g_value_get_string (value));
425                 break;
426         case PROP_CLIENT_ID:
427                 csm_inhibitor_set_client_id (self, g_value_get_string (value));
428                 break;
429         case PROP_REASON:
430                 csm_inhibitor_set_reason (self, g_value_get_string (value));
431                 break;
432         case PROP_FLAGS:
433                 csm_inhibitor_set_flags (self, g_value_get_uint (value));
434                 break;
435         case PROP_COOKIE:
436                 csm_inhibitor_set_cookie (self, g_value_get_uint (value));
437                 break;
438         case PROP_TOPLEVEL_XID:
439                 csm_inhibitor_set_toplevel_xid (self, g_value_get_uint (value));
440                 break;
441         default:
442                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
443                 break;
444         }
445 }
446 
447 static void
csm_inhibitor_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)448 csm_inhibitor_get_property (GObject    *object,
449                             guint       prop_id,
450                             GValue     *value,
451                             GParamSpec *pspec)
452 {
453         CsmInhibitor *self;
454 
455         self = CSM_INHIBITOR (object);
456 
457         switch (prop_id) {
458         case PROP_BUS_NAME:
459                 g_value_set_string (value, self->priv->bus_name);
460                 break;
461         case PROP_APP_ID:
462                 g_value_set_string (value, self->priv->app_id);
463                 break;
464         case PROP_CLIENT_ID:
465                 g_value_set_string (value, self->priv->client_id);
466                 break;
467         case PROP_REASON:
468                 g_value_set_string (value, self->priv->reason);
469                 break;
470         case PROP_FLAGS:
471                 g_value_set_uint (value, self->priv->flags);
472                 break;
473         case PROP_COOKIE:
474                 g_value_set_uint (value, self->priv->cookie);
475                 break;
476         case PROP_TOPLEVEL_XID:
477                 g_value_set_uint (value, self->priv->toplevel_xid);
478                 break;
479         default:
480                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
481                 break;
482         }
483 }
484 
485 static void
csm_inhibitor_finalize(GObject * object)486 csm_inhibitor_finalize (GObject *object)
487 {
488         CsmInhibitor *inhibitor = (CsmInhibitor *) object;
489 
490         g_free (inhibitor->priv->id);
491         g_free (inhibitor->priv->bus_name);
492         g_free (inhibitor->priv->app_id);
493         g_free (inhibitor->priv->client_id);
494         g_free (inhibitor->priv->reason);
495 
496         if (inhibitor->priv->skeleton != NULL) {
497                 g_dbus_interface_skeleton_unexport_from_connection (G_DBUS_INTERFACE_SKELETON (inhibitor->priv->skeleton),
498                                                                     inhibitor->priv->connection);
499                 g_clear_object (&inhibitor->priv->skeleton);
500         }
501 
502         g_clear_object (&inhibitor->priv->connection);
503 
504         G_OBJECT_CLASS (csm_inhibitor_parent_class)->finalize (object);
505 }
506 
507 static void
csm_inhibitor_class_init(CsmInhibitorClass * klass)508 csm_inhibitor_class_init (CsmInhibitorClass *klass)
509 {
510         GObjectClass *object_class = G_OBJECT_CLASS (klass);
511 
512         object_class->finalize             = csm_inhibitor_finalize;
513         object_class->constructor          = csm_inhibitor_constructor;
514         object_class->get_property         = csm_inhibitor_get_property;
515         object_class->set_property         = csm_inhibitor_set_property;
516 
517         g_object_class_install_property (object_class,
518                                          PROP_BUS_NAME,
519                                          g_param_spec_string ("bus-name",
520                                                               "bus-name",
521                                                               "bus-name",
522                                                               "",
523                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
524         g_object_class_install_property (object_class,
525                                          PROP_APP_ID,
526                                          g_param_spec_string ("app-id",
527                                                               "app-id",
528                                                               "app-id",
529                                                               "",
530                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
531         g_object_class_install_property (object_class,
532                                          PROP_CLIENT_ID,
533                                          g_param_spec_string ("client-id",
534                                                               "client-id",
535                                                               "client-id",
536                                                               "",
537                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
538         g_object_class_install_property (object_class,
539                                          PROP_REASON,
540                                          g_param_spec_string ("reason",
541                                                               "reason",
542                                                               "reason",
543                                                               "",
544                                                               G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
545         g_object_class_install_property (object_class,
546                                          PROP_FLAGS,
547                                          g_param_spec_uint ("flags",
548                                                             "flags",
549                                                             "flags",
550                                                             0,
551                                                             G_MAXINT,
552                                                             0,
553                                                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
554         g_object_class_install_property (object_class,
555                                          PROP_TOPLEVEL_XID,
556                                          g_param_spec_uint ("toplevel-xid",
557                                                             "toplevel-xid",
558                                                             "toplevel-xid",
559                                                             0,
560                                                             G_MAXINT,
561                                                             0,
562                                                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
563         g_object_class_install_property (object_class,
564                                          PROP_COOKIE,
565                                          g_param_spec_uint ("cookie",
566                                                             "cookie",
567                                                             "cookie",
568                                                             0,
569                                                             G_MAXINT,
570                                                             0,
571                                                             G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
572 
573         g_type_class_add_private (klass, sizeof (CsmInhibitorPrivate));
574 }
575 
576 CsmInhibitor *
csm_inhibitor_new(const char * app_id,guint toplevel_xid,guint flags,const char * reason,const char * bus_name,guint cookie)577 csm_inhibitor_new (const char    *app_id,
578                    guint          toplevel_xid,
579                    guint          flags,
580                    const char    *reason,
581                    const char    *bus_name,
582                    guint          cookie)
583 {
584         CsmInhibitor *inhibitor;
585 
586         inhibitor = g_object_new (CSM_TYPE_INHIBITOR,
587                                   "app-id", app_id,
588                                   "reason", reason,
589                                   "bus-name", bus_name,
590                                   "flags", flags,
591                                   "toplevel-xid", toplevel_xid,
592                                   "cookie", cookie,
593                                   NULL);
594 
595         return inhibitor;
596 }
597 
598 CsmInhibitor *
csm_inhibitor_new_for_client(const char * client_id,const char * app_id,guint flags,const char * reason,const char * bus_name,guint cookie)599 csm_inhibitor_new_for_client (const char    *client_id,
600                               const char    *app_id,
601                               guint          flags,
602                               const char    *reason,
603                               const char    *bus_name,
604                               guint          cookie)
605 {
606         CsmInhibitor *inhibitor;
607 
608         inhibitor = g_object_new (CSM_TYPE_INHIBITOR,
609                                   "client-id", client_id,
610                                   "app-id", app_id,
611                                   "reason", reason,
612                                   "bus-name", bus_name,
613                                   "flags", flags,
614                                   "cookie", cookie,
615                                   NULL);
616 
617         return inhibitor;
618 }
619