1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
// This file was generated by gir (https://github.com/gtk-rs/gir)
// from gir-files (https://github.com/gtk-rs/gir-files)
// DO NOT EDIT

use crate::{Cancellable, DBusConnection, DBusMethodInvocation, DebugController, Initable};
use glib::{
    prelude::*,
    signal::{connect_raw, SignalHandlerId},
    translate::*,
};
use std::boxed::Box as Box_;

glib::wrapper! {
    /// `GDebugControllerDBus` is an implementation of [`DebugController`][crate::DebugController]
    /// which exposes debug settings as a D-Bus object.
    ///
    /// It is a [`Initable`][crate::Initable] object, and will register an object at
    /// `/org/gtk/Debugging` on the bus given as
    /// [`connection`][struct@crate::DebugControllerDBus#connection] once it’s initialized. The
    /// object will be unregistered when the last reference to the
    /// `GDebugControllerDBus` is dropped.
    ///
    /// This D-Bus object can be used by remote processes to enable or disable debug
    /// output in this process. Remote processes calling
    /// `org.gtk.Debugging.SetDebugEnabled()` will affect the value of
    /// [`debug-enabled`][struct@crate::DebugController#debug-enabled] and, by default,
    /// `log_get_debug_enabled()`.
    ///
    /// By default, no processes are allowed to call `SetDebugEnabled()` unless a
    /// [`authorize`][struct@crate::DebugControllerDBus#authorize] signal handler is installed. This
    /// is because the process may be privileged, or might expose sensitive
    /// information in its debug output. You may want to restrict the ability to
    /// enable debug output to privileged users or processes.
    ///
    /// One option is to install a D-Bus security policy which restricts access to
    /// `SetDebugEnabled()`, installing something like the following in
    /// `$datadir/dbus-1/system.d/`:
    ///
    /// ```xml
    /// <?xml version="1.0"?> <!--*-nxml-*-->
    /// <!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
    ///      "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
    /// <busconfig>
    ///   <policy user="root">
    ///     <allow send_destination="com.example.MyService" send_interface="org.gtk.Debugging"/>
    ///   </policy>
    ///   <policy context="default">
    ///     <deny send_destination="com.example.MyService" send_interface="org.gtk.Debugging"/>
    ///   </policy>
    /// </busconfig>
    /// ```
    ///
    /// This will prevent the `SetDebugEnabled()` method from being called by all
    /// except root. It will not prevent the `DebugEnabled` property from being read,
    /// as it’s accessed through the `org.freedesktop.DBus.Properties` interface.
    ///
    /// Another option is to use polkit to allow or deny requests on a case-by-case
    /// basis, allowing for the possibility of dynamic authorisation. To do this,
    /// connect to the [`authorize`][struct@crate::DebugControllerDBus#authorize] signal and query
    /// polkit in it:
    ///
    /// **⚠️ The following code is in c ⚠️**
    ///
    /// ```c
    ///   g_autoptr(GError) child_error = NULL;
    ///   g_autoptr(GDBusConnection) connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL);
    ///   gulong debug_controller_authorize_id = 0;
    ///
    ///   // Set up the debug controller.
    ///   debug_controller = G_DEBUG_CONTROLLER (g_debug_controller_dbus_new (priv->connection, NULL, &child_error));
    ///   if (debug_controller == NULL)
    ///     {
    ///       g_error ("Could not register debug controller on bus: %s"),
    ///                child_error->message);
    ///     }
    ///
    ///   debug_controller_authorize_id = g_signal_connect (debug_controller,
    ///                                                     "authorize",
    ///                                                     G_CALLBACK (debug_controller_authorize_cb),
    ///                                                     self);
    ///
    ///   static gboolean
    ///   debug_controller_authorize_cb (GDebugControllerDBus  *debug_controller,
    ///                                  GDBusMethodInvocation *invocation,
    ///                                  gpointer               user_data)
    ///   {
    ///     g_autoptr(PolkitAuthority) authority = NULL;
    ///     g_autoptr(PolkitSubject) subject = NULL;
    ///     g_autoptr(PolkitAuthorizationResult) auth_result = NULL;
    ///     g_autoptr(GError) local_error = NULL;
    ///     GDBusMessage *message;
    ///     GDBusMessageFlags message_flags;
    ///     PolkitCheckAuthorizationFlags flags = POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE;
    ///
    ///     message = g_dbus_method_invocation_get_message (invocation);
    ///     message_flags = g_dbus_message_get_flags (message);
    ///
    ///     authority = polkit_authority_get_sync (NULL, &local_error);
    ///     if (authority == NULL)
    ///       {
    ///         g_warning ("Failed to get polkit authority: %s", local_error->message);
    ///         return FALSE;
    ///       }
    ///
    ///     if (message_flags & G_DBUS_MESSAGE_FLAGS_ALLOW_INTERACTIVE_AUTHORIZATION)
    ///       flags |= POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION;
    ///
    ///     subject = polkit_system_bus_name_new (g_dbus_method_invocation_get_sender (invocation));
    ///
    ///     auth_result = polkit_authority_check_authorization_sync (authority,
    ///                                                              subject,
    ///                                                              "com.example.MyService.set-debug-enabled",
    ///                                                              NULL,
    ///                                                              flags,
    ///                                                              NULL,
    ///                                                              &local_error);
    ///     if (auth_result == NULL)
    ///       {
    ///         g_warning ("Failed to get check polkit authorization: %s", local_error->message);
    ///         return FALSE;
    ///       }
    ///
    ///     return polkit_authorization_result_get_is_authorized (auth_result);
    ///   }
    /// ```
    ///
    /// ## Properties
    ///
    ///
    /// #### `connection`
    ///  The D-Bus connection to expose the debugging interface on.
    ///
    /// Typically this will be the same connection (to the system or session bus)
    /// which the rest of the application or service’s D-Bus objects are registered
    /// on.
    ///
    /// Readable | Writeable | Construct Only
    /// <details><summary><h4>DebugController</h4></summary>
    ///
    ///
    /// #### `debug-enabled`
    ///  [`true`] if debug output should be exposed (for example by forwarding it to
    /// the journal), [`false`] otherwise.
    ///
    /// Readable | Writeable
    /// </details>
    ///
    /// ## Signals
    ///
    ///
    /// #### `authorize`
    ///  Emitted when a D-Bus peer is trying to change the debug settings and used
    /// to determine if that is authorized.
    ///
    /// This signal is emitted in a dedicated worker thread, so handlers are
    /// allowed to perform blocking I/O. This means that, for example, it is
    /// appropriate to call `polkit_authority_check_authorization_sync()` to check
    /// authorization using polkit.
    ///
    /// If [`false`] is returned then no further handlers are run and the request to
    /// change the debug settings is rejected.
    ///
    /// Otherwise, if [`true`] is returned, signal emission continues. If no handlers
    /// return [`false`], then the debug settings are allowed to be changed.
    ///
    /// Signal handlers must not modify @invocation, or cause it to return a value.
    ///
    /// The default class handler just returns [`true`].
    ///
    ///
    ///
    /// # Implements
    ///
    /// [`DebugControllerDBusExt`][trait@crate::prelude::DebugControllerDBusExt], [`trait@glib::ObjectExt`], [`DebugControllerExt`][trait@crate::prelude::DebugControllerExt], [`InitableExt`][trait@crate::prelude::InitableExt], [`DebugControllerDBusExtManual`][trait@crate::prelude::DebugControllerDBusExtManual]
    #[doc(alias = "GDebugControllerDBus")]
    pub struct DebugControllerDBus(Object<ffi::GDebugControllerDBus, ffi::GDebugControllerDBusClass>) @implements DebugController, Initable;

    match fn {
        type_ => || ffi::g_debug_controller_dbus_get_type(),
    }
}

impl DebugControllerDBus {
    pub const NONE: Option<&'static DebugControllerDBus> = None;

    /// Create a new #GDebugControllerDBus and synchronously initialize it.
    ///
    /// Initializing the object will export the debug object on @connection. The
    /// object will remain registered until the last reference to the
    /// #GDebugControllerDBus is dropped.
    ///
    /// Initialization may fail if registering the object on @connection fails.
    /// ## `connection`
    /// a #GDBusConnection to register the debug object on
    /// ## `cancellable`
    /// a #GCancellable, or [`None`]
    ///
    /// # Returns
    ///
    /// a new #GDebugControllerDBus, or [`None`]
    ///   on failure
    #[doc(alias = "g_debug_controller_dbus_new")]
    pub fn new(
        connection: &DBusConnection,
        cancellable: Option<&impl IsA<Cancellable>>,
    ) -> Result<Option<DebugControllerDBus>, glib::Error> {
        unsafe {
            let mut error = std::ptr::null_mut();
            let ret = ffi::g_debug_controller_dbus_new(
                connection.to_glib_none().0,
                cancellable.map(|p| p.as_ref()).to_glib_none().0,
                &mut error,
            );
            if error.is_null() {
                Ok(from_glib_full(ret))
            } else {
                Err(from_glib_full(error))
            }
        }
    }
}

mod sealed {
    pub trait Sealed {}
    impl<T: super::IsA<super::DebugControllerDBus>> Sealed for T {}
}

/// Trait containing all [`struct@DebugControllerDBus`] methods.
///
/// # Implementors
///
/// [`DebugControllerDBus`][struct@crate::DebugControllerDBus]
pub trait DebugControllerDBusExt: IsA<DebugControllerDBus> + sealed::Sealed + 'static {
    /// Stop the debug controller, unregistering its object from the bus.
    ///
    /// Any pending method calls to the object will complete successfully, but new
    /// ones will return an error. This method will block until all pending
    /// #GDebugControllerDBus::authorize signals have been handled. This is expected
    /// to not take long, as it will just be waiting for threads to join. If any
    /// #GDebugControllerDBus::authorize signal handlers are still executing in other
    /// threads, this will block until after they have returned.
    ///
    /// This method will be called automatically when the final reference to the
    /// #GDebugControllerDBus is dropped. You may want to call it explicitly to know
    /// when the controller has been fully removed from the bus, or to break
    /// reference count cycles.
    ///
    /// Calling this method from within a #GDebugControllerDBus::authorize signal
    /// handler will cause a deadlock and must not be done.
    #[doc(alias = "g_debug_controller_dbus_stop")]
    fn stop(&self) {
        unsafe {
            ffi::g_debug_controller_dbus_stop(self.as_ref().to_glib_none().0);
        }
    }

    /// Emitted when a D-Bus peer is trying to change the debug settings and used
    /// to determine if that is authorized.
    ///
    /// This signal is emitted in a dedicated worker thread, so handlers are
    /// allowed to perform blocking I/O. This means that, for example, it is
    /// appropriate to call `polkit_authority_check_authorization_sync()` to check
    /// authorization using polkit.
    ///
    /// If [`false`] is returned then no further handlers are run and the request to
    /// change the debug settings is rejected.
    ///
    /// Otherwise, if [`true`] is returned, signal emission continues. If no handlers
    /// return [`false`], then the debug settings are allowed to be changed.
    ///
    /// Signal handlers must not modify @invocation, or cause it to return a value.
    ///
    /// The default class handler just returns [`true`].
    /// ## `invocation`
    /// A #GDBusMethodInvocation.
    ///
    /// # Returns
    ///
    /// [`true`] if the call is authorized, [`false`] otherwise.
    #[cfg(feature = "v2_72")]
    #[cfg_attr(docsrs, doc(cfg(feature = "v2_72")))]
    #[doc(alias = "authorize")]
    fn connect_authorize<F: Fn(&Self, &DBusMethodInvocation) -> bool + 'static>(
        &self,
        f: F,
    ) -> SignalHandlerId {
        unsafe extern "C" fn authorize_trampoline<
            P: IsA<DebugControllerDBus>,
            F: Fn(&P, &DBusMethodInvocation) -> bool + 'static,
        >(
            this: *mut ffi::GDebugControllerDBus,
            invocation: *mut ffi::GDBusMethodInvocation,
            f: glib::ffi::gpointer,
        ) -> glib::ffi::gboolean {
            let f: &F = &*(f as *const F);
            f(
                DebugControllerDBus::from_glib_borrow(this).unsafe_cast_ref(),
                &from_glib_borrow(invocation),
            )
            .into_glib()
        }
        unsafe {
            let f: Box_<F> = Box_::new(f);
            connect_raw(
                self.as_ptr() as *mut _,
                b"authorize\0".as_ptr() as *const _,
                Some(std::mem::transmute::<_, unsafe extern "C" fn()>(
                    authorize_trampoline::<Self, F> as *const (),
                )),
                Box_::into_raw(f),
            )
        }
    }
}

impl<O: IsA<DebugControllerDBus>> DebugControllerDBusExt for O {}