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
// 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;
use crate::DBusConnection;
use crate::DBusMethodInvocation;
use crate::DebugController;
use crate::Initable;
use glib::object::Cast;
use glib::object::IsA;
use glib::signal::connect_raw;
use glib::signal::SignalHandlerId;
use glib::translate::*;
use std::boxed::Box as Box_;
use std::fmt;
use std::mem::transmute;
use std::ptr;

glib::wrapper! {
    /// [`DebugControllerDBus`][crate::DebugControllerDBus] 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
    /// `property::DebugControllerDBus::connection` once it’s initialized. The object will be
    /// unregistered when the last reference to the [`DebugControllerDBus`][crate::DebugControllerDBus] 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
    /// `property::DebugController::debug-enabled` and, by default, `g_log_get_debug_enabled()`.
    /// default.
    ///
    /// By default, all processes will be able to call `SetDebugEnabled()`. If this
    /// process is 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/`:
    ///
    ///
    /// **⚠️ The following code is in XML ⚠️**
    ///
    /// ```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 `signal::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);
    ///   }
    /// ```
    ///
    /// # 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 [`DebugControllerDBus`][crate::DebugControllerDBus] 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
    /// [`DebugControllerDBus`][crate::DebugControllerDBus] is dropped.
    ///
    /// Initialization may fail if registering the object on `connection` fails.
    /// ## `connection`
    /// a [`DBusConnection`][crate::DBusConnection] to register the debug object on
    /// ## `cancellable`
    /// a [`Cancellable`][crate::Cancellable], or [`None`]
    ///
    /// # Returns
    ///
    /// a new [`DebugControllerDBus`][crate::DebugControllerDBus], 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 = 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))
            }
        }
    }
}

/// Trait containing all [`struct@DebugControllerDBus`] methods.
///
/// # Implementors
///
/// [`DebugControllerDBus`][struct@crate::DebugControllerDBus]
pub trait DebugControllerDBusExt: '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
    /// `signal::DebugControllerDBus::authorize` signals have been handled. This is expected
    /// to not take long, as it will just be waiting for threads to join. If any
    /// `signal::DebugControllerDBus::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
    /// [`DebugControllerDBus`][crate::DebugControllerDBus] 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 `signal::DebugControllerDBus::authorize` signal
    /// handler will cause a deadlock and must not be done.
    #[doc(alias = "g_debug_controller_dbus_stop")]
    fn stop(&self);

    /// 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 [`DBusMethodInvocation`][crate::DBusMethodInvocation].
    ///
    /// # Returns
    ///
    /// [`true`] if the call is authorized, [`false`] otherwise.
    #[cfg(any(feature = "v2_72", feature = "dox"))]
    #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_72")))]
    #[doc(alias = "authorize")]
    fn connect_authorize<F: Fn(&Self, &DBusMethodInvocation) -> bool + 'static>(
        &self,
        f: F,
    ) -> SignalHandlerId;
}

impl<O: IsA<DebugControllerDBus>> DebugControllerDBusExt for O {
    fn stop(&self) {
        unsafe {
            ffi::g_debug_controller_dbus_stop(self.as_ref().to_glib_none().0);
        }
    }

    #[cfg(any(feature = "v2_72", feature = "dox"))]
    #[cfg_attr(feature = "dox", doc(cfg(feature = "v2_72")))]
    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(transmute::<_, unsafe extern "C" fn()>(
                    authorize_trampoline::<Self, F> as *const (),
                )),
                Box_::into_raw(f),
            )
        }
    }
}

impl fmt::Display for DebugControllerDBus {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        f.write_str("DebugControllerDBus")
    }
}