From 192be127691af87a88f4ac15d4fe3dd9296499b0 Mon Sep 17 00:00:00 2001 From: Charles Kerr Date: Tue, 12 Jun 2012 00:39:31 -0500 Subject: use GDBus in users-service-dbus.c... major rewrite here. --- src/Makefile.am | 130 +-- src/accounts-service.xml | 194 ----- src/dialog.c | 47 +- src/display-manager.xml | 14 +- src/gtk-logout-helper.c | 2 +- src/lock-helper.c | 83 +- src/org.freedesktop.Accounts.User.xml | 744 ++++++++++++++++ src/org.freedesktop.Accounts.xml | 194 +++++ src/org.freedesktop.ConsoleKit.Seat.xml | 2 +- src/session-service.c | 10 - src/settings-helper.c | 3 - src/settings-helper.h | 3 - src/upower.xml | 2 +- src/user-menu-mgr.c | 206 +++-- src/users-service-dbus.c | 1417 +++++++++++++++---------------- src/users-service-dbus.h | 94 +- 16 files changed, 2027 insertions(+), 1118 deletions(-) delete mode 100644 src/accounts-service.xml create mode 100644 src/org.freedesktop.Accounts.User.xml create mode 100644 src/org.freedesktop.Accounts.xml diff --git a/src/Makefile.am b/src/Makefile.am index cfe083c..55262a1 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -23,53 +23,77 @@ libsession_la_SOURCES = \ dbus-shared-names.h \ dbusmenu-shared.h \ user-widget.c \ - user-widget.h \ - accounts-service-client.h + user-widget.h libsession_la_CFLAGS = \ $(APPLET_CFLAGS) \ $(COVERAGE_CFLAGS) \ - -Wall -Werror \ + -Wall -Wunused \ -DG_LOG_DOMAIN=\"Indicator-Session\" libsession_la_LIBADD = $(APPLET_LIBS) libsession_la_LDFLAGS = \ $(COVERAGE_LDFLAGS) \ -module -avoid-version -consolekit-manager-client.h: $(srcdir)/org.freedesktop.ConsoleKit.Manager.xml - dbus-binding-tool \ - --prefix=_consolekit_manager_client \ - --mode=glib-client \ - --output=consolekit-manager-client.h \ - $(srcdir)/org.freedesktop.ConsoleKit.Manager.xml - -consolekit-seat-client.h: $(srcdir)/org.freedesktop.ConsoleKit.Seat.xml - dbus-binding-tool \ - --prefix=_consolekit_seat_client \ - --mode=glib-client \ - --output=consolekit-seat-client.h \ - $(srcdir)/org.freedesktop.ConsoleKit.Seat.xml - -consolekit-session-client.h: $(srcdir)/org.freedesktop.ConsoleKit.Session.xml - dbus-binding-tool \ - --prefix=_consolekit_session_client \ - --mode=glib-client \ - --output=consolekit-session-client.h \ - $(srcdir)/org.freedesktop.ConsoleKit.Session.xml - -display-manager-client.h: $(srcdir)/display-manager.xml - dbus-binding-tool \ - --prefix=_gdm_local_display_factory_client \ - --mode=glib-client \ - --output=display-manager-client.h \ - $(srcdir)/display-manager.xml - -accounts-service-client.h: $(srcdir)/accounts-service.xml - dbus-binding-tool \ - --prefix=_accounts_service_client \ - --mode=glib-client \ - --output=accounts-service-client.h \ - $(srcdir)/accounts-service.xml +dbus_display_manager_sources = \ + dbus-display-manager.c \ + dbus-display-manager.h +$(dbus_display_manager_sources): display-manager.xml + gdbus-codegen \ + --interface-prefix org.freedesktop \ + --generate-c-code dbus-display-manager \ + $^ + +dbus_consolekit_manager_sources = \ + dbus-consolekit-manager.c \ + dbus-consolekit-manager.h + +$(dbus_consolekit_manager_sources): org.freedesktop.ConsoleKit.Manager.xml + gdbus-codegen \ + --interface-prefix org.freedesktop \ + --generate-c-code dbus-consolekit-manager \ + $^ + +dbus_consolekit_seat_sources = \ + dbus-consolekit-seat.c \ + dbus-consolekit-seat.h + +$(dbus_consolekit_seat_sources): org.freedesktop.ConsoleKit.Seat.xml + gdbus-codegen \ + --interface-prefix org.freedesktop \ + --generate-c-code dbus-consolekit-seat \ + $^ + +dbus_consolekit_session_sources = \ + dbus-consolekit-session.c \ + dbus-consolekit-session.h + +$(dbus_consolekit_session_sources): org.freedesktop.ConsoleKit.Session.xml + gdbus-codegen \ + --interface-prefix org.freedesktop \ + --generate-c-code dbus-consolekit-session \ + $^ + +dbus_accounts_sources = \ + dbus-accounts.c \ + dbus-accounts.h + +$(dbus_accounts_sources): org.freedesktop.Accounts.xml + gdbus-codegen \ + --interface-prefix org.freedesktop \ + --generate-c-code dbus-accounts \ + $^ + +dbus_user_sources = \ + dbus-user.c \ + dbus-user.h + +$(dbus_user_sources): org.freedesktop.Accounts.User.xml + gdbus-codegen \ + --interface-prefix org.freedesktop \ + --generate-c-code dbus-user \ + $^ + dbus_upower_sources = \ dbus-upower.c \ dbus-upower.h @@ -96,7 +120,13 @@ gen-%.xml.h: %.xml ################# indicator_session_service_SOURCES = \ + $(dbus_accounts_sources) \ + $(dbus_consolekit_manager_sources) \ + $(dbus_consolekit_seat_sources) \ + $(dbus_consolekit_session_sources) \ + $(dbus_display_manager_sources) \ $(dbus_upower_sources) \ + $(dbus_user_sources) \ lock-helper.c \ lock-helper.h \ session-service.c \ @@ -116,7 +146,7 @@ indicator_session_service_CFLAGS = \ $(SESSIONSERVICE_CFLAGS) \ $(GCONF_CFLAGS) \ -DLIBEXECDIR=\"$(libexecdir)\" \ - -Wall -Werror \ + -Wall \ -DG_LOG_DOMAIN=\"Indicator-Session\" \ $(COVERAGE_CFLAGS) indicator_session_service_LDADD = \ @@ -131,6 +161,7 @@ indicator_session_service_LDFLAGS = \ if BUILD_GTKLOGOUTHELPER gtk_logout_helper_SOURCES = \ + $(dbus_consolekit_manager_sources) \ gtk-logout-helper.c \ settings-helper.c \ settings-helper.h \ @@ -142,7 +173,7 @@ gtk_logout_helper_CFLAGS = \ $(GTKLOGOUTHELPER_CFLAGS) \ $(GCONF_CFLAGS) \ $(COVERAGE_CFLAGS) \ - -Wall -Werror \ + -Wall \ -DINDICATOR_ICONS_DIR="\"$(INDICATORICONSDIR)\"" gtk_logout_helper_LDADD = \ @@ -160,23 +191,24 @@ endif ############### BUILT_SOURCES = \ + $(dbus_accounts_sources) \ + $(dbus_consolekit_manager_sources) \ + $(dbus_consolekit_seat_sources) \ + $(dbus_consolekit_session_sources) \ + $(dbus_display_manager_sources) \ $(dbus_upower_sources) \ - consolekit-manager-client.h \ - consolekit-seat-client.h \ - consolekit-session-client.h \ - display-manager-client.h \ + $(dbus_user_sources) \ gen-session-dbus.xml.c \ - gen-session-dbus.xml.h \ - accounts-service-client.h + gen-session-dbus.xml.h EXTRA_DIST += \ + display-manager.xml \ + org.freedesktop.Accounts.User.xml \ + org.freedesktop.Accounts.xml \ org.freedesktop.ConsoleKit.Manager.xml \ org.freedesktop.ConsoleKit.Seat.xml \ org.freedesktop.ConsoleKit.Session.xml \ - display-manager.xml \ session-dbus.xml \ - upower.xml \ - accounts-service.xml \ - accounts-service-user.xml + upower.xml CLEANFILES += $(BUILT_SOURCES) diff --git a/src/accounts-service.xml b/src/accounts-service.xml deleted file mode 100644 index 9c19761..0000000 --- a/src/accounts-service.xml +++ /dev/null @@ -1,194 +0,0 @@ - - - - - - - - - - Object paths of cached users - - - - - - Lists users which have logged into the system locally before. - This is not meant to return an exhaustive list of all users. - It is possible for FindUserByName() - to return a user that's not on the list. - - - - - - - - - The uid to look up - - - Object path of user - - - - - - Finds a user by uid. - - - - if no user with the given uid exists - - - - - - - - The username to look up - - - Object path of user - - - - - - Finds a user by its username. - - - - if no user with the given username exists - - - - - - - - The username for the new user - - - - The real name for the new user - - - Object path of the new user - - - - The account type, encoded as an integer - - - - - - Creates a new user account. - - - The accountType argument can take the following values: - - - - 0 - Standard user - - - 1 - Administrator - - - 2 - Supervised user - - - - - The caller needs the org.freedesktop.accounts.user-administration PolicyKit authorization. - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - - The uid to delete - - - Whether to remove the users files - - - - - - Deletes a user account. - - - - The caller needs the org.freedesktop.accounts.user-administration PolicyKit authorization. - - - if the caller lacks the appropriate PolicyKit authorization - if the operation failed - - - - - - - Object path of the user that was added. - - - - - Emitted when a user is added. - - - - - - - - Object path of the user that was deleted. - - - - - Emitted when a user is deleted. - - - - - - - - Object path of the user that was changed. - - - - - Emitted when a user is changed. - - - - - - - - - - The version of the running daemon. - - - - - - - diff --git a/src/dialog.c b/src/dialog.c index 4b139ca..5686a95 100644 --- a/src/dialog.c +++ b/src/dialog.c @@ -26,7 +26,7 @@ with this program. If not, see . #include -#include "consolekit-manager-client.h" +#include "dbus-consolekit-manager.h" #include "dialog.h" /* Strings */ @@ -137,30 +137,31 @@ check_restart_required (void) static gboolean ck_check_allowed (LogoutDialogType type) { - DBusGConnection * system_bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, NULL); - g_return_val_if_fail(system_bus != NULL, TRUE); - - DBusGProxy * ck_proxy = dbus_g_proxy_new_for_name (system_bus, - "org.freedesktop.ConsoleKit", - "/org/freedesktop/ConsoleKit/Manager", - "org.freedesktop.ConsoleKit.Manager"); - g_return_val_if_fail(ck_proxy != NULL, TRUE); - - gboolean retval = TRUE; - switch (type) { - case LOGOUT_DIALOG_TYPE_RESTART: - org_freedesktop_ConsoleKit_Manager_can_restart(ck_proxy, &retval, NULL); - break; - case LOGOUT_DIALOG_TYPE_SHUTDOWN: - org_freedesktop_ConsoleKit_Manager_can_stop(ck_proxy, &retval, NULL); - break; - default: - break; - } + gboolean allowed = TRUE; + + ConsoleKitManager * ck_proxy = console_kit_manager_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + "org.freedesktop.ConsoleKit", + "/org/freedesktop/ConsoleKit/Manager", + NULL, + NULL); + if (ck_proxy != NULL) + { + switch (type) { + case LOGOUT_DIALOG_TYPE_RESTART: + console_kit_manager_call_can_restart_sync (ck_proxy, &allowed, NULL, NULL); + break; + case LOGOUT_DIALOG_TYPE_SHUTDOWN: + console_kit_manager_call_can_stop_sync (ck_proxy, &allowed, NULL, NULL); + break; + default: + break; + } - g_object_unref(ck_proxy); + g_object_unref(ck_proxy); + } - return retval; + return allowed; } LogoutDialog * diff --git a/src/display-manager.xml b/src/display-manager.xml index 92f5e05..07b5f29 100644 --- a/src/display-manager.xml +++ b/src/display-manager.xml @@ -1,20 +1,30 @@ + + + + + + + - + - + + + + diff --git a/src/gtk-logout-helper.c b/src/gtk-logout-helper.c index f5c11ba..8b8ff8f 100644 --- a/src/gtk-logout-helper.c +++ b/src/gtk-logout-helper.c @@ -24,8 +24,8 @@ with this program. If not, see . #include #include #include -#include #include +#include #include "dialog.h" #include "settings-helper.h" diff --git a/src/lock-helper.c b/src/lock-helper.c index 8eae674..11bcbd1 100644 --- a/src/lock-helper.c +++ b/src/lock-helper.c @@ -21,13 +21,13 @@ with this program. If not, see . #include #include -#include #include "lock-helper.h" #define SCREENSAVER_SCHEMA "org.gnome.desktop.screensaver" #define SCREENSAVER_LOCK_ENABLED_KEY "lock-enabled" -static DBusGProxy * gss_proxy = NULL; +static GDBusProxy * gss_proxy = NULL; + static GMainLoop * gss_mainloop = NULL; static gboolean is_guest = FALSE; @@ -52,16 +52,29 @@ will_lock_screen (void) return g_settings_get_boolean (settings, SCREENSAVER_LOCK_ENABLED_KEY); } -/* When the screensave go active, if we've got a mainloop - running we should quit it. */ +/* When the screensave goes active, + if we've got a mainloop running we should quit it. */ static void -gss_active_changed (DBusGProxy * proxy, gboolean active, gpointer data) +on_gss_signal (GDBusProxy *proxy, + gchar *sender_name, + gchar *signal_name, + GVariant *parameters, + gpointer user_data) { - if (active && gss_mainloop != NULL) { - g_main_loop_quit(gss_mainloop); + g_debug ("%s sender_name: %s", G_STRLOC, sender_name); + g_debug ("%s signal_name: %s", G_STRLOC, signal_name); + + if (!g_strcmp0 (signal_name, "ActiveChanged")) + { + gboolean active = FALSE; + g_variant_get_child (parameters, 0, "b", &active); + g_debug ("%s active: %i", G_STRLOC, active); + + if (active && gss_mainloop != NULL) + { + g_main_loop_quit(gss_mainloop); + } } - - return; } static gboolean @@ -72,7 +85,7 @@ get_greeter_mode (void) return (g_strcmp0(var, "1") == 0); } -/* Build the gss proxy and set up it's signals */ +/* Build the gss proxy and set up its signals */ void build_gss_proxy (void) { @@ -80,17 +93,23 @@ build_gss_proxy (void) if (get_greeter_mode ()) return; /* Don't start/lock the screensaver from the login screen */ - DBusGConnection * session_bus = dbus_g_bus_get(DBUS_BUS_SESSION, NULL); - g_return_if_fail(session_bus != NULL); - - gss_proxy = dbus_g_proxy_new_for_name(session_bus, - "org.gnome.ScreenSaver", - "/", - "org.gnome.ScreenSaver"); - g_return_if_fail(gss_proxy != NULL); - - dbus_g_proxy_add_signal(gss_proxy, "ActiveChanged", G_TYPE_BOOLEAN, G_TYPE_INVALID); - dbus_g_proxy_connect_signal(gss_proxy, "ActiveChanged", G_CALLBACK(gss_active_changed), NULL, NULL); + + GError * error = NULL; + gss_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.gnome.ScreenSaver", + "/", + "org.gnome.ScreenSaver", + NULL, + &error); + if (error != NULL) { + g_message ("Unable to get ScreenSaver proxy: %s", error->message); + g_error_free (error); + } + + g_return_if_fail (gss_proxy != NULL); + g_signal_connect (gss_proxy, "g-signal", G_CALLBACK(on_gss_signal), NULL); } return; @@ -113,8 +132,8 @@ activate_timeout (gpointer data) return FALSE; } -/* A fun little function to actually lock the screen. If, - that's what you want, let's do it! */ +/* A fun little function to actually lock the screen. + If that's what you want, let's do it! */ void lock_screen (DbusmenuMenuitem * mi, guint timestamp, gpointer data) { @@ -123,11 +142,19 @@ lock_screen (DbusmenuMenuitem * mi, guint timestamp, gpointer data) build_gss_proxy(); g_return_if_fail(gss_proxy != NULL); - dbus_g_proxy_call_no_reply(gss_proxy, - "Lock", - G_TYPE_INVALID, - G_TYPE_INVALID); - + GError * error = NULL; + GVariant * ret = g_dbus_proxy_call_sync (gss_proxy, + "Lock", + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + g_variant_unref (ret); + if (error != NULL) { + g_warning ("Unable to lock: %s", error->message); + g_error_free (error); + } if (gss_mainloop == NULL) { gss_mainloop = g_main_loop_new(NULL, FALSE); } diff --git a/src/org.freedesktop.Accounts.User.xml b/src/org.freedesktop.Accounts.User.xml new file mode 100644 index 0000000..53f54d4 --- /dev/null +++ b/src/org.freedesktop.Accounts.User.xml @@ -0,0 +1,744 @@ + + + + + + + + + + + The new username. + + + + + + + Sets the users username. Note that it is usually not allowed + to have multiple users with the same username. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To change the username of any user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new name, typically in the form "Firstname Lastname". + + + + + + + Sets the users real name. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change his own name + + + org.freedesktop.accounts.user-administration + To change the name of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new email address. + + + + + + + Sets the users email address. + + + Note that setting an email address in the AccountsService is + not the same as configuring a mail client. Mail clients might + default to email address that is configured here, though. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change his own email address + + + org.freedesktop.accounts.user-administration + To change the email address of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new language, as a locale specification like "de_DE.UTF-8". + + + + + + + Sets the users language. + + + The expectation is that display managers will start the + users session with this locale. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change his own language + + + org.freedesktop.accounts.user-administration + To change the language of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + + The new xsession to start (e.g. "gnome") + + + + + + + Sets the users x session. + + + The expectation is that display managers will log the user in to this + specified session, if available. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change his own language + + + org.freedesktop.accounts.user-administration + To change the language of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new location as a freeform string. + + + + + + + Sets the users location. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change his own location + + + org.freedesktop.accounts.user-administration + To change the location of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new homedir as an absolute path. + + + + + + + Sets the users home directory. + + + Note that changing the users home directory moves all the content + from the old location to the new one, and is potentially an + expensive operation. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To change the home directory of a user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new user shell. + + + + + + + Sets the users shell. + + + Note that setting the shell to a non-allowed program may + prevent the user from logging in. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To change the shell of a user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The absolute filename of a png file to use as the users icon. + + + + + + + Sets the users icon. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.change-own-user-data + To change his own icon + + + org.freedesktop.accounts.user-administration + To change the icon of another user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + Whether to lock or unlock the users account. + + + + + + + Locks or unlocks a users account. + + + Locking an account prevents the user from logging in. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To lock or unlock user accounts + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new account type, encoded as an integer: + + + 0 + Standard user + + + 1 + Administrator + + + + + + + + + Changes the users account type. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To change an account type + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The new password mode, encoded as an integer: + + + 0 + Regular password + + + 1 + Password must be set at next login + + + 2 + No password + + + + + + + + + Changes the users password mode. + + + Note that changing the password mode has the side-effect of + unlocking the account. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To change a users password mode + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + The crypted password. + + + + + + + The password hint. + + + + + + + Sets a new password for this user. + + + Note that setting a password has the side-effect of + unlocking the account. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.user-administration + To change the password of a user + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + + Whether to enable automatic login for this user. + + + + + + + Enables or disables automatic login for a user. + + + Note that usually only one user can have automatic login + enabled, so turning it on for a user will disable it for + the previously configured autologin user. + + + + The caller needs one of the following PolicyKit authorizations: + + + org.freedesktop.accounts.set-login-option + To change the login screen configuration + + + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + + The uid of the user. + + + + + + + + + + The username of the user. + + + + + + + + + + The users real name. + + + + + + + + + + The users account type, encoded as an integer: + + + 0 + Standard user + + + 1 + Administrator + + + + + + + + + + + + The users home directory. + + + + + + + + + + The users shell. + + + + + + + + + + The email address. + + + + + + + + + + The users language, as a locale specification like "de_DE.UTF-8". + + + + + + + + + + The users x session. + + + + + + + + + + The users location. + + + + + + + + + + How often the user has logged in. + + + + + + + + + + The filename of a png file containing the users icon. + + + + + + + + + + Whether the users account is locked. + + + + + + + + + + The password mode for the user account, encoded as an integer: + + + 0 + Regular password + + + 1 + Password must be set at next login + + + 2 + No password + + + + + + + + + + + + The password hint for the user. + + + + + + + + + + Whether automatic login is enabled for the user. + + + + + + + + + + Whether this is a 'system' account, like 'root' or 'nobody'. + System accounts should normally not appear in lists of + users, and ListCachedUsers will not include such accounts. + + + + + + + + + + Emitted when the user is changed. + + + + + + + diff --git a/src/org.freedesktop.Accounts.xml b/src/org.freedesktop.Accounts.xml new file mode 100644 index 0000000..9c19761 --- /dev/null +++ b/src/org.freedesktop.Accounts.xml @@ -0,0 +1,194 @@ + + + + + + + + + + Object paths of cached users + + + + + + Lists users which have logged into the system locally before. + This is not meant to return an exhaustive list of all users. + It is possible for FindUserByName() + to return a user that's not on the list. + + + + + + + + + The uid to look up + + + Object path of user + + + + + + Finds a user by uid. + + + + if no user with the given uid exists + + + + + + + + The username to look up + + + Object path of user + + + + + + Finds a user by its username. + + + + if no user with the given username exists + + + + + + + + The username for the new user + + + + The real name for the new user + + + Object path of the new user + + + + The account type, encoded as an integer + + + + + + Creates a new user account. + + + The accountType argument can take the following values: + + + + 0 + Standard user + + + 1 + Administrator + + + 2 + Supervised user + + + + + The caller needs the org.freedesktop.accounts.user-administration PolicyKit authorization. + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + + The uid to delete + + + Whether to remove the users files + + + + + + Deletes a user account. + + + + The caller needs the org.freedesktop.accounts.user-administration PolicyKit authorization. + + + if the caller lacks the appropriate PolicyKit authorization + if the operation failed + + + + + + + Object path of the user that was added. + + + + + Emitted when a user is added. + + + + + + + + Object path of the user that was deleted. + + + + + Emitted when a user is deleted. + + + + + + + + Object path of the user that was changed. + + + + + Emitted when a user is changed. + + + + + + + + + + The version of the running daemon. + + + + + + + diff --git a/src/org.freedesktop.ConsoleKit.Seat.xml b/src/org.freedesktop.ConsoleKit.Seat.xml index d95990b..58c2ce7 100644 --- a/src/org.freedesktop.ConsoleKit.Seat.xml +++ b/src/org.freedesktop.ConsoleKit.Seat.xml @@ -101,7 +101,7 @@ seat at a time. - + Session ID diff --git a/src/session-service.c b/src/session-service.c index 1dd1e14..6a07f29 100644 --- a/src/session-service.c +++ b/src/session-service.c @@ -32,9 +32,6 @@ with this program. If not, see . #include #include -#include -#include - #include #include #include @@ -51,13 +48,6 @@ with this program. If not, see . #include "device-menu-mgr.h" #include "session-dbus.h" -typedef struct _ActivateData ActivateData; -struct _ActivateData -{ - UsersServiceDbus *service; - UserData *user; -}; - //static UsersServiceDbus *dbus_interface = NULL; static SessionDbus *session_dbus = NULL; static GMainLoop * mainloop = NULL; diff --git a/src/settings-helper.c b/src/settings-helper.c index 007f83f..6a09498 100644 --- a/src/settings-helper.c +++ b/src/settings-helper.c @@ -22,9 +22,6 @@ with this program. If not, see . #include #include -#include -#include - #include #include diff --git a/src/settings-helper.h b/src/settings-helper.h index ea0c99f..f50c4d8 100644 --- a/src/settings-helper.h +++ b/src/settings-helper.h @@ -25,9 +25,6 @@ with this program. If not, see . #include -#include -#include - #include #include diff --git a/src/upower.xml b/src/upower.xml index a4066ff..18d5fbd 100644 --- a/src/upower.xml +++ b/src/upower.xml @@ -86,7 +86,7 @@ method return sender=:1.386 -> dest=:1.451 reply_serial=2 - + Object path of device that was changed. diff --git a/src/user-menu-mgr.c b/src/user-menu-mgr.c index 00ad8a2..f44f888 100644 --- a/src/user-menu-mgr.c +++ b/src/user-menu-mgr.c @@ -28,7 +28,7 @@ with this program. If not, see . struct ActivateUserSessionData { UserMenuMgr * menu_mgr; - UserData * user; + AccountsUser * user; }; struct _UserMenuMgr @@ -36,6 +36,7 @@ struct _UserMenuMgr GObject parent_instance; UsersServiceDbus* users_dbus_interface; DbusmenuMenuitem* root_item; + DbusmenuMenuitem * guest_mi; SessionDbus* session_dbus_interface; GSettings * lockdown_settings; gboolean greeter_mode; @@ -59,6 +60,13 @@ static void user_menu_mgr_rebuild_items (UserMenuMgr *self); static void user_change (UsersServiceDbus *service, const gchar *user_id, gpointer user_data); + +static void on_guest_logged_in_changed (UsersServiceDbus * users_dbus, + UserMenuMgr * self); + +static void on_user_logged_in_changed (UsersServiceDbus * users_dbus, + AccountsUser * user, + UserMenuMgr * self); static gboolean is_this_guest_session (void); static void activate_guest_session (DbusmenuMenuitem * mi, guint timestamp, @@ -67,6 +75,9 @@ static void activate_guest_session (DbusmenuMenuitem * mi, G_DEFINE_TYPE (UserMenuMgr, user_menu_mgr, G_TYPE_OBJECT); +/*** +**** +***/ static void user_menu_mgr_init (UserMenuMgr *self) @@ -74,14 +85,14 @@ user_menu_mgr_init (UserMenuMgr *self) self->lockdown_settings = g_settings_new (LOCKDOWN_SCHEMA); self->users_dbus_interface = g_object_new (USERS_SERVICE_DBUS_TYPE, NULL); self->root_item = dbusmenu_menuitem_new (); - g_signal_connect (G_OBJECT (self->users_dbus_interface), - "user-added", - G_CALLBACK (user_change), - self); - g_signal_connect (G_OBJECT (self->users_dbus_interface), - "user-deleted", - G_CALLBACK (user_change), - self); + g_signal_connect (self->users_dbus_interface, "user-added", + G_CALLBACK (user_change), self); + g_signal_connect (self->users_dbus_interface, "user-deleted", + G_CALLBACK (user_change), self); + g_signal_connect (self->users_dbus_interface, "user-logged-in-changed", + G_CALLBACK(on_user_logged_in_changed), self); + g_signal_connect (self->users_dbus_interface, "guest-logged-in-changed", + G_CALLBACK(on_guest_logged_in_changed), self); } static void @@ -108,8 +119,67 @@ user_menu_mgr_class_init (UserMenuMgrClass *klass) object_class->finalize = user_menu_mgr_finalize; } +/*** +**** +***/ + +static GQuark +get_menuitem_quark (void) +{ + static GQuark q = 0; + + if (G_UNLIKELY(!q)) + { + q = g_quark_from_static_string ("menuitem"); + } + + return q; +} + +static DbusmenuMenuitem* +user_get_menuitem (AccountsUser * user) +{ + return g_object_get_qdata (G_OBJECT(user), get_menuitem_quark()); +} + +static void +user_set_menuitem (AccountsUser * user, DbusmenuMenuitem * mi) +{ + g_message ("%s %s() associating user %s with mi %p", G_STRLOC, G_STRFUNC, accounts_user_get_user_name(user), mi); + g_object_set_qdata_full (G_OBJECT(user), get_menuitem_quark(), g_object_ref(G_OBJECT(mi)), g_object_unref); +} + +static GQuark +get_name_collision_quark (void) +{ + static GQuark q = 0; + + if (G_UNLIKELY(!q)) + { + q = g_quark_from_static_string ("name-collision"); + } + + return q; +} + +static gboolean +get_user_name_collision (AccountsUser * user) +{ + return g_object_get_qdata (G_OBJECT(user), get_name_collision_quark()) != NULL; +} + +static void +set_user_name_collision (AccountsUser * user, gboolean b) +{ + g_object_set_qdata (G_OBJECT(user), get_name_collision_quark(), GINT_TO_POINTER(b)); +} + +/*** +**** +***/ + static DbusmenuMenuitem* -create_user_menuitem (UserMenuMgr * menu_mgr, UserData * user) +create_user_menuitem (UserMenuMgr * menu_mgr, AccountsUser * user) { DbusmenuMenuitem * mi = dbusmenu_menuitem_new (); dbusmenu_menuitem_property_set (mi, @@ -117,27 +187,30 @@ create_user_menuitem (UserMenuMgr * menu_mgr, UserData * user) USER_ITEM_TYPE); /* set the name property */ - char * str = user->real_name_conflict - ? g_strdup_printf ("%s (%s)", user->real_name, user->user_name) - : g_strdup (user->real_name); + const gchar * const real_name = accounts_user_get_real_name (user); + const gchar * const user_name = accounts_user_get_user_name (user); + char * str = get_user_name_collision (user) + ? g_strdup_printf ("%s (%s)", real_name, user_name) + : g_strdup (real_name); dbusmenu_menuitem_property_set (mi, USER_ITEM_PROP_NAME, str); g_free (str); /* set the logged-in property */ + const gboolean is_logged_in = users_service_dbus_is_user_logged_in (menu_mgr->users_dbus_interface, user); dbusmenu_menuitem_property_set_bool (mi, USER_ITEM_PROP_LOGGED_IN, - user->sessions != NULL); + is_logged_in); /* set the icon property */ - str = user->icon_file; - if (!str || !*str) - str = USER_ITEM_ICON_DEFAULT; - dbusmenu_menuitem_property_set (mi, USER_ITEM_PROP_ICON, str); + const gchar * icon_str = accounts_user_get_icon_file (user); + if (!icon_str || !*icon_str) + icon_str = USER_ITEM_ICON_DEFAULT; + dbusmenu_menuitem_property_set (mi, USER_ITEM_PROP_ICON, icon_str); /* set the is-current-user property */ dbusmenu_menuitem_property_set_bool (mi, USER_ITEM_PROP_IS_CURRENT_USER, - !g_strcmp0 (user->user_name, g_get_user_name())); + !g_strcmp0 (user_name, g_get_user_name())); /* set the activate callback */ struct ActivateUserSessionData * data = g_new (struct ActivateUserSessionData, 1); @@ -148,10 +221,42 @@ create_user_menuitem (UserMenuMgr * menu_mgr, UserData * user) data, (GClosureNotify)g_free, 0); + /* give this AccountsUser a hook back to this menuitem */ + user_set_menuitem (user, mi); + /* done */ return mi; } +static void +on_guest_logged_in_changed (UsersServiceDbus * users_service_dbus, + UserMenuMgr * self) +{ + if (self->guest_mi != NULL) + { + const gboolean b = users_service_dbus_is_guest_logged_in (users_service_dbus); + dbusmenu_menuitem_property_set_bool (self->guest_mi, USER_ITEM_PROP_LOGGED_IN, b); + } +} + +/* When a user's login state changes, + update the corresponding menuitem's LOGGED_IN property */ +static void +on_user_logged_in_changed (UsersServiceDbus * users_service_dbus, + AccountsUser * user, + UserMenuMgr * self) +{ + DbusmenuMenuitem * mi = user_get_menuitem (user); +g_message ("%s %s() user %s corresponds to mi %p", G_STRLOC, G_STRFUNC, accounts_user_get_user_name(user), mi); + + if (mi != NULL) + { + const gboolean b = users_service_dbus_is_user_logged_in (users_service_dbus, user); +g_message ("setting %p USER_ITEM_PROP_LOGGED_IN to %d", mi, (int)b); + dbusmenu_menuitem_property_set_bool (mi, USER_ITEM_PROP_LOGGED_IN, b); + } +} + /* Builds up the menu for us */ static void user_menu_mgr_rebuild_items (UserMenuMgr *self) @@ -169,8 +274,8 @@ user_menu_mgr_rebuild_items (UserMenuMgr *self) g_list_foreach (children, (GFunc)g_object_unref, NULL); g_list_free (children); - /* Set to NULL just incase we don't end up building one */ - users_service_dbus_set_guest_item(self->users_dbus_interface, NULL); + /* Set to NULL in case we don't end up building one */ + self->guest_mi = NULL; /* Build all of the user switching items */ if (can_activate) @@ -201,24 +306,19 @@ user_menu_mgr_rebuild_items (UserMenuMgr *self) if ( !is_this_guest_session () && guest_enabled) { - DbusmenuMenuitem *guest_mi = NULL; - guest_mi = dbusmenu_menuitem_new (); - dbusmenu_menuitem_property_set (guest_mi, + self->guest_mi = dbusmenu_menuitem_new (); + dbusmenu_menuitem_property_set (self->guest_mi, DBUSMENU_MENUITEM_PROP_TYPE, USER_ITEM_TYPE); - dbusmenu_menuitem_property_set (guest_mi, + dbusmenu_menuitem_property_set (self->guest_mi, USER_ITEM_PROP_NAME, _("Guest Session")); - dbusmenu_menuitem_property_set_bool (guest_mi, - USER_ITEM_PROP_LOGGED_IN, - FALSE); - dbusmenu_menuitem_child_append (self->root_item, guest_mi); - g_signal_connect (G_OBJECT (guest_mi), + on_guest_logged_in_changed (self->users_dbus_interface, self); + dbusmenu_menuitem_child_append (self->root_item, self->guest_mi); + g_signal_connect (G_OBJECT (self->guest_mi), DBUSMENU_MENUITEM_SIGNAL_ITEM_ACTIVATED, G_CALLBACK (activate_guest_session), self); - users_service_dbus_set_guest_item (self->users_dbus_interface, - guest_mi); } else{ session_dbus_set_users_real_name (self->session_dbus_interface, @@ -231,14 +331,16 @@ user_menu_mgr_rebuild_items (UserMenuMgr *self) for (u = users; u != NULL; u = g_list_next (u)) { - UserData * user = u->data; + AccountsUser * user = u->data; DbusmenuMenuitem * mi = create_user_menuitem (self, user); dbusmenu_menuitem_child_append (self->root_item, mi); - if (!g_strcmp0 (user->user_name, g_get_user_name())) + const char * const user_name = accounts_user_get_user_name (user); + if (!g_strcmp0 (user_name, g_get_user_name())) { - session_dbus_set_users_real_name (self->session_dbus_interface, user->real_name); + const char * const real_name = accounts_user_get_real_name (user); + session_dbus_set_users_real_name (self->session_dbus_interface, real_name); } } @@ -305,20 +407,21 @@ activate_user_session (DbusmenuMenuitem *mi, guint timestamp, gpointer user_data /* Comparison function to look into the UserData struct to compare by using the username value */ static gint -compare_users_by_username (gconstpointer a, gconstpointer b) +compare_users_by_username (gconstpointer ga, gconstpointer gb) { - UserData *user1 = (UserData *)a; - UserData *user2 = (UserData *)b; + AccountsUser * a = ACCOUNTS_USER(ga); + AccountsUser * b = ACCOUNTS_USER(gb); - gint retval = g_strcmp0 (user1->real_name, user2->real_name); + const int ret = g_strcmp0 (accounts_user_get_real_name (a), + accounts_user_get_real_name (b)); - /* If they're the same, they're both in conflict. */ - if (retval == 0) { - user1->real_name_conflict = TRUE; - user2->real_name_conflict = TRUE; - } + if (!ret) /* names are the same, so both have a name collision */ + { + set_user_name_collision (a, TRUE); + set_user_name_collision (b, TRUE); + } - return retval; + return ret; } static void @@ -334,15 +437,16 @@ activate_user_accounts (DbusmenuMenuitem *mi, } } -/* Signal called when a user is added. It updates the count and - rebuilds the menu */ +/* Signal called when a user is added. + It updates the count and rebuilds the menu */ static void -user_change (UsersServiceDbus *service, - const gchar *user_id, +user_change (UsersServiceDbus *service G_GNUC_UNUSED, + const gchar *user_id G_GNUC_UNUSED, gpointer user_data) { - g_return_if_fail (USER_IS_MENU_MGR (user_data)); - UserMenuMgr* user_mgr = USER_MENU_MGR(user_data); + UserMenuMgr* user_mgr = USER_MENU_MGR (user_data); + g_return_if_fail (user_mgr != NULL); + user_menu_mgr_rebuild_items (user_mgr); } diff --git a/src/users-service-dbus.c b/src/users-service-dbus.c index e6d094c..382c2dc 100644 --- a/src/users-service-dbus.c +++ b/src/users-service-dbus.c @@ -4,6 +4,7 @@ * * Authors: * Cody Russell + * Charles Kerr * * 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 @@ -19,946 +20,938 @@ */ #ifdef HAVE_CONFIG_H -#include "config.h" + #include "config.h" #endif -#include +#include + #include -#include +#include -#include -#include -#include +#include /* getpwuid() */ #include "dbus-shared-names.h" -#include "display-manager-client.h" +#include "dbus-accounts.h" +#include "dbus-consolekit-manager.h" +#include "dbus-consolekit-seat.h" +#include "dbus-consolekit-session.h" +#include "dbus-display-manager.h" +#include "dbus-user.h" #include "users-service-dbus.h" -#include "accounts-service-client.h" -#include "consolekit-manager-client.h" -#include "consolekit-session-client.h" -#include "consolekit-seat-client.h" #define CK_ADDR "org.freedesktop.ConsoleKit" #define CK_SESSION_IFACE "org.freedesktop.ConsoleKit.Session" +/** +*** +**/ -static void users_service_dbus_class_init (UsersServiceDbusClass *klass); -static void users_service_dbus_init (UsersServiceDbus *self); -static void users_service_dbus_dispose (GObject *object); -static void users_service_dbus_finalize (GObject *object); -static void create_display_manager_proxy (UsersServiceDbus *self); -static void create_accounts_service_proxy (UsersServiceDbus *self); -static void create_seat_proxy (UsersServiceDbus *self); -static void create_ck_proxy (UsersServiceDbus *self); -static void create_cksession_proxy (UsersServiceDbus *self); -static gchar *get_seat (UsersServiceDbus *service); -static void user_added (DBusGProxy *proxy, - const gchar *user_id, - gpointer user_data); -static void user_deleted (DBusGProxy *proxy, - const gchar *user_id, - gpointer user_data); -static void user_changed (DBusGProxy *proxy, - gpointer user_data); -static void seat_proxy_session_added (DBusGProxy *seat_proxy, - const gchar *session_id, - UsersServiceDbus *service); -static void seat_proxy_session_removed (DBusGProxy *seat_proxy, - const gchar *session_id, - UsersServiceDbus *service); -static void sync_users (UsersServiceDbus *self); -static gboolean do_add_session (UsersServiceDbus *service, - UserData *user, - const gchar *ssid); -static gchar * get_seat_internal (DBusGProxy *proxy); - -/* Private */ -typedef struct _UsersServiceDbusPrivate UsersServiceDbusPrivate; +static void init_users (UsersServiceDbus * self); -struct _UsersServiceDbusPrivate -{ - GHashTable *users; - gint count; - gchar *seat; - gchar *ssid; +static gchar* get_seat (UsersServiceDbus * service); - DBusGConnection *system_bus; +static void on_user_added (Accounts * o, + const gchar * user_object_path, + UsersServiceDbus * service); - DBusGProxy *accounts_service_proxy; - DBusGProxy *display_manager_proxy; - DBusGProxy *display_manager_props_proxy; - DBusGProxy *ck_proxy; - DBusGProxy *seat_proxy; - DBusGProxy *session_proxy; +static void on_user_deleted (Accounts * o, + const gchar * user_object_path, + UsersServiceDbus * service); - GHashTable *exclusions; - GHashTable *sessions; +static void on_session_added (ConsoleKitSeat * seat, + const gchar * ssid, + UsersServiceDbus * service); - DbusmenuMenuitem * guest_item; - gchar * guest_session_id; - gboolean guest_session_enabled; -}; - -#define USERS_SERVICE_DBUS_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), USERS_SERVICE_DBUS_TYPE, UsersServiceDbusPrivate)) - -/* Signals */ -enum { - USER_ADDED, - USER_DELETED, - LAST_SIGNAL -}; +static void on_session_removed (ConsoleKitSeat * seat, + const gchar * ssid, + UsersServiceDbus * service); -static guint signals[LAST_SIGNAL] = { 0 }; +static void on_session_list (ConsoleKitSeat * seat, + GAsyncResult * result, + UsersServiceDbus * service); -/* GObject Boilerplate */ -G_DEFINE_TYPE (UsersServiceDbus, users_service_dbus, G_TYPE_OBJECT); +/*** +**** Priv Struct +***/ -static void -users_service_dbus_class_init (UsersServiceDbusClass *klass) +struct _UsersServiceDbusPrivate { - GObjectClass *object_class = G_OBJECT_CLASS (klass); + gchar * seat; + gchar * guest_ssid; - g_type_class_add_private (object_class, sizeof (UsersServiceDbusPrivate)); + /* ssid -> AccountsUser lookup */ + GHashTable * sessions; - object_class->dispose = users_service_dbus_dispose; - object_class->finalize = users_service_dbus_finalize; + /* user object path -> AccountsUser lookup */ + GHashTable * users; - signals[USER_ADDED] = g_signal_new ("user-added", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (UsersServiceDbusClass, user_added), - NULL, NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, 1, G_TYPE_STRING); + GCancellable * cancellable; + ConsoleKitSeat * seat_proxy; + ConsoleKitManager * ck_manager_proxy; + Accounts * accounts_proxy; + DisplayManagerSeat * display_proxy; +}; - signals[USER_DELETED] = g_signal_new ("user-deleted", - G_TYPE_FROM_CLASS (klass), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (UsersServiceDbusClass, user_deleted), - NULL, NULL, - g_cclosure_marshal_VOID__STRING, - G_TYPE_NONE, 1, G_TYPE_STRING); -} +/*** +**** GObject +***/ -static void -users_service_dbus_init (UsersServiceDbus *self) +enum { - GError *error = NULL; - UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self); - - priv->users = NULL; - priv->count = 0; - priv->guest_item = NULL; - priv->guest_session_id = NULL; - - priv->guest_session_enabled = FALSE; - - /* Get the system bus */ - priv->system_bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error); - if (error != NULL) - { - g_error ("Unable to get system bus"); - g_error_free(error); - - return; - } - - priv->sessions = g_hash_table_new_full (g_str_hash, - g_str_equal, - g_free, - g_free); + USER_ADDED, + USER_DELETED, + USER_LOGGED_IN_CHANGED, + GUEST_LOGGED_IN_CHANGED, + N_SIGNALS +}; - priv->users = g_hash_table_new_full (g_str_hash, - g_str_equal, - g_free, - NULL); +static guint signals[N_SIGNALS] = { 0 }; - create_ck_proxy (self); - create_seat_proxy (self); - create_display_manager_proxy (self); - create_accounts_service_proxy (self); -} +G_DEFINE_TYPE (UsersServiceDbus, users_service_dbus, G_TYPE_OBJECT); static void users_service_dbus_dispose (GObject *object) { - G_OBJECT_CLASS (users_service_dbus_parent_class)->dispose (object); -} - -static void -users_service_dbus_finalize (GObject *object) -{ - UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (object); - - if (priv->guest_session_id != NULL) { - g_free(priv->guest_session_id); - priv->guest_session_id = NULL; - } - - G_OBJECT_CLASS (users_service_dbus_parent_class)->finalize (object); -} + UsersServiceDbusPrivate * priv = USERS_SERVICE_DBUS(object)->priv; + g_clear_object (&priv->accounts_proxy); + g_clear_object (&priv->display_proxy); + g_clear_object (&priv->seat_proxy); + g_clear_object (&priv->ck_manager_proxy); -static void -create_display_manager_proxy (UsersServiceDbus *self) -{ - UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self); - GError *error = NULL; - const gchar *seat = NULL; - - seat = g_getenv ("XDG_SEAT_PATH"); - g_debug ("CREATING DM PROXIES WITH %s", seat); - priv->display_manager_proxy = dbus_g_proxy_new_for_name (priv->system_bus, - "org.freedesktop.DisplayManager", - seat, - "org.freedesktop.DisplayManager.Seat"); - - priv->display_manager_props_proxy = dbus_g_proxy_new_for_name (priv->system_bus, - "org.freedesktop.DisplayManager", - seat, - "org.freedesktop.DBus.Properties"); - - - if (!priv->display_manager_proxy) + if (priv->cancellable != NULL) { - g_warning ("Failed to get DisplayManager seat proxy."); - return; + g_cancellable_cancel (priv->cancellable); + g_clear_object (&priv->cancellable); } - if (!priv->display_manager_props_proxy) - { - g_warning ("Failed to get DisplayManager Properties seat proxy."); - return; - } - - GValue has_guest_session = {0}; - g_value_init (&has_guest_session, G_TYPE_BOOLEAN); - if (!dbus_g_proxy_call (priv->display_manager_props_proxy, - "Get", - &error, - G_TYPE_STRING, - "org.freedesktop.DisplayManager.Seat", - G_TYPE_STRING, - "HasGuestAccount", - G_TYPE_INVALID, - G_TYPE_VALUE, - &has_guest_session, - G_TYPE_INVALID)) + + if (priv->users != NULL) { - g_warning ("Failed to get the HasGuestSession property from the DisplayManager Properties seat proxy. error: %s", error->message); - g_error_free (error); - return; + g_hash_table_destroy (priv->users); + priv->users = NULL; } - g_debug ("Does seat have a guest account = %i", g_value_get_boolean (&has_guest_session)); - priv->guest_session_enabled = g_value_get_boolean (&has_guest_session); -} -static void -create_accounts_service_proxy (UsersServiceDbus *self) -{ - UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self); - GPtrArray *users = g_ptr_array_new (); - GError *error = NULL; - - priv->accounts_service_proxy = dbus_g_proxy_new_for_name (priv->system_bus, - "org.freedesktop.Accounts", - "/org/freedesktop/Accounts", - "org.freedesktop.Accounts"); - - dbus_g_proxy_add_signal (priv->accounts_service_proxy, - "UserAdded", - DBUS_TYPE_G_OBJECT_PATH, - G_TYPE_INVALID); - - dbus_g_proxy_add_signal (priv->accounts_service_proxy, - "UserChanged", - DBUS_TYPE_G_OBJECT_PATH, - G_TYPE_INVALID); - - dbus_g_proxy_add_signal (priv->accounts_service_proxy, - "UserDeleted", - DBUS_TYPE_G_OBJECT_PATH, - G_TYPE_INVALID); - - dbus_g_proxy_connect_signal (priv->accounts_service_proxy, - "UserAdded", - G_CALLBACK (user_added), - self, - NULL); - - dbus_g_proxy_connect_signal (priv->accounts_service_proxy, - "UserDeleted", - G_CALLBACK (user_deleted), - self, - NULL); - - if (!org_freedesktop_Accounts_list_cached_users (priv->accounts_service_proxy, - &users, - &error)) + if (priv->sessions != NULL) { - g_warning ("failed to retrieve user count: %s", error->message); - g_error_free (error); - - return; + g_hash_table_destroy (priv->sessions); + priv->sessions = NULL; } - priv->count = users->len; - g_ptr_array_free (users, TRUE); - sync_users (self); + G_OBJECT_CLASS (users_service_dbus_parent_class)->dispose (object); } static void -create_ck_proxy (UsersServiceDbus *self) +users_service_dbus_finalize (GObject *object) { - UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self); + UsersServiceDbusPrivate * priv = USERS_SERVICE_DBUS(object)->priv; - priv->ck_proxy = dbus_g_proxy_new_for_name (priv->system_bus, - "org.freedesktop.ConsoleKit", - "/org/freedesktop/ConsoleKit/Manager", - "org.freedesktop.ConsoleKit.Manager"); + g_free (priv->guest_ssid); + g_free (priv->seat); - if (!priv->ck_proxy) - { - g_warning ("Failed to get ConsoleKit proxy."); - return; - } + G_OBJECT_CLASS (users_service_dbus_parent_class)->finalize (object); } -/* Get the initial sessions when starting up */ -static void -get_cksessions_cb (DBusGProxy *proxy, GPtrArray * sessions, GError * error, gpointer userdata) +static void +users_service_dbus_class_init (UsersServiceDbusClass *klass) { - if (error != NULL) { - g_warning("Unable to get initial sessions: %s", error->message); - return; - } + GObjectClass *object_class = G_OBJECT_CLASS (klass); - /* If there's no error we should at least get an - array of zero entries */ - g_return_if_fail(sessions != NULL); - g_debug("Got %d initial sessions", sessions->len); + g_type_class_add_private (object_class, sizeof (UsersServiceDbusPrivate)); - int i; - for (i = 0; i < sessions->len; i++) { - seat_proxy_session_added(proxy, g_ptr_array_index(sessions, i), USERS_SERVICE_DBUS(userdata)); - } + object_class->dispose = users_service_dbus_dispose; + object_class->finalize = users_service_dbus_finalize; - return; + signals[USER_ADDED] = g_signal_new ( + "user-added", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (UsersServiceDbusClass, user_added), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); + + signals[USER_DELETED] = g_signal_new ( + "user-deleted", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (UsersServiceDbusClass, user_deleted), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); + + signals[USER_LOGGED_IN_CHANGED] = g_signal_new ( + "user-logged-in-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (UsersServiceDbusClass, user_logged_in_changed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); + + signals[GUEST_LOGGED_IN_CHANGED] = g_signal_new ( + "guest-logged-in-changed", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (UsersServiceDbusClass, guest_logged_in_changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); } static void -create_seat_proxy (UsersServiceDbus *self) +users_service_dbus_init (UsersServiceDbus *self) { - UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self); - GError *error = NULL; + GError * error = NULL; + + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + USERS_SERVICE_DBUS_TYPE, + UsersServiceDbusPrivate); + + UsersServiceDbusPrivate * p = self->priv; - priv->seat = get_seat (self); - if (priv->seat == NULL) + p->cancellable = g_cancellable_new (); + + /* ssid -> AccountsUser */ + p->sessions = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + g_object_unref); + + /* user object path -> AccountsUser */ + p->users = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + g_object_unref); + + /** + *** create the consolekit manager proxy... + **/ + + p->ck_manager_proxy = console_kit_manager_proxy_new_for_bus_sync ( + G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + "org.freedesktop.ConsoleKit", + "/org/freedesktop/ConsoleKit/Manager", + NULL, + &error); + if (error != NULL) { - return; + g_warning ("%s: %s", G_STRLOC, error->message); + g_clear_error (&error); } - priv->seat_proxy = dbus_g_proxy_new_for_name_owner (priv->system_bus, - "org.freedesktop.ConsoleKit", - priv->seat, - "org.freedesktop.ConsoleKit.Seat", - &error); + p->seat = get_seat (self); - if (!priv->seat_proxy) + /** + *** create the consolekit seat proxy... + **/ + + if (p->seat != NULL) { + ConsoleKitSeat * proxy = console_kit_seat_proxy_new_for_bus_sync ( + G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + "org.freedesktop.ConsoleKit", + p->seat, + NULL, + &error); + if (error != NULL) { g_warning ("Failed to connect to the ConsoleKit seat: %s", error->message); - g_error_free (error); + g_clear_error (&error); } + else + { + g_signal_connect (proxy, "session-added", + G_CALLBACK (on_session_added), self); + g_signal_connect (proxy, "session-removed", + G_CALLBACK (on_session_removed), self); + console_kit_seat_call_get_sessions (proxy, p->cancellable, + (GAsyncReadyCallback)on_session_list, self); + p->seat_proxy = proxy; + } + } - return; + /** + *** create the accounts manager proxy... + **/ + + Accounts * proxy = accounts_proxy_new_for_bus_sync ( + G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + "org.freedesktop.Accounts", + "/org/freedesktop/Accounts", + NULL, + &error); + if (error != NULL) + { + g_warning ("%s: %s", G_STRFUNC, error->message); + g_clear_error (&error); } + else + { + g_signal_connect (proxy, "user-added", G_CALLBACK(on_user_added), self); + g_signal_connect (proxy, "user-deleted", G_CALLBACK(on_user_deleted), self); + p->accounts_proxy = proxy; + init_users (self); + } +} - dbus_g_proxy_add_signal (priv->seat_proxy, - "SessionAdded", - DBUS_TYPE_G_OBJECT_PATH, - G_TYPE_INVALID); - dbus_g_proxy_add_signal (priv->seat_proxy, - "SessionRemoved", - DBUS_TYPE_G_OBJECT_PATH, - G_TYPE_INVALID); +/*** +**** +***/ - dbus_g_proxy_connect_signal (priv->seat_proxy, - "SessionAdded", - G_CALLBACK (seat_proxy_session_added), - self, - NULL); - dbus_g_proxy_connect_signal (priv->seat_proxy, - "SessionRemoved", - G_CALLBACK (seat_proxy_session_removed), - self, - NULL); +static void +emit_user_added (UsersServiceDbus * self, AccountsUser * user) +{ + g_signal_emit (self, signals[USER_ADDED], 0, user); +} - org_freedesktop_ConsoleKit_Seat_get_sessions_async (priv->seat_proxy, get_cksessions_cb, self); +static void +emit_user_deleted (UsersServiceDbus * self, AccountsUser * user) +{ + g_signal_emit (self, signals[USER_DELETED], 0, user); +} - return; +static void +emit_user_login_changed (UsersServiceDbus * self, AccountsUser * user) +{ + g_signal_emit (self, signals[USER_LOGGED_IN_CHANGED], 0, user); } static void -create_cksession_proxy (UsersServiceDbus *service) +emit_guest_login_changed (UsersServiceDbus * self) { - UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (service); + g_signal_emit (self, signals[GUEST_LOGGED_IN_CHANGED], 0); +} - priv->session_proxy = dbus_g_proxy_new_for_name (priv->system_bus, - CK_ADDR, - priv->ssid, - CK_SESSION_IFACE); +/*** +**** +***/ - if (!priv->session_proxy) +static ConsoleKitSession* +create_consolekit_session_proxy (const char * ssid) +{ + GError * error = NULL; + + ConsoleKitSession * p = console_kit_session_proxy_new_for_bus_sync ( + G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + CK_ADDR, + ssid, + NULL, + &error); + + if (error != NULL) { - g_warning ("Failed to get ConsoleKit session proxy"); - return; + g_warning ("%s: %s", G_STRLOC, error->message); + g_error_free (error); } + + return p; } static gchar * -get_seat (UsersServiceDbus *service) +get_seat_from_session_proxy (ConsoleKitSession * session_proxy) { - UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (service); - GError *error = NULL; - gchar *ssid = NULL; - gchar *seat; - - if (!dbus_g_proxy_call (priv->ck_proxy, - "GetCurrentSession", - &error, - G_TYPE_INVALID, - DBUS_TYPE_G_OBJECT_PATH, - &ssid, - G_TYPE_INVALID)) - { - if (error) - { - g_debug ("Failed to call GetCurrentSession: %s", error->message); - g_error_free (error); - } - - if (ssid) - g_free (ssid); + gchar * seat = NULL; - return NULL; + GError * error = NULL; + console_kit_session_call_get_seat_id_sync (session_proxy, + &seat, + NULL, + &error); + if (error != NULL) + { + g_debug ("%s: %s", G_STRLOC, error->message); + g_error_free (error); } - priv->ssid = ssid; - create_cksession_proxy (service); - - seat = get_seat_internal (priv->session_proxy); - return seat; } static gchar * -get_seat_internal (DBusGProxy *proxy) +get_seat (UsersServiceDbus *service) { - GError *error = NULL; - gchar *seat = NULL; + gchar * seat = NULL; + gchar * ssid = NULL; + GError * error = NULL; + UsersServiceDbusPrivate * priv = service->priv; + + console_kit_manager_call_get_current_session_sync (priv->ck_manager_proxy, + &ssid, + NULL, + &error); - if (!org_freedesktop_ConsoleKit_Session_get_seat_id (proxy, &seat, &error)) + if (error != NULL) { - if (error) - { - g_debug ("Failed to call GetSeatId: %s", error->message); + g_debug ("%s: %s", G_STRLOC, error->message); + g_error_free (error); + } + else + { + ConsoleKitSession * session = create_consolekit_session_proxy (ssid); - return NULL; + if (session != NULL) + { + seat = get_seat_from_session_proxy (session); + g_object_unref (session); } } return seat; } -static gboolean -get_unix_user (UsersServiceDbus *service, - const gchar *session_id, - uid_t *uidp) -{ - UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (service); - GError *error = NULL; - guint uid; - DBusGProxy *session_proxy; - - g_debug("Building session proxy for: %s", session_id); - session_proxy = dbus_g_proxy_new_for_name_owner(priv->system_bus, - CK_ADDR, - session_id, - CK_SESSION_IFACE, - &error); - - if (error != NULL) { - g_warning("Unable to get CK Session proxy: %s", error->message); - g_error_free(error); - return FALSE; - } - - if (!org_freedesktop_ConsoleKit_Session_get_unix_user(session_proxy, &uid, &error)) +/* lazy-create the display manager proxy */ +static DisplayManagerSeat * +get_display_proxy (UsersServiceDbus * self) +{ + UsersServiceDbusPrivate * priv = self->priv; + + if (priv->display_proxy == NULL) { - if (error) + const gchar * const seat = g_getenv ("XDG_SEAT_PATH"); + g_debug ("%s lazy-creating the DisplayManager proxy for seat %s", G_STRLOC, seat); + + GError * error = NULL; + DisplayManagerSeat * p = display_manager_seat_proxy_new_for_bus_sync ( + G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + "org.freedesktop.DisplayManager", + seat, + NULL, + &error); + + if (error == NULL) + { + priv->display_proxy = p; + } + else { - g_warning ("Failed to call GetUnixUser: %s", error->message); + g_warning ("%s: %s", G_STRLOC, error->message); g_error_free (error); } + } + + return priv->display_proxy; +} - g_object_unref(session_proxy); - return FALSE; +/*** +**** AccountsUser add-ons for tracking sessions +***/ + +static GHashTable* +user_get_sessions_hashset (AccountsUser * user) +{ + static GQuark q = 0; + + if (G_UNLIKELY(!q)) + { + q = g_quark_from_static_string ("sessions"); } - if (uidp != NULL) + GObject * o = G_OBJECT (user); + GHashTable * h = g_object_get_qdata (o, q); + if (h == NULL) { - *uidp = (uid_t)uid; + h = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + g_object_set_qdata_full (o, q, h, (GDestroyNotify)g_hash_table_destroy); } - g_object_unref(session_proxy); - return TRUE; + return h; } -static gboolean -do_add_session (UsersServiceDbus *service, - UserData *user, - const gchar *ssid) -{ - UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (service); - GError *error = NULL; - gchar *seat = NULL; - gchar *xdisplay = NULL; - DBusGProxy * session_proxy; - GList *l; - - session_proxy = dbus_g_proxy_new_for_name_owner(priv->system_bus, - CK_ADDR, - ssid, - CK_SESSION_IFACE, - &error); - - if (error != NULL) { - g_warning("Unable to get CK Session proxy: %s", error->message); - g_error_free(error); - return FALSE; - } - - seat = get_seat_internal (session_proxy); - - if (!seat || !priv->seat || strcmp (seat, priv->seat) != 0) { - g_object_unref(session_proxy); - return FALSE; - } - - if (!org_freedesktop_ConsoleKit_Session_get_x11_display (session_proxy, &xdisplay, &error)) +static void +user_add_session (AccountsUser * user, const char * ssid) +{ + g_hash_table_add (user_get_sessions_hashset(user), g_strdup(ssid)); +} + +static void +user_remove_session (AccountsUser * user, const char * ssid) +{ + g_hash_table_remove (user_get_sessions_hashset(user), ssid); +} + +static guint +user_count_sessions (AccountsUser * user) +{ + return g_hash_table_size (user_get_sessions_hashset(user)); +} + +/*** +**** Users +***/ + +/* adds this user session to the user's and service's session tables */ +static void +add_user_session (UsersServiceDbus * service, + AccountsUser * user, + const gchar * ssid) +{ + ConsoleKitSession * session_proxy = create_consolekit_session_proxy (ssid); + if (session_proxy != NULL) { - if (error) + UsersServiceDbusPrivate * priv = service->priv; + gchar * seat = get_seat_from_session_proxy (session_proxy); + + /* is this session in our seat? */ + if (seat && priv->seat && !g_strcmp0 (seat, priv->seat)) { - g_debug ("Failed to call GetX11Display: %s", error->message); - g_error_free (error); + /* does this session have a display? */ + gchar * display = NULL; + console_kit_session_call_get_x11_display_sync (session_proxy, + &display, + NULL, NULL); + const gboolean has_display = display && *display; + g_free (display); + + if (has_display) + { + const gchar * username = accounts_user_get_user_name (user); + g_debug ("%s adding %s's session '%s' to our tables", + G_STRLOC, username, ssid); + + g_hash_table_insert (priv->sessions, + g_strdup (ssid), + g_object_ref (user)); + + user_add_session (user, ssid); + } } - g_object_unref(session_proxy); - return FALSE; + g_free (seat); + g_object_unref (session_proxy); } +} - g_object_unref(session_proxy); +/* calls add_user_session() for each of this user's sessions */ +static void +add_user (UsersServiceDbus *self, AccountsUser * user) +{ + const guint64 uid = accounts_user_get_uid (user); + const char * username = accounts_user_get_user_name (user); + g_debug ("%s adding %s (%i)", G_STRLOC, username, (int)uid); + + GError * error = NULL; + gchar ** sessions = NULL; + console_kit_manager_call_get_sessions_for_unix_user_sync ( + self->priv->ck_manager_proxy, + uid, + &sessions, + NULL, + &error); - if (!xdisplay || xdisplay[0] == '\0') - return FALSE; + if (error != NULL) + { + g_debug ("%s: %s", G_STRLOC, error->message); + g_error_free (error); + } + else if (sessions != NULL) + { + int i; - g_hash_table_insert (priv->sessions, - g_strdup (ssid), - g_strdup (user->user_name)); + for (i=0; sessions[i]; i++) + { + const char * const ssid = sessions[i]; + g_debug ("%s adding %s's session %s", G_STRLOC, username, ssid); + add_user_session (self, user, ssid); + } - l = g_list_find_custom (user->sessions, ssid, (GCompareFunc)g_strcmp0); - if (l == NULL) - { - g_debug ("Adding session %s", ssid); + g_strfreev (sessions); + } +} - user->sessions = g_list_prepend (user->sessions, g_strdup (ssid)); +static void +add_user_from_object_path (UsersServiceDbus * self, + const char * user_object_path) +{ + GError * error = NULL; + AccountsUser * user = accounts_user_proxy_new_for_bus_sync ( + G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + "org.freedesktop.Accounts", + user_object_path, + NULL, + &error); - if (user->menuitem != NULL) { - dbusmenu_menuitem_property_set_bool(user->menuitem, USER_ITEM_PROP_LOGGED_IN, TRUE); - } + if (error != NULL) + { + g_warning ("%s: %s", G_STRLOC, error->message); + g_clear_error (&error); } else { - g_debug ("User %s already has session %s", user->user_name, ssid); + g_debug ("%s adding user %s from object path %s", G_STRLOC, + accounts_user_get_user_name(user), + user_object_path); + g_hash_table_insert (self->priv->users, g_strdup(user_object_path), user); + add_user (self, user); } - - return TRUE; } + +/* calls add_user_from_object_path() on a list of user object paths */ static void -add_sessions_for_user (UsersServiceDbus *self, - UserData *user) +init_users (UsersServiceDbus *self) { - g_return_if_fail (IS_USERS_SERVICE_DBUS(self)); + g_return_if_fail(IS_USERS_SERVICE_DBUS(self)); - g_debug ("!!!!!!!!!! - add_sessions_for_user %i %s", - (int)user->uid, user->user_name); + GError * error = NULL; + char ** object_paths = NULL; + UsersServiceDbusPrivate * priv = self->priv; + g_debug ("%s bootstrapping the user list", G_STRLOC); - UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self); - GError *error; - GPtrArray *sessions; - int i; + accounts_call_list_cached_users_sync (priv->accounts_proxy, + &object_paths, + NULL, + &error); - error = NULL; - if (!org_freedesktop_ConsoleKit_Manager_get_sessions_for_unix_user(priv->ck_proxy, user->uid, &sessions, &error)) + if (error != NULL) { - g_debug ("Failed to call GetSessionsForUnixUser: %s", error->message); - g_error_free (error); - - return; + g_warning ("%s: %s", G_STRFUNC, error->message); + g_clear_error (&error); } - - for (i = 0; i < sessions->len; i++) + else if (object_paths != NULL) { - char *ssid; + gint i; - ssid = g_ptr_array_index (sessions, i); - do_add_session (self, user, ssid); + for (i=0; object_paths[i] != NULL; ++i) + { + add_user_from_object_path (self, object_paths[i]); + } + + g_strfreev (object_paths); } - g_ptr_array_foreach (sessions, (GFunc)g_free, NULL); - g_ptr_array_free (sessions, TRUE); + g_debug ("%s finished bootstrapping the user list", G_STRLOC); } +static void +on_user_added (Accounts * o G_GNUC_UNUSED, + const gchar * user_path, + UsersServiceDbus * service) +{ + add_user_from_object_path (service, user_path); + + AccountsUser * user = g_hash_table_lookup (service->priv->users, user_path); + emit_user_added (service, user); +} static void -seat_proxy_session_added (DBusGProxy *seat_proxy, - const gchar *session_id, - UsersServiceDbus *service) +on_user_deleted (Accounts * o G_GNUC_UNUSED, + const gchar * user_path, + UsersServiceDbus * service) { - g_return_if_fail(IS_USERS_SERVICE_DBUS(service)); - UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (service); - uid_t uid; - struct passwd *pwent; - UserData *user; + AccountsUser * user = g_hash_table_lookup (service->priv->users, user_path); - if (!get_unix_user (service, session_id, &uid)) + if (user != NULL) { - g_warning ("Failed to lookup user for session"); - return; + GObject * o = g_object_ref (G_OBJECT(user)); + g_hash_table_remove (service->priv->users, user_path); + emit_user_deleted (service, user); + g_object_unref (o); } +} - errno = 0; - pwent = getpwuid (uid); - if (!pwent) - { - g_warning ("Failed to lookup user id %d: %s", (int)uid, g_strerror (errno)); - return; - } +static AccountsUser * +find_user_from_username (UsersServiceDbus * self, + const gchar * username) +{ + AccountsUser * match = NULL; - /* We need to special case guest here because it doesn't - show up in the GDM user tables. */ - if (g_strcmp0("guest", pwent->pw_name) == 0) { - if (priv->guest_item != NULL) { - dbusmenu_menuitem_property_set_bool(priv->guest_item, USER_ITEM_PROP_LOGGED_IN, TRUE); - } - priv->guest_session_id = g_strdup(session_id); - g_debug("Found guest session: %s", priv->guest_session_id); - return; - } + g_return_val_if_fail (IS_USERS_SERVICE_DBUS(self), match); - user = users_service_dbus_get_user_by_username (service, pwent->pw_name); - if (!user) - return; + gpointer user; + GHashTableIter iter; + g_hash_table_iter_init (&iter, self->priv->users); + while (!match && g_hash_table_iter_next (&iter, NULL, &user)) + { + if (!g_strcmp0 (username, accounts_user_get_user_name (user))) + { + match = user; + } + } - do_add_session (service, user, session_id); + return match; } +/*** +**** Sessions +***/ + static void -seat_proxy_session_removed (DBusGProxy *seat_proxy, - const gchar *session_id, - UsersServiceDbus *service) -{ - g_return_if_fail(IS_USERS_SERVICE_DBUS(service)); - UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (service); - UserData *user; - gchar *username; - GList *l; - - username = g_hash_table_lookup (priv->sessions, session_id); - if (!username) { - if (g_strcmp0(session_id, priv->guest_session_id) == 0) { - g_debug("Removing guest session: %s", priv->guest_session_id); - if (priv->guest_item != NULL) { - dbusmenu_menuitem_property_set_bool(priv->guest_item, USER_ITEM_PROP_LOGGED_IN, FALSE); - } - g_free(priv->guest_session_id); - priv->guest_session_id = NULL; - } - return; - } +on_session_removed (ConsoleKitSeat * seat_proxy, + const gchar * ssid, + UsersServiceDbus * service) +{ + g_return_if_fail (IS_USERS_SERVICE_DBUS (service)); - user = users_service_dbus_get_user_by_username (service, username); - if (!user) - return; + UsersServiceDbusPrivate * priv = service->priv; + g_debug ("%s %s() session removed %s", G_STRLOC, G_STRFUNC, ssid); - l = g_list_find_custom (user->sessions, - session_id, - (GCompareFunc)g_strcmp0); - if (l) + if (!g_strcmp0 (ssid, priv->guest_ssid)) { - g_debug ("Removing session %s", session_id); - - g_free (l->data); - user->sessions = g_list_delete_link (user->sessions, l); - if (user->menuitem != NULL && user->sessions == NULL) { - dbusmenu_menuitem_property_set_bool(user->menuitem, USER_ITEM_PROP_LOGGED_IN, FALSE); - } + g_debug ("%s removing guest session %s", G_STRLOC, ssid); + g_clear_pointer (&priv->guest_ssid, g_free); + emit_guest_login_changed (service); } else { - g_debug ("Session not found: %s", session_id); + AccountsUser * user = g_hash_table_lookup (priv->sessions, ssid); + if (user == NULL) + { + g_debug ("%s we're not tracking ssid %s", G_STRLOC, ssid); + } + else + { + GObject * o = g_object_ref (G_OBJECT(user)); + g_hash_table_remove (service->priv->users, ssid); + user_remove_session (user, ssid); + emit_user_login_changed (service, user); + g_object_unref (o); + } } } -static void -sync_users (UsersServiceDbus *self) +static gchar* +get_unix_username_from_ssid (UsersServiceDbus * self, + const gchar * ssid) { - g_return_if_fail(IS_USERS_SERVICE_DBUS(self)); - UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self); - - GPtrArray *users = NULL; - GError *error = NULL; - gint i; - - users = g_ptr_array_new (); - - if (!org_freedesktop_Accounts_list_cached_users (priv->accounts_service_proxy, - &users, - &error)) - { - g_warning ("failed to retrieve user list: %s", error->message); - g_error_free (error); + gchar * username = NULL; - return; - } - - for (i = 0; i < users->len; i++) + ConsoleKitSession * session_proxy = create_consolekit_session_proxy (ssid); + if (session_proxy != NULL) { - gchar *id; - DBusGProxy *proxy; - UserData *user; - GError *error = NULL; - - id = g_ptr_array_index (users, i); - - proxy = dbus_g_proxy_new_for_name (priv->system_bus, - "org.freedesktop.Accounts", - id, - "org.freedesktop.DBus.Properties"); - - GHashTable *properties; - if (!dbus_g_proxy_call (proxy, "GetAll", &error, - G_TYPE_STRING, "org.freedesktop.Accounts.User", G_TYPE_INVALID, - dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE), &properties, G_TYPE_INVALID)) - { - g_warning ("unable to retrieve user info: %s", error->message); - g_error_free (error); - - continue; - } - - user = g_hash_table_lookup (priv->users, id); - // Double check we havent processed this user already - if (user != NULL) + guint uid = 0; + GError * error = NULL; + console_kit_session_call_get_unix_user_sync (session_proxy, + &uid, + NULL, &error); + if (error != NULL) { - g_free(user->user_name); - g_free(user->real_name); - g_free(user->icon_file); - user->real_name_conflict = FALSE; - //continue; + g_warning ("%s: %s", G_STRLOC, error->message); + g_clear_error (&error); } else - { - user = g_new0 (UserData, 1); + { + errno = 0; + const struct passwd * pwent = getpwuid (uid); + if (pwent == NULL) + { + g_warning ("Failed to lookup user id %d: %s", (int)uid, g_strerror(errno)); + } + else + { + username = g_strdup (pwent->pw_name); + } } - // Can't subscribe to the Changed signal on each individual user path - // for some reason. - dbus_g_proxy_add_signal (proxy, - "Changed", - G_TYPE_INVALID); - - dbus_g_proxy_connect_signal (proxy, "Changed", - G_CALLBACK(user_changed), - self, - NULL); - user->uid = g_value_get_uint64 (g_hash_table_lookup (properties, "Uid")); - user->user_name = g_strdup (g_value_get_string (g_hash_table_lookup (properties, "UserName"))); - user->real_name = g_strdup (g_value_get_string (g_hash_table_lookup (properties, "RealName"))); - user->icon_file = g_strdup (g_value_get_string (g_hash_table_lookup (properties, "IconFile"))); - user->real_name_conflict = FALSE; - user->menuitem = NULL; - - g_hash_table_unref (properties); - - g_hash_table_insert (priv->users, - g_strdup (id), - user); - - add_sessions_for_user (self, user); + + g_object_unref (session_proxy); } - g_ptr_array_free (users, TRUE); + return username; } -static void -user_changed (DBusGProxy *proxy, - gpointer user_data) +static gboolean +is_guest_username (const char * username) { - g_debug ("JUST RESYNCED THE USERS FROM A USER CHANGE"); - UsersServiceDbus *service = (UsersServiceDbus *)user_data; - sync_users (service); + if (!g_strcmp0 (username, "guest")) + return TRUE; + + if ((strlen(username)==12) && !memcmp(username,"guest-",6)) + return TRUE; + + return FALSE; } +/* If the new session belongs to 'guest', update our guest_ssid. + Otherwise, call add_user_session() to update our session tables */ static void -user_added (DBusGProxy *proxy, - const gchar *user_id, - gpointer user_data) +on_session_added (ConsoleKitSeat * seat_proxy G_GNUC_UNUSED, + const gchar * ssid, + UsersServiceDbus * service) { - UsersServiceDbus *service = (UsersServiceDbus *)user_data; - UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (service); - priv->count++; - sync_users (service); - g_signal_emit (service, - signals[USER_ADDED], - 0, - user_id); -} + g_return_if_fail (IS_USERS_SERVICE_DBUS(service)); -static void -user_deleted (DBusGProxy *proxy, - const gchar *user_id, - gpointer user_data) -{ - UsersServiceDbus *service = (UsersServiceDbus *)user_data; - UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (service); + gchar * username = get_unix_username_from_ssid (service, ssid); + g_debug ("%s %s() username %s has new session %s", G_STRLOC, G_STRFUNC, username, ssid); - priv->count--; - g_hash_table_remove (priv->users, user_id); + if (is_guest_username (username)) + { + /* handle guest as a special case -- it's not in the GDM + user tables and there isn't be an AccountsUser for it */ + g_debug("Found guest session: %s", ssid); + g_free (service->priv->guest_ssid); + service->priv->guest_ssid = g_strdup (ssid); + emit_guest_login_changed (service); + } + else + { + AccountsUser * user = find_user_from_username (service, username); + + if (user != NULL) + { + add_user_session (service, user, ssid); + emit_user_login_changed (service, user); + } + } - g_signal_emit (service, - signals[USER_DELETED], - 0, - user_id); - + g_free (username); } -UserData * -users_service_dbus_get_user_by_username (UsersServiceDbus *self, - const gchar *username) +/* Receives a list of sessions and calls on_session_added() for each of them */ +static void +on_session_list (ConsoleKitSeat * seat_proxy, + GAsyncResult * result, + UsersServiceDbus * self) { - GHashTableIter iter; - gpointer value; + GError * error = NULL; + gchar ** sessions = NULL; + g_debug ("%s bootstrapping the session list", G_STRLOC); - g_return_val_if_fail(IS_USERS_SERVICE_DBUS(self), NULL); + console_kit_seat_call_get_sessions_finish (seat_proxy, + &sessions, + result, + &error); - UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self); - - g_hash_table_iter_init (&iter, priv->users); - while (g_hash_table_iter_next (&iter, NULL, &value)) + if (error != NULL) { - UserData *user = value; - if (strcmp (user->user_name, username) == 0) - return user; + g_debug ("%s: %s", G_STRLOC, error->message); + g_error_free (error); + } + else if (sessions != NULL) + { + int i; + + for (i=0; sessions[i]; i++) + { + g_debug ("%s adding initial session '%s'", G_STRLOC, sessions[i]); + on_session_added (seat_proxy, sessions[i], self); + } + + g_strfreev (sessions); } - return NULL; + g_debug ("%s done bootstrapping the session list", G_STRLOC); } +/*** +**** Public API +***/ + +/** + * users_service_dbus_get_user_list: + * + * Returns: (transfer container): a list of AccountsUser objects + */ GList * -users_service_dbus_get_user_list (UsersServiceDbus *self) +users_service_dbus_get_user_list (UsersServiceDbus * self) { g_return_val_if_fail(IS_USERS_SERVICE_DBUS(self), NULL); - UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self); + return g_hash_table_get_values (self->priv->users); +} - return g_hash_table_get_values (priv->users); +/** + * users_service_dbus_show_greeter: + * + * Ask the Display Mnaager to switch to the greeter screen. + */ +void +users_service_dbus_show_greeter (UsersServiceDbus * self) +{ + g_return_if_fail (IS_USERS_SERVICE_DBUS(self)); + + display_manager_seat_call_switch_to_greeter_sync (get_display_proxy(self), + NULL, + NULL); } -gboolean -users_service_dbus_show_greeter (UsersServiceDbus *self) +/** + * users_service_dbus_activate_guest_session: + * + * Activates the guest account. + */ +void +users_service_dbus_activate_guest_session (UsersServiceDbus * self) { - g_return_val_if_fail(IS_USERS_SERVICE_DBUS(self), FALSE); - UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self); - return org_freedesktop_DisplayManager_Seat_switch_to_greeter(priv->display_manager_proxy, NULL); + g_return_if_fail(IS_USERS_SERVICE_DBUS(self)); + + display_manager_seat_call_switch_to_guest_sync (get_display_proxy(self), + "", + NULL, + NULL); } -/* Activates the guest account if it can. */ -gboolean -users_service_dbus_activate_guest_session (UsersServiceDbus *self) +/** + * users_service_dbus_activate_user_session: + * + * Activates a specific user. + */ +void +users_service_dbus_activate_user_session (UsersServiceDbus * self, + AccountsUser * user) { - g_return_val_if_fail(IS_USERS_SERVICE_DBUS(self), FALSE); - UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self); - return org_freedesktop_DisplayManager_Seat_switch_to_guest(priv->display_manager_proxy, "", NULL); + g_return_if_fail (IS_USERS_SERVICE_DBUS(self)); + + const char * const username = accounts_user_get_user_name (user); + display_manager_seat_call_switch_to_user_sync (get_display_proxy(self), + username, + "", + NULL, + NULL); } -/* Activates a specific user */ +/** + * users_service_dbus_guest_session_enabled: + * + * Tells whether or not guest sessions are allowed. + */ gboolean -users_service_dbus_activate_user_session (UsersServiceDbus *self, - UserData *user) +users_service_dbus_guest_session_enabled (UsersServiceDbus * self) { - g_return_val_if_fail(IS_USERS_SERVICE_DBUS(self), FALSE); - UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self); - return org_freedesktop_DisplayManager_Seat_switch_to_user(priv->display_manager_proxy, user->user_name, "", NULL); + g_return_val_if_fail(IS_USERS_SERVICE_DBUS(self), FALSE); + + return display_manager_seat_get_has_guest_account (get_display_proxy(self)); } gboolean -users_service_dbus_can_activate_session (UsersServiceDbus *self) +users_service_dbus_can_activate_session (UsersServiceDbus * self) { - g_return_val_if_fail(IS_USERS_SERVICE_DBUS(self), FALSE); - UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self); gboolean can_activate = FALSE; - GError *error = NULL; - if (!priv->seat_proxy) - { - create_seat_proxy (self); - } + g_return_val_if_fail (IS_USERS_SERVICE_DBUS(self), can_activate); - if (!priv->seat || priv->seat[0] == '\0') - { - return FALSE; - } - - if (!dbus_g_proxy_call (priv->seat_proxy, - "CanActivateSessions", - &error, - G_TYPE_INVALID, - G_TYPE_BOOLEAN, &can_activate, - G_TYPE_INVALID)) + GError * error = NULL; + console_kit_seat_call_can_activate_sessions_sync (self->priv->seat_proxy, + &can_activate, + NULL, + &error); + if (error != NULL) { - if (error != NULL){ - g_warning ("Failed to determine if seat can activate sessions: %s", - error->message); - g_error_free (error); - } - return FALSE; + g_warning ("%s: %s", G_STRLOC, error->message); + g_error_free (error); } return can_activate; } -/* Sets the menu item that represents the guest account */ -void -users_service_dbus_set_guest_item (UsersServiceDbus * self, DbusmenuMenuitem * mi) +gboolean +users_service_dbus_is_guest_logged_in (UsersServiceDbus * self) { - g_return_if_fail(IS_USERS_SERVICE_DBUS(self)); - UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self); - priv->guest_item = mi; - - if (priv->guest_session_id != NULL) { - dbusmenu_menuitem_property_set_bool(priv->guest_item, USER_ITEM_PROP_LOGGED_IN, TRUE); - } + g_return_val_if_fail (IS_USERS_SERVICE_DBUS(self), FALSE); - return; + return self->priv->guest_ssid != NULL; } -gboolean users_service_dbus_guest_session_enabled (UsersServiceDbus * self) +gboolean +users_service_dbus_is_user_logged_in (UsersServiceDbus * self, + AccountsUser * user) { - g_return_val_if_fail(IS_USERS_SERVICE_DBUS(self), FALSE); - UsersServiceDbusPrivate *priv = USERS_SERVICE_DBUS_GET_PRIVATE (self); - - return priv->guest_session_enabled; -} + g_return_val_if_fail (IS_USERS_SERVICE_DBUS(self), FALSE); + g_return_val_if_fail (IS_ACCOUNTS_USER(user), FALSE); + return user_count_sessions (user) > 0; +} diff --git a/src/users-service-dbus.h b/src/users-service-dbus.h index 66f3b9d..bc153df 100644 --- a/src/users-service-dbus.h +++ b/src/users-service-dbus.h @@ -3,6 +3,7 @@ * * Authors: * Cody Russell + * Charles Kerr * * 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 @@ -22,62 +23,75 @@ #include #include -#include + +#include "dbus-user.h" /* for AccountsUser */ G_BEGIN_DECLS -#define USERS_SERVICE_DBUS_TYPE (users_service_dbus_get_type ()) -#define USERS_SERVICE_DBUS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), USERS_SERVICE_DBUS_TYPE, UsersServiceDbus)) -#define USERS_SERVICE_DBUS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), USERS_SERVICE_DBUS_TYPE, UsersServiceDbusClass)) -#define IS_USERS_SERVICE_DBUS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), USERS_SERVICE_DBUS_TYPE)) -#define IS_USERS_SERVICE_DBUS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), USERS_SERVICE_DBUS_TYPE)) -#define USERS_SERVICE_DBUS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), USERS_SERVICE_DBUS_TYPE, UsersServiceDbusClass)) +#define USERS_SERVICE_DBUS_TYPE (users_service_dbus_get_type ()) +#define USERS_SERVICE_DBUS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), USERS_SERVICE_DBUS_TYPE, UsersServiceDbus)) +#define IS_USERS_SERVICE_DBUS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), USERS_SERVICE_DBUS_TYPE)) -typedef struct _UsersServiceDbus UsersServiceDbus; -typedef struct _UsersServiceDbusClass UsersServiceDbusClass; -typedef struct _UserData UserData; +typedef struct _UsersServiceDbus UsersServiceDbus; +typedef struct _UsersServiceDbusClass UsersServiceDbusClass; +typedef struct _UsersServiceDbusPrivate UsersServiceDbusPrivate; -struct _UserData +/** + * A class which interacts with multiple DBus services to track + * info which is useful to the interactor's user menu: + * + * 1. A list of users to add to the user menu. + * + * Each user is an AccountsUser object, which is a GDBusProxy + * to an org.freedesktop.Accounts.User object. + * + * We initially build this list by calling org.freedesktop.Accounts' + * GetCachedUsers method. We also monitor o.f.Accounts' UserAdded + * and UserDeleted and update the list accordingly. + * + * 2. Track which users currently have X sessions. + * This is used for the menuitems' USER_ITEM_PROP_LOGGED_IN property. + * + * We initially build this list by calling org.freedesktop.ConsoleKit.Seat's + * GetDevices method. We also monitor the seat for SessionAdded and + * SessionRemoved and update the list accordingly. + * + * 3. Provide an API for user switching and guest sessions. + * These are typically pass-through functions to GDBusProxies. + * + */ +struct _UsersServiceDbus { - gint64 uid; - gchar *user_name; - gchar *real_name; - gchar *icon_file; - - GList *sessions; - - /* Whether the real name here conflicts with another in the system */ - gboolean real_name_conflict; - /* The menuitem representing this user if there is one. */ - DbusmenuMenuitem * menuitem; -}; - -struct _UsersServiceDbus { + /*< private >*/ GObject parent; + UsersServiceDbusPrivate * priv; }; -struct _UsersServiceDbusClass { +struct _UsersServiceDbusClass +{ GObjectClass parent_class; /* Signals */ - void (* user_added) (UsersServiceDbus *self, const gchar *user_id, gpointer user_data); - void (* user_deleted) (UsersServiceDbus *self, const gchar *user_id, gpointer user_data); + void (* user_added) (UsersServiceDbus*, AccountsUser*, gpointer); + void (* user_deleted) (UsersServiceDbus*, AccountsUser*, gpointer); + void (* user_logged_in_changed) (UsersServiceDbus*, AccountsUser*, gpointer); + void (* guest_logged_in_changed) (UsersServiceDbus*, gpointer); }; -GType users_service_dbus_get_type (void) G_GNUC_CONST; +GType users_service_dbus_get_type (void) G_GNUC_CONST; + +GList * users_service_dbus_get_user_list (UsersServiceDbus * self); -UserData *users_service_dbus_get_user_by_username (UsersServiceDbus *self, - const gchar *username); -GList *users_service_dbus_get_user_list (UsersServiceDbus *self); -gboolean users_service_dbus_show_greeter (UsersServiceDbus *self); -gboolean users_service_dbus_can_activate_session (UsersServiceDbus *self); -gboolean users_service_dbus_activate_user_session (UsersServiceDbus *self, - UserData *user); -gboolean users_service_dbus_activate_guest_session (UsersServiceDbus *self); -void users_service_dbus_set_guest_item (UsersServiceDbus * self, - DbusmenuMenuitem * mi); +gboolean users_service_dbus_is_guest_logged_in (UsersServiceDbus * self); +gboolean users_service_dbus_is_user_logged_in (UsersServiceDbus * self, + AccountsUser * user); -gboolean users_service_dbus_guest_session_enabled (UsersServiceDbus * self); +void users_service_dbus_show_greeter (UsersServiceDbus * self); +gboolean users_service_dbus_guest_session_enabled (UsersServiceDbus * self); +gboolean users_service_dbus_can_activate_session (UsersServiceDbus * self); +void users_service_dbus_activate_guest_session (UsersServiceDbus * self); +void users_service_dbus_activate_user_session (UsersServiceDbus * self, + AccountsUser * user); G_END_DECLS -- cgit v1.2.3