1 /* ****************************************************************************
2
3 * eID Middleware Project.
4 * Copyright (C) 2014 FedICT.
5 *
6 * This is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License version
8 * 3.0 as published by the Free Software Foundation.
9 *
10 * This software 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 GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this software; if not, see
17 * http://www.gnu.org/licenses/.
18
19 **************************************************************************** */
20
21 #define _GNU_SOURCE
22
23 #include <config.h>
24
25 #define _GNU_SOURCE
26
27 #include <errno.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <unistd.h>
32
33 #include <sys/stat.h>
34 #include <sys/types.h>
35 #include <sys/wait.h>
36 #include <sys/utsname.h>
37
38 #include <gtk/gtk.h>
39 #include <gdk/gdkkeysyms.h>
40
41 #include "about_glade.h"
42 #include "now.h"
43
44 #include "gettext.h"
45
46 #if GTK_CHECK_VERSION(3, 96, 0)
47 #define GtkClipboard GdkClipboard
48 #define gtk_clipboard_get(a) gdk_display_get_clipboard(gdk_display_get_default())
49 #define gtk_clipboard_set_text(c, t, l) gdk_clipboard_set_text(c, t)
50 #define gtk_init(a, b) gtk_init()
51
gtk_widget_show_all_ll(GtkWidget * widget,gpointer data G_GNUC_UNUSED)52 void gtk_widget_show_all_ll(GtkWidget *widget, gpointer data G_GNUC_UNUSED) {
53 if(GTK_IS_CONTAINER(widget)) {
54 gtk_container_foreach(GTK_CONTAINER(widget), gtk_widget_show_all_ll, NULL);
55 }
56 gtk_widget_show(widget);
57 }
58
gtk_widget_show_all(GtkWidget * widget)59 void gtk_widget_show_all(GtkWidget *widget) {
60 gtk_widget_show_all_ll(widget, NULL);
61 }
62 #endif
63
64 #ifndef _
65 #define _(s) gettext(s)
66 #endif
67
68 static enum _bits {
69 BITS_UNKNOWN,
70 BITS_32,
71 BITS_64,
72 BITS_FOREIGN,
73 } bitness;
74
check_pcsc(GtkWidget * top G_GNUC_UNUSED,GtkListStore * data)75 void check_pcsc(GtkWidget* top G_GNUC_UNUSED, GtkListStore* data) {
76 FILE* f = popen("pidof pcscd", "r");
77 GtkTreeIter iter;
78 char pid[6];
79 char* tmp;
80
81 gtk_list_store_append(data, &iter);
82 if(!f) {
83 gtk_list_store_set(data, &iter, 0, _("PCSC daemon status"), 1, _("(check failed)"), -1);
84 return;
85 }
86 if(feof(f)) {
87 gtk_list_store_set(data, &iter, 0, _("PCSC daemon status"), 1, _("(not running)"), -1);
88 goto exit;
89 }
90 pid[5]='\0';
91 if(fgets(pid, 5, f)==NULL) {
92 gtk_list_store_set(data, &iter, 0, _("PCSC daemon status"), 1, _("(not running)"), -1);
93 goto exit;
94 }
95 if((tmp = strchr(pid, '\n'))) {
96 *tmp = '\0';
97 }
98 if(strlen(pid)==0) {
99 gtk_list_store_set(data, &iter, 0, _("PCSC daemon status"), 1, _("(not running)"), -1);
100 goto exit;
101 }
102 tmp = g_strdup_printf(_("running; pid: %s"), pid);
103 gtk_list_store_set(data, &iter, 0, _("PCSC daemon status"), 1, tmp, -1);
104 g_free(tmp);
105 exit:
106 pclose(f);
107 }
108
do_viewer(GtkWidget * top G_GNUC_UNUSED,GtkListStore * data)109 void do_viewer(GtkWidget* top G_GNUC_UNUSED, GtkListStore* data) {
110 FILE* f = popen("which eid-viewer", "r");
111 GtkTreeIter iter;
112 char tmp[PATH_MAX];
113 char* loc;
114
115 gtk_list_store_append(data, &iter);
116 if(!f) {
117 gtk_list_store_set(data, &iter, 0, _("eID Viewer location"), 1, _("(not found)"), -1);
118 return;
119 }
120 tmp[PATH_MAX-1]='\0';
121 if(fgets(tmp, PATH_MAX, f) == NULL) {
122 gtk_list_store_set(data, &iter, 0, _("eID Viewer location"), 1, _("(not found)"), -1);
123 goto exit;
124 }
125 if((loc = strrchr(tmp, '\n')) != NULL) {
126 *loc = '\0';
127 }
128 if(strlen(tmp) == 0) {
129 gtk_list_store_set(data, &iter, 0, _("eID Viewer location"), 1, _("(not found)"), -1);
130 goto exit;
131 }
132 gtk_list_store_set(data, &iter, 0, _("eID Viewer location"), 1, tmp, -1);
133 exit:
134 pclose(f);
135 }
136
do_files(GtkWidget * top,GtkListStore * data)137 void do_files(GtkWidget* top, GtkListStore* data) {
138 GtkWidget* dialog;
139 struct stat st;
140 struct {
141 enum _bits bitness;
142 char* loc;
143 } locs[] = {
144 { BITS_32, "/usr/lib/libbeidpkcs11.so.0" },
145 { BITS_32, "/usr/lib/i386-linux-gnu/libbeidpkcs11.so.0" },
146 { BITS_64, "/usr/lib64/libbeidpkcs11.so.0" },
147 { BITS_64, "/usr/lib/x86_64-linux-gnu/libbeidpkcs11.so.0" },
148 { bitness, LIBDIR "/libbeidpkcs11.so.0" },
149 };
150 unsigned int i;
151 gboolean found32 = FALSE;
152 gboolean found64 = FALSE;
153 gboolean foundforeign = FALSE;
154 GtkTreeIter iter;
155
156 for(i=0;i<(sizeof(locs) / sizeof(locs[0]));i++) {
157 if(stat(locs[i].loc, &st) < 0) {
158 switch(errno) {
159 case ENOENT:
160 /* file does not exist */
161 break;
162 default:
163 dialog = gtk_message_dialog_new(GTK_WINDOW(top), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "stat: %s", strerror(errno));
164 gtk_dialog_run(GTK_DIALOG(dialog));
165 gtk_widget_destroy(dialog);
166 break;
167 }
168 } else {
169 gchar* str;
170 switch(locs[i].bitness) {
171 case BITS_32:
172 if(found32) continue;
173 str = _("32-bit PKCS#11 location");
174 found32 = TRUE;
175 break;
176 case BITS_64:
177 if(found64) continue;
178 str = _("64-bit PKCS#11 location");
179 found64 = TRUE;
180 break;
181 default:
182 str = _("PKCS#11 location");
183 foundforeign = TRUE;
184 break;
185 }
186
187 gtk_list_store_append(data, &iter);
188 gtk_list_store_set(data, &iter, 0, str, 1, locs[i].loc, -1);
189 }
190 }
191 switch(bitness) {
192 case BITS_32:
193 case BITS_64:
194 if(!found32) {
195 gtk_list_store_append(data, &iter);
196 gtk_list_store_set(data, &iter, 0, _("32-bit PKCS#11 location"), 1, _("(not found)"), -1);
197 }
198 if(!found64) {
199 gtk_list_store_append(data, &iter);
200 gtk_list_store_set(data, &iter, 0, _("64-bit PKCS#11 location"), 1, _("(not found)"), -1);
201 }
202 break;
203 default:
204 if(!foundforeign) {
205 gtk_list_store_append(data, &iter);
206 gtk_list_store_set(data, &iter, 0, _("PKCS#11 location"), 1, _("(not found)"), -1);
207 }
208 break;
209 }
210 }
211
do_gtk(GtkWidget * top,GtkListStore * data)212 void do_gtk(GtkWidget* top, GtkListStore* data) {
213 guint maj = gtk_get_major_version();
214 guint min = gtk_get_minor_version();
215 guint mic = gtk_get_micro_version();
216 GtkTreeIter iter;
217
218 gtk_list_store_append(data, &iter);
219 gchar *version = g_strdup_printf("%d.%d.%d", maj, min, mic);
220 gtk_list_store_set(data, &iter, 0, _("GTK library version"), 1, version, -1);
221 }
222
copyline_simple(GtkTreeModel * model,GtkTreePath * path G_GNUC_UNUSED,GtkTreeIter * iter,gchar ** text)223 void copyline_simple(GtkTreeModel* model, GtkTreePath *path G_GNUC_UNUSED, GtkTreeIter *iter, gchar** text) {
224 gchar *old = *text;
225 gchar *value;
226
227 gtk_tree_model_get(model, iter, 1, &value, -1);
228 if(*text == NULL) {
229 *text = g_strdup_printf("%s", value);
230 } else {
231 // should not happen, but better safe than sorry...
232 *text = g_strdup_printf("%s\n%s", old, value);
233 g_free(old);
234 }
235 }
236
copyline_detail(GtkTreeModel * model,GtkTreePath * path G_GNUC_UNUSED,GtkTreeIter * iter,gchar ** text)237 void copyline_detail(GtkTreeModel* model, GtkTreePath *path G_GNUC_UNUSED, GtkTreeIter *iter, gchar** text) {
238 gchar *old = *text;
239 gchar *name, *value;
240
241 gtk_tree_model_get(model, iter, 0, &name, 1, &value, -1);
242 if(*text == NULL) {
243 *text = g_strdup_printf("%s: %s", name, value);
244 } else {
245 *text = g_strdup_printf("%s\n%s: %s", old, name, value);
246 g_free(old);
247 }
248 }
249
copy2clip(GtkTreeView * tv)250 void copy2clip(GtkTreeView* tv) {
251 GtkClipboard* clip = gtk_clipboard_get(GDK_SELECTION_CLIPBOARD);
252 GtkTreeSelection* sel = gtk_tree_view_get_selection(tv);
253 GtkTreeSelectionForeachFunc copyline = (GtkTreeSelectionForeachFunc)copyline_detail;
254 gchar* text = NULL;
255 gint rowcount = gtk_tree_selection_count_selected_rows(sel);
256
257 if(rowcount == 1) {
258 copyline = (GtkTreeSelectionForeachFunc)copyline_simple;
259 }
260
261 gtk_tree_selection_selected_foreach(sel, copyline, &text);
262 if(!text) return;
263 gtk_clipboard_set_text(clip, text, strlen(text));
264 }
265
copy2prim(GtkTreeSelection * sel,gpointer user_data G_GNUC_UNUSED)266 void copy2prim(GtkTreeSelection* sel, gpointer user_data G_GNUC_UNUSED) {
267 GtkClipboard* clip = gtk_clipboard_get(GDK_SELECTION_PRIMARY);
268 gchar* text = NULL;
269 gint rowcount = gtk_tree_selection_count_selected_rows(sel);
270
271 if(rowcount != 1) {
272 return;
273 }
274 gtk_tree_selection_selected_foreach(sel, (GtkTreeSelectionForeachFunc)copyline_simple, &text);
275 gtk_clipboard_set_text(clip, text, strlen(text));
276 }
277
do_uname(GtkWidget * top,GtkListStore * data)278 void do_uname(GtkWidget* top, GtkListStore* data) {
279 GtkTreeIter iter;
280 struct utsname undat;
281 char* values;
282
283 if(uname(&undat) < 0) {
284 GtkWidget* dialog = gtk_message_dialog_new(GTK_WINDOW(top), GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "uname: %s", strerror(errno));
285 gtk_dialog_run(GTK_DIALOG(dialog));
286 gtk_widget_destroy(dialog);
287 }
288
289 gtk_list_store_append(data, &iter);
290 if(!strcmp(undat.machine, "x86_64")) {
291 bitness = BITS_64;
292 gtk_list_store_set(data, &iter, 0, _("System architecture"), 1, _("64-bit PC"), -1);
293 } else if(undat.machine[0] == 'i' && undat.machine[2] == '8' && undat.machine[3] == '6') {
294 bitness = BITS_32;
295 gtk_list_store_set(data, &iter, 0, _("System architecture"), 1, _("32-bit PC"), -1);
296 } else {
297 bitness = BITS_FOREIGN;
298 if(!strncmp(undat.machine, "arm", 3)) {
299 values = strdup(undat.machine);
300 } else {
301 asprintf(&values, _("Unknown (%s)"), undat.machine);
302 }
303 gtk_list_store_set(data, &iter, 0, _("System architecture"), 1, values, -1);
304 free(values);
305 }
306
307 gtk_list_store_append(data, &iter);
308 asprintf(&values, "%s %s %s %s %s", undat.sysname, undat.nodename, undat.release, undat.version, undat.machine);
309 gtk_list_store_set(data, &iter, 0, "uname", 1, values, -1);
310 free(values);
311 }
312
get_lsb_info(char opt)313 char* get_lsb_info(char opt) {
314 char cmd[] = "lsb_release -. -s";
315 char *rv, *loc;
316 FILE *f;
317
318 *(strchr(cmd, '.')) = opt;
319 f=popen(cmd, "r");
320 if(!f) {
321 return strdup(_("(unknown)"));
322 }
323 rv = malloc(80);
324 rv[79]='\0';
325 rv[0]='\0';
326 if(fgets(rv, 79, f) == NULL) {
327 free(rv);
328 rv = strdup(_("(unknown)"));
329 goto exit;
330 }
331 if(strlen(rv) == 0) {
332 free(rv);
333 rv = strdup(_("(unknown)"));
334 goto exit;
335 }
336 if((loc = strrchr(rv, '\n')) != NULL) {
337 *loc = '\0';
338 }
339 exit:
340 pclose(f);
341 return rv;
342 }
343
do_distro(GtkWidget * top G_GNUC_UNUSED,GtkListStore * data)344 void do_distro(GtkWidget* top G_GNUC_UNUSED, GtkListStore* data) {
345 GtkTreeIter iter;
346 char *dat;
347
348 dat = get_lsb_info('i');
349 gtk_list_store_append(data, &iter);
350 gtk_list_store_set(data, &iter, 0, _("Distribution"), 1, dat, -1);
351 free(dat);
352
353 dat = get_lsb_info('r');
354 gtk_list_store_append(data, &iter);
355 gtk_list_store_set(data, &iter, 0, _("Distribution version"), 1, dat, -1);
356 free(dat);
357
358 dat = get_lsb_info('c');
359 gtk_list_store_append(data, &iter);
360 gtk_list_store_set(data, &iter, 0, _("Distribution codename"), 1, dat, -1);
361 free(dat);
362 }
363
main(int argc,char ** argv)364 int main(int argc, char** argv) {
365 GtkBuilder* builder;
366 GtkWidget *window, *treeview, *button;
367 GtkCellRenderer *renderer;
368 GtkTreeViewColumn* col;
369 GtkTreeIter iter;
370 GtkListStore *store;
371 GtkAccelGroup *group;
372 GtkTreeSelection* sel;
373 gchar *tmp, *loc;
374 GError *err = NULL;
375
376 bindtextdomain("about-eid-mw", DATAROOTDIR "/locale");
377 textdomain("about-eid-mw");
378
379 gtk_init(&argc, &argv);
380
381 builder = gtk_builder_new();
382 if(!gtk_builder_add_from_string(builder, ABOUT_GLADE_STRING, strlen(ABOUT_GLADE_STRING), &err)) {
383 g_critical("could not load builder: %s", err->message);
384 exit(EXIT_FAILURE);
385 }
386 window = GTK_WIDGET(gtk_builder_get_object(builder, "window"));
387 group = gtk_accel_group_new();
388 gtk_window_add_accel_group(GTK_WINDOW(window), group);
389
390 treeview = GTK_WIDGET(gtk_builder_get_object(builder, "treeview"));
391
392 store = GTK_LIST_STORE(gtk_builder_get_object(builder, "infodata"));
393
394 tmp = g_strdup(PACKAGE_VERSION);
395 loc = strchr(tmp, '-');
396 *loc = '\0';
397 gtk_list_store_append(store, &iter);
398 gtk_list_store_set(store, &iter, 0, _("Middleware version"), 1, tmp, -1);
399 gtk_list_store_append(store, &iter);
400 gtk_list_store_set(store, &iter, 0, _("Middleware build ID"), 1, loc+1, -1);
401
402 gtk_list_store_append(store, &iter);
403 gtk_list_store_set(store, &iter, 0, _("Middleware build date"), 1, EID_NOW_STRING, -1);
404
405 check_pcsc(window, store);
406 do_viewer(window, store);
407 do_distro(window, store);
408 do_uname(window, store);
409 do_files(window, store);
410 do_gtk(window, store);
411
412 renderer = gtk_cell_renderer_text_new();
413 col = gtk_tree_view_column_new_with_attributes(_("Item"), renderer, "text", 0, NULL);
414 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), col);
415 col = gtk_tree_view_column_new_with_attributes(_("Value"), renderer, "text", 1, NULL);
416 gtk_tree_view_append_column(GTK_TREE_VIEW(treeview), col);
417
418 sel = GTK_TREE_SELECTION(gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview)));
419 gtk_tree_selection_set_mode(sel, GTK_SELECTION_MULTIPLE);
420 g_signal_connect(G_OBJECT(sel), "changed", G_CALLBACK(copy2prim), NULL);
421
422 g_signal_connect(G_OBJECT(window), "delete-event", gtk_main_quit, NULL);
423 button = GTK_WIDGET(gtk_builder_get_object(builder, "quitbtn"));
424 g_signal_connect(G_OBJECT(button), "clicked", gtk_main_quit, NULL);
425 gtk_widget_add_accelerator(button, "clicked", group, GDK_KEY_q, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
426 gtk_widget_add_accelerator(button, "clicked", group, GDK_KEY_w, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
427 button = GTK_WIDGET(gtk_builder_get_object(builder, "copybtn"));
428 g_signal_connect_swapped(G_OBJECT(button), "clicked", G_CALLBACK(copy2clip), treeview);
429 gtk_widget_add_accelerator(button, "clicked", group, GDK_KEY_c, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
430
431 gtk_widget_show_all(window);
432
433 gtk_main();
434
435 return 0;
436 }
437