/*
* Copyright © 2014 Canonical Ltd.
* Copyright © 2021 Robert Tari
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 3, as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranties of
* MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*
* Authors:
* Ted Gould
* Robert Tari
*/
#include
#include "im-accounts-service.h"
typedef struct {
ActUserManager * user_manager;
GDBusProxy * touch_settings;
GCancellable * cancel;
} ImAccountsServicePrivate;
static void im_accounts_service_class_init (ImAccountsServiceClass *klass);
static void im_accounts_service_init (ImAccountsService *self);
static void im_accounts_service_dispose (GObject *object);
static void im_accounts_service_finalize (GObject *object);
static void user_changed (ActUserManager * manager, ActUser * user, gpointer user_data);
static void on_user_manager_loaded (ActUserManager * manager, GParamSpec * pspect, gpointer user_data);
static void security_privacy_ready (GObject * obj, GAsyncResult * res, gpointer user_data);
G_DEFINE_TYPE_WITH_PRIVATE (ImAccountsService, im_accounts_service, G_TYPE_OBJECT);
static void
im_accounts_service_class_init (ImAccountsServiceClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = im_accounts_service_dispose;
object_class->finalize = im_accounts_service_finalize;
}
static void
im_accounts_service_init (ImAccountsService *self)
{
ImAccountsServicePrivate * priv = im_accounts_service_get_instance_private(self);
priv->cancel = g_cancellable_new();
priv->user_manager = act_user_manager_get_default();
g_signal_connect(priv->user_manager, "user-added", G_CALLBACK(user_changed), self);
g_signal_connect(priv->user_manager, "user-changed", G_CALLBACK(user_changed), self);
g_signal_connect(priv->user_manager, "notify::is-loaded", G_CALLBACK(on_user_manager_loaded), self);
gboolean isLoaded = FALSE;
g_object_get(G_OBJECT(priv->user_manager), "is-loaded", &isLoaded, NULL);
if (isLoaded) {
on_user_manager_loaded(priv->user_manager, NULL, NULL);
}
}
static void
im_accounts_service_dispose (GObject *object)
{
ImAccountsService * self = IM_ACCOUNTS_SERVICE(object);
ImAccountsServicePrivate * priv = im_accounts_service_get_instance_private(self);
if (priv->cancel != NULL) {
g_cancellable_cancel(priv->cancel);
g_clear_object(&priv->cancel);
}
g_clear_object(&priv->user_manager);
G_OBJECT_CLASS (im_accounts_service_parent_class)->dispose (object);
}
static void
im_accounts_service_finalize (GObject *object)
{
G_OBJECT_CLASS (im_accounts_service_parent_class)->finalize (object);
}
/* Handles a User getting updated */
static void
user_changed (ActUserManager * manager, ActUser * user, gpointer user_data)
{
if (g_strcmp0(act_user_get_user_name(user), g_get_user_name()) != 0) {
return;
}
ImAccountsService * self = IM_ACCOUNTS_SERVICE(user_data);
ImAccountsServicePrivate * priv = im_accounts_service_get_instance_private(self);
g_debug("User Updated");
/* Clear old proxies */
g_clear_object(&priv->touch_settings);
g_cancellable_cancel(priv->cancel);
g_clear_object(&priv->cancel);
priv->cancel = g_cancellable_new();
/* Start getting a new proxy */
g_dbus_proxy_new_for_bus(G_BUS_TYPE_SYSTEM,
G_DBUS_PROXY_FLAGS_NONE,
NULL,
"org.freedesktop.Accounts",
act_user_get_object_path(user),
"com.lomiri.touch.AccountsService.SecurityPrivacy",
priv->cancel,
security_privacy_ready,
user_data);
}
/* Respond to the async of setting up the proxy. Mostly we get it or we error. */
static void
security_privacy_ready (GObject * obj, GAsyncResult * res, gpointer user_data)
{
GError * error = NULL;
GDBusProxy * proxy = g_dbus_proxy_new_for_bus_finish(res, &error);
if (error != NULL) {
if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
g_warning("Unable to get a proxy on accounts service for touch settings: %s",
error->message);
}
g_error_free(error);
return;
}
ImAccountsService * self = IM_ACCOUNTS_SERVICE(user_data);
ImAccountsServicePrivate * priv = im_accounts_service_get_instance_private(self);
/* Ensure we didn't get a proxy while we weren't looking */
g_clear_object(&priv->touch_settings);
priv->touch_settings = proxy;
}
/* When the user manager is loaded see if we have a user already loaded
along with. */
static void
on_user_manager_loaded (ActUserManager * manager, GParamSpec * pspect, gpointer user_data)
{
ImAccountsService * self = IM_ACCOUNTS_SERVICE(user_data);
ImAccountsServicePrivate * priv = im_accounts_service_get_instance_private(self);
ActUser * user = NULL;
g_debug("Accounts Manager Loaded");
user = act_user_manager_get_user(priv->user_manager, g_get_user_name());
if (user != NULL) {
user_changed(priv->user_manager, user, user_data);
}
}
/* Not the most testable way to do this but, it is a less invasive one, and we'll
probably restructure this codebase soonish */
/* Gets an account service wrapper reference, so then it can be free'd */
ImAccountsService *
im_accounts_service_ref_default (void)
{
static ImAccountsService * as = NULL;
if (as == NULL) {
as = IM_ACCOUNTS_SERVICE(g_object_new(IM_ACCOUNTS_SERVICE_TYPE, NULL));
g_object_add_weak_pointer(G_OBJECT(as), (gpointer *)&as);
return as;
}
return g_object_ref(as);
}
/* The draws attention setting is very legacy right now, we've patched and not changed
things much. We're gonna do better in the future, this function abstracts out the ugly */
void
im_accounts_service_set_draws_attention (ImAccountsService * service, gboolean draws_attention)
{
g_return_if_fail(IM_IS_ACCOUNTS_SERVICE(service));
ImAccountsService * self = IM_ACCOUNTS_SERVICE(service);
ImAccountsServicePrivate * priv = im_accounts_service_get_instance_private(self);
if (priv->touch_settings == NULL) {
return;
}
g_dbus_connection_call(g_dbus_proxy_get_connection(priv->touch_settings),
g_dbus_proxy_get_name(priv->touch_settings),
g_dbus_proxy_get_object_path(priv->touch_settings),
"org.freedesktop.Accounts.User",
"SetXHasMessages",
g_variant_new("(b)", draws_attention),
NULL, /* reply */
G_DBUS_CALL_FLAGS_NONE,
-1, /* timeout */
priv->cancel, /* cancellable */
NULL, NULL); /* cb */
}
/* Looks at the property that is set by settings. We default to off in any case
that we can or we don't know what the state is. */
gboolean
im_accounts_service_get_show_on_greeter (ImAccountsService * service)
{
g_return_val_if_fail(IM_IS_ACCOUNTS_SERVICE(service), FALSE);
ImAccountsService * self = IM_ACCOUNTS_SERVICE(service);
ImAccountsServicePrivate * priv = im_accounts_service_get_instance_private(self);
if (priv->touch_settings == NULL) {
return FALSE;
}
GVariant * val = g_dbus_proxy_get_cached_property(priv->touch_settings, "MessagesWelcomeScreen");
if (val == NULL) {
return FALSE;
}
gboolean retval = g_variant_get_boolean(val);
g_variant_unref(val);
return retval;
}