GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gnc-gwen-gui.c
1 /*
2  * gnc-gwen-gui.c --
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, contact:
16  *
17  * Free Software Foundation Voice: +1-617-542-5942
18  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
19  * Boston, MA 02110-1301, USA [email protected]
20  */
21 
31 #include "config.h"
32 
33 #include <ctype.h>
34 #include <glib/gi18n.h>
35 #include <gwenhywfar/gui_be.h>
36 #include <gwenhywfar/inherit.h>
37 
38 #include "dialog-utils.h"
39 #include "gnc-ab-utils.h"
40 #include "gnc-component-manager.h"
41 #include "gnc-gwen-gui.h"
42 #include "gnc-session.h"
43 #include "gnc-prefs.h"
44 #include "gnc-ui.h"
45 #include "gnc-plugin-aqbanking.h"
46 #include "qof.h"
47 
48 #if GWENHYWFAR_VERSION_INT >= 39921
49 /* For sufficiently new gwenhywfar (>=3.99.21) the gtk2 gui object is
50  * working fine and it is enabled here here. */
51 # define USING_GWENHYWFAR_GTK2_GUI
52 # define GNC_GWENHYWFAR_CB GWENHYWFAR_CB
53 #else
54 # define GNC_GWENHYWFAR_CB
55 #endif
56 
57 #define GWEN_GUI_CM_CLASS "dialog-hbcilog"
58 #define GNC_PREFS_GROUP_CONNECTION GNC_PREFS_GROUP_AQBANKING ".connection-dialog"
59 #define GNC_PREF_CLOSE_ON_FINISH "close-on-finish"
60 #define GNC_PREF_REMEMBER_PIN "remember-pin"
61 
62 #ifdef USING_GWENHYWFAR_GTK2_GUI
63 # include <gwen-gui-gtk2/gtk2_gui.h>
64 #endif
65 
66 /* This static indicates the debugging module that this .o belongs to. */
67 static QofLogModule log_module = G_LOG_DOMAIN;
68 
69 /* The following block can be enabled, but the gwen-gtk2 widgets might
70  * still need some work. */
71 #if 0 /*#ifdef USING_GWENHYWFAR_GTK2_GUI*/
72 
73 /* A GWEN_GUI implementation using gtk2 widgets */
74 static GWEN_GUI *gwen_gui = NULL;
75 
76 void gnc_GWEN_Gui_log_init(void)
77 {
78  if (!gwen_gui)
79  {
80  gwen_gui = Gtk2_Gui_new();
81  GWEN_Gui_SetGui(gwen_gui);
82  }
83 }
84 GncGWENGui *gnc_GWEN_Gui_get(GtkWidget *parent)
85 {
86  if (!gwen_gui)
88  return (GncGWENGui*) gwen_gui;
89 }
90 void gnc_GWEN_Gui_release(GncGWENGui *gui)
91 {
92 }
93 void gnc_GWEN_Gui_shutdown(void)
94 {
95  if (gwen_gui)
96  {
97  GWEN_Gui_free(gwen_gui);
98  gwen_gui = NULL;
99  GWEN_Gui_SetGui(NULL);
100  }
101 }
102 void
103 gnc_GWEN_Gui_set_close_flag(gboolean close_when_finished)
104 {
106  GNC_PREFS_GROUP_AQBANKING, GNC_PREF_CLOSE_ON_FINISH,
107  close_when_finished);
108 }
109 gboolean
111 {
112  return gnc_prefs_get_bool (GNC_PREFS_GROUP_AQBANKING, GNC_PREF_CLOSE_ON_FINISH);
113 }
114 
115 gboolean
117 {
118  return TRUE;
119 }
120 
121 void
123 {
124 }
125 
126 #else
127 
128 /* A unique full-blown GUI, featuring */
129 static GncGWENGui *full_gui = NULL;
130 
131 /* A unique Gwenhywfar GUI for hooking our logging into the gwenhywfar logging
132  * framework */
133 static GWEN_GUI *log_gwen_gui = NULL;
134 
135 /* A mapping from gwenhywfar log levels to glib ones */
136 static GLogLevelFlags log_levels[] =
137 {
138  G_LOG_LEVEL_ERROR, /* GWEN_LoggerLevel_Emergency */
139  G_LOG_LEVEL_ERROR, /* GWEN_LoggerLevel_Alert */
140  G_LOG_LEVEL_CRITICAL, /* GWEN_LoggerLevel_Critical */
141  G_LOG_LEVEL_CRITICAL, /* GWEN_LoggerLevel_Error */
142  G_LOG_LEVEL_WARNING, /* GWEN_LoggerLevel_Warning */
143  G_LOG_LEVEL_MESSAGE, /* GWEN_LoggerLevel_Notice */
144  G_LOG_LEVEL_INFO, /* GWEN_LoggerLevel_Info */
145  G_LOG_LEVEL_DEBUG, /* GWEN_LoggerLevel_Debug */
146  G_LOG_LEVEL_DEBUG /* GWEN_LoggerLevel_Verbous */
147 };
148 static guint8 n_log_levels = G_N_ELEMENTS(log_levels);
149 
150 /* Macros to determine the GncGWENGui* from a GWEN_GUI* */
151 GWEN_INHERIT(GWEN_GUI, GncGWENGui)
152 #define SETDATA_GUI(gwen_gui, gui) GWEN_INHERIT_SETDATA(GWEN_GUI, GncGWENGui, \
153  (gwen_gui), (gui), NULL)
154 #define GETDATA_GUI(gwen_gui) GWEN_INHERIT_GETDATA(GWEN_GUI, GncGWENGui, (gwen_gui))
155 
156 #define OTHER_ENTRIES_ROW_OFFSET 3
157 
158 typedef struct _Progress Progress;
159 typedef enum _GuiState GuiState;
160 
161 static void register_callbacks(GncGWENGui *gui);
162 static void unregister_callbacks(GncGWENGui *gui);
163 static void setup_dialog(GncGWENGui *gui);
164 static void enable_password_cache(GncGWENGui *gui, gboolean enabled);
165 static void reset_dialog(GncGWENGui *gui);
166 static void set_finished(GncGWENGui *gui);
167 static void set_aborted(GncGWENGui *gui);
168 static void show_dialog(GncGWENGui *gui, gboolean clear_log);
169 static void hide_dialog(GncGWENGui *gui);
170 static gboolean show_progress_cb(gpointer user_data);
171 static void show_progress(GncGWENGui *gui, Progress *progress);
172 static void hide_progress(GncGWENGui *gui, Progress *progress);
173 static void free_progress(Progress *progress, gpointer unused);
174 static gboolean keep_alive(GncGWENGui *gui);
175 static void cm_close_handler(gpointer user_data);
176 static void erase_password(gchar *password);
177 static gchar *strip_html(gchar *text);
178 static void get_input(GncGWENGui *gui, guint32 flags, const gchar *title,
179  const gchar *text, gchar **input, gint min_len,
180  gint max_len);
181 static gint messagebox_cb(GWEN_GUI *gwen_gui, guint32 flags, const gchar *title,
182  const gchar *text, const gchar *b1, const gchar *b2,
183  const gchar *b3, guint32 guiid);
184 static gint inputbox_cb(GWEN_GUI *gwen_gui, guint32 flags, const gchar *title,
185  const gchar *text, gchar *buffer, gint min_len,
186  gint max_len, guint32 guiid);
187 static guint32 showbox_cb(GWEN_GUI *gwen_gui, guint32 flags, const gchar *title,
188  const gchar *text, guint32 guiid);
189 static void hidebox_cb(GWEN_GUI *gwen_gui, guint32 id);
190 static guint32 progress_start_cb(GWEN_GUI *gwen_gui, uint32_t progressFlags,
191  const char *title, const char *text,
192  uint64_t total, uint32_t guiid);
193 static gint progress_advance_cb(GWEN_GUI *gwen_gui, uint32_t id,
194  uint64_t new_progress);
195 static gint progress_log_cb(GWEN_GUI *gwen_gui, guint32 id,
196  GWEN_LOGGER_LEVEL level, const gchar *text);
197 static gint progress_end_cb(GWEN_GUI *gwen_gui, guint32 id);
198 static gint GNC_GWENHYWFAR_CB getpassword_cb(GWEN_GUI *gwen_gui, guint32 flags, const gchar *token,
199  const gchar *title, const gchar *text, gchar *buffer,
200  gint min_len, gint max_len, guint32 guiid);
201 static gint GNC_GWENHYWFAR_CB setpasswordstatus_cb(GWEN_GUI *gwen_gui, const gchar *token,
202  const gchar *pin,
203  GWEN_GUI_PASSWORD_STATUS status, guint32 guiid);
204 static gint GNC_GWENHYWFAR_CB loghook_cb(GWEN_GUI *gwen_gui, const gchar *log_domain,
205  GWEN_LOGGER_LEVEL priority, const gchar *text);
206 #ifdef AQBANKING_VERSION_5_PLUS
207 typedef GWEN_SYNCIO GWEN_IO_LAYER;
208 #endif
209 static gint GNC_GWENHYWFAR_CB checkcert_cb(GWEN_GUI *gwen_gui, const GWEN_SSLCERTDESCR *cert,
210  GWEN_IO_LAYER *io, guint32 guiid);
211 
212 gboolean ggg_delete_event_cb(GtkWidget *widget, GdkEvent *event,
213  gpointer user_data);
214 void ggg_abort_clicked_cb(GtkButton *button, gpointer user_data);
215 void ggg_close_clicked_cb(GtkButton *button, gpointer user_data);
216 void ggg_close_toggled_cb(GtkToggleButton *button, gpointer user_data);
217 
218 enum _GuiState
219 {
220  INIT,
221  RUNNING,
222  FINISHED,
223  ABORTED,
224  HIDDEN
225 };
226 
228 {
229  GWEN_GUI *gwen_gui;
230  GtkWidget *parent;
231  GtkWidget *dialog;
232 
233  /* Progress bars */
234  GtkWidget *entries_table;
235  GtkWidget *top_entry;
236  GtkWidget *top_progress;
237  GtkWidget *second_entry;
238  GtkWidget *other_entries_box;
239 
240  /* Stack of nested Progresses */
241  GList *progresses;
242 
243  /* Number of steps in top-level progress or -1 */
244  guint64 max_actions;
245  guint64 current_action;
246 
247  /* Log window */
248  GtkWidget *log_text;
249 
250  /* Buttons */
251  GtkWidget *abort_button;
252  GtkWidget *close_button;
253  GtkWidget *close_checkbutton;
254 
255  /* Flags to keep track on whether an HBCI action is running or not */
256  gboolean keep_alive;
257  GuiState state;
258 
259  /* Password caching */
260  gboolean cache_passwords;
261  GHashTable *passwords;
262 
263  /* Certificates handling */
264  GHashTable *accepted_certs;
265  GWEN_DB_NODE *permanently_accepted_certs;
266  GWEN_GUI_CHECKCERT_FN builtin_checkcert;
267 
268  /* Dialogs */
269  guint32 showbox_id;
270  GHashTable *showbox_hash;
271  GtkWidget *showbox_last;
272 
273  /* Cache the lowest loglevel, corresponding to the most serious warning */
274  GWEN_LOGGER_LEVEL min_loglevel;
275 };
276 
277 struct _Progress
278 {
279  GncGWENGui *gui;
280 
281  /* Title of the process */
282  gchar *title;
283 
284  /* Event source id for showing delayed */
285  guint source;
286 };
287 
288 void
290 {
291  if (!log_gwen_gui)
292  {
293  log_gwen_gui =
294 #ifdef USING_GWENHYWFAR_GTK2_GUI
295  Gtk2_Gui_new()
296 #else
297  GWEN_Gui_new()
298 #endif
299  ;
300 
301  /* Always use our own logging */
302  GWEN_Gui_SetLogHookFn(log_gwen_gui, loghook_cb);
303 
304  /* Keep a reference so that the GWEN_GUI survives a GUI switch */
305  GWEN_Gui_Attach(log_gwen_gui);
306  }
307  GWEN_Gui_SetGui(log_gwen_gui);
308 }
309 
310 GncGWENGui *
311 gnc_GWEN_Gui_get(GtkWidget *parent)
312 {
313  GncGWENGui *gui;
314 
315  ENTER("parent=%p", parent);
316 
317  if (full_gui)
318  {
319  if (full_gui->state == INIT || full_gui->state == RUNNING)
320  {
321  LEAVE("full_gui in use, state=%d", full_gui->state);
322  return NULL;
323  }
324 
325  gui = full_gui;
326  gui->parent = parent;
327  reset_dialog(gui);
328  register_callbacks(gui);
329 
330  LEAVE("gui=%p", gui);
331  return gui;
332  }
333 
334  gui = g_new0(GncGWENGui, 1);
335  gui->parent = parent;
336  setup_dialog(gui);
337  register_callbacks(gui);
338 
339  full_gui = gui;
340 
341  LEAVE("new gui=%p", gui);
342  return gui;
343 }
344 
345 void
346 gnc_GWEN_Gui_release(GncGWENGui *gui)
347 {
348  g_return_if_fail(gui && gui == full_gui);
349 
350  /* Currently a no-op */
351  ENTER("gui=%p", gui);
352  LEAVE(" ");
353 }
354 
355 void
357 {
358  GncGWENGui *gui = full_gui;
359 
360  ENTER(" ");
361 
362  if (log_gwen_gui)
363  {
364  GWEN_Gui_free(log_gwen_gui);
365  log_gwen_gui = NULL;
366  }
367  GWEN_Gui_SetGui(NULL);
368 
369  if (!gui)
370  return;
371 
372  gui->parent = NULL;
373  reset_dialog(gui);
374  if (gui->passwords)
375  g_hash_table_destroy(gui->passwords);
376  if (gui->showbox_hash)
377  g_hash_table_destroy(gui->showbox_hash);
378  if (gui->permanently_accepted_certs)
379  GWEN_DB_Group_free(gui->permanently_accepted_certs);
380  if (gui->accepted_certs)
381  g_hash_table_destroy(gui->accepted_certs);
382  gtk_widget_destroy(gui->dialog);
383  g_free(gui);
384 
385  full_gui = NULL;
386 
387  LEAVE(" ");
388 }
389 
390 void
391 gnc_GWEN_Gui_set_close_flag(gboolean close_when_finished)
392 {
394  GNC_PREFS_GROUP_AQBANKING, GNC_PREF_CLOSE_ON_FINISH,
395  close_when_finished);
396 
397  if (full_gui)
398  {
399  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(full_gui->close_checkbutton))
400  != close_when_finished)
401  {
402  gtk_toggle_button_set_active(
403  GTK_TOGGLE_BUTTON(full_gui->close_checkbutton),
404  close_when_finished);
405  }
406  }
407 }
408 
409 gboolean
411 {
412  return gnc_prefs_get_bool (GNC_PREFS_GROUP_AQBANKING, GNC_PREF_CLOSE_ON_FINISH);
413 }
414 
415 gboolean
417 {
418  GncGWENGui *gui = full_gui;
419 
420  if (!gui)
421  {
422  gnc_GWEN_Gui_get(NULL);
423  }
424 
425  if (gui)
426  {
427  if (gui->state == HIDDEN)
428  {
429  gui->state = FINISHED;
430  }
431  gtk_toggle_button_set_active(
432  GTK_TOGGLE_BUTTON(gui->close_checkbutton),
433  gnc_prefs_get_bool (GNC_PREFS_GROUP_AQBANKING, GNC_PREF_CLOSE_ON_FINISH));
434 
435  show_dialog(gui, FALSE);
436 
437  return TRUE;
438  }
439 
440  return FALSE;
441 }
442 
443 void
445 {
446  GncGWENGui *gui = full_gui;
447 
448  if (gui)
449  {
450  hide_dialog(gui);
451  }
452 }
453 
454 static void
455 register_callbacks(GncGWENGui *gui)
456 {
457  GWEN_GUI *gwen_gui;
458 
459  g_return_if_fail(gui && !gui->gwen_gui);
460 
461  ENTER("gui=%p", gui);
462 
463  gwen_gui =
464 #ifdef USING_GWENHYWFAR_GTK2_GUI
465  Gtk2_Gui_new()
466 #else
467  GWEN_Gui_new()
468 #endif
469  ;
470  gui->gwen_gui = gwen_gui;
471 
472  GWEN_Gui_SetMessageBoxFn(gwen_gui, messagebox_cb);
473  GWEN_Gui_SetInputBoxFn(gwen_gui, inputbox_cb);
474  GWEN_Gui_SetShowBoxFn(gwen_gui, showbox_cb);
475  GWEN_Gui_SetHideBoxFn(gwen_gui, hidebox_cb);
476  GWEN_Gui_SetProgressStartFn(gwen_gui, progress_start_cb);
477  GWEN_Gui_SetProgressAdvanceFn(gwen_gui, progress_advance_cb);
478  GWEN_Gui_SetProgressLogFn(gwen_gui, progress_log_cb);
479  GWEN_Gui_SetProgressEndFn(gwen_gui, progress_end_cb);
480  GWEN_Gui_SetGetPasswordFn(gwen_gui, getpassword_cb);
481  GWEN_Gui_SetSetPasswordStatusFn(gwen_gui, setpasswordstatus_cb);
482  GWEN_Gui_SetLogHookFn(gwen_gui, loghook_cb);
483  gui->builtin_checkcert = GWEN_Gui_SetCheckCertFn(gwen_gui, checkcert_cb);
484 
485  GWEN_Gui_SetGui(gwen_gui);
486  SETDATA_GUI(gwen_gui, gui);
487 
488  LEAVE(" ");
489 }
490 
491 static void
492 unregister_callbacks(GncGWENGui *gui)
493 {
494  g_return_if_fail(gui);
495 
496  ENTER("gui=%p", gui);
497 
498  if (!gui->gwen_gui)
499  {
500  LEAVE("already unregistered");
501  return;
502  }
503 
504  /* Switch to log_gwen_gui and free gui->gwen_gui */
506 
507  gui->gwen_gui = NULL;
508 
509  LEAVE(" ");
510 }
511 
512 static void
513 setup_dialog(GncGWENGui *gui)
514 {
515  GtkBuilder *builder;
516  gint component_id;
517 
518  g_return_if_fail(gui);
519 
520  ENTER("gui=%p", gui);
521 
522  builder = gtk_builder_new();
523  gnc_builder_add_from_file (builder, "dialog-ab.glade", "Connection Dialog");
524 
525  gui->dialog = GTK_WIDGET(gtk_builder_get_object (builder, "Connection Dialog"));
526 
527  gui->entries_table = GTK_WIDGET(gtk_builder_get_object (builder, "entries_table"));
528  gui->top_entry = GTK_WIDGET(gtk_builder_get_object (builder, "top_entry"));
529  gui->top_progress = GTK_WIDGET(gtk_builder_get_object (builder, "top_progress"));
530  gui->second_entry = GTK_WIDGET(gtk_builder_get_object (builder, "second_entry"));
531  gui->other_entries_box = NULL;
532  gui->progresses = NULL;
533  gui->log_text = GTK_WIDGET(gtk_builder_get_object (builder, "log_text"));
534  gui->abort_button = GTK_WIDGET(gtk_builder_get_object (builder, "abort_button"));
535  gui->close_button = GTK_WIDGET(gtk_builder_get_object (builder, "close_button"));
536  gui->close_checkbutton = GTK_WIDGET(gtk_builder_get_object (builder, "close_checkbutton"));
537  gui->accepted_certs = NULL;
538  gui->permanently_accepted_certs = NULL;
539  gui->showbox_hash = NULL;
540  gui->showbox_id = 1;
541 
542  /* Connect the Signals */
543  gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, gui);
544 
545  gtk_toggle_button_set_active(
546  GTK_TOGGLE_BUTTON(gui->close_checkbutton),
547  gnc_prefs_get_bool (GNC_PREFS_GROUP_AQBANKING, GNC_PREF_CLOSE_ON_FINISH));
548 
549  component_id = gnc_register_gui_component(GWEN_GUI_CM_CLASS, NULL,
550  cm_close_handler, gui);
551  gnc_gui_component_set_session(component_id, gnc_get_current_session());
552 
553 
554 
555  g_object_unref(G_OBJECT(builder));
556 
557  reset_dialog(gui);
558 
559  LEAVE(" ");
560 }
561 
562 static void
563 enable_password_cache(GncGWENGui *gui, gboolean enabled)
564 {
565  g_return_if_fail(gui);
566 
567  if (enabled && !gui->passwords)
568  {
569  /* Remember passwords in memory, mapping tokens to passwords */
570  gui->passwords = g_hash_table_new_full(
571  g_str_hash, g_str_equal, (GDestroyNotify) g_free,
572  (GDestroyNotify) erase_password);
573  }
574  else if (!enabled && gui->passwords)
575  {
576  /* Erase and free remembered passwords from memory */
577  g_hash_table_destroy(gui->passwords);
578  gui->passwords = NULL;
579  }
580  gui->cache_passwords = enabled;
581 }
582 
583 static void
584 reset_dialog(GncGWENGui *gui)
585 {
586  gboolean cache_passwords;
587 
588  g_return_if_fail(gui);
589 
590  ENTER("gui=%p", gui);
591 
592  gtk_entry_set_text(GTK_ENTRY(gui->top_entry), "");
593  gtk_entry_set_text(GTK_ENTRY(gui->second_entry), "");
594  g_list_foreach(gui->progresses, (GFunc) free_progress, NULL);
595  g_list_free(gui->progresses);
596  gui->progresses = NULL;
597 
598  if (gui->other_entries_box)
599  {
600  gtk_table_resize(GTK_TABLE(gui->entries_table),
601  OTHER_ENTRIES_ROW_OFFSET, 2);
602  gtk_widget_destroy(gui->other_entries_box);
603  gui->other_entries_box = NULL;
604  }
605  if (gui->showbox_hash)
606  g_hash_table_destroy(gui->showbox_hash);
607  gui->showbox_last = NULL;
608  gui->showbox_hash = g_hash_table_new_full(
609  NULL, NULL, NULL, (GDestroyNotify) gtk_widget_destroy);
610 
611  if (gui->parent)
612  gtk_window_set_transient_for(GTK_WINDOW(gui->dialog),
613  GTK_WINDOW(gui->parent));
614  gnc_restore_window_size(GNC_PREFS_GROUP_CONNECTION, GTK_WINDOW(gui->dialog));
615 
616  gui->keep_alive = TRUE;
617  gui->state = INIT;
618  gui->min_loglevel = GWEN_LoggerLevel_Verbous;
619 
620  cache_passwords = gnc_prefs_get_bool(GNC_PREFS_GROUP_AQBANKING,
621  GNC_PREF_REMEMBER_PIN);
622  enable_password_cache(gui, cache_passwords);
623 
624  if (!gui->accepted_certs)
625  gui->accepted_certs = g_hash_table_new_full(
626  g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
627  if (!gui->permanently_accepted_certs)
628  gui->permanently_accepted_certs = gnc_ab_get_permanent_certs();
629 
630  LEAVE(" ");
631 }
632 
633 static void
634 set_running(GncGWENGui *gui)
635 {
636  g_return_if_fail(gui);
637 
638  ENTER("gui=%p", gui);
639 
640  gui->state = RUNNING;
641  gtk_widget_set_sensitive(gui->abort_button, TRUE);
642  gtk_widget_set_sensitive(gui->close_button, FALSE);
643  gui->keep_alive = TRUE;
644 
645  LEAVE(" ");
646 }
647 
648 static void
649 set_finished(GncGWENGui *gui)
650 {
651  g_return_if_fail(gui);
652 
653  ENTER("gui=%p", gui);
654 
655  /* Do not serve as GUI anymore */
656  gui->state = FINISHED;
657  unregister_callbacks(gui);
658 
659  gtk_widget_set_sensitive(gui->abort_button, FALSE);
660  gtk_widget_set_sensitive(gui->close_button, TRUE);
661  if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gui->close_checkbutton)))
662  hide_dialog(gui);
663 
664  LEAVE(" ");
665 }
666 
667 static void
668 set_aborted(GncGWENGui *gui)
669 {
670  g_return_if_fail(gui);
671 
672  ENTER("gui=%p", gui);
673 
674  /* Do not serve as GUI anymore */
675  gui->state = ABORTED;
676  unregister_callbacks(gui);
677 
678  gtk_widget_set_sensitive(gui->abort_button, FALSE);
679  gtk_widget_set_sensitive(gui->close_button, TRUE);
680  gui->keep_alive = FALSE;
681 
682  LEAVE(" ");
683 }
684 
685 static void
686 show_dialog(GncGWENGui *gui, gboolean clear_log)
687 {
688  g_return_if_fail(gui);
689 
690  ENTER("gui=%p, clear_log=%d", gui, clear_log);
691 
692  gtk_widget_show(gui->dialog);
693 
695 
696  /* Clear the log window */
697  if (clear_log)
698  {
699  gtk_text_buffer_set_text(
700  gtk_text_view_get_buffer(GTK_TEXT_VIEW(gui->log_text)), "", 0);
701  }
702 
703  LEAVE(" ");
704 }
705 
706 static void
707 hide_dialog(GncGWENGui *gui)
708 {
709  g_return_if_fail(gui);
710 
711  ENTER("gui=%p", gui);
712 
713  /* Hide the dialog */
714  gtk_widget_hide(gui->dialog);
715 
717 
718  /* Remember whether the dialog is to be closed when finished */
720  GNC_PREFS_GROUP_AQBANKING, GNC_PREF_CLOSE_ON_FINISH,
721  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gui->close_checkbutton)));
722 
723  /* Remember size and position of the dialog */
724  gnc_save_window_size(GNC_PREFS_GROUP_CONNECTION, GTK_WINDOW(gui->dialog));
725 
726  /* Do not serve as GUI anymore */
727  gui->state = HIDDEN;
728  unregister_callbacks(gui);
729 
730  LEAVE(" ");
731 }
732 
733 static gboolean
734 show_progress_cb(gpointer user_data)
735 {
736  Progress *progress = user_data;
737 
738  g_return_val_if_fail(progress, FALSE);
739 
740  ENTER("progress=%p", progress);
741 
742  show_progress(progress->gui, progress);
743 
744  LEAVE(" ");
745  return FALSE;
746 }
747 
751 static void
752 show_progress(GncGWENGui *gui, Progress *progress)
753 {
754  GList *item;
755  Progress *current;
756 
757  g_return_if_fail(gui);
758 
759  ENTER("gui=%p, progress=%p", gui, progress);
760 
761  for (item = g_list_last(gui->progresses); item; item = item->prev)
762  {
763  current = (Progress*) item->data;
764 
765  if (!current->source
766  && current != progress)
767  /* Already showed */
768  continue;
769 
770  /* Show it */
771  if (!item->next)
772  {
773  /* Top-level progress */
774  show_dialog(gui, TRUE);
775  gtk_entry_set_text(GTK_ENTRY(gui->top_entry), current->title);
776  }
777  else if (!item->next->next)
778  {
779  /* Second-level progress */
780  gtk_entry_set_text(GTK_ENTRY(gui->second_entry), current->title);
781  }
782  else
783  {
784  /* Other progress */
785  GtkWidget *entry = gtk_entry_new();
786  GtkWidget *box = gui->other_entries_box;
787  gboolean new_box = box == NULL;
788 
789  gtk_entry_set_text(GTK_ENTRY(entry), current->title);
790  if (new_box)
791  gui->other_entries_box = box = gtk_vbox_new(TRUE, 6);
792  gtk_box_pack_start(GTK_BOX(box), entry, TRUE, TRUE, 0);
793  gtk_widget_show(entry);
794  if (new_box)
795  {
796  gtk_table_resize(GTK_TABLE(gui->entries_table),
797  OTHER_ENTRIES_ROW_OFFSET + 1, 2);
798  gtk_table_attach_defaults(
799  GTK_TABLE(gui->entries_table), box, 1, 2,
800  OTHER_ENTRIES_ROW_OFFSET, OTHER_ENTRIES_ROW_OFFSET + 1);
801  gtk_widget_show(box);
802  }
803  }
804 
805  if (current->source)
806  {
807  /* Stop delayed call */
808  g_source_remove(current->source);
809  current->source = 0;
810  }
811 
812  if (current == progress)
813  break;
814  }
815 
816  LEAVE(" ");
817 }
818 
822 static void
823 hide_progress(GncGWENGui *gui, Progress *progress)
824 {
825  GList *item;
826  Progress *current;
827 
828  g_return_if_fail(gui);
829 
830  ENTER("gui=%p, progress=%p", gui, progress);
831 
832  for (item = gui->progresses; item; item = item->next)
833  {
834  current = (Progress*) item->data;
835 
836  if (current->source)
837  {
838  /* Not yet showed */
839  g_source_remove(current->source);
840  current->source = 0;
841  if (current == progress)
842  break;
843  else
844  continue;
845  }
846 
847  /* Hide it */
848  if (!item->next)
849  {
850  /* Top-level progress */
851  gtk_entry_set_text(GTK_ENTRY(gui->second_entry), "");
852  }
853  else if (!item->next->next)
854  {
855  /* Second-level progress */
856  gtk_entry_set_text(GTK_ENTRY(gui->second_entry), "");
857  }
858  else
859  {
860  /* Other progress */
861  GtkWidget *box = gui->other_entries_box;
862  GList *entries;
863 
864  g_return_if_fail(box);
865  entries = gtk_container_get_children(GTK_CONTAINER(box));
866  g_return_if_fail(entries);
867  if (entries->next)
868  {
869  /* Another progress is still to be showed */
870  gtk_widget_destroy(GTK_WIDGET(g_list_last(entries)->data));
871  }
872  else
873  {
874  /* Last other progress to be hided */
875  gtk_table_resize(GTK_TABLE(gui->entries_table),
876  OTHER_ENTRIES_ROW_OFFSET, 2);
877  gtk_widget_destroy(box);
878  gui->other_entries_box = NULL;
879  }
880  g_list_free(entries);
881  }
882 
883  if (current == progress)
884  break;
885  }
886 
887  LEAVE(" ");
888 }
889 
890 static void
891 free_progress(Progress *progress, gpointer unused)
892 {
893  if (progress->source)
894  g_source_remove(progress->source);
895  g_free(progress->title);
896  g_free(progress);
897 }
898 
899 static gboolean
900 keep_alive(GncGWENGui *gui)
901 {
902  g_return_val_if_fail(gui, FALSE);
903 
904  ENTER("gui=%p", gui);
905 
906  /* Let the widgets be redrawn */
907  while (g_main_context_iteration(NULL, FALSE));
908 
909  LEAVE("alive=%d", gui->keep_alive);
910  return gui->keep_alive;
911 }
912 
913 static void
914 cm_close_handler(gpointer user_data)
915 {
916  GncGWENGui *gui = user_data;
917 
918  g_return_if_fail(gui);
919 
920  ENTER("gui=%p", gui);
921 
922  /* FIXME */
923  set_aborted(gui);
924 
925  LEAVE(" ");
926 }
927 
928 static void
929 erase_password(gchar *password)
930 {
931  g_return_if_fail(password);
932 
933  ENTER(" ");
934 
935  memset(password, 0, strlen(password));
936  g_free(password);
937 
938  LEAVE(" ");
939 }
940 
944 static gchar *
945 strip_html(gchar *text)
946 {
947  gchar *p, *q;
948 
949  if (!text)
950  return NULL;
951 
952  p = text;
953  while (strchr(p, '<'))
954  {
955  q = p + 1;
956  if (*q && toupper(*q++) == 'H'
957  && *q && toupper(*q++) == 'T'
958  && *q && toupper(*q++) == 'M'
959  && *q && toupper(*q) == 'L')
960  {
961  *p = '\0';
962  return text;
963  }
964  p++;
965  }
966  return text;
967 }
968 
969 static void
970 get_input(GncGWENGui *gui, guint32 flags, const gchar *title, const gchar *text,
971  gchar **input, gint min_len, gint max_len)
972 {
973  GtkBuilder *builder;
974  GtkWidget *dialog;
975  GtkWidget *heading_label;
976  GtkWidget *input_entry;
977  GtkWidget *confirm_entry;
978  GtkWidget *confirm_label;
979  GtkWidget *remember_pin_checkbutton;
980  const gchar *internal_input, *internal_confirmed;
981  gboolean confirm = (flags & GWEN_GUI_INPUT_FLAGS_CONFIRM) != 0;
982  gboolean is_tan = (flags & GWEN_GUI_INPUT_FLAGS_TAN) != 0;
983 
984  g_return_if_fail(input);
985  g_return_if_fail(max_len >= min_len && max_len > 0);
986 
987  ENTER(" ");
988 
989  /* Set up dialog */
990  builder = gtk_builder_new();
991  gnc_builder_add_from_file (builder, "dialog-ab.glade", "Password Dialog");
992  dialog = GTK_WIDGET(gtk_builder_get_object (builder, "Password Dialog"));
993 
994  heading_label = GTK_WIDGET(gtk_builder_get_object (builder, "heading_pw_label"));
995  input_entry = GTK_WIDGET(gtk_builder_get_object (builder, "input_entry"));
996  confirm_entry = GTK_WIDGET(gtk_builder_get_object (builder, "confirm_entry"));
997  confirm_label = GTK_WIDGET(gtk_builder_get_object (builder, "confirm_label"));
998  remember_pin_checkbutton = GTK_WIDGET(gtk_builder_get_object (builder, "remember_pin"));
999  if (is_tan)
1000  {
1001  gtk_widget_hide(remember_pin_checkbutton);
1002  }
1003  else
1004  {
1005  gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(remember_pin_checkbutton),
1006  gui->cache_passwords);
1007  }
1008 
1009  if (gui->parent)
1010  gtk_window_set_transient_for(GTK_WINDOW(dialog),
1011  GTK_WINDOW(gui->parent));
1012  if (title)
1013  gtk_window_set_title(GTK_WINDOW(dialog), title);
1014 
1015  if (text)
1016  {
1017  gchar *raw_text = strip_html(g_strdup(text));
1018  gtk_label_set_text(GTK_LABEL(heading_label), raw_text);
1019  g_free(raw_text);
1020  }
1021 
1022  if (*input)
1023  {
1024  gtk_entry_set_text(GTK_ENTRY(input_entry), *input);
1025  erase_password(*input);
1026  *input = NULL;
1027  }
1028 
1029  if (confirm)
1030  {
1031  gtk_entry_set_activates_default(GTK_ENTRY(input_entry), FALSE);
1032  gtk_entry_set_activates_default(GTK_ENTRY(confirm_entry), TRUE);
1033  gtk_entry_set_max_length(GTK_ENTRY(input_entry), max_len);
1034  gtk_entry_set_max_length(GTK_ENTRY(confirm_entry), max_len);
1035  }
1036  else
1037  {
1038  gtk_entry_set_activates_default(GTK_ENTRY(input_entry), TRUE);
1039  gtk_entry_set_max_length(GTK_ENTRY(input_entry), max_len);
1040  gtk_widget_hide(confirm_entry);
1041  gtk_widget_hide(confirm_label);
1042  }
1043  gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
1044 
1045  /* Ask the user until he enters a valid input or cancels */
1046  while (TRUE)
1047  {
1048  gboolean remember_pin;
1049 
1050  if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_OK)
1051  break;
1052 
1053  if (!is_tan)
1054  {
1055  /* Enable or disable the password cache */
1056  remember_pin = gtk_toggle_button_get_active(
1057  GTK_TOGGLE_BUTTON(remember_pin_checkbutton));
1058  enable_password_cache(gui, remember_pin);
1059  gnc_prefs_set_bool(GNC_PREFS_GROUP_AQBANKING, GNC_PREF_REMEMBER_PIN,
1060  remember_pin);
1061  }
1062 
1063  internal_input = gtk_entry_get_text(GTK_ENTRY(input_entry));
1064  if (strlen(internal_input) < min_len)
1065  {
1066  gboolean retval;
1067  gchar *msg = g_strdup_printf(
1068  _("The PIN needs to be at least %d characters \n"
1069  "long. Do you want to try again?"), min_len);
1070  retval = gnc_verify_dialog(gui->parent, TRUE, "%s", msg);
1071  g_free(msg);
1072  if (!retval)
1073  break;
1074  continue;
1075  }
1076 
1077  if (!confirm)
1078  {
1079  *input = g_strdup(internal_input);
1080  break;
1081  }
1082 
1083  internal_confirmed = gtk_entry_get_text(GTK_ENTRY(confirm_entry));
1084  if (strcmp(internal_input, internal_confirmed) == 0)
1085  {
1086  *input = g_strdup(internal_input);
1087  break;
1088  }
1089  }
1090 
1091  g_object_unref(G_OBJECT(builder));
1092 
1093  /* This trashes passwords in the entries' memory as well */
1094  gtk_widget_destroy(dialog);
1095 
1096  LEAVE("input %s", *input ? "non-NULL" : "NULL");
1097 }
1098 
1099 static gint
1100 messagebox_cb(GWEN_GUI *gwen_gui, guint32 flags, const gchar *title,
1101  const gchar *text, const gchar *b1, const gchar *b2,
1102  const gchar *b3, guint32 guiid)
1103 {
1104  GncGWENGui *gui = GETDATA_GUI(gwen_gui);
1105  GtkWidget *dialog;
1106  GtkWidget *vbox;
1107  GtkWidget *label;
1108  gchar *raw_text;
1109  gint result;
1110 
1111  ENTER("gui=%p, flags=%d, title=%s, b1=%s, b2=%s, b3=%s", gui, flags,
1112  title ? title : "(null)", b1 ? b1 : "(null)", b2 ? b2 : "(null)",
1113  b3 ? b3 : "(null)");
1114 
1115  dialog = gtk_dialog_new_with_buttons(
1116  title, gui->parent ? GTK_WINDOW(gui->parent) : NULL,
1117  GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1118  b1, 1, b2, 2, b3, 3, (gchar*) NULL);
1119 
1120  raw_text = strip_html(g_strdup(text));
1121  label = gtk_label_new(raw_text);
1122  g_free(raw_text);
1123  gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
1124  vbox = gtk_vbox_new(TRUE, 0);
1125  gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
1126  gtk_container_add(GTK_CONTAINER(vbox), label);
1127  gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
1128  gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), vbox);
1129  gtk_widget_show_all(dialog);
1130 
1131  result = gtk_dialog_run(GTK_DIALOG(dialog));
1132  gtk_widget_destroy(dialog);
1133 
1134  if (result < 1 || result > 3)
1135  {
1136  g_warning("messagebox_cb: Bad result %d", result);
1137  result = 0;
1138  }
1139 
1140  LEAVE("result=%d", result);
1141  return result;
1142 }
1143 
1144 static gint
1145 inputbox_cb(GWEN_GUI *gwen_gui, guint32 flags, const gchar *title,
1146  const gchar *text, gchar *buffer, gint min_len, gint max_len,
1147  guint32 guiid)
1148 {
1149  GncGWENGui *gui = GETDATA_GUI(gwen_gui);
1150  gchar *input = NULL;
1151 
1152  g_return_val_if_fail(gui, -1);
1153 
1154  ENTER("gui=%p, flags=%d", gui, flags);
1155 
1156  get_input(gui, flags, title, text, &input, min_len, max_len);
1157 
1158  if (input)
1159  {
1160  /* Copy the input to the result buffer */
1161  strncpy(buffer, input, max_len);
1162  buffer[max_len-1] = '\0';
1163  }
1164 
1165  LEAVE(" ");
1166  return input ? 0 : -1;
1167 }
1168 
1169 static guint32
1170 showbox_cb(GWEN_GUI *gwen_gui, guint32 flags, const gchar *title,
1171  const gchar *text, guint32 guiid)
1172 {
1173  GncGWENGui *gui = GETDATA_GUI(gwen_gui);
1174  GtkWidget *dialog;
1175  guint32 showbox_id;
1176 
1177  g_return_val_if_fail(gui, -1);
1178 
1179  ENTER("gui=%p, flags=%d, title=%s", gui, flags, title ? title : "(null)");
1180 
1181  dialog = gtk_message_dialog_new(
1182  gui->parent ? GTK_WINDOW(gui->parent) : NULL, 0, GTK_MESSAGE_INFO,
1183  GTK_BUTTONS_OK, "%s", text);
1184 
1185  if (title)
1186  gtk_window_set_title(GTK_WINDOW(dialog), title);
1187 
1188  g_signal_connect(dialog, "response", G_CALLBACK(gtk_widget_hide), NULL);
1189  gtk_widget_show_all(dialog);
1190 
1191  showbox_id = gui->showbox_id++;
1192  g_hash_table_insert(gui->showbox_hash, GUINT_TO_POINTER(showbox_id),
1193  dialog);
1194  gui->showbox_last = dialog;
1195 
1196  /* Give it a change to be showed */
1197  if (!keep_alive(gui))
1198  showbox_id = 0;
1199 
1200  LEAVE("id=%" G_GUINT32_FORMAT, showbox_id);
1201  return showbox_id;
1202 }
1203 
1204 static void
1205 hidebox_cb(GWEN_GUI *gwen_gui, guint32 id)
1206 {
1207  GncGWENGui *gui = GETDATA_GUI(gwen_gui);
1208 
1209  g_return_if_fail(gui && gui->showbox_hash);
1210 
1211  ENTER("gui=%p, id=%d", gui, id);
1212 
1213  if (id == 0)
1214  {
1215  if (gui->showbox_last)
1216  {
1217  g_hash_table_remove(gui->showbox_hash,
1218  GUINT_TO_POINTER(gui->showbox_id));
1219  gui->showbox_last = NULL;
1220  }
1221  else
1222  {
1223  g_warning("hidebox_cb: Last showed message box already destroyed");
1224  }
1225  }
1226  else
1227  {
1228  gpointer p_var;
1229  p_var = g_hash_table_lookup(gui->showbox_hash, GUINT_TO_POINTER(id));
1230  if (p_var)
1231  {
1232  g_hash_table_remove(gui->showbox_hash, GUINT_TO_POINTER(id));
1233  if (p_var == gui->showbox_last)
1234  gui->showbox_last = NULL;
1235  }
1236  else
1237  {
1238  g_warning("hidebox_cb: Message box %d could not been found", id);
1239  }
1240  }
1241 
1242  LEAVE(" ");
1243 }
1244 
1245 static guint32
1246 progress_start_cb(GWEN_GUI *gwen_gui, uint32_t progressFlags, const char *title,
1247  const char *text, uint64_t total, uint32_t guiid)
1248 {
1249  GncGWENGui *gui = GETDATA_GUI(gwen_gui);
1250  Progress *progress;
1251 
1252  g_return_val_if_fail(gui, -1);
1253 
1254  ENTER("gui=%p, flags=%d, title=%s, total=%" G_GUINT64_FORMAT, gui,
1255  progressFlags, title ? title : "(null)", (guint64)total);
1256 
1257  if (!gui->progresses)
1258  {
1259  /* Top-level progress */
1260  if (progressFlags & GWEN_GUI_PROGRESS_SHOW_PROGRESS)
1261  {
1262  gtk_widget_set_sensitive(gui->top_progress, TRUE);
1263  gtk_progress_bar_set_fraction(
1264  GTK_PROGRESS_BAR(gui->top_progress), 0.0);
1265  gui->max_actions = total;
1266  }
1267  else
1268  {
1269  gtk_widget_set_sensitive(gui->top_progress, FALSE);
1270  gui->max_actions = -1;
1271  }
1272  set_running(gui);
1273  }
1274 
1275  /* Put progress onto the stack */
1276  progress = g_new0(Progress, 1);
1277  progress->gui = gui;
1278  progress->title = title ? g_strdup(title) : "";
1279  gui->progresses = g_list_prepend(gui->progresses, progress);
1280 
1281  if (progressFlags & GWEN_GUI_PROGRESS_DELAY)
1282  {
1283  /* Show progress later */
1284  progress->source = g_timeout_add(GWEN_GUI_DELAY_SECS * 1000,
1285  (GSourceFunc) show_progress_cb,
1286  progress);
1287  }
1288  else
1289  {
1290  /* Show it now */
1291  progress->source = 0;
1292  show_progress(gui, progress);
1293  }
1294 
1295  LEAVE(" ");
1296  return g_list_length(gui->progresses);
1297 }
1298 
1299 static gint
1300 progress_advance_cb(GWEN_GUI *gwen_gui, uint32_t id, uint64_t progress)
1301 {
1302  GncGWENGui *gui = GETDATA_GUI(gwen_gui);
1303 
1304  g_return_val_if_fail(gui, -1);
1305 
1306  ENTER("gui=%p, progress=%" G_GUINT64_FORMAT, gui, (guint64)progress);
1307 
1308  if (id == 1 /* top-level progress */
1309  && gui->max_actions > 0 /* progressbar active */
1310  && progress != GWEN_GUI_PROGRESS_NONE) /* progressbar update needed */
1311  {
1312  if (progress == GWEN_GUI_PROGRESS_ONE)
1313  gui->current_action++;
1314  else
1315  gui->current_action = progress;
1316 
1317  gtk_progress_bar_set_fraction(
1318  GTK_PROGRESS_BAR(gui->top_progress),
1319  ((gdouble) gui->current_action) / ((gdouble) gui->max_actions));
1320  }
1321 
1322  LEAVE(" ");
1323  return !keep_alive(gui);
1324 }
1325 
1326 static gint
1327 progress_log_cb(GWEN_GUI *gwen_gui, guint32 id, GWEN_LOGGER_LEVEL level,
1328  const gchar *text)
1329 {
1330  GncGWENGui *gui = GETDATA_GUI(gwen_gui);
1331  GtkTextBuffer *tb;
1332  GtkTextView *tv;
1333 
1334  g_return_val_if_fail(gui, -1);
1335 
1336  ENTER("gui=%p, text=%s", gui, text ? text : "(null)");
1337 
1338  tv = GTK_TEXT_VIEW(gui->log_text);
1339  tb = gtk_text_view_get_buffer(tv);
1340  gtk_text_buffer_insert_at_cursor(tb, text, -1);
1341  gtk_text_buffer_insert_at_cursor(tb, "\n", -1);
1342 
1343  /* Scroll to the end of the buffer */
1344  gtk_text_view_scroll_to_mark(tv, gtk_text_buffer_get_insert(tb),
1345  0.0, FALSE, 0.0, 0.0);
1346 
1347  /* Cache loglevel */
1348  if (level < gui->min_loglevel)
1349  gui->min_loglevel = level;
1350 
1351  LEAVE(" ");
1352  return !keep_alive(gui);
1353 }
1354 
1355 static gint
1356 progress_end_cb(GWEN_GUI *gwen_gui, guint32 id)
1357 {
1358  GncGWENGui *gui = GETDATA_GUI(gwen_gui);
1359  Progress *progress;
1360 
1361  g_return_val_if_fail(gui, -1);
1362  g_return_val_if_fail(id == g_list_length(gui->progresses), -1);
1363 
1364  ENTER("gui=%p, id=%d", gui, id);
1365 
1366  if (gui->state != RUNNING)
1367  {
1368  /* Ignore finishes of progresses we do not track */
1369  LEAVE("not running anymore");
1370  return 0;
1371  }
1372 
1373  /* Hide progress */
1374  progress = (Progress*) gui->progresses->data;
1375  hide_progress(gui, progress);
1376 
1377  /* Remove progress from stack and free memory */
1378  gui->progresses = g_list_delete_link(gui->progresses, gui->progresses);
1379  free_progress(progress, NULL);
1380 
1381  if (!gui->progresses)
1382  {
1383  /* top-level progress finished */
1384  set_finished(gui);
1385  }
1386 
1387  LEAVE(" ");
1388  return 0;
1389 }
1390 
1391 static gint GNC_GWENHYWFAR_CB
1392 getpassword_cb(GWEN_GUI *gwen_gui, guint32 flags, const gchar *token,
1393  const gchar *title, const gchar *text, gchar *buffer,
1394  gint min_len, gint max_len, guint32 guiid)
1395 {
1396  GncGWENGui *gui = GETDATA_GUI(gwen_gui);
1397  gchar *password = NULL;
1398  gboolean is_tan = (flags & GWEN_GUI_INPUT_FLAGS_TAN) != 0;
1399 
1400  g_return_val_if_fail(gui, -1);
1401 
1402  ENTER("gui=%p, flags=%d, token=%s", gui, flags, token ? token : "(null");
1403 
1404  /* Check remembered passwords, excluding TANs */
1405  if (!is_tan && gui->cache_passwords && gui->passwords && token)
1406  {
1407  if (flags & GWEN_GUI_INPUT_FLAGS_RETRY)
1408  {
1409  /* If remembered, remove password from memory */
1410  g_hash_table_remove(gui->passwords, token);
1411  }
1412  else
1413  {
1414  gpointer p_var;
1415  if (g_hash_table_lookup_extended(gui->passwords, token, NULL,
1416  &p_var))
1417  {
1418  /* Copy the password to the result buffer */
1419  password = p_var;
1420  strncpy(buffer, password, max_len);
1421  buffer[max_len-1] = '\0';
1422 
1423  LEAVE("chose remembered password");
1424  return 0;
1425  }
1426  }
1427  }
1428 
1429  get_input(gui, flags, title, text, &password, min_len, max_len);
1430 
1431  if (password)
1432  {
1433  /* Copy the password to the result buffer */
1434  strncpy(buffer, password, max_len);
1435  buffer[max_len-1] = '\0';
1436 
1437  if (!is_tan && token)
1438  {
1439  if (gui->cache_passwords && gui->passwords)
1440  {
1441  /* Remember password */
1442  DEBUG("Remember password, token=%s", token);
1443  g_hash_table_insert(gui->passwords, g_strdup(token), password);
1444  }
1445  else
1446  {
1447  /* Remove the password from memory */
1448  DEBUG("Forget password, token=%s", token);
1449  erase_password(password);
1450  }
1451  }
1452  }
1453 
1454  LEAVE(" ");
1455  return password ? 0 : -1;
1456 }
1457 
1458 static gint GNC_GWENHYWFAR_CB
1459 setpasswordstatus_cb(GWEN_GUI *gwen_gui, const gchar *token, const gchar *pin,
1460  GWEN_GUI_PASSWORD_STATUS status, guint32 guiid)
1461 {
1462  GncGWENGui *gui = GETDATA_GUI(gwen_gui);
1463 
1464  g_return_val_if_fail(gui, -1);
1465 
1466  ENTER("gui=%p, token=%s, status=%d", gui, token ? token : "(null)", status);
1467 
1468  if (gui->passwords && status != GWEN_Gui_PasswordStatus_Ok)
1469  {
1470  /* If remembered, remove password from memory */
1471  g_hash_table_remove(gui->passwords, token);
1472  }
1473 
1474  LEAVE(" ");
1475  return 0;
1476 }
1477 
1478 static gint GNC_GWENHYWFAR_CB
1479 loghook_cb(GWEN_GUI *gwen_gui, const gchar *log_domain,
1480  GWEN_LOGGER_LEVEL priority, const gchar *text)
1481 {
1482  if (G_LIKELY(priority < n_log_levels))
1483  g_log(log_domain, log_levels[priority], "%s", text);
1484 
1485  return 1;
1486 }
1487 
1488 static gint GNC_GWENHYWFAR_CB
1489 checkcert_cb(GWEN_GUI *gwen_gui, const GWEN_SSLCERTDESCR *cert,
1490  GWEN_IO_LAYER *io, guint32 guiid)
1491 {
1492  GncGWENGui *gui = GETDATA_GUI(gwen_gui);
1493  const gchar *hash, *status;
1494  GChecksum *gcheck = g_checksum_new (G_CHECKSUM_MD5);
1495  gchar cert_hash[16];
1496  gint retval, i;
1497  gsize hashlen = 0;
1498 
1499  g_return_val_if_fail(gui && gui->accepted_certs, -1);
1500 
1501  ENTER("gui=%p, cert=%p", gui, cert);
1502 
1503  hash = GWEN_SslCertDescr_GetFingerPrint(cert);
1504  status = GWEN_SslCertDescr_GetStatusText(cert);
1505 
1506  g_checksum_update (gcheck, hash, strlen (hash));
1507  g_checksum_update (gcheck, status, strlen (status));
1508 
1509  /* Did we get the permanently accepted certs from AqBanking? */
1510  if (gui->permanently_accepted_certs)
1511  {
1512  /* Generate a hex string of the cert_hash for usage by AqBanking cert store */
1513  retval = GWEN_DB_GetIntValue(gui->permanently_accepted_certs,
1514  g_checksum_get_string (gcheck), 0, -1);
1515  if (retval == 0)
1516  {
1517  /* Certificate is marked as accepted in AqBanking's cert store */
1518  g_checksum_free (gcheck);
1519  LEAVE("Certificate accepted by AqBanking's permanent cert store");
1520  return 0;
1521  }
1522  }
1523  else
1524  {
1525  g_warning("Can't check permanently accepted certs from invalid AqBanking cert store.");
1526  }
1527 
1528  g_checksum_get_digest (gcheck, cert_hash, &hashlen);
1529  g_checksum_free (gcheck);
1530  g_assert (hashlen <= sizeof (cert_hash));
1531 
1532  if (g_hash_table_lookup(gui->accepted_certs, cert_hash))
1533  {
1534  /* Certificate has been accepted by Gnucash before */
1535  LEAVE("Automatically accepting certificate");
1536  return 0;
1537  }
1538 
1539  retval = gui->builtin_checkcert(gwen_gui, cert, io, guiid);
1540  if (retval == 0)
1541  {
1542  /* Certificate has been accepted */
1543  g_hash_table_insert(gui->accepted_certs, g_strdup(cert_hash), cert_hash);
1544  }
1545 
1546  LEAVE("retval=%d", retval);
1547  return retval;
1548 }
1549 
1550 gboolean
1551 ggg_delete_event_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data)
1552 {
1553  GncGWENGui *gui = user_data;
1554 
1555  g_return_val_if_fail(gui, FALSE);
1556 
1557  ENTER("gui=%p, state=%d", gui, gui->state);
1558 
1559  if (gui->state == RUNNING)
1560  {
1561  const char *still_running_msg =
1562  _("The Online Banking job is still running; are you "
1563  "sure you want to cancel?");
1564  if (!gnc_verify_dialog(gui->dialog, FALSE, "%s", still_running_msg))
1565  return FALSE;
1566 
1567  set_aborted(gui);
1568  }
1569 
1570  hide_dialog(gui);
1571 
1572  LEAVE(" ");
1573  return TRUE;
1574 }
1575 
1576 void
1577 ggg_abort_clicked_cb(GtkButton *button, gpointer user_data)
1578 {
1579  GncGWENGui *gui = user_data;
1580 
1581  g_return_if_fail(gui && gui->state == RUNNING);
1582 
1583  ENTER("gui=%p", gui);
1584 
1585  set_aborted(gui);
1586 
1587  LEAVE(" ");
1588 }
1589 
1590 void
1591 ggg_close_clicked_cb(GtkButton *button, gpointer user_data)
1592 {
1593  GncGWENGui *gui = user_data;
1594 
1595  g_return_if_fail(gui);
1596  g_return_if_fail(gui->state == FINISHED || gui->state == ABORTED);
1597 
1598  ENTER("gui=%p", gui);
1599 
1600  hide_dialog(gui);
1601 
1602  LEAVE(" ");
1603 }
1604 
1605 void
1606 ggg_close_toggled_cb(GtkToggleButton *button, gpointer user_data)
1607 {
1608  GncGWENGui *gui = user_data;
1609 
1610  g_return_if_fail(gui);
1611  g_return_if_fail(gui->parent);
1612 
1613  ENTER("gui=%p", gui);
1614 
1616  GNC_PREFS_GROUP_AQBANKING, GNC_PREF_CLOSE_ON_FINISH,
1617  gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)));
1618 
1619  LEAVE(" ");
1620 }
1621 #endif
gboolean gnc_GWEN_Gui_show_dialog()
Definition: gnc-gwen-gui.c:416
void gnc_GWEN_Gui_shutdown(void)
Definition: gnc-gwen-gui.c:356
#define G_LOG_DOMAIN
Functions providing the SX List as a plugin page.
gboolean gnc_GWEN_Gui_get_close_flag()
Definition: gnc-gwen-gui.c:410
#define DEBUG(format, args...)
Definition: qoflog.h:255
#define ENTER(format, args...)
Definition: qoflog.h:261
GncGWENGui * gnc_GWEN_Gui_get(GtkWidget *parent)
Definition: gnc-gwen-gui.c:311
GWEN_DB_NODE * gnc_ab_get_permanent_certs(void)
void gnc_GWEN_Gui_release(GncGWENGui *gui)
Definition: gnc-gwen-gui.c:346
void gnc_plugin_aqbanking_set_logwindow_visible(gboolean logwindow_visible)
gboolean gnc_prefs_set_bool(const gchar *group, const gchar *pref_name, gboolean value)
Definition: gnc-prefs.c:282
Generic api to store and retrieve preferences.
Plugin registration of the AqBanking module.
gboolean gnc_prefs_get_bool(const gchar *group, const gchar *pref_name)
Definition: gnc-prefs.c:196
#define LEAVE(format, args...)
Definition: qoflog.h:271
GUI callbacks for AqBanking.
void gnc_GWEN_Gui_log_init(void)
Definition: gnc-gwen-gui.c:289
AqBanking utility functions.
void gnc_GWEN_Gui_set_close_flag(gboolean close_when_finished)
Definition: gnc-gwen-gui.c:391
void gnc_GWEN_Gui_hide_dialog()
Definition: gnc-gwen-gui.c:444
const gchar * QofLogModule
Definition: qofid.h:89