GnuCash 2.4.99
gnc-gwen-gui.c
00001 /*
00002  * gnc-gwen-gui.c --
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of
00007  * the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, contact:
00016  *
00017  * Free Software Foundation           Voice:  +1-617-542-5942
00018  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652
00019  * Boston, MA  02110-1301,  USA       gnu@gnu.org
00020  */
00021 
00031 #include "config.h"
00032 
00033 #include <ctype.h>
00034 #include <glib/gi18n.h>
00035 #include <gwenhywfar/gui_be.h>
00036 #include <gwenhywfar/inherit.h>
00037 
00038 #include "dialog-utils.h"
00039 #include "gnc-ab-utils.h"
00040 #include "gnc-component-manager.h"
00041 #include "gnc-gconf-utils.h"
00042 #include "gnc-gwen-gui.h"
00043 #include "gnc-session.h"
00044 #include "gnc-ui.h"
00045 #include "gnc-plugin-aqbanking.h"
00046 #include "md5.h"
00047 #include "qof.h"
00048 
00049 #if GWENHYWFAR_VERSION_INT >= 39921
00050 /* For sufficiently new gwenhywfar (>=3.99.21) the gtk2 gui object is
00051  * working fine and it is enabled here here. */
00052 # define USING_GWENHYWFAR_GTK2_GUI
00053 # define GNC_GWENHYWFAR_CB GWENHYWFAR_CB
00054 #else
00055 # define GNC_GWENHYWFAR_CB
00056 #endif
00057 
00058 #ifdef USING_GWENHYWFAR_GTK2_GUI
00059 # include <gwen-gui-gtk2/gtk2_gui.h>
00060 #endif
00061 
00062 /* This static indicates the debugging module that this .o belongs to.  */
00063 static QofLogModule log_module = G_LOG_DOMAIN;
00064 
00065 /* The following block can be enabled, but the gwen-gtk2 widgets might
00066  * still need some work. */
00067 #if 0 /*#ifdef USING_GWENHYWFAR_GTK2_GUI*/
00068 
00069 /* A GWEN_GUI implementation using gtk2 widgets  */
00070 static GWEN_GUI *gwen_gui = NULL;
00071 
00072 void gnc_GWEN_Gui_log_init(void)
00073 {
00074     if (!gwen_gui)
00075     {
00076         gwen_gui = Gtk2_Gui_new();
00077         GWEN_Gui_SetGui(gwen_gui);
00078     }
00079 }
00080 GncGWENGui *gnc_GWEN_Gui_get(GtkWidget *parent)
00081 {
00082     if (!gwen_gui)
00083         gnc_GWEN_Gui_log_init();
00084     return (GncGWENGui*) gwen_gui;
00085 }
00086 void gnc_GWEN_Gui_release(GncGWENGui *gui)
00087 {
00088 }
00089 void gnc_GWEN_Gui_shutdown(void)
00090 {
00091     if (gwen_gui)
00092     {
00093         GWEN_Gui_free(gwen_gui);
00094         gwen_gui = NULL;
00095         GWEN_Gui_SetGui(NULL);
00096     }
00097 }
00098 void
00099 gnc_GWEN_Gui_set_close_flag(gboolean close_when_finished)
00100 {
00101     gnc_gconf_set_bool(
00102         GCONF_SECTION_AQBANKING, KEY_CLOSE_ON_FINISH,
00103         close_when_finished,
00104         NULL);
00105 }
00106 gboolean
00107 gnc_GWEN_Gui_get_close_flag()
00108 {
00109     return gnc_gconf_get_bool(GCONF_SECTION_AQBANKING, KEY_CLOSE_ON_FINISH, NULL);
00110 }
00111 
00112 gboolean
00113 gnc_GWEN_Gui_show_dialog()
00114 {
00115     return;
00116 }
00117 
00118 void
00119 gnc_GWEN_Gui_hide_dialog()
00120 {
00121 }
00122 
00123 #else
00124 
00125 /* A unique full-blown GUI, featuring  */
00126 static GncGWENGui *full_gui = NULL;
00127 
00128 /* A unique Gwenhywfar GUI for hooking our logging into the gwenhywfar logging
00129  * framework */
00130 static GWEN_GUI *log_gwen_gui = NULL;
00131 
00132 /* A mapping from gwenhywfar log levels to glib ones */
00133 static GLogLevelFlags log_levels[] =
00134 {
00135     G_LOG_LEVEL_ERROR,     /* GWEN_LoggerLevel_Emergency */
00136     G_LOG_LEVEL_ERROR,     /* GWEN_LoggerLevel_Alert */
00137     G_LOG_LEVEL_CRITICAL,  /* GWEN_LoggerLevel_Critical */
00138     G_LOG_LEVEL_CRITICAL,  /* GWEN_LoggerLevel_Error */
00139     G_LOG_LEVEL_WARNING,   /* GWEN_LoggerLevel_Warning */
00140     G_LOG_LEVEL_MESSAGE,   /* GWEN_LoggerLevel_Notice */
00141     G_LOG_LEVEL_INFO,      /* GWEN_LoggerLevel_Info */
00142     G_LOG_LEVEL_DEBUG,     /* GWEN_LoggerLevel_Debug */
00143     G_LOG_LEVEL_DEBUG      /* GWEN_LoggerLevel_Verbous */
00144 };
00145 static guint8 n_log_levels = G_N_ELEMENTS(log_levels);
00146 
00147 /* Macros to determine the GncGWENGui* from a GWEN_GUI* */
00148 GWEN_INHERIT(GWEN_GUI, GncGWENGui)
00149 #define SETDATA_GUI(gwen_gui, gui) GWEN_INHERIT_SETDATA(GWEN_GUI, GncGWENGui, \
00150                                                         (gwen_gui), (gui), NULL)
00151 #define GETDATA_GUI(gwen_gui) GWEN_INHERIT_GETDATA(GWEN_GUI, GncGWENGui, (gwen_gui))
00152 
00153 #define GWEN_GUI_CM_CLASS "dialog-hbcilog"
00154 #define GCONF_SECTION_CONNECTION GCONF_SECTION_AQBANKING "/connection_dialog"
00155 #define KEY_CLOSE_ON_FINISH "close_on_finish"
00156 #define KEY_REMEMBER_PIN "remember_pin"
00157 
00158 #define OTHER_ENTRIES_ROW_OFFSET 3
00159 
00160 typedef struct _Progress Progress;
00161 typedef enum _GuiState GuiState;
00162 
00163 static void register_callbacks(GncGWENGui *gui);
00164 static void unregister_callbacks(GncGWENGui *gui);
00165 static void setup_dialog(GncGWENGui *gui);
00166 static void enable_password_cache(GncGWENGui *gui, gboolean enabled);
00167 static void reset_dialog(GncGWENGui *gui);
00168 static void set_finished(GncGWENGui *gui);
00169 static void set_aborted(GncGWENGui *gui);
00170 static void show_dialog(GncGWENGui *gui, gboolean clear_log);
00171 static void hide_dialog(GncGWENGui *gui);
00172 static gboolean show_progress_cb(gpointer user_data);
00173 static void show_progress(GncGWENGui *gui, Progress *progress);
00174 static void hide_progress(GncGWENGui *gui, Progress *progress);
00175 static void free_progress(Progress *progress, gpointer unused);
00176 static gboolean keep_alive(GncGWENGui *gui);
00177 static void cm_close_handler(gpointer user_data);
00178 static void erase_password(gchar *password);
00179 static gchar *strip_html(gchar *text);
00180 static void get_input(GncGWENGui *gui, guint32 flags, const gchar *title,
00181                       const gchar *text, gchar **input, gint min_len,
00182                       gint max_len);
00183 static gint messagebox_cb(GWEN_GUI *gwen_gui, guint32 flags, const gchar *title,
00184                           const gchar *text, const gchar *b1, const gchar *b2,
00185                           const gchar *b3, guint32 guiid);
00186 static gint inputbox_cb(GWEN_GUI *gwen_gui, guint32 flags, const gchar *title,
00187                         const gchar *text, gchar *buffer, gint min_len,
00188                         gint max_len, guint32 guiid);
00189 static guint32 showbox_cb(GWEN_GUI *gwen_gui, guint32 flags, const gchar *title,
00190                           const gchar *text, guint32 guiid);
00191 static void hidebox_cb(GWEN_GUI *gwen_gui, guint32 id);
00192 static guint32 progress_start_cb(GWEN_GUI *gwen_gui, uint32_t progressFlags,
00193                                  const char *title, const char *text,
00194                                  uint64_t total, uint32_t guiid);
00195 static gint progress_advance_cb(GWEN_GUI *gwen_gui, uint32_t id,
00196                                 uint64_t new_progress);
00197 static gint progress_log_cb(GWEN_GUI *gwen_gui, guint32 id,
00198                             GWEN_LOGGER_LEVEL level, const gchar *text);
00199 static gint progress_end_cb(GWEN_GUI *gwen_gui, guint32 id);
00200 static gint GNC_GWENHYWFAR_CB getpassword_cb(GWEN_GUI *gwen_gui, guint32 flags, const gchar *token,
00201         const gchar *title, const gchar *text, gchar *buffer,
00202         gint min_len, gint max_len, guint32 guiid);
00203 static gint GNC_GWENHYWFAR_CB setpasswordstatus_cb(GWEN_GUI *gwen_gui, const gchar *token,
00204         const gchar *pin,
00205         GWEN_GUI_PASSWORD_STATUS status, guint32 guiid);
00206 static gint GNC_GWENHYWFAR_CB loghook_cb(GWEN_GUI *gwen_gui, const gchar *log_domain,
00207         GWEN_LOGGER_LEVEL priority, const gchar *text);
00208 #ifdef AQBANKING_VERSION_5_PLUS
00209 typedef GWEN_SYNCIO GWEN_IO_LAYER;
00210 #endif
00211 static gint GNC_GWENHYWFAR_CB checkcert_cb(GWEN_GUI *gwen_gui, const GWEN_SSLCERTDESCR *cert,
00212         GWEN_IO_LAYER *io, guint32 guiid);
00213 
00214 gboolean ggg_delete_event_cb(GtkWidget *widget, GdkEvent *event,
00215                              gpointer user_data);
00216 void ggg_abort_clicked_cb(GtkButton *button, gpointer user_data);
00217 void ggg_close_clicked_cb(GtkButton *button, gpointer user_data);
00218 void ggg_close_toggled_cb(GtkToggleButton *button, gpointer user_data);
00219 
00220 enum _GuiState
00221 {
00222     INIT,
00223     RUNNING,
00224     FINISHED,
00225     ABORTED,
00226     HIDDEN
00227 };
00228 
00229 struct _GncGWENGui
00230 {
00231     GWEN_GUI *gwen_gui;
00232     GtkWidget *parent;
00233     GtkWidget *dialog;
00234 
00235     /* Progress bars */
00236     GtkWidget *entries_table;
00237     GtkWidget *top_entry;
00238     GtkWidget *top_progress;
00239     GtkWidget *second_entry;
00240     GtkWidget *other_entries_box;
00241 
00242     /* Stack of nested Progresses */
00243     GList *progresses;
00244 
00245     /* Number of steps in top-level progress or -1 */
00246     guint64 max_actions;
00247     guint64 current_action;
00248 
00249     /* Log window */
00250     GtkWidget *log_text;
00251 
00252     /* Buttons */
00253     GtkWidget *abort_button;
00254     GtkWidget *close_button;
00255     GtkWidget *close_checkbutton;
00256 
00257     /* Flags to keep track on whether an HBCI action is running or not */
00258     gboolean keep_alive;
00259     GuiState state;
00260 
00261     /* Password caching */
00262     gboolean cache_passwords;
00263     GHashTable *passwords;
00264 
00265     /* Certificates handling */
00266     GHashTable *accepted_certs;
00267     GWEN_DB_NODE *permanently_accepted_certs;
00268     GWEN_GUI_CHECKCERT_FN builtin_checkcert;
00269 
00270     /* Dialogs */
00271     guint32 showbox_id;
00272     GHashTable *showbox_hash;
00273     GtkWidget *showbox_last;
00274 
00275     /* Cache the lowest loglevel, corresponding to the most serious warning */
00276     GWEN_LOGGER_LEVEL min_loglevel;
00277 };
00278 
00279 struct _Progress
00280 {
00281     GncGWENGui *gui;
00282 
00283     /* Title of the process */
00284     gchar *title;
00285 
00286     /* Event source id for showing delayed */
00287     guint source;
00288 };
00289 
00290 void
00291 gnc_GWEN_Gui_log_init(void)
00292 {
00293     if (!log_gwen_gui)
00294     {
00295         log_gwen_gui =
00296 #ifdef USING_GWENHYWFAR_GTK2_GUI
00297             Gtk2_Gui_new()
00298 #else
00299         GWEN_Gui_new()
00300 #endif
00301             ;
00302 
00303         /* Always use our own logging */
00304         GWEN_Gui_SetLogHookFn(log_gwen_gui, loghook_cb);
00305 
00306         /* Keep a reference so that the GWEN_GUI survives a GUI switch */
00307         GWEN_Gui_Attach(log_gwen_gui);
00308     }
00309     GWEN_Gui_SetGui(log_gwen_gui);
00310 }
00311 
00312 GncGWENGui *
00313 gnc_GWEN_Gui_get(GtkWidget *parent)
00314 {
00315     GncGWENGui *gui;
00316 
00317     ENTER("parent=%p", parent);
00318 
00319     if (full_gui)
00320     {
00321         if (full_gui->state == INIT || full_gui->state == RUNNING)
00322         {
00323             LEAVE("full_gui in use, state=%d", full_gui->state);
00324             return NULL;
00325         }
00326 
00327         gui = full_gui;
00328         gui->parent = parent;
00329         reset_dialog(gui);
00330         register_callbacks(gui);
00331 
00332         LEAVE("gui=%p", gui);
00333         return gui;
00334     }
00335 
00336     gui = g_new0(GncGWENGui, 1);
00337     gui->parent = parent;
00338     setup_dialog(gui);
00339     register_callbacks(gui);
00340 
00341     full_gui = gui;
00342 
00343     LEAVE("new gui=%p", gui);
00344     return gui;
00345 }
00346 
00347 void
00348 gnc_GWEN_Gui_release(GncGWENGui *gui)
00349 {
00350     g_return_if_fail(gui && gui == full_gui);
00351 
00352     /* Currently a no-op */
00353     ENTER("gui=%p", gui);
00354     LEAVE(" ");
00355 }
00356 
00357 void
00358 gnc_GWEN_Gui_shutdown(void)
00359 {
00360     GncGWENGui *gui = full_gui;
00361 
00362     ENTER(" ");
00363 
00364     if (log_gwen_gui)
00365     {
00366         GWEN_Gui_free(log_gwen_gui);
00367         log_gwen_gui = NULL;
00368     }
00369     GWEN_Gui_SetGui(NULL);
00370 
00371     if (!gui)
00372         return;
00373 
00374     gui->parent = NULL;
00375     reset_dialog(gui);
00376     if (gui->passwords)
00377         g_hash_table_destroy(gui->passwords);
00378     if (gui->showbox_hash)
00379         g_hash_table_destroy(gui->showbox_hash);
00380     if (gui->permanently_accepted_certs)
00381         GWEN_DB_Group_free(gui->permanently_accepted_certs);
00382     if (gui->accepted_certs)
00383         g_hash_table_destroy(gui->accepted_certs);
00384     gtk_widget_destroy(gui->dialog);
00385     g_free(gui);
00386 
00387     full_gui = NULL;
00388 
00389     LEAVE(" ");
00390 }
00391 
00392 void
00393 gnc_GWEN_Gui_set_close_flag(gboolean close_when_finished)
00394 {
00395     gnc_gconf_set_bool(
00396         GCONF_SECTION_AQBANKING, KEY_CLOSE_ON_FINISH,
00397         close_when_finished,
00398         NULL);
00399 
00400     if (full_gui)
00401     {
00402         if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(full_gui->close_checkbutton))
00403                 != close_when_finished)
00404         {
00405             gtk_toggle_button_set_active(
00406                 GTK_TOGGLE_BUTTON(full_gui->close_checkbutton),
00407                 close_when_finished);
00408         }
00409     }
00410 }
00411 
00412 gboolean
00413 gnc_GWEN_Gui_get_close_flag()
00414 {
00415     return gnc_gconf_get_bool(GCONF_SECTION_AQBANKING, KEY_CLOSE_ON_FINISH, NULL);
00416 }
00417 
00418 gboolean
00419 gnc_GWEN_Gui_show_dialog()
00420 {
00421     GncGWENGui *gui = full_gui;
00422 
00423     if (!gui)
00424     {
00425         gnc_GWEN_Gui_get(NULL);
00426     }
00427 
00428     if (gui)
00429     {
00430         if (gui->state == HIDDEN)
00431         {
00432             gui->state = FINISHED;
00433         }
00434         gtk_toggle_button_set_active(
00435             GTK_TOGGLE_BUTTON(gui->close_checkbutton),
00436             gnc_gconf_get_bool(GCONF_SECTION_AQBANKING, KEY_CLOSE_ON_FINISH, NULL));
00437 
00438         show_dialog(gui, FALSE);
00439 
00440         return TRUE;
00441     }
00442 
00443     return FALSE;
00444 }
00445 
00446 void
00447 gnc_GWEN_Gui_hide_dialog()
00448 {
00449     GncGWENGui *gui = full_gui;
00450 
00451     if (gui)
00452     {
00453         hide_dialog(gui);
00454     }
00455 }
00456 
00457 static void
00458 register_callbacks(GncGWENGui *gui)
00459 {
00460     GWEN_GUI *gwen_gui;
00461 
00462     g_return_if_fail(gui && !gui->gwen_gui);
00463 
00464     ENTER("gui=%p", gui);
00465 
00466     gwen_gui =
00467 #ifdef USING_GWENHYWFAR_GTK2_GUI
00468         Gtk2_Gui_new()
00469 #else
00470         GWEN_Gui_new()
00471 #endif
00472         ;
00473     gui->gwen_gui = gwen_gui;
00474 
00475     GWEN_Gui_SetMessageBoxFn(gwen_gui, messagebox_cb);
00476     GWEN_Gui_SetInputBoxFn(gwen_gui, inputbox_cb);
00477     GWEN_Gui_SetShowBoxFn(gwen_gui, showbox_cb);
00478     GWEN_Gui_SetHideBoxFn(gwen_gui, hidebox_cb);
00479     GWEN_Gui_SetProgressStartFn(gwen_gui, progress_start_cb);
00480     GWEN_Gui_SetProgressAdvanceFn(gwen_gui, progress_advance_cb);
00481     GWEN_Gui_SetProgressLogFn(gwen_gui, progress_log_cb);
00482     GWEN_Gui_SetProgressEndFn(gwen_gui, progress_end_cb);
00483     GWEN_Gui_SetGetPasswordFn(gwen_gui, getpassword_cb);
00484     GWEN_Gui_SetSetPasswordStatusFn(gwen_gui, setpasswordstatus_cb);
00485     GWEN_Gui_SetLogHookFn(gwen_gui, loghook_cb);
00486     gui->builtin_checkcert = GWEN_Gui_SetCheckCertFn(gwen_gui, checkcert_cb);
00487 
00488     GWEN_Gui_SetGui(gwen_gui);
00489     SETDATA_GUI(gwen_gui, gui);
00490 
00491     LEAVE(" ");
00492 }
00493 
00494 static void
00495 unregister_callbacks(GncGWENGui *gui)
00496 {
00497     g_return_if_fail(gui);
00498 
00499     ENTER("gui=%p", gui);
00500 
00501     if (!gui->gwen_gui)
00502     {
00503         LEAVE("already unregistered");
00504         return;
00505     }
00506 
00507     /* Switch to log_gwen_gui and free gui->gwen_gui */
00508     gnc_GWEN_Gui_log_init();
00509 
00510     gui->gwen_gui = NULL;
00511 
00512     LEAVE(" ");
00513 }
00514 
00515 static void
00516 setup_dialog(GncGWENGui *gui)
00517 {
00518     GtkBuilder *builder;
00519     gint component_id;
00520 
00521     g_return_if_fail(gui);
00522 
00523     ENTER("gui=%p", gui);
00524 
00525     builder = gtk_builder_new();
00526     gnc_builder_add_from_file (builder, "dialog-ab.glade", "Connection Dialog");
00527 
00528     gui->dialog = GTK_WIDGET(gtk_builder_get_object (builder, "Connection Dialog"));
00529 
00530     gui->entries_table = GTK_WIDGET(gtk_builder_get_object (builder, "entries_table"));
00531     gui->top_entry = GTK_WIDGET(gtk_builder_get_object (builder, "top_entry"));
00532     gui->top_progress = GTK_WIDGET(gtk_builder_get_object (builder, "top_progress"));
00533     gui->second_entry = GTK_WIDGET(gtk_builder_get_object (builder, "second_entry"));
00534     gui->other_entries_box = NULL;
00535     gui->progresses = NULL;
00536     gui->log_text = GTK_WIDGET(gtk_builder_get_object (builder, "log_text"));
00537     gui->abort_button = GTK_WIDGET(gtk_builder_get_object (builder, "abort_button"));
00538     gui->close_button = GTK_WIDGET(gtk_builder_get_object (builder, "close_button"));
00539     gui->close_checkbutton = GTK_WIDGET(gtk_builder_get_object (builder, "close_checkbutton"));
00540     gui->accepted_certs = NULL;
00541     gui->permanently_accepted_certs = NULL;
00542     gui->showbox_hash = NULL;
00543     gui->showbox_id = 1;
00544 
00545     /* Connect the Signals */
00546     gtk_builder_connect_signals_full (builder, gnc_builder_connect_full_func, gui);
00547 
00548     gtk_toggle_button_set_active(
00549         GTK_TOGGLE_BUTTON(gui->close_checkbutton),
00550         gnc_gconf_get_bool(GCONF_SECTION_AQBANKING, KEY_CLOSE_ON_FINISH, NULL));
00551 
00552     component_id = gnc_register_gui_component(GWEN_GUI_CM_CLASS, NULL,
00553                    cm_close_handler, gui);
00554     gnc_gui_component_set_session(component_id, gnc_get_current_session());
00555 
00556 
00557 
00558     g_object_unref(G_OBJECT(builder));
00559 
00560     reset_dialog(gui);
00561 
00562     LEAVE(" ");
00563 }
00564 
00565 static void
00566 enable_password_cache(GncGWENGui *gui, gboolean enabled)
00567 {
00568     g_return_if_fail(gui);
00569 
00570     if (enabled && !gui->passwords)
00571     {
00572         /* Remember passwords in memory, mapping tokens to passwords */
00573         gui->passwords = g_hash_table_new_full(
00574                              g_str_hash, g_str_equal, (GDestroyNotify) g_free,
00575                              (GDestroyNotify) erase_password);
00576     }
00577     else if (!enabled && gui->passwords)
00578     {
00579         /* Erase and free remembered passwords from memory */
00580         g_hash_table_destroy(gui->passwords);
00581         gui->passwords = NULL;
00582     }
00583     gui->cache_passwords = enabled;
00584 }
00585 
00586 static void
00587 reset_dialog(GncGWENGui *gui)
00588 {
00589     gboolean cache_passwords;
00590 
00591     g_return_if_fail(gui);
00592 
00593     ENTER("gui=%p", gui);
00594 
00595     gtk_entry_set_text(GTK_ENTRY(gui->top_entry), "");
00596     gtk_entry_set_text(GTK_ENTRY(gui->second_entry), "");
00597     g_list_foreach(gui->progresses, (GFunc) free_progress, NULL);
00598     g_list_free(gui->progresses);
00599     gui->progresses = NULL;
00600 
00601     if (gui->other_entries_box)
00602     {
00603         gtk_table_resize(GTK_TABLE(gui->entries_table),
00604                          OTHER_ENTRIES_ROW_OFFSET, 2);
00605         gtk_widget_destroy(gui->other_entries_box);
00606         gui->other_entries_box = NULL;
00607     }
00608     if (gui->showbox_hash)
00609         g_hash_table_destroy(gui->showbox_hash);
00610     gui->showbox_last = NULL;
00611     gui->showbox_hash = g_hash_table_new_full(
00612                             NULL, NULL, NULL, (GDestroyNotify) gtk_widget_destroy);
00613 
00614     if (gui->parent)
00615         gtk_window_set_transient_for(GTK_WINDOW(gui->dialog),
00616                                      GTK_WINDOW(gui->parent));
00617     gnc_restore_window_size(GCONF_SECTION_CONNECTION, GTK_WINDOW(gui->dialog));
00618 
00619     gui->keep_alive = TRUE;
00620     gui->state = INIT;
00621     gui->min_loglevel = GWEN_LoggerLevel_Verbous;
00622 
00623     cache_passwords = gnc_gconf_get_bool(GCONF_SECTION_AQBANKING,
00624                                          KEY_REMEMBER_PIN, NULL);
00625     enable_password_cache(gui, cache_passwords);
00626 
00627     if (!gui->accepted_certs)
00628         gui->accepted_certs = g_hash_table_new_full(
00629                                   g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
00630     if (!gui->permanently_accepted_certs)
00631         gui->permanently_accepted_certs = gnc_ab_get_permanent_certs();
00632 
00633     LEAVE(" ");
00634 }
00635 
00636 static void
00637 set_running(GncGWENGui *gui)
00638 {
00639     g_return_if_fail(gui);
00640 
00641     ENTER("gui=%p", gui);
00642 
00643     gui->state = RUNNING;
00644     gtk_widget_set_sensitive(gui->abort_button, TRUE);
00645     gtk_widget_set_sensitive(gui->close_button, FALSE);
00646     gui->keep_alive = TRUE;
00647 
00648     LEAVE(" ");
00649 }
00650 
00651 static void
00652 set_finished(GncGWENGui *gui)
00653 {
00654     g_return_if_fail(gui);
00655 
00656     ENTER("gui=%p", gui);
00657 
00658     /* Do not serve as GUI anymore */
00659     gui->state = FINISHED;
00660     unregister_callbacks(gui);
00661 
00662     gtk_widget_set_sensitive(gui->abort_button, FALSE);
00663     gtk_widget_set_sensitive(gui->close_button, TRUE);
00664     if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gui->close_checkbutton)))
00665         hide_dialog(gui);
00666 
00667     LEAVE(" ");
00668 }
00669 
00670 static void
00671 set_aborted(GncGWENGui *gui)
00672 {
00673     g_return_if_fail(gui);
00674 
00675     ENTER("gui=%p", gui);
00676 
00677     /* Do not serve as GUI anymore */
00678     gui->state = ABORTED;
00679     unregister_callbacks(gui);
00680 
00681     gtk_widget_set_sensitive(gui->abort_button, FALSE);
00682     gtk_widget_set_sensitive(gui->close_button, TRUE);
00683     gui->keep_alive = FALSE;
00684 
00685     LEAVE(" ");
00686 }
00687 
00688 static void
00689 show_dialog(GncGWENGui *gui, gboolean clear_log)
00690 {
00691     gboolean cache_pin;
00692 
00693     g_return_if_fail(gui);
00694 
00695     ENTER("gui=%p, clear_log=%d", gui, clear_log);
00696 
00697     gtk_widget_show(gui->dialog);
00698 
00699     gnc_plugin_aqbanking_set_logwindow_visible(TRUE);
00700 
00701     /* Clear the log window */
00702     if (clear_log)
00703     {
00704         gtk_text_buffer_set_text(
00705             gtk_text_view_get_buffer(GTK_TEXT_VIEW(gui->log_text)), "", 0);
00706     }
00707 
00708     LEAVE(" ");
00709 }
00710 
00711 static void
00712 hide_dialog(GncGWENGui *gui)
00713 {
00714     g_return_if_fail(gui);
00715 
00716     ENTER("gui=%p", gui);
00717 
00718     /* Hide the dialog */
00719     gtk_widget_hide(gui->dialog);
00720 
00721     gnc_plugin_aqbanking_set_logwindow_visible(FALSE);
00722 
00723     /* Remember whether the dialog is to be closed when finished */
00724     gnc_gconf_set_bool(
00725         GCONF_SECTION_AQBANKING, KEY_CLOSE_ON_FINISH,
00726         gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gui->close_checkbutton)),
00727         NULL);
00728 
00729     /* Remember size and position of the dialog */
00730     gnc_save_window_size(GCONF_SECTION_CONNECTION, GTK_WINDOW(gui->dialog));
00731 
00732     /* Do not serve as GUI anymore */
00733     gui->state = HIDDEN;
00734     unregister_callbacks(gui);
00735 
00736     LEAVE(" ");
00737 }
00738 
00739 static gboolean
00740 show_progress_cb(gpointer user_data)
00741 {
00742     Progress *progress = user_data;
00743     GncGWENGui *gui;
00744     GList *item;
00745 
00746     g_return_val_if_fail(progress, FALSE);
00747 
00748     ENTER("progress=%p", progress);
00749 
00750     show_progress(progress->gui, progress);
00751 
00752     LEAVE(" ");
00753     return FALSE;
00754 }
00755 
00759 static void
00760 show_progress(GncGWENGui *gui, Progress *progress)
00761 {
00762     GList *item;
00763     Progress *current;
00764 
00765     g_return_if_fail(gui);
00766 
00767     ENTER("gui=%p, progress=%p", gui, progress);
00768 
00769     for (item = g_list_last(gui->progresses); item; item = item->prev)
00770     {
00771         current = (Progress*) item->data;
00772 
00773         if (!current->source
00774                 && current != progress)
00775             /* Already showed */
00776             continue;
00777 
00778         /* Show it */
00779         if (!item->next)
00780         {
00781             /* Top-level progress */
00782             show_dialog(gui, TRUE);
00783             gtk_entry_set_text(GTK_ENTRY(gui->top_entry), current->title);
00784         }
00785         else if (!item->next->next)
00786         {
00787             /* Second-level progress */
00788             gtk_entry_set_text(GTK_ENTRY(gui->second_entry), current->title);
00789         }
00790         else
00791         {
00792             /* Other progress */
00793             GtkWidget *entry = gtk_entry_new();
00794             GtkWidget *box = gui->other_entries_box;
00795             gboolean new_box = box == NULL;
00796 
00797             gtk_entry_set_text(GTK_ENTRY(entry), current->title);
00798             if (new_box)
00799                 gui->other_entries_box = box = gtk_vbox_new(TRUE, 6);
00800             gtk_box_pack_start_defaults(GTK_BOX(box), entry);
00801             gtk_widget_show(entry);
00802             if (new_box)
00803             {
00804                 gtk_table_resize(GTK_TABLE(gui->entries_table),
00805                                  OTHER_ENTRIES_ROW_OFFSET + 1, 2);
00806                 gtk_table_attach_defaults(
00807                     GTK_TABLE(gui->entries_table), box, 1, 2,
00808                     OTHER_ENTRIES_ROW_OFFSET, OTHER_ENTRIES_ROW_OFFSET + 1);
00809                 gtk_widget_show(box);
00810             }
00811         }
00812 
00813         if (current->source)
00814         {
00815             /* Stop delayed call */
00816             g_source_remove(current->source);
00817             current->source = 0;
00818         }
00819 
00820         if (current == progress)
00821             break;
00822     }
00823 
00824     LEAVE(" ");
00825 }
00826 
00830 static void
00831 hide_progress(GncGWENGui *gui, Progress *progress)
00832 {
00833     GList *item;
00834     Progress *current;
00835 
00836     g_return_if_fail(gui);
00837 
00838     ENTER("gui=%p, progress=%p", gui, progress);
00839 
00840     for (item = gui->progresses; item; item = item->next)
00841     {
00842         current = (Progress*) item->data;
00843 
00844         if (current->source)
00845         {
00846             /* Not yet showed */
00847             g_source_remove(current->source);
00848             current->source = 0;
00849             if (current == progress)
00850                 break;
00851             else
00852                 continue;
00853         }
00854 
00855         /* Hide it */
00856         if (!item->next)
00857         {
00858             /* Top-level progress */
00859             gtk_entry_set_text(GTK_ENTRY(gui->second_entry), "");
00860         }
00861         else if (!item->next->next)
00862         {
00863             /* Second-level progress */
00864             gtk_entry_set_text(GTK_ENTRY(gui->second_entry), "");
00865         }
00866         else
00867         {
00868             /* Other progress */
00869             GtkWidget *box = gui->other_entries_box;
00870             GList *entries;
00871 
00872             g_return_if_fail(box);
00873             entries = gtk_container_get_children(GTK_CONTAINER(box));
00874             g_return_if_fail(entries);
00875             if (entries->next)
00876             {
00877                 /* Another progress is still to be showed */
00878                 gtk_widget_destroy(GTK_WIDGET(g_list_last(entries)->data));
00879             }
00880             else
00881             {
00882                 /* Last other progress to be hided */
00883                 gtk_table_resize(GTK_TABLE(gui->entries_table),
00884                                  OTHER_ENTRIES_ROW_OFFSET, 2);
00885                 gtk_widget_destroy(box);
00886                 gui->other_entries_box = NULL;
00887             }
00888             g_list_free(entries);
00889         }
00890 
00891         if (current == progress)
00892             break;
00893     }
00894 
00895     LEAVE(" ");
00896 }
00897 
00898 static void
00899 free_progress(Progress *progress, gpointer unused)
00900 {
00901     if (progress->source)
00902         g_source_remove(progress->source);
00903     g_free(progress->title);
00904     g_free(progress);
00905 }
00906 
00907 static gboolean
00908 keep_alive(GncGWENGui *gui)
00909 {
00910     g_return_val_if_fail(gui, FALSE);
00911 
00912     ENTER("gui=%p", gui);
00913 
00914     /* Let the widgets be redrawn */
00915     while (g_main_context_iteration(NULL, FALSE));
00916 
00917     LEAVE("alive=%d", gui->keep_alive);
00918     return gui->keep_alive;
00919 }
00920 
00921 static void
00922 cm_close_handler(gpointer user_data)
00923 {
00924     GncGWENGui *gui = user_data;
00925 
00926     g_return_if_fail(gui);
00927 
00928     ENTER("gui=%p", gui);
00929 
00930     /* FIXME */
00931     set_aborted(gui);
00932 
00933     LEAVE(" ");
00934 }
00935 
00936 static void
00937 erase_password(gchar *password)
00938 {
00939     g_return_if_fail(password);
00940 
00941     ENTER(" ");
00942 
00943     memset(password, 0, strlen(password));
00944     g_free(password);
00945 
00946     LEAVE(" ");
00947 }
00948 
00952 static gchar *
00953 strip_html(gchar *text)
00954 {
00955     gchar *p, *q;
00956 
00957     if (!text)
00958         return NULL;
00959 
00960     p = text;
00961     while (strchr(p, '<'))
00962     {
00963         q = p + 1;
00964         if (*q && toupper(*q++) == 'H'
00965                 && *q && toupper(*q++) == 'T'
00966                 && *q && toupper(*q++) == 'M'
00967                 && *q && toupper(*q) == 'L')
00968         {
00969             *p = '\0';
00970             return text;
00971         }
00972         p++;
00973     }
00974     return text;
00975 }
00976 
00977 static void
00978 get_input(GncGWENGui *gui, guint32 flags, const gchar *title, const gchar *text,
00979           gchar **input, gint min_len, gint max_len)
00980 {
00981     GtkBuilder *builder;
00982     GtkWidget *dialog;
00983     GtkWidget *heading_label;
00984     GtkWidget *input_entry;
00985     GtkWidget *confirm_entry;
00986     GtkWidget *confirm_label;
00987     GtkWidget *remember_pin_checkbutton;
00988     const gchar *internal_input, *internal_confirmed;
00989     gboolean confirm = (flags & GWEN_GUI_INPUT_FLAGS_CONFIRM) != 0;
00990     gboolean hidden = (flags & GWEN_GUI_INPUT_FLAGS_SHOW) == 0;
00991     gboolean is_tan = (flags & GWEN_GUI_INPUT_FLAGS_TAN) != 0;
00992     gint retval;
00993 
00994     g_return_if_fail(input);
00995     g_return_if_fail(max_len >= min_len && max_len > 0);
00996 
00997     ENTER(" ");
00998 
00999     /* Set up dialog */
01000     builder = gtk_builder_new();
01001     gnc_builder_add_from_file (builder, "dialog-ab.glade", "Password Dialog");
01002     dialog = GTK_WIDGET(gtk_builder_get_object (builder, "Password Dialog"));
01003 
01004     heading_label = GTK_WIDGET(gtk_builder_get_object (builder, "heading_label"));
01005     input_entry = GTK_WIDGET(gtk_builder_get_object (builder, "input_entry"));
01006     confirm_entry = GTK_WIDGET(gtk_builder_get_object (builder, "confirm_entry"));
01007     confirm_label = GTK_WIDGET(gtk_builder_get_object (builder, "confirm_label"));
01008     remember_pin_checkbutton = GTK_WIDGET(gtk_builder_get_object (builder, "remember_pin"));
01009     if (is_tan)
01010     {
01011         gtk_widget_hide(remember_pin_checkbutton);
01012     }
01013     else
01014     {
01015         gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(remember_pin_checkbutton),
01016                                      gui->cache_passwords);
01017     }
01018 
01019     if (gui->parent)
01020         gtk_window_set_transient_for(GTK_WINDOW(dialog),
01021                                      GTK_WINDOW(gui->parent));
01022     if (title)
01023         gtk_window_set_title(GTK_WINDOW(dialog), title);
01024 
01025     if (text)
01026     {
01027         gchar *raw_text = strip_html(g_strdup(text));
01028         gtk_label_set_text(GTK_LABEL(heading_label), raw_text);
01029         g_free(raw_text);
01030     }
01031 
01032     if (*input)
01033     {
01034         gtk_entry_set_text(GTK_ENTRY(input_entry), *input);
01035         erase_password(*input);
01036         *input = NULL;
01037     }
01038 
01039     if (confirm)
01040     {
01041         gtk_entry_set_activates_default(GTK_ENTRY(input_entry), FALSE);
01042         gtk_entry_set_activates_default(GTK_ENTRY(confirm_entry), TRUE);
01043         gtk_entry_set_max_length(GTK_ENTRY(input_entry), max_len);
01044         gtk_entry_set_max_length(GTK_ENTRY(confirm_entry), max_len);
01045     }
01046     else
01047     {
01048         gtk_entry_set_activates_default(GTK_ENTRY(input_entry), TRUE);
01049         gtk_entry_set_max_length(GTK_ENTRY(input_entry), max_len);
01050         gtk_widget_hide(confirm_entry);
01051         gtk_widget_hide(confirm_label);
01052     }
01053     gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
01054 
01055     /* Ask the user until he enters a valid input or cancels */
01056     while (TRUE)
01057     {
01058         gboolean remember_pin;
01059 
01060         if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_OK)
01061             break;
01062 
01063         if (!is_tan)
01064         {
01065             /* Enable or disable the password cache */
01066             remember_pin = gtk_toggle_button_get_active(
01067                                GTK_TOGGLE_BUTTON(remember_pin_checkbutton));
01068             enable_password_cache(gui, remember_pin);
01069             gnc_gconf_set_bool(GCONF_SECTION_AQBANKING, KEY_REMEMBER_PIN,
01070                                remember_pin, NULL);
01071         }
01072 
01073         internal_input = gtk_entry_get_text(GTK_ENTRY(input_entry));
01074         if (strlen(internal_input) < min_len)
01075         {
01076             gboolean retval;
01077             gchar *msg = g_strdup_printf(
01078                              _("The PIN needs to be at least %d characters \n"
01079                                "long. Do you want to try again?"), min_len);
01080             retval = gnc_verify_dialog(gui->parent, TRUE, "%s", msg);
01081             g_free(msg);
01082             if (!retval)
01083                 break;
01084             continue;
01085         }
01086 
01087         if (!confirm)
01088         {
01089             *input = g_strdup(internal_input);
01090             break;
01091         }
01092 
01093         internal_confirmed = gtk_entry_get_text(GTK_ENTRY(confirm_entry));
01094         if (strcmp(internal_input, internal_confirmed) == 0)
01095         {
01096             *input = g_strdup(internal_input);
01097             break;
01098         }
01099     }
01100 
01101     g_object_unref(G_OBJECT(builder));
01102 
01103     /* This trashes passwords in the entries' memory as well */
01104     gtk_widget_destroy(dialog);
01105 
01106     LEAVE("input %s", *input ? "non-NULL" : "NULL");
01107 }
01108 
01109 static gint
01110 messagebox_cb(GWEN_GUI *gwen_gui, guint32 flags, const gchar *title,
01111               const gchar *text, const gchar *b1, const gchar *b2,
01112               const gchar *b3, guint32 guiid)
01113 {
01114     GncGWENGui *gui = GETDATA_GUI(gwen_gui);
01115     GtkWidget *dialog;
01116     GtkWidget *vbox;
01117     GtkWidget *label;
01118     gchar *raw_text;
01119     gint result;
01120 
01121     ENTER("gui=%p, flags=%d, title=%s, b1=%s, b2=%s, b3=%s", gui, flags,
01122           title ? title : "(null)", b1 ? b1 : "(null)", b2 ? b2 : "(null)",
01123           b3 ? b3 : "(null)");
01124 
01125     dialog = gtk_dialog_new_with_buttons(
01126                  title, gui->parent ? GTK_WINDOW(gui->parent) : NULL,
01127                  GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
01128                  b1, 1, b2, 2, b3, 3, (gchar*) NULL);
01129 
01130     raw_text = strip_html(g_strdup(text));
01131     label = gtk_label_new(raw_text);
01132     g_free(raw_text);
01133     gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
01134     vbox = gtk_vbox_new(TRUE, 0);
01135     gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
01136     gtk_container_add(GTK_CONTAINER(vbox), label);
01137     gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
01138     gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), vbox);
01139     gtk_widget_show_all(dialog);
01140 
01141     result = gtk_dialog_run(GTK_DIALOG(dialog));
01142     gtk_widget_destroy(dialog);
01143 
01144     if (result < 1 || result > 3)
01145     {
01146         g_warning("messagebox_cb: Bad result %d", result);
01147         result = 0;
01148     }
01149 
01150     LEAVE("result=%d", result);
01151     return result;
01152 }
01153 
01154 static gint
01155 inputbox_cb(GWEN_GUI *gwen_gui, guint32 flags, const gchar *title,
01156             const gchar *text, gchar *buffer, gint min_len, gint max_len,
01157             guint32 guiid)
01158 {
01159     GncGWENGui *gui = GETDATA_GUI(gwen_gui);
01160     gchar *input = NULL;
01161 
01162     g_return_val_if_fail(gui, -1);
01163 
01164     ENTER("gui=%p, flags=%d", gui, flags);
01165 
01166     get_input(gui, flags, title, text, &input, min_len, max_len);
01167 
01168     if (input)
01169     {
01170         /* Copy the input to the result buffer */
01171         strncpy(buffer, input, max_len);
01172         buffer[max_len-1] = '\0';
01173     }
01174 
01175     LEAVE(" ");
01176     return input ? 0 : -1;
01177 }
01178 
01179 static guint32
01180 showbox_cb(GWEN_GUI *gwen_gui, guint32 flags, const gchar *title,
01181            const gchar *text, guint32 guiid)
01182 {
01183     GncGWENGui *gui = GETDATA_GUI(gwen_gui);
01184     GtkWidget *dialog;
01185     guint32 showbox_id;
01186 
01187     g_return_val_if_fail(gui, -1);
01188 
01189     ENTER("gui=%p, flags=%d, title=%s", gui, flags, title ? title : "(null)");
01190 
01191     dialog = gtk_message_dialog_new(
01192                  gui->parent ? GTK_WINDOW(gui->parent) : NULL, 0, GTK_MESSAGE_INFO,
01193                  GTK_BUTTONS_OK, "%s", text);
01194 
01195     if (title)
01196         gtk_window_set_title(GTK_WINDOW(dialog), title);
01197 
01198     g_signal_connect(dialog, "response", G_CALLBACK(gtk_widget_hide), NULL);
01199     gtk_widget_show_all(dialog);
01200 
01201     showbox_id = gui->showbox_id++;
01202     g_hash_table_insert(gui->showbox_hash, GUINT_TO_POINTER(showbox_id),
01203                         dialog);
01204     gui->showbox_last = dialog;
01205 
01206     /* Give it a change to be showed */
01207     if (!keep_alive(gui))
01208         showbox_id = 0;
01209 
01210     LEAVE("id=%" G_GUINT32_FORMAT, showbox_id);
01211     return showbox_id;
01212 }
01213 
01214 static void
01215 hidebox_cb(GWEN_GUI *gwen_gui, guint32 id)
01216 {
01217     GncGWENGui *gui = GETDATA_GUI(gwen_gui);
01218     GtkWidget *dialog;
01219 
01220     g_return_if_fail(gui && gui->showbox_hash);
01221 
01222     ENTER("gui=%p, id=%d", gui, id);
01223 
01224     if (id == 0)
01225     {
01226         if (gui->showbox_last)
01227         {
01228             g_hash_table_remove(gui->showbox_hash,
01229                                 GUINT_TO_POINTER(gui->showbox_id));
01230             gui->showbox_last = NULL;
01231         }
01232         else
01233         {
01234             g_warning("hidebox_cb: Last showed message box already destroyed");
01235         }
01236     }
01237     else
01238     {
01239         gpointer p_var;
01240         p_var = g_hash_table_lookup(gui->showbox_hash, GUINT_TO_POINTER(id));
01241         if (p_var)
01242         {
01243             g_hash_table_remove(gui->showbox_hash, GUINT_TO_POINTER(id));
01244             if (p_var == gui->showbox_last)
01245                 gui->showbox_last = NULL;
01246         }
01247         else
01248         {
01249             g_warning("hidebox_cb: Message box %d could not been found", id);
01250         }
01251     }
01252 
01253     LEAVE(" ");
01254 }
01255 
01256 static guint32
01257 progress_start_cb(GWEN_GUI *gwen_gui, uint32_t progressFlags, const char *title,
01258                   const char *text, uint64_t total, uint32_t guiid)
01259 {
01260     GncGWENGui *gui = GETDATA_GUI(gwen_gui);
01261     Progress *progress;
01262 
01263     g_return_val_if_fail(gui, -1);
01264 
01265     ENTER("gui=%p, flags=%d, title=%s, total=%" G_GUINT64_FORMAT, gui,
01266           progressFlags, title ? title : "(null)", (guint64)total);
01267 
01268     if (!gui->progresses)
01269     {
01270         /* Top-level progress */
01271         if (progressFlags & GWEN_GUI_PROGRESS_SHOW_PROGRESS)
01272         {
01273             gtk_widget_set_sensitive(gui->top_progress, TRUE);
01274             gtk_progress_bar_set_fraction(
01275                 GTK_PROGRESS_BAR(gui->top_progress), 0.0);
01276             gui->max_actions = total;
01277         }
01278         else
01279         {
01280             gtk_widget_set_sensitive(gui->top_progress, FALSE);
01281             gui->max_actions = -1;
01282         }
01283         set_running(gui);
01284     }
01285 
01286     /* Put progress onto the stack */
01287     progress = g_new0(Progress, 1);
01288     progress->gui = gui;
01289     progress->title = title ? g_strdup(title) : "";
01290     gui->progresses = g_list_prepend(gui->progresses, progress);
01291 
01292     if (progressFlags & GWEN_GUI_PROGRESS_DELAY)
01293     {
01294         /* Show progress later */
01295         progress->source = g_timeout_add(GWEN_GUI_DELAY_SECS * 1000,
01296                                          (GSourceFunc) show_progress_cb,
01297                                          progress);
01298     }
01299     else
01300     {
01301         /* Show it now */
01302         progress->source = 0;
01303         show_progress(gui, progress);
01304     }
01305 
01306     LEAVE(" ");
01307     return g_list_length(gui->progresses);
01308 }
01309 
01310 static gint
01311 progress_advance_cb(GWEN_GUI *gwen_gui, uint32_t id, uint64_t progress)
01312 {
01313     GncGWENGui *gui = GETDATA_GUI(gwen_gui);
01314 
01315     g_return_val_if_fail(gui, -1);
01316 
01317     ENTER("gui=%p, progress=%" G_GUINT64_FORMAT, gui, (guint64)progress);
01318 
01319     if (id == 1                                  /* top-level progress */
01320             && gui->max_actions > 0                  /* progressbar active */
01321             && progress != GWEN_GUI_PROGRESS_NONE)   /* progressbar update needed */
01322     {
01323         if (progress == GWEN_GUI_PROGRESS_ONE)
01324             gui->current_action++;
01325         else
01326             gui->current_action = progress;
01327 
01328         gtk_progress_bar_set_fraction(
01329             GTK_PROGRESS_BAR(gui->top_progress),
01330             ((gdouble) gui->current_action) / ((gdouble) gui->max_actions));
01331     }
01332 
01333     LEAVE(" ");
01334     return !keep_alive(gui);
01335 }
01336 
01337 static gint
01338 progress_log_cb(GWEN_GUI *gwen_gui, guint32 id, GWEN_LOGGER_LEVEL level,
01339                 const gchar *text)
01340 {
01341     GncGWENGui *gui = GETDATA_GUI(gwen_gui);
01342     GtkTextBuffer *tb;
01343     GtkTextView *tv;
01344 
01345     g_return_val_if_fail(gui, -1);
01346 
01347     ENTER("gui=%p, text=%s", gui, text ? text : "(null)");
01348 
01349     tv = GTK_TEXT_VIEW(gui->log_text);
01350     tb = gtk_text_view_get_buffer(tv);
01351     gtk_text_buffer_insert_at_cursor(tb, text, -1);
01352     gtk_text_buffer_insert_at_cursor(tb, "\n", -1);
01353 
01354     /* Scroll to the end of the buffer */
01355     gtk_text_view_scroll_to_mark(tv, gtk_text_buffer_get_insert(tb),
01356                                  0.0, FALSE, 0.0, 0.0);
01357 
01358     /* Cache loglevel */
01359     if (level < gui->min_loglevel)
01360         gui->min_loglevel = level;
01361 
01362     LEAVE(" ");
01363     return !keep_alive(gui);
01364 }
01365 
01366 static gint
01367 progress_end_cb(GWEN_GUI *gwen_gui, guint32 id)
01368 {
01369     GncGWENGui *gui = GETDATA_GUI(gwen_gui);
01370     Progress *progress;
01371 
01372     g_return_val_if_fail(gui, -1);
01373     g_return_val_if_fail(id == g_list_length(gui->progresses), -1);
01374 
01375     ENTER("gui=%p, id=%d", gui, id);
01376 
01377     if (gui->state != RUNNING)
01378     {
01379         /* Ignore finishes of progresses we do not track */
01380         LEAVE("not running anymore");
01381         return 0;
01382     }
01383 
01384     /* Hide progress */
01385     progress = (Progress*) gui->progresses->data;
01386     hide_progress(gui, progress);
01387 
01388     /* Remove progress from stack and free memory */
01389     gui->progresses = g_list_delete_link(gui->progresses, gui->progresses);
01390     free_progress(progress, NULL);
01391 
01392     if (!gui->progresses)
01393     {
01394         /* top-level progress finished */
01395         set_finished(gui);
01396     }
01397 
01398     LEAVE(" ");
01399     return 0;
01400 }
01401 
01402 static gint GNC_GWENHYWFAR_CB
01403 getpassword_cb(GWEN_GUI *gwen_gui, guint32 flags, const gchar *token,
01404                const gchar *title, const gchar *text, gchar *buffer,
01405                gint min_len, gint max_len, guint32 guiid)
01406 {
01407     GncGWENGui *gui = GETDATA_GUI(gwen_gui);
01408     gchar *password = NULL;
01409     gboolean is_tan = (flags & GWEN_GUI_INPUT_FLAGS_TAN) != 0;
01410 
01411     g_return_val_if_fail(gui, -1);
01412 
01413     ENTER("gui=%p, flags=%d, token=%s", gui, flags, token ? token : "(null");
01414 
01415     /* Check remembered passwords, excluding TANs */
01416     if (!is_tan && gui->cache_passwords && gui->passwords && token)
01417     {
01418         if (flags & GWEN_GUI_INPUT_FLAGS_RETRY)
01419         {
01420             /* If remembered, remove password from memory */
01421             g_hash_table_remove(gui->passwords, token);
01422         }
01423         else
01424         {
01425             gpointer p_var;
01426             if (g_hash_table_lookup_extended(gui->passwords, token, NULL,
01427                                              &p_var))
01428             {
01429                 /* Copy the password to the result buffer */
01430                 password = p_var;
01431                 strncpy(buffer, password, max_len);
01432                 buffer[max_len-1] = '\0';
01433 
01434                 LEAVE("chose remembered password");
01435                 return 0;
01436             }
01437         }
01438     }
01439 
01440     get_input(gui, flags, title, text, &password, min_len, max_len);
01441 
01442     if (password)
01443     {
01444         /* Copy the password to the result buffer */
01445         strncpy(buffer, password, max_len);
01446         buffer[max_len-1] = '\0';
01447 
01448         if (!is_tan && token)
01449         {
01450             if (gui->cache_passwords && gui->passwords)
01451             {
01452                 /* Remember password */
01453                 DEBUG("Remember password, token=%s", token);
01454                 g_hash_table_insert(gui->passwords, g_strdup(token), password);
01455             }
01456             else
01457             {
01458                 /* Remove the password from memory */
01459                 DEBUG("Forget password, token=%s", token);
01460                 erase_password(password);
01461             }
01462         }
01463     }
01464 
01465     LEAVE(" ");
01466     return password ? 0 : -1;
01467 }
01468 
01469 static gint GNC_GWENHYWFAR_CB
01470 setpasswordstatus_cb(GWEN_GUI *gwen_gui, const gchar *token, const gchar *pin,
01471                      GWEN_GUI_PASSWORD_STATUS status, guint32 guiid)
01472 {
01473     GncGWENGui *gui = GETDATA_GUI(gwen_gui);
01474 
01475     g_return_val_if_fail(gui, -1);
01476 
01477     ENTER("gui=%p, token=%s, status=%d", gui, token ? token : "(null)", status);
01478 
01479     if (gui->passwords && status != GWEN_Gui_PasswordStatus_Ok)
01480     {
01481         /* If remembered, remove password from memory */
01482         g_hash_table_remove(gui->passwords, token);
01483     }
01484 
01485     LEAVE(" ");
01486     return 0;
01487 }
01488 
01489 static gint GNC_GWENHYWFAR_CB
01490 loghook_cb(GWEN_GUI *gwen_gui, const gchar *log_domain,
01491            GWEN_LOGGER_LEVEL priority, const gchar *text)
01492 {
01493     if (G_LIKELY(priority < n_log_levels))
01494         g_log(log_domain, log_levels[priority], "%s", text);
01495 
01496     return 1;
01497 }
01498 
01499 static gint GNC_GWENHYWFAR_CB
01500 checkcert_cb(GWEN_GUI *gwen_gui, const GWEN_SSLCERTDESCR *cert,
01501              GWEN_IO_LAYER *io, guint32 guiid)
01502 {
01503     GncGWENGui *gui = GETDATA_GUI(gwen_gui);
01504     const gchar *hash, *status;
01505     struct md5_ctx md5_context;
01506     gchar cert_hash[16];
01507     gchar *cert_hash_hex;
01508     gint retval, i;
01509 
01510     g_return_val_if_fail(gui && gui->accepted_certs, -1);
01511 
01512     ENTER("gui=%p, cert=%p", gui, cert);
01513 
01514     hash = GWEN_SslCertDescr_GetFingerPrint(cert);
01515     status = GWEN_SslCertDescr_GetStatusText(cert);
01516 
01517     /* Operate on an md5sum of the pair of hash and status */
01518     md5_init_ctx(&md5_context);
01519     md5_process_bytes(hash, strlen(hash), &md5_context);
01520     md5_process_bytes(status, strlen(status), &md5_context);
01521     md5_finish_ctx(&md5_context, cert_hash);
01522 
01523     /* Did we get the permanently accepted certs from AqBanking? */
01524     if (gui->permanently_accepted_certs)
01525     {
01526         /* Generate a hex string of the cert_hash for usage by AqBanking cert store */
01527         cert_hash_hex = g_new0(gchar, 33);
01528         for (i = 0; i < 16; i++)
01529             g_snprintf(cert_hash_hex + 2 * i, 3, "%02X", (unsigned char)cert_hash[i]);
01530 
01531         retval = GWEN_DB_GetIntValue(gui->permanently_accepted_certs, cert_hash_hex, 0, -1);
01532         g_free(cert_hash_hex);
01533         if (retval == 0)
01534         {
01535             /* Certificate is marked as accepted in AqBanking's cert store */
01536             LEAVE("Certificate accepted by AqBanking's permanent cert store");
01537             return 0;
01538         }
01539     }
01540     else
01541     {
01542         g_warning("Can't check permanently accepted certs from invalid AqBanking cert store.");
01543     }
01544 
01545     if (g_hash_table_lookup(gui->accepted_certs, cert_hash))
01546     {
01547         /* Certificate has been accepted by Gnucash before */
01548         LEAVE("Automatically accepting certificate");
01549         return 0;
01550     }
01551 
01552     retval = gui->builtin_checkcert(gwen_gui, cert, io, guiid);
01553     if (retval == 0)
01554     {
01555         /* Certificate has been accepted */
01556         g_hash_table_insert(gui->accepted_certs, g_strdup(cert_hash), cert_hash);
01557     }
01558 
01559     LEAVE("retval=%d", retval);
01560     return retval;
01561 }
01562 
01563 gboolean
01564 ggg_delete_event_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data)
01565 {
01566     GncGWENGui *gui = user_data;
01567 
01568     g_return_val_if_fail(gui, FALSE);
01569 
01570     ENTER("gui=%p, state=%d", gui, gui->state);
01571 
01572     if (gui->state == RUNNING)
01573     {
01574         const char *still_running_msg =
01575             _("The Online Banking job is still running; are you "
01576               "sure you want to cancel?");
01577         if (!gnc_verify_dialog(gui->dialog, FALSE, "%s", still_running_msg))
01578             return FALSE;
01579 
01580         set_aborted(gui);
01581     }
01582 
01583     hide_dialog(gui);
01584 
01585     LEAVE(" ");
01586     return TRUE;
01587 }
01588 
01589 void
01590 ggg_abort_clicked_cb(GtkButton *button, gpointer user_data)
01591 {
01592     GncGWENGui *gui = user_data;
01593 
01594     g_return_if_fail(gui && gui->state == RUNNING);
01595 
01596     ENTER("gui=%p", gui);
01597 
01598     set_aborted(gui);
01599 
01600     LEAVE(" ");
01601 }
01602 
01603 void
01604 ggg_close_clicked_cb(GtkButton *button, gpointer user_data)
01605 {
01606     GncGWENGui *gui = user_data;
01607 
01608     g_return_if_fail(gui);
01609     g_return_if_fail(gui->state == FINISHED || gui->state == ABORTED);
01610 
01611     ENTER("gui=%p", gui);
01612 
01613     hide_dialog(gui);
01614 
01615     LEAVE(" ");
01616 }
01617 
01618 void
01619 ggg_close_toggled_cb(GtkToggleButton *button, gpointer user_data)
01620 {
01621     GncGWENGui *gui = user_data;
01622 
01623     g_return_if_fail(gui);
01624     g_return_if_fail(gui->parent);
01625 
01626     ENTER("gui=%p", gui);
01627 
01628     gnc_gconf_set_bool(
01629         GCONF_SECTION_AQBANKING, KEY_CLOSE_ON_FINISH,
01630         gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(button)),
01631         NULL);
01632 
01633     LEAVE(" ");
01634 }
01635 #endif
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines