Bug 667490 - Support chipTAN optical "Flicker code"

Partly fixes bug 667490.
It implements the display of flashing optical TAN challenges (aka
flicker) in the "Enter TAN" dialog box.
This commit is contained in:
CWehli 2020-11-15 15:06:09 +01:00
parent 743df212a1
commit 580975b924
7 changed files with 718 additions and 22 deletions

View File

@ -13,6 +13,7 @@ set (aqbanking_SOURCES
gnc-ab-transfer.c
gnc-ab-utils.c
gnc-file-aqb-import.c
gnc-flicker-gui.c
gnc-gwen-gui.c
gnc-plugin-aqbanking.c
gncmod-aqbanking.c
@ -31,6 +32,7 @@ set (aqbanking_noinst_HEADERS
gnc-ab-transfer.h
gnc-ab-utils.h
gnc-file-aqb-import.h
gnc-flicker-gui.h
gnc-gwen-gui.h
gnc-plugin-aqbanking.h
)

View File

@ -634,14 +634,90 @@
</packing>
</child>
<child>
<object class="GtkImage" id="optical_challenge">
<property name="name">optical_challenge</property>
<object class="GtkBox" id="flicker_hbox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="spacing">7</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
<property name="label" translatable="yes">Bar_width</property>
<property name="xalign">0.7</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">spin_barwidth</property>
<attributes>
<attribute name="gravity" value="west"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="spin_barwidth">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip-text" translatable="yes" comments="TAN generator with flicker interface common in DE only">Setting the bar width, adapting to the size of the TAN generator.</property>
<property name="numeric">True</property>
<property name="update_policy">if-valid</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
<property name="label" translatable="yes">_Delay</property>
<property name="xalign">0.7</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">spin_delay</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="spin_delay">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="tooltip-text" translatable="yes" comments="TAN generator with flicker interface common in DE only">Setting the delay time, with small values the flicker graphic is repeated faster.</property>
<property name="numeric">True</property>
<property name="update_policy">if-valid</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkDrawingArea" id="flicker_marker">
<property name="visible">True</property>
<property name="app_paintable">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="icon_name">image-missing</property>
<property name="icon_size">6</property>
</object>
<packing>
<property name="expand">False</property>
@ -649,6 +725,48 @@
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkImage" id="optical_challenge">
<property name="name">optical_challenge</property>
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="icon_name">image-missing</property>
<property name="icon_size">6</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkDrawingArea" id="flicker_challenge">
<property name="visible">True</property>
<property name="app_paintable">True</property>
<property name="tooltip_text" translatable="yes" comments="TAN generator with flicker interface common in DE only">Hold the TAN generator in front of the animated graphic. The markings (triangles) on the graphic must match those on the TAN generator.</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkGrid" id="grid1">
<property name="visible">True</property>
@ -736,7 +854,7 @@
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
<property name="position">4</property>
</packing>
</child>
</object>

View File

@ -0,0 +1,445 @@
/*
* gnc-flicker-gui.c --
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, contact:
*
* Free Software Foundation Voice: +1-617-542-5942
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
* Boston, MA 02110-1301, USA gnu@gnu.org
*/
/**
* @internal
* @file gnc-flicker-gui.c
* @brief GUI callbacks for Flicker and ChipTAN(optisch)
* @author Copyright (C) 2020 Christian Wehling <christian.wehling@web.de>
*/
#include <config.h>
#include <gtk/gtk.h>
#include <glib/gi18n.h>
#include "dialog-utils.h"
#include "gnc-flicker-gui.h"
#include "gnc-state.h"
#include "gnc-ui.h"
#define GNC_PREFS_GROUP "dialogs.flicker"
#define GNC_STATE_SECTION "Flicker"
#define STATE_KEY_BAR_WIDTH "barwidth"
#define STATE_KEY_DELAY "delay"
#define BAR_WIDTH 44 /* Width of the flicker bars */
#define BAR_HEIGHT 200 /* Height of the flicker bars */
#define MARGIN 12 /* Distance between the flicker bars */
#define DELAY 50 /* Pause between the flickering painting */
static char *flicker_data (char const *challenge);
static gboolean time_handler (GtkWidget *widget);
static void do_marker_drawing (cairo_t *cr);
static void draw_bit (cairo_t *cr, _Bool bit, int i);
static void do_flicker_drawing (GtkWidget *widget, cairo_t *cr);
static void do_flicker_load_state (GtkWidget *dialog);
static void do_flicker_store_state (GtkWidget *dialog);
static gboolean on_flicker_challenge_draw (GtkWidget *widget, cairo_t *cr,
gpointer user_data);
static void on_flicker_challenge_map (GtkWidget *widget);
static void on_flicker_challenge_destroy (GtkWidget *widget, gpointer user_data);
static gboolean on_flicker_marker_draw (GtkWidget *widget, cairo_t *cr,
gpointer user_data);
static void on_flicker_marker_map (GtkWidget *widget);
static void on_spin_barwidth_value_changed (GtkSpinButton *spin, GtkWidget *widget);
static void on_spin_delay_value_changed (GtkSpinButton *spin, GtkWidget *widget);
static void on_dialog_destroy (GtkWidget *dialog, gpointer user_data);
/* structured data for the flicker variables */
struct Flickerdraw {
const char *challenge;
guint challenge_length;
guint margin; /* Distance between bars */
guint barwidth; /* Bar width */
guint barheight; /* Bar height */
guint x_barpos; /* x-value for the position of the bar */
guint y_barpos; /* y-value for the position of the bar */
guint x_drawpos; /* x-value of the first painting position */
guint y_drawpos; /* y-value of the first painting position */
guint height; /* Height of the drawing area */
guint width; /* Width of the drawing area */
guint delay; /* Waiting time between frames in milliseconds */
guint halfbyteid;
guint clock;
guint interval;
gboolean change_interval;
};
static struct Flickerdraw flickerdraw;
static GncFlickerGui *flickergui = NULL;
static _Bool bitarray[255][5];
/* this function will return number corresponding 0,1,2..,9,A,B,C,D,E,F */
static uint
get_num (const char ch)
{
int num =0;
if (ch >= '0' && ch <= '9')
num = ch - 0x30;
else
{
switch (ch)
{
case 'A': case 'a': num = 10; break;
case 'B': case 'b': num = 11; break;
case 'C': case 'c': num = 12; break;
case 'D': case 'd': num = 13; break;
case 'E': case 'e': num = 14; break;
case 'F': case 'f': num = 15; break;
default: num = 0;
}
}
/* The bank challenge has been verified by Aqbanking,
* so I assume that no error can occur. */
return num;
}
/* convert the bank challenge into the 5 bits for the flicker data */
static char
*flicker_data (const char *challenge)
{
/* bitfield is a clock bit and a 4-bit code with the bits reversed
(bit 1 is the least significant and bit 4 the most
so 0x1 is 1000 and 0x8 is 0001) */
static const _Bool bits[16][5] =
{
{0, 0, 0, 0, 0}, {0, 1, 0, 0, 0}, {0, 0, 1, 0, 0}, {0, 1, 1, 0, 0},
{0, 0, 0, 1, 0}, {0, 1, 0, 1, 0}, {0, 0, 1, 1, 0}, {0, 1, 1, 1, 0},
{0, 0, 0, 0, 1}, {0, 1, 0, 0, 1}, {0, 0, 1, 0, 1}, {0, 1, 1, 0, 1},
{0, 0, 0, 1, 1}, {0, 1, 0, 1, 1}, {0, 0, 1, 1, 1}, {0, 1, 1, 1, 1}
};
/* prepend synchronization identifier */
const char pre[] = {'0', 'F', 'F', 'F'};
size_t len = sizeof (pre) + strlen (challenge) + 1;
char* code = (char*)malloc (len);
memcpy (code, pre, sizeof (pre));
memcpy (code + sizeof (pre), challenge, strlen (challenge));
/* Swap the position of the bits in pairs throughout the bank challenge
(low-order nibble first). */
for (uint i = 0; i < len - 1; i += 2)
{
u_int val1 = get_num (code[i]);
u_int val2 = get_num (code[i+1]);
memcpy (&bitarray[i], bits[val2], sizeof(bits[val2]));
memcpy (&bitarray[i+1], bits[val1], sizeof(bits[val1]));
}
return code;
}
/* A timer for redrawing the flickering painting, is started here and
* called up again when the "Delay" value is changed */
static gboolean
time_handler (GtkWidget *widget)
{
/* Change of waiting time */
if (flickerdraw.change_interval)
{
g_source_remove (flickerdraw.interval);
flickerdraw.interval = g_timeout_add (flickerdraw.delay,
(GSourceFunc) time_handler,
(gpointer) widget);
flickerdraw.change_interval = FALSE;
return FALSE;
}
gtk_widget_queue_draw (widget);
return TRUE;
}
/* Show the colored triangle as a pointer for the position of the TAN generator */
static void
do_marker_drawing (cairo_t *cr)
{
guint pos1;
guint pos2;
/* Initialize the drawing area to black */
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_paint (cr);
cairo_set_source_rgb (cr, 0.9, 0.1, 0.1);
/* draw the left triangle */
pos1 = flickerdraw.x_drawpos + flickerdraw.barwidth / 2;
cairo_move_to (cr, pos1, 20);
cairo_line_to (cr, pos1 + 10, 2);
cairo_line_to (cr, pos1 - 10, 2);
cairo_close_path (cr);
cairo_stroke_preserve (cr);
cairo_fill (cr);
/* draw the right triangle */
pos2 = flickerdraw.x_drawpos + 4 * flickerdraw.margin + 4 * flickerdraw.barwidth +
flickerdraw.barwidth / 2;
cairo_move_to (cr, pos2, 20);
cairo_line_to (cr, pos2 + 10, 2);
cairo_line_to (cr, pos2 - 10, 2);
cairo_close_path (cr);
cairo_stroke_preserve (cr);
cairo_fill (cr);
}
/* draws the 5 flickering bars of the bank data into the drawing area */
static void
draw_bit (cairo_t *cr, _Bool bit, int i)
{
if (bit & 1)
cairo_set_source_rgb (cr, 1, 1, 1);
else
cairo_set_source_rgb (cr, 0, 0, 0);
flickerdraw.x_barpos = flickerdraw.x_drawpos + i * flickerdraw.margin +
i * flickerdraw.barwidth;
cairo_rectangle (cr, flickerdraw.x_barpos, flickerdraw.y_barpos,
flickerdraw.barwidth, flickerdraw.barheight);
cairo_fill (cr);
}
/* Prepares the drawing area for the flicker graphic. */
static void
do_flicker_drawing (GtkWidget *widget, cairo_t *cr)
{
/* Always align the flicker display in the middle of the drawing area */
flickerdraw.width = gtk_widget_get_allocated_width (widget);
/* Start position of the first bar */
flickerdraw.x_drawpos = (flickerdraw.width - 4 * flickerdraw.margin -
5 * flickerdraw.barwidth) / 2;
/* Initialize the drawing area to black */
cairo_set_source_rgb (cr, 0, 0, 0);
cairo_paint (cr);
/* paint the flicker graphic */
bitarray[flickerdraw.halfbyteid][0] = flickerdraw.clock;
draw_bit (cr, flickerdraw.clock, 0);
for (int i = 1; i <= 4; i++)
draw_bit (cr, bitarray[flickerdraw.halfbyteid][i], i);
/* Each flicker point is drawn twice. Once with clock = 1 and once with clock = 0 */
if (!flickerdraw.clock)
{
flickerdraw.clock = 1;
flickerdraw.halfbyteid++;
if (flickerdraw.halfbyteid >= flickerdraw.challenge_length)
flickerdraw.halfbyteid = 0;
}
else if (flickerdraw.clock)
flickerdraw.clock = 0;
}
/* Load the state of the GUI (Size of the Dialog, Value of the Spinbutton) */
static void
do_flicker_load_state (GtkWidget *dialog)
{
/* Load the values in the spin button */
GKeyFile *state_file = gnc_state_get_current ();
if (g_key_file_has_key (state_file, GNC_STATE_SECTION, STATE_KEY_BAR_WIDTH, NULL))
flickerdraw.barwidth = g_key_file_get_integer (state_file,
GNC_STATE_SECTION,
STATE_KEY_BAR_WIDTH, NULL);
else
flickerdraw.barwidth = BAR_WIDTH;
if (g_key_file_has_key (state_file, GNC_STATE_SECTION, STATE_KEY_DELAY, NULL))
flickerdraw.delay = g_key_file_get_integer (state_file,
GNC_STATE_SECTION,
STATE_KEY_DELAY, NULL);
else
flickerdraw.delay = DELAY;
/* Load window size and position */
gnc_restore_window_size (GNC_PREFS_GROUP, GTK_WINDOW (dialog),
gnc_ui_get_main_window (NULL));
}
/* Stores the state of the GUI (Size of the Dialog, Value of the Spinbutton) */
static void
do_flicker_store_state (GtkWidget *dialog)
{
/* Save the values in the spin button */
GKeyFile *state_file = gnc_state_get_current ();
if (flickerdraw.barwidth != BAR_WIDTH)
g_key_file_set_integer (state_file, GNC_STATE_SECTION,
STATE_KEY_BAR_WIDTH, flickerdraw.barwidth);
else if (g_key_file_has_key (state_file, GNC_STATE_SECTION,
STATE_KEY_BAR_WIDTH, NULL))
g_key_file_remove_key (state_file, GNC_STATE_SECTION,
STATE_KEY_BAR_WIDTH, NULL);
if (flickerdraw.delay != DELAY)
g_key_file_set_integer (state_file, GNC_STATE_SECTION,
STATE_KEY_DELAY, flickerdraw.delay);
else if (g_key_file_has_key (state_file, GNC_STATE_SECTION,
STATE_KEY_DELAY, NULL))
g_key_file_remove_key (state_file, GNC_STATE_SECTION,
STATE_KEY_DELAY, NULL);
/* Save window size and position */
gnc_save_window_size (GNC_PREFS_GROUP, GTK_WINDOW (dialog));
}
/* This signal is emitted when the drawing area "flicker challenge" is visible */
static void
on_flicker_challenge_map (GtkWidget *widget)
{
gchar *code = g_malloc (strlen (flickerdraw.challenge) + 4);
code = flicker_data (flickerdraw.challenge);
flickerdraw.challenge_length = strlen (code);
/* Set the height of the drawing area */
flickerdraw.height = flickerdraw.barheight + 2 * flickerdraw.y_barpos;
gtk_widget_set_size_request (widget, -1, flickerdraw.height);
/* Call up the time function and start the flicker display */
flickerdraw.interval = g_timeout_add (flickerdraw.delay,
(GSourceFunc) time_handler,
(gpointer) widget);
}
/* Initialize the drawingarea to black and paint the flickerchallenge */
static gboolean
on_flicker_challenge_draw (GtkWidget *widget, cairo_t *cr,
__attribute__((unused)) gpointer user_data)
{
do_flicker_drawing (widget, cr);
return FALSE;
}
/* called when the drawing area is destroyed */
static void
on_flicker_challenge_destroy (GtkWidget *widget,
__attribute__((unused)) gpointer user_data)
{
/* remove the timeout function */
g_source_remove (flickerdraw.interval);
}
/* Initialize the drawing area "flicker marker" in black and draw the marker for
* the position of the TAN-Generator */
static gboolean
on_flicker_marker_draw (__attribute__((unused)) GtkWidget *widget, cairo_t *cr,
__attribute__((unused)) gpointer data)
{
do_marker_drawing (cr);
return FALSE;
}
/* This signal is emitted when the drawing area "flicker marker" is visible */
static void
on_flicker_marker_map (GtkWidget *widget)
{
/* Set the height of the drawing area */
gtk_widget_set_size_request (widget, -1, flickerdraw.y_barpos);
}
/* The value for "Field width" has been changed on the spin button and the
* flicker display is updated */
static void
on_spin_barwidth_value_changed (GtkSpinButton *spin, GtkWidget *widget)
{
flickerdraw.barwidth = gtk_spin_button_get_value_as_int (spin);
flickerdraw.x_drawpos = (flickerdraw.width - 4 * flickerdraw.margin -
5 * flickerdraw.barwidth) / 2;
/* Moving the position triangles */
gtk_widget_queue_draw (widget);
}
/* The value for "waiting time" was changed on the spin button and
* the speed of the flickering display is updated */
static void
on_spin_delay_value_changed (GtkSpinButton *spin, GtkWidget *widget)
{
flickerdraw.delay = gtk_spin_button_get_value_as_int (spin);
flickerdraw.change_interval = TRUE;
time_handler (widget);
}
static void
on_dialog_destroy (GtkWidget *dialog, __attribute__((unused)) gpointer user_data)
{
/* Store window size and initial setting values */
do_flicker_store_state (dialog);
}
/* The widgets for the GUI are prepared and the first parameters are set */
void
ini_flicker_gui (const char *pChallenge, GncFlickerGui *gui)
{
/* Establish reference to the dialog widgets created in gnc_gwen_gui */
flickergui = gui;
/* Load window size and initial setting values */
do_flicker_load_state (GTK_WIDGET (flickergui->dialog));
/* Initialize application */
flickerdraw.barheight = BAR_HEIGHT;
flickerdraw.margin = MARGIN;
flickerdraw.y_barpos = 20; /* First painting position */
flickerdraw.halfbyteid = 0;
flickerdraw.clock = 1;
flickerdraw.challenge = pChallenge;
g_signal_connect (GTK_WINDOW (flickergui->dialog), "destroy",
G_CALLBACK (on_dialog_destroy), NULL);
g_signal_connect (GTK_WIDGET (flickergui->flicker_challenge), "map",
G_CALLBACK (on_flicker_challenge_map), NULL);
g_signal_connect (GTK_WIDGET (flickergui->flicker_challenge), "draw",
G_CALLBACK (on_flicker_challenge_draw), NULL);
g_signal_connect (GTK_WIDGET (flickergui->flicker_challenge), "destroy",
G_CALLBACK (on_flicker_challenge_destroy), NULL);
g_signal_connect (GTK_WIDGET (flickergui->flicker_marker), "map",
G_CALLBACK (on_flicker_marker_map), NULL);
g_signal_connect (GTK_WIDGET (flickergui->flicker_marker), "draw",
G_CALLBACK (on_flicker_marker_draw), NULL);
flickergui->adj_barwidth = gtk_adjustment_new (0.0, 10.0, 80.0, 1.0, 10.0, 0.0);
gtk_spin_button_set_adjustment (flickergui->spin_barwidth, flickergui->adj_barwidth);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (flickergui->spin_barwidth),
flickerdraw.barwidth);
g_signal_connect (GTK_WIDGET (flickergui->spin_barwidth), "value-changed",
G_CALLBACK (on_spin_barwidth_value_changed),
flickergui->flicker_marker);
gtk_widget_set_focus_on_click (GTK_WIDGET (flickergui->spin_barwidth), FALSE);
flickergui->adj_delay = gtk_adjustment_new (0.0, 10.0, 100.0, 10.0, 10.0, 0.0);
gtk_spin_button_set_adjustment (flickergui->spin_delay, flickergui->adj_delay);
gtk_spin_button_set_value (GTK_SPIN_BUTTON (flickergui->spin_delay),
flickerdraw.delay);
g_signal_connect (GTK_WIDGET (flickergui->spin_delay), "value-changed",
G_CALLBACK (on_spin_delay_value_changed),
flickergui->flicker_challenge);
gtk_widget_set_focus_on_click (GTK_WIDGET (flickergui->spin_delay), FALSE);
gtk_widget_grab_focus (GTK_WIDGET (flickergui->input_entry));
}

View File

@ -0,0 +1,63 @@
/*
* gnc-flicker-gui.h
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, contact:
*
* Free Software Foundation Voice: +1-617-542-5942
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652
* Boston, MA 02110-1301, USA gnu@gnu.org
*/
/**
* @addtogroup Import_Export
* @{
* @addtogroup AqBanking
* @{
* @file gnc-flicker-gui.h
* @brief GUI callbacks for Flicker and ChipTAN(optisch)
* @author Copyright (C) 2020 Christian Wehling <christian.wehling@web.de>
*/
#ifndef GNC_FLICKER_GUI_H
#define GNC_FLICKER_GUI_H
#include <gtk/gtk.h>
G_BEGIN_DECLS
// structured data for the GUI
typedef struct
{
GtkWidget *dialog;
GtkWidget *input_entry;
GtkWidget *flicker_challenge;
GtkWidget *flicker_marker;
GtkWidget *flicker_hbox;
GtkAdjustment *adj_barwidth;
GtkAdjustment *adj_delay;
GtkSpinButton *spin_barwidth;
GtkSpinButton *spin_delay;
} GncFlickerGui;
/**
* Initialize the dialog and drawing area
*
* @param pChallenge: The answer from the bank which is shown as a flickering picture
* @param gui: The structure of the Dialog-Widgets
*/
void ini_flicker_gui (const char *pChallenge, GncFlickerGui *gui);
G_END_DECLS
#endif /* GNC_FLICKER_GUI_H */

View File

@ -46,6 +46,8 @@
#include "gnc-plugin-aqbanking.h"
#include "qof.h"
#include "gnc-flicker-gui.h"
# define GNC_GWENHYWFAR_CB GWENHYWFAR_CB
#define GWEN_GUI_CM_CLASS "dialog-hbcilog"
@ -928,6 +930,9 @@ get_input(GncGWENGui *gui, guint32 flags, const gchar *title,
GtkWidget *confirm_label;
GtkWidget *remember_pin_checkbutton;
GtkImage *optical_challenge;
static GncFlickerGui *flickergui = NULL;
const gchar *internal_input, *internal_confirmed;
gboolean confirm = (flags & GWEN_GUI_INPUT_FLAGS_CONFIRM) != 0;
gboolean is_tan = (flags & GWEN_GUI_INPUT_FLAGS_TAN) != 0;
@ -949,9 +954,33 @@ get_input(GncGWENGui *gui, guint32 flags, const gchar *title,
remember_pin_checkbutton = GTK_WIDGET(gtk_builder_get_object (builder, "remember_pin"));
optical_challenge = GTK_IMAGE(gtk_builder_get_object (builder, "optical_challenge"));
gtk_widget_set_visible(GTK_WIDGET(optical_challenge), FALSE);
flickergui = g_slice_new(GncFlickerGui);
flickergui->flicker_challenge = GTK_WIDGET(gtk_builder_get_object(builder, "flicker_challenge"));
flickergui->flicker_marker = GTK_WIDGET(gtk_builder_get_object(builder, "flicker_marker"));
flickergui->flicker_hbox = GTK_WIDGET(gtk_builder_get_object(builder, "flicker_hbox"));
flickergui->spin_barwidth = GTK_SPIN_BUTTON(gtk_builder_get_object(builder, "spin_barwidth"));
flickergui->spin_delay = GTK_SPIN_BUTTON(gtk_builder_get_object(builder, "spin_delay"));
gtk_widget_set_visible(GTK_WIDGET(flickergui->flicker_challenge), FALSE);
gtk_widget_set_visible(GTK_WIDGET(flickergui->flicker_marker), FALSE);
gtk_widget_set_visible(GTK_WIDGET(flickergui->flicker_hbox), FALSE);
gtk_widget_set_visible(GTK_WIDGET(flickergui->spin_barwidth), FALSE);
gtk_widget_set_visible(GTK_WIDGET(flickergui->spin_delay), FALSE);
#ifdef AQBANKING6
if(mimeType != NULL && pChallenge != NULL && lChallenge > 0)
if (g_strcmp0(mimeType,"text/x-flickercode") == 0 && pChallenge != NULL)
{
/* Chiptan Optic (aka Flicker) */
gtk_widget_set_visible(GTK_WIDGET(flickergui->flicker_challenge), TRUE);
gtk_widget_set_visible(GTK_WIDGET(flickergui->flicker_marker), TRUE);
gtk_widget_set_visible(GTK_WIDGET(flickergui->flicker_hbox), TRUE);
gtk_widget_set_visible(GTK_WIDGET(flickergui->spin_barwidth), TRUE);
gtk_widget_set_visible(GTK_WIDGET(flickergui->spin_delay), TRUE);
}
else if(mimeType != NULL && pChallenge != NULL && lChallenge > 0)
{
/* Phototan or Chiptan QR */
gtk_widget_set_visible(GTK_WIDGET(optical_challenge), TRUE);
}
#endif
@ -969,6 +998,7 @@ get_input(GncGWENGui *gui, guint32 flags, const gchar *title,
if ((flags & (GWEN_GUI_INPUT_FLAGS_TAN | GWEN_GUI_INPUT_FLAGS_SHOW)) != 0)
{
gtk_widget_set_visible(input_entry, TRUE);
gtk_entry_set_visibility(GTK_ENTRY(input_entry), TRUE);
}
if (gui->dialog)
@ -996,6 +1026,7 @@ get_input(GncGWENGui *gui, guint32 flags, const gchar *title,
//if (optical_challenge)
if(mimeType != NULL && pChallenge != NULL && lChallenge > 0)
{
/* Phototan or Chiptan QR */
// convert PNG and load into widget
// TBD: check mimeType?
guchar *gudata = (guchar*)pChallenge;
@ -1019,6 +1050,15 @@ get_input(GncGWENGui *gui, guint32 flags, const gchar *title,
gtk_image_set_from_pixbuf(optical_challenge, pixbuf);
}
else if (g_strcmp0(mimeType,"text/x-flickercode") == 0 && pChallenge != NULL)
{
/* Chiptan Optic (aka Flicker) */
flickergui->dialog = dialog;
flickergui->input_entry = input_entry;
ini_flicker_gui(pChallenge, flickergui);
g_slice_free(GncFlickerGui, flickergui);
}
#endif
if (*input)
@ -1425,28 +1465,43 @@ getpassword_cb(GWEN_GUI *gwen_gui, guint32 flags, const gchar *token,
if(is_tan && methodId == GWEN_Gui_PasswordMethod_OpticalHHD)
{
/**
* TODO: How to handle Flicker code (use WebView and JS???)
*
* use GWEN_Gui_PasswordMethod_Mask to get the basic method id
* cf. gui/gui.h of gwenhywfar
*/
opticalMethodId=GWEN_DB_GetIntValue(methodParams, "tanMethodId", 0, AB_BANKING_TANMETHOD_TEXT);
switch(opticalMethodId)
{
case AB_BANKING_TANMETHOD_CHIPTAN:
break;
case AB_BANKING_TANMETHOD_CHIPTAN_OPTIC:
mimeType = "text/x-flickercode";
pChallenge = GWEN_DB_GetCharValue(methodParams, "challenge", 0, NULL);
if ((pChallenge == NULL) || (pChallenge[0] == '\0'))
{
/* empty flicker-data */
return GWEN_ERROR_NO_DATA;
}
break;
case AB_BANKING_TANMETHOD_CHIPTAN_USB:
/**
* ToDo: is this the same as CHIPTAN_OPTIC ?
*/
break;
case AB_BANKING_TANMETHOD_PHOTOTAN:
case AB_BANKING_TANMETHOD_CHIPTAN_QR:
/**
* image data is in methodParams
*/
mimeType=GWEN_DB_GetCharValue(methodParams, "mimeType", 0, NULL);
pChallenge=(const char*) GWEN_DB_GetBinValue(methodParams, "imageData", 0, NULL, 0, &lChallenge);
if (!(pChallenge && lChallenge)) {
/* empty optical data */
return GWEN_ERROR_NO_DATA;
}
break;
default:
break;
/**
* image data is in methodParams
*/
mimeType=GWEN_DB_GetCharValue(methodParams, "mimeType", 0, NULL);
pChallenge=(const char*) GWEN_DB_GetBinValue(methodParams, "imageData", 0, NULL, 0, &lChallenge);
if (!(pChallenge && lChallenge))
{
/* empty optical data */
return GWEN_ERROR_NO_DATA;
}
break;
default:
break;
}
}
#endif

View File

@ -1,8 +1,8 @@
if (WITH_AQBANKING)
set(aqb_GSCHEMA org.gnucash.dialogs.import.hbci.gschema.xml)
set(aqb_GSCHEMA org.gnucash.dialogs.import.hbci.gschema.xml org.gnucash.dialogs.flicker.gschema.xml)
add_gschema_targets("${aqb_GSCHEMA}")
endif()
set_dist_list(aqbanking_gschema_DIST CMakeLists.txt org.gnucash.dialogs.import.hbci.gschema.xml.in)
set_dist_list(aqbanking_gschema_DIST CMakeLists.txt org.gnucash.dialogs.import.hbci.gschema.xml.in org.gnucash.dialogs.flicker.gschema.xml.in)

View File

@ -0,0 +1,13 @@
<schemalist gettext-domain="@PROJECT_NAME@">
<schema id="org.gnucash.dialogs.flicker" path="/org/gnucash/dialogs/flicker/">
<key name="last-geometry" type="(iiii)">
<default>(-1,-1,-1,-1)</default>
<summary>Last window position and size</summary>
<description>This setting describes the size and position of the window when it was last closed.
The numbers are the X and Y coordinates of the top left corner of the window
followed by the width and height of the window.</description>
</key>
</schema>
</schemalist>