1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright 2012 Red Hat, Inc,
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, see <http://www.gnu.org/licenses/>.
17 *
18 * Written by: Ondrej Holy <oholy@redhat.com>
19 */
20
21 #include "config.h"
22
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <sys/types.h>
26 #include <sys/wait.h>
27
28 #include <glib.h>
29 #include <glib/gi18n.h>
30 #include <gtk/gtk.h>
31 #include <act/act.h>
32
33 #include "cc-login-history-dialog.h"
34 #include "cc-user-accounts-resources.h"
35 #include "cc-util.h"
36 #include "user-utils.h"
37
38 struct _CcLoginHistoryDialog
39 {
40 GtkDialog parent_instance;
41
42 GtkHeaderBar *header_bar;
43 GtkListBox *history_box;
44 GtkButton *next_button;
45 GtkButton *previous_button;
46
47 GDateTime *week;
48 GDateTime *current_week;
49
50 ActUser *user;
51 };
52
53 G_DEFINE_TYPE (CcLoginHistoryDialog, cc_login_history_dialog, GTK_TYPE_DIALOG)
54
55 typedef struct {
56 gint64 login_time;
57 gint64 logout_time;
58 const gchar *type;
59 } CcLoginHistory;
60
61 static void
show_week_label(CcLoginHistoryDialog * self)62 show_week_label (CcLoginHistoryDialog *self)
63 {
64 g_autofree gchar *label = NULL;
65 GTimeSpan span;
66
67 span = g_date_time_difference (self->current_week, self->week);
68 if (span == 0) {
69 label = g_strdup (_("This Week"));
70 }
71 else if (span == G_TIME_SPAN_DAY * 7) {
72 label = g_strdup (_("Last Week"));
73 }
74 else {
75 g_autofree gchar *from = NULL;
76 g_autofree gchar *to = NULL;
77 g_autoptr(GDateTime) date = NULL;
78
79 date = g_date_time_add_days (self->week, 6);
80 /* Translators: This is a date format string in the style of "Feb 18",
81 shown as the first day of a week on login history dialog. */
82 from = g_date_time_format (self->week, C_("login history week label","%b %e"));
83 if (g_date_time_get_year (self->week) == g_date_time_get_year (self->current_week)) {
84 /* Translators: This is a date format string in the style of "Feb 24",
85 shown as the last day of a week on login history dialog. */
86 to = g_date_time_format (date, C_("login history week label","%b %e"));
87 }
88 else {
89 /* Translators: This is a date format string in the style of "Feb 24, 2013",
90 shown as the last day of a week on login history dialog. */
91 to = g_date_time_format (date, C_("login history week label","%b %e, %Y"));
92 }
93
94 /* Translators: This indicates a week label on a login history.
95 The first %s is the first day of a week, and the second %s the last day. */
96 label = g_strdup_printf(C_("login history week label", "%s — %s"), from, to);
97 }
98
99 gtk_header_bar_set_subtitle (self->header_bar, label);
100 }
101
102 static void
clear_history(CcLoginHistoryDialog * self)103 clear_history (CcLoginHistoryDialog *self)
104 {
105 g_autoptr(GList) list = NULL;
106 GList *it;
107
108 list = gtk_container_get_children (GTK_CONTAINER (self->history_box));
109 for (it = list; it != NULL; it = it->next) {
110 gtk_container_remove (GTK_CONTAINER (self->history_box), GTK_WIDGET (it->data));
111 }
112 }
113
114 static GArray *
get_login_history(ActUser * user)115 get_login_history (ActUser *user)
116 {
117 GArray *login_history;
118 GVariantIter *iter, *iter2;
119 GVariant *variant;
120 const GVariant *value;
121 const gchar *key;
122 CcLoginHistory history;
123
124 login_history = NULL;
125 value = act_user_get_login_history (user);
126 g_variant_get ((GVariant *) value, "a(xxa{sv})", &iter);
127 while (g_variant_iter_loop (iter, "(xxa{sv})", &history.login_time, &history.logout_time, &iter2)) {
128 while (g_variant_iter_loop (iter2, "{&sv}", &key, &variant)) {
129 if (g_strcmp0 (key, "type") == 0) {
130 history.type = g_variant_get_string (variant, NULL);
131 }
132 }
133
134 if (login_history == NULL) {
135 login_history = g_array_new (FALSE, TRUE, sizeof (CcLoginHistory));
136 }
137
138 g_array_append_val (login_history, history);
139 }
140
141 return login_history;
142 }
143
144 static void
set_sensitivity(CcLoginHistoryDialog * self)145 set_sensitivity (CcLoginHistoryDialog *self)
146 {
147 g_autoptr(GArray) login_history = NULL;
148 CcLoginHistory history;
149 gboolean sensitive = FALSE;
150
151 login_history = get_login_history (self->user);
152 if (login_history != NULL) {
153 history = g_array_index (login_history, CcLoginHistory, 0);
154 sensitive = g_date_time_to_unix (self->week) > history.login_time;
155 }
156 gtk_widget_set_sensitive (GTK_WIDGET (self->previous_button), sensitive);
157
158 sensitive = (g_date_time_compare (self->current_week, self->week) == 1);
159 gtk_widget_set_sensitive (GTK_WIDGET (self->next_button), sensitive);
160 }
161
162 static void
add_record(CcLoginHistoryDialog * self,GDateTime * datetime,gchar * record_string,gint line)163 add_record (CcLoginHistoryDialog *self, GDateTime *datetime, gchar *record_string, gint line)
164 {
165 g_autofree gchar *date = NULL;
166 g_autofree gchar *time = NULL;
167 g_autofree gchar *str = NULL;
168 GtkWidget *label, *row;
169
170 date = cc_util_get_smart_date (datetime);
171 /* Translators: This is a time format string in the style of "22:58".
172 It indicates a login time which follows a date. */
173 time = g_date_time_format (datetime, C_("login date-time", "%k:%M"));
174 /* Translators: This indicates a login date-time.
175 The first %s is a date, and the second %s a time. */
176 str = g_strdup_printf(C_("login date-time", "%s, %s"), date, time);
177
178 row = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
179 gtk_widget_show (row);
180 gtk_box_set_homogeneous (GTK_BOX (row), TRUE);
181 gtk_container_set_border_width (GTK_CONTAINER (row), 6);
182
183 label = gtk_label_new (record_string);
184 gtk_widget_show (label);
185 gtk_widget_set_halign (label, GTK_ALIGN_START);
186 gtk_box_pack_start (GTK_BOX (row), label, TRUE, TRUE, 0);
187
188 label = gtk_label_new (str);
189 gtk_widget_show (label);
190 gtk_widget_set_halign (label, GTK_ALIGN_START);
191 gtk_box_pack_start (GTK_BOX (row), label, TRUE, TRUE, 0);
192
193 gtk_list_box_insert (self->history_box, row, line);
194 }
195
196 static void
show_week(CcLoginHistoryDialog * self)197 show_week (CcLoginHistoryDialog *self)
198 {
199 g_autoptr(GArray) login_history = NULL;
200 g_autoptr(GDateTime) datetime = NULL;
201 g_autoptr(GDateTime) temp = NULL;
202 gint64 from, to;
203 gint i, line;
204 CcLoginHistory history;
205
206 show_week_label (self);
207 clear_history (self);
208 set_sensitivity (self);
209
210 login_history = get_login_history (self->user);
211 if (login_history == NULL) {
212 return;
213 }
214
215 /* Find first record for week */
216 from = g_date_time_to_unix (self->week);
217 temp = g_date_time_add_weeks (self->week, 1);
218 to = g_date_time_to_unix (temp);
219 for (i = login_history->len - 1; i >= 0; i--) {
220 history = g_array_index (login_history, CcLoginHistory, i);
221 if (history.login_time < to) {
222 break;
223 }
224 }
225
226 /* Add new session records */
227 line = 0;
228 for (;i >= 0; i--) {
229 history = g_array_index (login_history, CcLoginHistory, i);
230
231 /* Display only x-session and tty records */
232 if (!g_str_has_prefix (history.type, ":") &&
233 !g_str_has_prefix (history.type, "tty")) {
234 continue;
235 }
236
237 if (history.logout_time > 0 && history.logout_time < from) {
238 break;
239 }
240
241 if (history.logout_time > 0 && history.logout_time < to) {
242 datetime = g_date_time_new_from_unix_local (history.logout_time);
243 add_record (self, datetime, _("Session Ended"), line);
244 line++;
245 }
246
247 if (history.login_time >= from) {
248 datetime = g_date_time_new_from_unix_local (history.login_time);
249 add_record (self, datetime, _("Session Started"), line);
250 line++;
251 }
252 }
253 }
254
255 static void
previous_button_clicked_cb(CcLoginHistoryDialog * self)256 previous_button_clicked_cb (CcLoginHistoryDialog *self)
257 {
258 g_autoptr(GDateTime) temp = NULL;
259
260 temp = self->week;
261 self->week = g_date_time_add_weeks (self->week, -1);
262
263 show_week (self);
264 }
265
266 static void
next_button_clicked_cb(CcLoginHistoryDialog * self)267 next_button_clicked_cb (CcLoginHistoryDialog *self)
268 {
269 g_autoptr(GDateTime) temp = NULL;
270
271 temp = self->week;
272 self->week = g_date_time_add_weeks (self->week, 1);
273
274 show_week (self);
275 }
276
277 static void
cc_login_history_dialog_dispose(GObject * object)278 cc_login_history_dialog_dispose (GObject *object)
279 {
280 CcLoginHistoryDialog *self = CC_LOGIN_HISTORY_DIALOG (object);
281
282 g_clear_object (&self->user);
283 g_clear_pointer (&self->week, g_date_time_unref);
284 g_clear_pointer (&self->current_week, g_date_time_unref);
285
286 G_OBJECT_CLASS (cc_login_history_dialog_parent_class)->dispose (object);
287 }
288
289 void
cc_login_history_dialog_class_init(CcLoginHistoryDialogClass * klass)290 cc_login_history_dialog_class_init (CcLoginHistoryDialogClass *klass)
291 {
292 GObjectClass *object_class = G_OBJECT_CLASS (klass);
293 GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
294
295 object_class->dispose = cc_login_history_dialog_dispose;
296
297 gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/user-accounts/cc-login-history-dialog.ui");
298
299 gtk_widget_class_bind_template_child (widget_class, CcLoginHistoryDialog, header_bar);
300 gtk_widget_class_bind_template_child (widget_class, CcLoginHistoryDialog, history_box);
301 gtk_widget_class_bind_template_child (widget_class, CcLoginHistoryDialog, next_button);
302 gtk_widget_class_bind_template_child (widget_class, CcLoginHistoryDialog, previous_button);
303
304 gtk_widget_class_bind_template_callback (widget_class, next_button_clicked_cb);
305 gtk_widget_class_bind_template_callback (widget_class, previous_button_clicked_cb);
306 }
307
308 void
cc_login_history_dialog_init(CcLoginHistoryDialog * self)309 cc_login_history_dialog_init (CcLoginHistoryDialog *self)
310 {
311 g_resources_register (cc_user_accounts_get_resource ());
312
313 gtk_widget_init_template (GTK_WIDGET (self));
314 }
315
316 CcLoginHistoryDialog *
cc_login_history_dialog_new(ActUser * user)317 cc_login_history_dialog_new (ActUser *user)
318 {
319 CcLoginHistoryDialog *self;
320 g_autoptr(GDateTime) temp = NULL;
321 g_autoptr(GDateTime) local = NULL;
322 g_autofree gchar *title = NULL;
323
324 g_return_val_if_fail (ACT_IS_USER (user), NULL);
325
326 self = g_object_new (CC_TYPE_LOGIN_HISTORY_DIALOG,
327 "use-header-bar", 1,
328 NULL);
329
330 self->user = g_object_ref (user);
331
332 /* Set the first day of this week */
333 local = g_date_time_new_now_local ();
334 temp = g_date_time_new_local (g_date_time_get_year (local),
335 g_date_time_get_month (local),
336 g_date_time_get_day_of_month (local),
337 0, 0, 0);
338 self->week = g_date_time_add_days (temp, 1 - g_date_time_get_day_of_week (temp));
339 self->current_week = g_date_time_ref (self->week);
340
341 /* Translators: This is the title of the "Account Activity" dialog.
342 The %s is the user real name. */
343 title = g_strdup_printf (_("%s — Account Activity"),
344 act_user_get_real_name (self->user));
345 gtk_header_bar_set_title (self->header_bar, title);
346
347 show_week (self);
348
349 return self;
350 }
351