[7d3ae3e] | 1 | /* |
---|
| 2 | * Estonian ID card plugin for web browsers |
---|
| 3 | * |
---|
| 4 | * Copyright (C) 2010-2011 Codeborne <info@codeborne.com> |
---|
| 5 | * |
---|
| 6 | * This is free software; you can redistribute it and/or |
---|
| 7 | * modify it under the terms of the GNU Lesser General Public |
---|
| 8 | * License as published by the Free Software Foundation; either |
---|
| 9 | * version 2.1 of the License, or (at your option) any later version. |
---|
| 10 | * |
---|
| 11 | * This software is distributed in the hope that it will be useful, |
---|
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
| 14 | * Lesser General Public License for more details. |
---|
| 15 | * |
---|
| 16 | * You should have received a copy of the GNU Lesser General Public |
---|
| 17 | * License along with this library; if not, write to the Free Software |
---|
| 18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
---|
| 19 | * |
---|
| 20 | */ |
---|
| 21 | |
---|
| 22 | #include <stdlib.h> |
---|
| 23 | #include <stdio.h> |
---|
| 24 | #include <string.h> |
---|
| 25 | #include <gtk/gtk.h> |
---|
| 26 | #include <gdk/gdkx.h> |
---|
| 27 | #include <gdk/gdkkeysyms.h> |
---|
| 28 | |
---|
| 29 | #include <gdk/gdk.h> |
---|
| 30 | #include "dialogs.h" |
---|
| 31 | #include "esteid_log.h" |
---|
| 32 | #include "l10n.h" |
---|
| 33 | #include "esteid_map.h" |
---|
| 34 | #include "esteid_certinfo.h" |
---|
| 35 | #include "esteid_time.h" |
---|
| 36 | #include "esteid_dialog_common.h" |
---|
| 37 | |
---|
| 38 | GtkWidget *dialog; |
---|
| 39 | GtkWidget* progressBar; |
---|
| 40 | int timeoutCounter; |
---|
| 41 | guint timerID; |
---|
| 42 | |
---|
| 43 | typedef struct { |
---|
| 44 | GtkWidget* button; |
---|
| 45 | unsigned minPin2Length; |
---|
| 46 | } EstEID_PIN2LengthControlData; |
---|
| 47 | |
---|
| 48 | void setDialogProperties(GtkWidget *dialog, GtkWidget *window) { |
---|
| 49 | gtk_container_set_border_width(GTK_CONTAINER(dialog), 5); |
---|
| 50 | gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(window)); |
---|
| 51 | gtk_window_set_modal(GTK_WINDOW(dialog), TRUE); |
---|
| 52 | gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK); |
---|
| 53 | gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE); |
---|
| 54 | gtk_window_set_urgency_hint(GTK_WINDOW(dialog), TRUE); |
---|
| 55 | } |
---|
| 56 | |
---|
| 57 | static void enableButtonWhenPINLengthIsCorrect(GtkWidget* entry, EstEID_PIN2LengthControlData* pin2LengthControl) { |
---|
| 58 | gtk_widget_set_sensitive(GTK_WIDGET(pin2LengthControl->button), gtk_entry_get_text_length(GTK_ENTRY(entry)) >= pin2LengthControl->minPin2Length); |
---|
| 59 | } |
---|
| 60 | |
---|
| 61 | GtkWidget *createPIN2Dialog(GtkWidget *window, GtkWidget *entry, const char *nameAndID, const char *message, const unsigned minPin2Length) { |
---|
| 62 | dialog = gtk_dialog_new_with_buttons(createDialogTitle(nameAndID), GTK_WINDOW(window), |
---|
| 63 | GTK_DIALOG_DESTROY_WITH_PARENT, |
---|
| 64 | NULL); |
---|
| 65 | |
---|
| 66 | gtk_dialog_add_button((GtkDialog*) dialog, (const gchar*) l10n("Cancel"), GTK_RESPONSE_CANCEL); |
---|
| 67 | GtkWidget* signButton = gtk_dialog_add_button((GtkDialog*) dialog, (const gchar*) l10n("Sign"), GTK_RESPONSE_OK); |
---|
| 68 | gtk_widget_set_sensitive(signButton, FALSE); |
---|
| 69 | |
---|
| 70 | setDialogProperties(dialog, window); |
---|
| 71 | |
---|
| 72 | GtkWidget* vbox = gtk_vbox_new(FALSE, 12); |
---|
| 73 | |
---|
| 74 | if (message && message[0]) { |
---|
| 75 | GtkWidget *messageLabel = gtk_label_new(NULL); |
---|
| 76 | char *markup = g_markup_printf_escaped("<span color='red'>%s</span>", message); |
---|
| 77 | gtk_label_set_markup(GTK_LABEL(messageLabel), markup); |
---|
| 78 | free(markup); |
---|
| 79 | gtk_container_add(GTK_CONTAINER(vbox), messageLabel); |
---|
| 80 | } |
---|
| 81 | GtkWidget *nameLabel = gtk_label_new(nameAndID); |
---|
| 82 | gtk_container_add(GTK_CONTAINER(vbox), nameLabel); |
---|
| 83 | gtk_misc_set_alignment(GTK_MISC(nameLabel), 0.0, 0.0); |
---|
| 84 | |
---|
| 85 | GtkWidget* hbox = gtk_hbox_new(FALSE, 12); |
---|
| 86 | |
---|
| 87 | EstEID_PIN2LengthControlData* pin2LengthControl; |
---|
| 88 | pin2LengthControl = g_new0(EstEID_PIN2LengthControlData, 1); |
---|
| 89 | pin2LengthControl->button = signButton; |
---|
| 90 | pin2LengthControl->minPin2Length = minPin2Length; |
---|
| 91 | |
---|
| 92 | g_signal_connect(G_OBJECT(entry), "changed", G_CALLBACK(enableButtonWhenPINLengthIsCorrect), (gpointer) pin2LengthControl); |
---|
| 93 | gtk_entry_set_visibility(GTK_ENTRY(entry), FALSE); |
---|
| 94 | gtk_entry_set_max_length(GTK_ENTRY(entry), 12); |
---|
| 95 | gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE); |
---|
| 96 | |
---|
| 97 | GtkWidget *label = gtk_label_new(l10n("For signing enter PIN2:")); |
---|
| 98 | gtk_label_set_use_underline(GTK_LABEL(label), TRUE); |
---|
| 99 | gtk_label_set_mnemonic_widget(GTK_LABEL(label), entry); |
---|
| 100 | |
---|
| 101 | gtk_container_add(GTK_CONTAINER(hbox), label); |
---|
| 102 | gtk_container_add(GTK_CONTAINER(hbox), entry); |
---|
| 103 | |
---|
| 104 | gtk_container_add(GTK_CONTAINER(vbox), hbox); |
---|
| 105 | gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); |
---|
| 106 | |
---|
| 107 | gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), vbox); |
---|
| 108 | gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); |
---|
| 109 | |
---|
| 110 | gtk_container_set_border_width(GTK_CONTAINER(dialog), 5); |
---|
| 111 | |
---|
| 112 | g_signal_connect(G_OBJECT(dialog), "destroy", G_CALLBACK(gtk_main_quit), NULL); |
---|
| 113 | |
---|
| 114 | gtk_widget_show_all(dialog); |
---|
| 115 | return dialog; |
---|
| 116 | } |
---|
| 117 | |
---|
| 118 | gint keyHandler(GtkWidget *window, GdkEventKey *key) { |
---|
| 119 | LOG_LOCATION; |
---|
| 120 | return TRUE; |
---|
| 121 | } |
---|
| 122 | |
---|
| 123 | static gboolean closingPreventionHandler(GtkWidget *window, GdkEvent *event, gpointer data) { |
---|
| 124 | LOG_LOCATION; |
---|
| 125 | EstEID_log("preventing to close widget %s", gtk_widget_get_name(GTK_WIDGET(window))); |
---|
| 126 | return TRUE; |
---|
| 127 | } |
---|
| 128 | |
---|
| 129 | GtkWidget *createPINPadDialog(GtkWidget *window, const char *nameAndID, const char *message) { |
---|
| 130 | LOG_LOCATION; |
---|
| 131 | dialog = gtk_dialog_new_with_buttons(createDialogTitle(nameAndID), GTK_WINDOW(window), |
---|
| 132 | GTK_DIALOG_DESTROY_WITH_PARENT, NULL); |
---|
| 133 | |
---|
| 134 | setDialogProperties(dialog, window); |
---|
| 135 | |
---|
| 136 | GtkWidget* vbox = gtk_vbox_new(FALSE, 12); |
---|
| 137 | |
---|
| 138 | if (message && message[0]) { |
---|
| 139 | GtkWidget* messageLabel = gtk_label_new(NULL); |
---|
| 140 | char* markup = g_markup_printf_escaped("<span color='red'>%s</span>", message); |
---|
| 141 | gtk_label_set_markup(GTK_LABEL(messageLabel), markup); |
---|
| 142 | free(markup); |
---|
| 143 | gtk_container_add(GTK_CONTAINER(vbox), messageLabel); |
---|
| 144 | } |
---|
| 145 | GtkWidget *nameLabel = gtk_label_new(nameAndID); |
---|
| 146 | gtk_container_add(GTK_CONTAINER(vbox), nameLabel); |
---|
| 147 | gtk_misc_set_alignment(GTK_MISC(nameLabel), 0.0, 0.0); |
---|
| 148 | |
---|
| 149 | GtkWidget* hbox = gtk_hbox_new(FALSE, 12); |
---|
| 150 | |
---|
| 151 | GtkWidget* label = gtk_label_new(l10n("For signing enter PIN2 from PIN pad")); |
---|
| 152 | gtk_label_set_use_underline(GTK_LABEL(label), TRUE); |
---|
| 153 | |
---|
| 154 | progressBar = gtk_progress_bar_new(); |
---|
| 155 | gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progressBar), (gdouble) 1.0); |
---|
| 156 | |
---|
| 157 | gtk_container_add(GTK_CONTAINER(hbox), label); |
---|
| 158 | |
---|
| 159 | gtk_container_add(GTK_CONTAINER(vbox), hbox); |
---|
| 160 | gtk_container_add(GTK_CONTAINER(vbox), progressBar); |
---|
| 161 | gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); |
---|
| 162 | |
---|
| 163 | gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), vbox); |
---|
| 164 | gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); |
---|
| 165 | |
---|
| 166 | gtk_container_set_border_width(GTK_CONTAINER(dialog), 5); |
---|
| 167 | |
---|
| 168 | g_signal_connect(G_OBJECT(dialog), "key_press_event", G_CALLBACK(keyHandler), NULL); |
---|
| 169 | g_signal_connect(G_OBJECT(dialog), "delete-event", G_CALLBACK(closingPreventionHandler), NULL); |
---|
| 170 | g_signal_connect(G_OBJECT(dialog), "destroy", G_CALLBACK(gtk_main_quit), NULL); |
---|
| 171 | |
---|
| 172 | gtk_widget_show_all(dialog); |
---|
| 173 | return dialog; |
---|
| 174 | } |
---|
| 175 | |
---|
| 176 | GtkWidget *getGtkWindow(void *nativeWindowHandle) { |
---|
| 177 | GdkWindow *p = (GdkWindow *) gdk_window_lookup((XID) nativeWindowHandle); |
---|
| 178 | GtkWidget *window = NULL; |
---|
| 179 | gdk_window_get_user_data(p, (gpointer *) & window); |
---|
| 180 | return window; |
---|
| 181 | } |
---|
| 182 | |
---|
| 183 | void showAlert(void *nativeWindowHandle, const char *message) { |
---|
| 184 | GtkWidget *window = getGtkWindow(nativeWindowHandle); |
---|
| 185 | GtkWidget *alertDialog = gtk_message_dialog_new(GTK_WINDOW(window), GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, message, ""); |
---|
| 186 | gtk_window_set_title(GTK_WINDOW(alertDialog), l10n("Error")); |
---|
| 187 | gtk_dialog_run(GTK_DIALOG(alertDialog)); |
---|
| 188 | gtk_widget_destroy(alertDialog); |
---|
| 189 | } |
---|
| 190 | |
---|
| 191 | void killCountdownTimer() { |
---|
| 192 | if (timerID) { |
---|
| 193 | if (g_source_remove(timerID)) { |
---|
| 194 | EstEID_log("killed timer %u", timerID); |
---|
| 195 | } |
---|
| 196 | else { |
---|
| 197 | EstEID_log("unable to kill timer %u (probably dead already)", timerID); |
---|
| 198 | } |
---|
| 199 | timerID = 0; |
---|
| 200 | } |
---|
| 201 | } |
---|
| 202 | |
---|
| 203 | static gboolean updateCountdownProgressBar() { |
---|
| 204 | --timeoutCounter; |
---|
| 205 | if (timeoutCounter <= 0) { |
---|
| 206 | EstEID_log("countdown reached 0, killing timer by returning FALSE from callback"); |
---|
| 207 | timerID = 0; |
---|
| 208 | return FALSE; |
---|
| 209 | } |
---|
| 210 | gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(progressBar), (gdouble) timeoutCounter / (gdouble) 30); |
---|
| 211 | return TRUE; |
---|
| 212 | } |
---|
| 213 | |
---|
| 214 | char *promptForPIN(void *nativeWindowHandle, const char *name, const char *message, unsigned minPin2Length, int usePinPad) { |
---|
| 215 | LOG_LOCATION; |
---|
| 216 | GtkWidget *window = getGtkWindow(nativeWindowHandle); |
---|
| 217 | GtkWidget *entry = gtk_entry_new(); |
---|
| 218 | char *pin; |
---|
| 219 | |
---|
| 220 | if (!usePinPad) { |
---|
| 221 | // Simple card reader |
---|
| 222 | dialog = createPIN2Dialog(window, entry, name, message, minPin2Length); |
---|
| 223 | |
---|
| 224 | gint result = gtk_dialog_run(GTK_DIALOG(dialog)); |
---|
| 225 | gtk_widget_hide(dialog); |
---|
| 226 | if (result == GTK_RESPONSE_OK) { |
---|
| 227 | pin = strdup(gtk_entry_get_text(GTK_ENTRY(entry))); |
---|
| 228 | EstEID_log("promptForPIN\t got pin"); |
---|
| 229 | } |
---|
| 230 | else { |
---|
| 231 | pin = strdup(""); |
---|
| 232 | EstEID_log("promptForPIN\t user canceled"); |
---|
| 233 | } |
---|
| 234 | } |
---|
| 235 | else { |
---|
| 236 | // PIN pad |
---|
| 237 | killCountdownTimer(); |
---|
| 238 | timeoutCounter = 30; |
---|
| 239 | EstEID_log("timeoutCounter value set to %i", timeoutCounter); |
---|
| 240 | dialog = createPINPadDialog(window, name, message); |
---|
| 241 | g_signal_connect(G_OBJECT(dialog), "destroy", G_CALLBACK(updateCountdownProgressBar), NULL); |
---|
| 242 | timerID = g_timeout_add_seconds(1, (GSourceFunc) updateCountdownProgressBar, NULL); |
---|
| 243 | EstEID_log("created timer %u", timerID); |
---|
| 244 | gtk_dialog_run(GTK_DIALOG(dialog)); |
---|
| 245 | pin = strdup(""); |
---|
| 246 | } |
---|
| 247 | |
---|
| 248 | return pin; |
---|
| 249 | } |
---|
| 250 | |
---|
| 251 | static GtkTreeModel* createAndFillModel() { |
---|
| 252 | GtkListStore *certificatesList = gtk_list_store_new(4, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); |
---|
| 253 | GtkTreeIter iterator; |
---|
| 254 | char *validTo = NULL; |
---|
| 255 | |
---|
| 256 | EstEID_Certs *certs = EstEID_loadCerts(); |
---|
| 257 | EstEID_log("%i certificates found", certs->count); |
---|
| 258 | for (int i = 0; i < certs->count; i++) { |
---|
| 259 | EstEID_Map cert = certs->certs[i]; |
---|
| 260 | if (!EstEID_mapGet(cert, "usageNonRepudiation")) continue; |
---|
| 261 | |
---|
| 262 | validTo = getDateFromDateTime(EstEID_mapGet(cert, "validTo")); |
---|
| 263 | |
---|
| 264 | gtk_list_store_append(certificatesList, &iterator); |
---|
| 265 | gtk_list_store_set(certificatesList, &iterator, |
---|
| 266 | 0, EstEID_mapGet(cert, "commonName"), |
---|
| 267 | 1, EstEID_mapGet(cert, "organizationName"), |
---|
| 268 | 2, validTo, |
---|
| 269 | 3, EstEID_mapGet(cert, "certHash"), |
---|
| 270 | -1); |
---|
| 271 | if (validTo) { |
---|
| 272 | free(validTo); |
---|
| 273 | validTo = NULL; |
---|
| 274 | } |
---|
| 275 | } |
---|
| 276 | return GTK_TREE_MODEL(certificatesList); |
---|
| 277 | } |
---|
| 278 | |
---|
| 279 | static void selectionFunction(GtkTreeSelection* selection, GtkDialog* dialog) { |
---|
| 280 | gtk_dialog_set_response_sensitive(dialog, GTK_RESPONSE_OK, gtk_tree_selection_count_selected_rows(selection) > 0); |
---|
| 281 | } |
---|
| 282 | |
---|
| 283 | static void doubleClick(GtkTreeView* treeView, GtkTreePath* path, GtkTreeViewColumn *col, GtkDialog* dialog) { |
---|
| 284 | gtk_dialog_response(dialog, GTK_RESPONSE_OK); |
---|
| 285 | } |
---|
| 286 | |
---|
| 287 | GtkWidget *createCertificateSelectionView(GtkWidget *window) { |
---|
| 288 | GtkWidget* certificatesView = gtk_tree_view_new(); |
---|
| 289 | |
---|
| 290 | gtk_widget_set_size_request(certificatesView, 400, 200); |
---|
| 291 | |
---|
| 292 | GtkCellRenderer* renderer; |
---|
| 293 | |
---|
| 294 | renderer = gtk_cell_renderer_text_new(); |
---|
| 295 | |
---|
| 296 | GtkTreeViewColumn* col1 = gtk_tree_view_column_new_with_attributes(l10n("Certificate"), renderer, "text", 0, NULL); |
---|
| 297 | col1->expand = TRUE; |
---|
| 298 | gtk_tree_view_append_column(GTK_TREE_VIEW(certificatesView), col1); |
---|
| 299 | |
---|
| 300 | renderer = gtk_cell_renderer_text_new(); |
---|
| 301 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(certificatesView), -1, l10n("Type"), renderer, "text", 1, NULL); |
---|
| 302 | |
---|
| 303 | renderer = gtk_cell_renderer_text_new(); |
---|
| 304 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(certificatesView), -1, l10n("Valid to"), renderer, "text", 2, NULL); |
---|
| 305 | |
---|
| 306 | gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(certificatesView), TRUE); |
---|
| 307 | GtkTreeModel* model = createAndFillModel(); |
---|
| 308 | |
---|
| 309 | gtk_tree_view_set_model(GTK_TREE_VIEW(certificatesView), model); |
---|
| 310 | |
---|
| 311 | GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(certificatesView)); |
---|
| 312 | GtkTreeIter iter; |
---|
| 313 | if (gtk_tree_model_get_iter_first(model, &iter)) { |
---|
| 314 | gtk_tree_selection_select_iter(selection, &iter); |
---|
| 315 | selectionFunction(selection, GTK_DIALOG(window)); |
---|
| 316 | } |
---|
| 317 | |
---|
| 318 | g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(selectionFunction), GTK_DIALOG(window)); |
---|
| 319 | g_signal_connect(G_OBJECT(certificatesView), "row-activated", G_CALLBACK(doubleClick), GTK_DIALOG(window)); |
---|
| 320 | |
---|
| 321 | return certificatesView; |
---|
| 322 | } |
---|
| 323 | |
---|
| 324 | int promptForCertificate(void *nativeWindowHandle, char* certId) { |
---|
| 325 | certId[0] = '\0'; |
---|
| 326 | |
---|
| 327 | GtkWidget *window = getGtkWindow(nativeWindowHandle); |
---|
| 328 | dialog = gtk_dialog_new_with_buttons(l10n("Select certificate"), GTK_WINDOW(window), // ToDo l10n |
---|
| 329 | GTK_DIALOG_DESTROY_WITH_PARENT, |
---|
| 330 | NULL); |
---|
| 331 | |
---|
| 332 | gtk_dialog_add_button((GtkDialog*) dialog, (const gchar*) l10n("Cancel"), GTK_RESPONSE_CANCEL); |
---|
| 333 | gtk_dialog_add_button((GtkDialog*) dialog, (const gchar*) l10n("Select"), GTK_RESPONSE_OK); |
---|
| 334 | |
---|
| 335 | gtk_dialog_set_response_sensitive(GTK_DIALOG(dialog), GTK_RESPONSE_OK, FALSE); |
---|
| 336 | |
---|
| 337 | GtkWidget *warningLabel = gtk_label_new((const gchar*) l10n("By selecting a certificate I accept that my name and personal ID code will be sent to service provider.")); |
---|
| 338 | GtkWidget* vbox = gtk_vbox_new(FALSE, 12); |
---|
| 339 | gtk_container_set_border_width(GTK_CONTAINER(vbox), 10); |
---|
| 340 | gtk_container_add(GTK_CONTAINER(vbox), warningLabel); |
---|
| 341 | gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), vbox); |
---|
| 342 | |
---|
| 343 | GtkWidget* certificatesView = createCertificateSelectionView(dialog); |
---|
| 344 | |
---|
| 345 | gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), certificatesView); |
---|
| 346 | |
---|
| 347 | setDialogProperties(dialog, window); |
---|
| 348 | gtk_dialog_set_has_separator(GTK_DIALOG(dialog), FALSE); |
---|
| 349 | gtk_widget_show_all(dialog); |
---|
| 350 | |
---|
| 351 | gint result = gtk_dialog_run(GTK_DIALOG(dialog)); |
---|
| 352 | |
---|
| 353 | gtk_widget_hide(dialog); |
---|
| 354 | |
---|
| 355 | int returnValue = IDCANCEL; |
---|
| 356 | if (result == GTK_RESPONSE_OK) { |
---|
| 357 | GtkTreeSelection* selectedRow = gtk_tree_view_get_selection(GTK_TREE_VIEW(certificatesView)); |
---|
| 358 | GtkTreeModel* model = NULL; |
---|
| 359 | GtkTreeIter iter; |
---|
| 360 | if (gtk_tree_selection_get_selected(selectedRow, &model, &iter)) { |
---|
| 361 | gchar* id; |
---|
| 362 | gtk_tree_model_get(model, &iter, 3, &id, -1); |
---|
| 363 | strcpy(certId, id); |
---|
| 364 | g_free(id); |
---|
| 365 | returnValue = IDOK; |
---|
| 366 | EstEID_log("promptForCertificate dialog returned cert ID %s", certId); |
---|
| 367 | } |
---|
| 368 | else { |
---|
| 369 | EstEID_log("promptForCertificate dialog returned without cert selection"); |
---|
| 370 | } |
---|
| 371 | } |
---|
| 372 | else { |
---|
| 373 | EstEID_log("promptForCertificate dialog canceled by user"); |
---|
| 374 | } |
---|
| 375 | gtk_widget_destroy(dialog); |
---|
| 376 | return returnValue; |
---|
| 377 | } |
---|
| 378 | |
---|
| 379 | void closePinPadModalSheet() { |
---|
| 380 | LOG_LOCATION; |
---|
| 381 | killCountdownTimer(); |
---|
| 382 | gtk_widget_destroy(dialog); |
---|
| 383 | } |
---|