From 07dfa0b9708662a934e9d6f2f7054f97212a53f1 Mon Sep 17 00:00:00 2001 From: Ondrej Holy Date: Thu, 1 Nov 2012 12:28:56 +0100 Subject: [PATCH 3/4] accountsservice: Add User.LogoutTimes property https://bugzilla.gnome.org/show_bug.cgi?id=681772 --- data/org.freedesktop.Accounts.User.xml | 10 ++++ src/daemon.c | 89 ++++++++++++++++++++++++++++------ src/libaccountsservice/act-user.c | 39 +++++++++++++-- src/libaccountsservice/act-user.h | 1 + src/user.c | 16 ++++++ 5 files changed, 135 insertions(+), 20 deletions(-) diff --git a/data/org.freedesktop.Accounts.User.xml b/data/org.freedesktop.Accounts.User.xml index 94ccd52..0aecc27 100644 --- a/data/org.freedesktop.Accounts.User.xml +++ b/data/org.freedesktop.Accounts.User.xml @@ -673,6 +673,16 @@ + + + + + The logout times. + + + + + diff --git a/src/daemon.c b/src/daemon.c index b31d5da..869ffbb 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -209,18 +209,29 @@ static struct passwd * entry_generator_wtmp (GHashTable *users, gpointer *state) { - GHashTable *login_frequency_hash; + GHashTable *login_hash, *logout_hash; struct utmpx *wtmp_entry; GHashTableIter iter; gpointer key, value; struct passwd *pwent; User *user; struct hash_data *data; + struct state_data *state_data; + gint64 *time; + gint64 *time_ptr; + gint i; + GVariantBuilder *logout_times; struct hash_data { int frequency; gint64 time; - GVariantBuilder *times; + GVariantBuilder *login_times; + GArray *logout_times; + }; + + struct state_data { + GHashTable *login_hash; + GHashTable *logout_hash; }; if (*state == NULL) { @@ -233,12 +244,34 @@ entry_generator_wtmp (GHashTable *users, utmpxname (_PATH_WTMPX); setutxent (); #endif - *state = g_hash_table_new (g_str_hash, g_str_equal); + *state = g_new (struct state_data, 1); + state_data = *state; + state_data->login_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + state_data->logout_hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); } /* Every iteration */ - login_frequency_hash = *state; + state_data = *state; + login_hash = state_data->login_hash; + logout_hash = state_data->logout_hash; while ((wtmp_entry = getutxent ())) { + if (wtmp_entry->ut_type == BOOT_TIME) { + /* Set boot time for missing logout records */ + g_hash_table_iter_init (&iter, logout_hash); + while (g_hash_table_iter_next (&iter, &key, &value)) { + time_ptr = value; + *time_ptr = wtmp_entry->ut_tv.tv_sec; + } + g_hash_table_remove_all (logout_hash); + } else if (wtmp_entry->ut_type == DEAD_PROCESS) { + /* Save correspoding logout time */ + if (g_hash_table_lookup_extended (logout_hash, wtmp_entry->ut_line, &key, &value)) { + time_ptr = value; + *time_ptr = wtmp_entry->ut_tv.tv_sec; + g_hash_table_remove (logout_hash, wtmp_entry->ut_line); + } + } + if (wtmp_entry->ut_type != USER_PROCESS) { continue; } @@ -252,22 +285,34 @@ entry_generator_wtmp (GHashTable *users, continue; } - if (!g_hash_table_lookup_extended (login_frequency_hash, + if (!g_hash_table_lookup_extended (login_hash, wtmp_entry->ut_user, &key, &value)) { data = g_new (struct hash_data, 1); data->frequency = 1; data->time = wtmp_entry->ut_tv.tv_sec; - data->times = g_variant_builder_new (G_VARIANT_TYPE ("ax")); - g_variant_builder_add (data->times, "x", data->time); - g_hash_table_insert (login_frequency_hash, - g_strdup (wtmp_entry->ut_user), - data); + data->login_times = g_variant_builder_new (G_VARIANT_TYPE ("ax")); + g_variant_builder_add (data->login_times, "x", data->time); + + /* Add zero logout time to change it later on logout record */ + data->logout_times = g_array_new (FALSE, FALSE, sizeof (gint64)); + time = 0; + g_array_append_val (data->logout_times, time); + time_ptr = &g_array_index (data->logout_times, gint64, data->logout_times->len - 1); + g_hash_table_insert (logout_hash, g_strdup (wtmp_entry->ut_line), time_ptr); + + g_hash_table_insert (login_hash, g_strdup (wtmp_entry->ut_user), data); } else { data = value; data->frequency++; data->time = wtmp_entry->ut_tv.tv_sec; - g_variant_builder_add (data->times, "x", data->time); + g_variant_builder_add (data->login_times, "x", data->time); + + /* Add zero logout time to change it later on logout record */ + time = 0; + g_array_append_val (data->logout_times, time); + time_ptr = &g_array_index (data->logout_times, gint64, data->logout_times->len - 1); + g_hash_table_insert (logout_hash, g_strdup (wtmp_entry->ut_line), time_ptr); } return pwent; @@ -276,24 +321,36 @@ entry_generator_wtmp (GHashTable *users, /* Last iteration */ endutxent (); - g_hash_table_iter_init (&iter, login_frequency_hash); + g_hash_table_iter_init (&iter, login_hash); while (g_hash_table_iter_next (&iter, &key, &value)) { data = value; user = g_hash_table_lookup (users, key); if (user == NULL) { + g_array_unref (data->logout_times); + g_variant_builder_unref (data->login_times); continue; } + logout_times = g_variant_builder_new (G_VARIANT_TYPE ("ax")); + for (i = 0; i < data->logout_times->len; i++) { + time = g_array_index (data->logout_times, gint64, i); + g_variant_builder_add (logout_times, "x", time); + } + g_object_set (user, "login-frequency", data->frequency, NULL); g_object_set (user, "login-time", data->time, NULL); - g_object_set (user, "login-times", g_variant_new ("ax", data->times), NULL); + g_object_set (user, "login-times", g_variant_new ("ax", data->login_times), NULL); + g_object_set (user, "logout-times", g_variant_new ("ax", logout_times), NULL); - g_variant_builder_unref (data->times); + g_variant_builder_unref (data->login_times); + g_variant_builder_unref (logout_times); + g_array_unref (data->logout_times); } - g_hash_table_foreach (login_frequency_hash, (GHFunc) g_free, NULL); - g_hash_table_unref (login_frequency_hash); + g_hash_table_unref (login_hash); + g_hash_table_unref (logout_hash); + g_free (state_data); *state = NULL; return NULL; } diff --git a/src/libaccountsservice/act-user.c b/src/libaccountsservice/act-user.c index 1fb0b43..eeb7f9c 100644 --- a/src/libaccountsservice/act-user.c +++ b/src/libaccountsservice/act-user.c @@ -59,6 +59,7 @@ enum { PROP_LOGIN_FREQUENCY, PROP_LOGIN_TIME, PROP_LOGIN_TIMES, + PROP_LOGOUT_TIMES, PROP_ICON_FILE, PROP_LANGUAGE, PROP_X_SESSION, @@ -95,6 +96,7 @@ struct _ActUser { int login_frequency; gint64 login_time; GVariant *login_times; + GVariant *logout_times; ActUserAccountType account_type; ActUserPasswordMode password_mode; @@ -216,6 +218,9 @@ act_user_get_property (GObject *object, case PROP_LOGIN_TIMES: g_value_set_variant (value, user->login_times); break; + case PROP_LOGOUT_TIMES: + g_value_set_variant (value, user->logout_times); + break; case PROP_SHELL: g_value_set_string (value, user->shell); break; @@ -362,10 +367,10 @@ act_user_class_init (ActUserClass *class) 0, G_PARAM_READABLE)); g_object_class_install_property (gobject_class, - PROP_LOGIN_TIMES, - g_param_spec_variant ("login-times", - "Login times", - "The login times for this user.", + PROP_LOGOUT_TIMES, + g_param_spec_variant ("logout-times", + "Logout times", + "The logout times for this user.", G_VARIANT_TYPE ("ax"), NULL, G_PARAM_READABLE)); @@ -457,6 +462,7 @@ act_user_init (ActUser *user) user->real_name = NULL; user->sessions = NULL; user->login_times = NULL; + user->logout_times = NULL; user->connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error); if (user->connection == NULL) { @@ -483,6 +489,7 @@ act_user_finalize (GObject *object) g_free (user->email); g_free (user->location); g_variant_unref (user->login_times); + g_variant_unref (user->logout_times); if (user->accounts_proxy != NULL) { g_object_unref (user->accounts_proxy); @@ -736,6 +743,22 @@ act_user_get_login_times (ActUser *user) { return user->login_times; } +/** + * act_user_get_logout_times: + * @user: a #ActUser + * + * Returns the logout times for @user. + * + * Returns: (transfer none): a pointer to GVariant of type "ax" which must not be modified or + * freed, or %NULL. + */ +const GVariant * +act_user_get_logout_times (ActUser *user) { + g_return_val_if_fail (ACT_IS_USER (user), NULL); + + return user->logout_times; +} + int act_user_collate (ActUser *user1, ActUser *user2) @@ -1111,6 +1134,14 @@ collect_props (const gchar *key, user->login_times = g_variant_ref (new_login_times); g_object_notify (G_OBJECT (user), "login-times"); } + } else if (strcmp (key, "LogoutTimes") == 0) { + GVariant *new_logout_times = value; + + if (!g_variant_compare (user->logout_times, new_logout_times)) { + g_variant_unref (user->logout_times); + user->logout_times = g_variant_ref (new_logout_times); + g_object_notify (G_OBJECT (user), "logout-times"); + } } else if (strcmp (key, "IconFile") == 0) { const char *new_icon_file; diff --git a/src/libaccountsservice/act-user.h b/src/libaccountsservice/act-user.h index 4ed2780..18a8e75 100644 --- a/src/libaccountsservice/act-user.h +++ b/src/libaccountsservice/act-user.h @@ -68,6 +68,7 @@ gboolean act_user_is_logged_in (ActUser *user); int act_user_get_login_frequency (ActUser *user); gint64 act_user_get_login_time (ActUser *user); const GVariant*act_user_get_login_times (ActUser *user); +const GVariant*act_user_get_logout_times (ActUser *user); gboolean act_user_get_locked (ActUser *user); gboolean act_user_get_automatic_login (ActUser *user); gboolean act_user_is_system_account (ActUser *user); diff --git a/src/user.c b/src/user.c index 49b1885..6505bfb 100644 --- a/src/user.c +++ b/src/user.c @@ -61,6 +61,7 @@ enum { PROP_LOGIN_FREQUENCY, PROP_LOGIN_TIME, PROP_LOGIN_TIMES, + PROP_LOGOUT_TIMES, PROP_ICON_FILE, PROP_LOCKED, PROP_PASSWORD_MODE, @@ -94,6 +95,7 @@ struct User { guint64 login_frequency; gint64 login_time; GVariant *login_times; + GVariant *logout_times; gchar *icon_file; gchar *default_icon_file; gboolean locked; @@ -1699,6 +1701,12 @@ user_real_get_login_times (AccountsUser *user) return USER (user)->login_times; } +static const GVariant * +user_real_get_logout_times (AccountsUser *user) +{ + return USER (user)->logout_times; +} + static const gchar * user_real_get_icon_file (AccountsUser *user) { @@ -1792,6 +1800,9 @@ user_set_property (GObject *object, case PROP_LOGIN_TIMES: user->login_times = g_variant_ref (g_value_get_variant (value)); break; + case PROP_LOGOUT_TIMES: + user->logout_times = g_variant_ref (g_value_get_variant (value)); + break; case PROP_AUTOMATIC_LOGIN: user->automatic_login = g_value_get_boolean (value); break; @@ -1868,6 +1879,9 @@ user_get_property (GObject *object, case PROP_LOGIN_TIMES: g_value_set_variant (value, user->login_times); break; + case PROP_LOGOUT_TIMES: + g_value_set_variant (value, user->logout_times); + break; case PROP_LOCKED: g_value_set_boolean (value, user->locked); break; @@ -1930,6 +1944,7 @@ user_accounts_user_iface_init (AccountsUserIface *iface) iface->get_login_frequency = user_real_get_login_frequency; iface->get_login_time = user_real_get_login_time; iface->get_login_times = user_real_get_login_times; + iface->get_logout_times = user_real_get_logout_times; iface->get_icon_file = user_real_get_icon_file; iface->get_locked = user_real_get_locked; iface->get_password_mode = user_real_get_password_mode; @@ -1960,4 +1975,5 @@ user_init (User *user) user->automatic_login = FALSE; user->system_account = FALSE; user->login_times = NULL; + user->logout_times = NULL; } -- 1.7.11.7