diff --git a/configure.in b/configure.in index 5d19aa16ed..cd1037aa72 100644 --- a/configure.in +++ b/configure.in @@ -831,38 +831,46 @@ AC_SUBST(OFX_DIR) ### -------------------------------------------------------------------------- ### MT940 AC_ARG_ENABLE( mt940, - [ --enable-mt940 Obsolete, included in --enable-hbci], + [ --enable-mt940 obsolete, included in --enable-aqbanking], if test "x$enableval" != "xno" ; then - AC_MSG_ERROR([--enable-mt940 is obsolete -- all functionality is already included in --enable-hbci]) + AC_MSG_ERROR([--enable-mt940 is obsolete -- all functionality is already included in --enable-aqbanking]) fi) ### -------------------------------------------------------------------------- -### HBCI -AC_ARG_ENABLE( hbci, - [ --enable-hbci compile with HBCI support (needs AqBanking)], +### AqBanking + +AC_ARG_ENABLE( aqbanking, + [ --enable-aqbanking compile with AqBanking support], if test "x$enableval" != "xno" ; then - HBCI_DIR=hbci + want_aqbanking=yes fi) -if test x${HBCI_DIR} = xhbci ; +AC_ARG_ENABLE( hbci, + [ --enable-hbci an alias for --enable-aqbanking], + if test "x$enableval" != "xno" ; then + want_aqbanking=yes + fi) +if test x${want_aqbanking} = xyes ; then - # Check for Aqbanking library - # aqbanking-1.6.1 was released on 2005-11-04; aqbanking ships with - # a pkg-config file since 1.6.1. - PKG_CHECK_MODULES(HBCI, aqbanking >= 1.6.1 aqbanking < 2.9.0 gwenhywfar, [], [ - AC_MSG_ERROR([Could not find aqbanking > 1.6.0 and < 2.9.0. If you use --enable-hbci, you *have* to have aqbanking installed. Note that gnucash requires aqbanking2 and not (yet) aqbanking3!]) + # Check for Aqbanking library + # aqbanking-1.6.1 was released on 2005-11-04; aqbanking ships with + # a pkg-config file since 1.6.1. + PKG_CHECK_MODULES(AQBANKING, aqbanking >= 3.0.0 gwenhywfar, [AQBANKING_DIR=aqbanking], [ + PKG_CHECK_MODULES(AQBANKING, aqbanking >= 1.6.1 aqbanking < 2.9.0 gwenhywfar, [AQBANKING_DIR=hbci], [ + AC_MSG_ERROR([Could not find aqbanking > 1.6.0. If you use --enable-aqbanking or --enable-hbci, you *have* to have aqbanking installed!]) ]) + ]) - # also check for ktoblzcheck - AC_CHECK_HEADERS(ktoblzcheck.h) - if test "x$ac_cv_header_ktoblzcheck_h" != xno; then - HBCI_LIBS="${HBCI_LIBS} -lktoblzcheck" - fi + # also check for ktoblzcheck + AC_CHECK_HEADERS(ktoblzcheck.h) + if test "x$ac_cv_header_ktoblzcheck_h" != xno; then + AQBANKING_LIBS="${AQBANKING_LIBS} -lktoblzcheck" + fi - AS_SCRUB_INCLUDE(HBCI_CFLAGS) - AC_SUBST(HBCI_LIBS) - AC_SUBST(HBCI_CFLAGS) + AS_SCRUB_INCLUDE(AQBANKING_CFLAGS) + AC_SUBST(AQBANKING_LIBS) + AC_SUBST(AQBANKING_CFLAGS) fi -AC_SUBST(HBCI_DIR) +AC_SUBST(AQBANKING_DIR) ### -------------------------------------------------------------------------- ### i18n @@ -1537,6 +1545,8 @@ AC_CONFIG_FILES(po/Makefile.in src/import-export/ofx/test/Makefile src/import-export/csv/Makefile src/import-export/log-replay/Makefile + src/import-export/aqbanking/Makefile + src/import-export/aqbanking/schemas/Makefile src/import-export/hbci/Makefile src/import-export/hbci/glade/Makefile src/import-export/hbci/schemas/Makefile @@ -1606,8 +1616,8 @@ fi if test x${OFX_DIR} != x; then components="$components ofx" fi -if test x${HBCI_DIR} != x; then -components="$components hbci" +if test x${AQBANKING_DIR} != x; then +components="$components $AQBANKING_DIR" fi if test x${PYTHON_DIR} != x; then components="$components python-bindings" diff --git a/doc/examples/downloaded.mt940 b/doc/examples/downloaded.mt940 index 8699b2f84d..3ddb2e181d 100644 --- a/doc/examples/downloaded.mt940 +++ b/doc/examples/downloaded.mt940 @@ -1,4 +1,3 @@ - :20:STARTUMS :25:80007777/2602272001 :28C:0 diff --git a/macros/svn2cl.xsl b/macros/svn2cl.xsl index 7515da1845..76045f31d9 100644 --- a/macros/svn2cl.xsl +++ b/macros/svn2cl.xsl @@ -101,6 +101,9 @@ + + gnucash/branches/aqbanking3 + gnucash/branches/csv-import diff --git a/src/bin/gnucash-bin.c b/src/bin/gnucash-bin.c index c76df39682..0a9b6a94e8 100644 --- a/src/bin/gnucash-bin.c +++ b/src/bin/gnucash-bin.c @@ -340,6 +340,7 @@ load_gnucash_modules() { "gnucash/import-export/ofx", 0, TRUE }, { "gnucash/import-export/csv", 0, TRUE }, { "gnucash/import-export/log-replay", 0, TRUE }, + { "gnucash/import-export/aqbanking", 0, TRUE }, { "gnucash/import-export/hbci", 0, TRUE }, { "gnucash/report/report-system", 0, FALSE }, { "gnucash/report/stylesheets", 0, FALSE }, diff --git a/src/import-export/Makefile.am b/src/import-export/Makefile.am index 75516a6711..db11d52f1e 100644 --- a/src/import-export/Makefile.am +++ b/src/import-export/Makefile.am @@ -1,7 +1,7 @@ SUBDIRS = . schemas qif qif-import \ - ${OFX_DIR} ${HBCI_DIR} log-replay test csv + ${OFX_DIR} ${AQBANKING_DIR} log-replay test csv DIST_SUBDIRS = schemas qif qif-import qif-io-core \ - ofx hbci log-replay test csv + ofx aqbanking hbci log-replay test csv pkglib_LTLIBRARIES=libgncmod-generic-import.la diff --git a/src/import-export/aqbanking/Makefile.am b/src/import-export/aqbanking/Makefile.am new file mode 100644 index 0000000000..f743229874 --- /dev/null +++ b/src/import-export/aqbanking/Makefile.am @@ -0,0 +1,78 @@ +SUBDIRS = . schemas + +pkglib_LTLIBRARIES = libgncmod-aqbanking.la + +libgncmod_aqbanking_la_SOURCES = \ + dialog-ab-trans.c \ + dialog-daterange.c \ + druid-ab-initial.c \ + gnc-ab-getbalance.c \ + gnc-ab-gettrans.c \ + gnc-ab-kvp.c \ + gnc-ab-trans-templ.c \ + gnc-ab-transfer.c \ + gnc-ab-utils.c \ + gnc-file-aqb-import.c \ + gnc-gwen-gui.c \ + gnc-plugin-aqbanking.c \ + gncmod-aqbanking.c + +noinst_HEADERS = \ + dialog-ab-trans.h \ + dialog-daterange.h \ + druid-ab-initial.h \ + gnc-ab-getbalance.h \ + gnc-ab-gettrans.h \ + gnc-ab-kvp.h \ + gnc-ab-trans-templ.h \ + gnc-ab-transfer.h \ + gnc-ab-utils.h \ + gnc-file-aqb-import.h \ + gnc-gwen-gui.h \ + gnc-plugin-aqbanking.h + +libgncmod_aqbanking_la_LDFLAGS = -avoid-version + +libgncmod_aqbanking_la_LIBADD = \ + ${top_builddir}/src/import-export/libgncmod-generic-import.la \ + ${top_builddir}/src/gnome/libgnc-gnome.la \ + ${top_builddir}/src/gnome-utils/libgncmod-gnome-utils.la \ + ${top_builddir}/src/app-utils/libgncmod-app-utils.la \ + ${top_builddir}/src/engine/libgncmod-engine.la \ + ${top_builddir}/src/core-utils/libgnc-core-utils.la \ + ${top_builddir}/src/gnc-module/libgnc-module.la \ + ${GNOME_LIBS} \ + ${GLADE_LIBS} \ + ${QOF_LIBS} \ + ${GLIB_LIBS} \ + ${AQBANKING_LIBS} + +AM_CFLAGS = \ + -I${top_srcdir}/src \ + -I${top_srcdir}/src/import-export \ + -I${top_srcdir}/src/gnome \ + -I${top_srcdir}/src/register/ledger-core \ + -I${top_srcdir}/src/register/register-gnome \ + -I${top_srcdir}/src/register/register-core \ + -I${top_srcdir}/src/gnome-utils \ + -I${top_srcdir}/src/app-utils \ + -I${top_srcdir}/src/engine \ + -I${top_srcdir}/src/core-utils \ + -I${top_srcdir}/src/gnc-module \ + ${GNOME_CFLAGS} \ + ${GLADE_CFLAGS} \ + ${QOF_CFLAGS} \ + ${GLIB_CFLAGS} \ + ${AQBANKING_CFLAGS} + +uidir = $(GNC_UI_DIR) +ui_DATA = \ + gnc-plugin-aqbanking-ui.xml + +gladedir = $(GNC_GLADE_DIR) +glade_DATA = \ + aqbanking.glade + +EXTRA_DIST = ${ui_DATA} ${glade_DATA} + +INCLUDES = -DG_LOG_DOMAIN=\"gnc.import.aqbanking\" diff --git a/src/import-export/aqbanking/aqbanking.glade b/src/import-export/aqbanking/aqbanking.glade new file mode 100644 index 0000000000..7fadce2701 --- /dev/null +++ b/src/import-export/aqbanking/aqbanking.glade @@ -0,0 +1,2655 @@ + + + + + + + + Initial Online Banking Setup + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 650 + 580 + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + + + + + + 4 + True + False + + + + + True + GNOME_EDGE_START + Initial Online Banking Setup + This druid helps you setting up your Online Banking connection with your bank. + +You first need to apply for Online Banking access at your bank. If your bank decides to grant you electronic access, they will send you a letter containing + +* The bank code of your bank +* The user ID that identifies you to your bank +* The Internet address of your bank's Online Banking server +* For HBCI Online Banking, information about the cryptographic public key of your bank ("Ini-Letter"). + +This information will be needed in the following. Press "Forward" now. + +NOTE: NO WARRANTIES FOR ANYTHING. Some banks run a poorly implemented Online Banking server. You should not rely on time-critical transfers through Online Banking, because sometimes the bank does not give you correct feedback when a transfer is rejected. + +Press "Cancel" if you do not wish to setup any Online Banking connection now. + #ffffffffffff + #000000000000 + #9999bfbf9999 + #ffffffffffff + #ffffffffffff + + + + + + True + Start Online Banking Wizard + #ffffffffffff + #9999bfbf9999 + #ffffffffffff + + + + + 12 + True + False + 12 + + + + True + The Setup of your Online Banking connection is handled by the external program "AqBanking Setup Wizard". Please press the button below to start this program. + False + False + GTK_JUSTIFY_LEFT + True + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + 0 + 0.5 + 0 + 1 + 0 + 0 + 0 + 0 + + + + True + True + _Start AqBanking Wizard + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + False + False + + + + + + + + + + True + Match Online Banking accounts with GnuCash accounts + #ffffffffffff + #9999bfbf9999 + #ffffffffffff + + + + + 12 + True + False + 0 + + + + True + False + 12 + + + + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + True + True + False + True + False + False + False + + + + + 0 + True + True + + + + + + True + Click on the line of an Online Banking account name if you want to match it to a GnuCash account. Click "Forward" when all desired accounts are matching. + False + False + GTK_JUSTIFY_LEFT + True + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + 0 + True + True + + + + + + + + + + True + GNOME_EDGE_FINISH + Online Banking Setup Finished + The setup for matching Online Banking accounts to GnuCash accounts is now finished. You can now invoke Online Banking actions on those accounts. + +If you want to add another bank, user, or account, you can start this druid again anytime. + +Press "Apply" now. + #ffffffffffff + #000000000000 + #9999bfbf9999 + #ffffffffffff + #ffffffffffff + + + + + + + + + 5 + Online Transaction + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + True + + + + True + False + 2 + + + + True + GTK_BUTTONBOX_END + + + + True + True + Execute later (unimpl.) + True + GTK_RELIEF_NORMAL + True + -9 + + + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + -6 + + + + + + True + Execute this online transaction now + True + True + True + GTK_RELIEF_NORMAL + True + -8 + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-execute + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Execute Now + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + + + 0 + False + True + GTK_PACK_END + + + + + + 5 + True + False + 0 + + + + True + Enter an Online Transaction + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + + + 0 + False + False + + + + + + True + 21 + 3 + False + 0 + 0 + + + + True + True + True + True + 12 + + True + * + False + + + 0 + 1 + 3 + 4 + + + + + + + True + Recipient Account Number + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 2 + 3 + fill + + + + + + + True + True + True + True + 8 + + True + * + False + + + + 2 + 3 + 3 + 4 + + + + + + + True + Recipient Bank Code + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 2 + 3 + 2 + 3 + fill + + + + + + + True + True + True + True + 27 + + True + * + False + + + 0 + 3 + 1 + 2 + + + + + + + True + Recipient Name + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 3 + 0 + 1 + fill + + + + + + + True + at Bank + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 3 + 4 + 5 + fill + + + + + + + True + (filled in automatically) + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 3 + 5 + 6 + fill + + + + + + + True + Amount + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 7 + 8 + fill + + + + + + + True + Payment Purpose (only for recipient) + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 3 + 10 + 11 + fill + + + + + + + True + Payment Purpose continued + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 3 + 12 + 13 + fill + + + + + + + True + Originator Name + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 15 + 16 + fill + + + + + + + True + something + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 16 + 17 + fill + + + + + + + True + at Bank + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 17 + 18 + fill + + + + + + + True + something + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 18 + 19 + fill + + + + + + + True + Originator Account Number + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 2 + 3 + 15 + 16 + fill + + + + + + + True + something + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 2 + 3 + 16 + 17 + fill + + + + + + + True + Bank Code + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 2 + 3 + 17 + 18 + fill + + + + + + + True + something + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 2 + 3 + 18 + 19 + fill + + + + + + + True + False + 4 + + + + True + GTK_BUTTONBOX_DEFAULT_STYLE + 0 + + + + True + Add the current online transaction as a new transaction template + True + GTK_RELIEF_NORMAL + True + + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-add + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Add current + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + + + + True + Move the selected transaction template one row up + True + gtk-go-up + True + GTK_RELIEF_NORMAL + True + + + + + + + True + Move the selected transaction template one row down + True + gtk-go-down + True + GTK_RELIEF_NORMAL + True + + + + + + + True + Sort the list of transaction templates alphabetically + True + GTK_RELIEF_NORMAL + True + + + + + True + 0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + + + + True + False + 2 + + + + True + gtk-sort-ascending + 4 + 0.5 + 0.5 + 0 + 0 + + + 0 + False + False + + + + + + True + Sort + True + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + + + + + + + True + Delete the currently selected transaction template + True + gtk-delete + True + GTK_RELIEF_NORMAL + True + + + + + + 0 + False + False + GTK_PACK_END + + + + + + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + False + True + False + True + False + False + False + + + + + + 0 + True + True + GTK_PACK_END + + + + + + True + Use Transaction Template + False + False + GTK_JUSTIFY_CENTER + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + 0 + 3 + 20 + 21 + fill + + + + + + True + True + True + True + 27 + + True + * + False + + + 0 + 1 + 11 + 12 + + + + + + + True + True + True + True + 27 + + True + * + False + + + 0 + 1 + 13 + 14 + + + + + + + True + True + True + True + 27 + + True + * + False + + + 2 + 3 + 11 + 12 + + + + + + + True + True + True + True + 27 + + True + * + False + + + 2 + 3 + 13 + 14 + + + + + + + True + False + 0 + + + + + + + 0 + 1 + 8 + 9 + + + + + + + True + + + 0 + 3 + 19 + 20 + 1 + fill + + + + + + + True + + + 0 + 3 + 14 + 15 + fill + + + + + + + True + + + 0 + 3 + 6 + 7 + 1 + fill + + + + + + + True + + + 0 + 3 + 9 + 10 + fill + + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + + + 5 + Online Banking Connection Window + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + 350 + 420 + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + True + + + + + True + False + 2 + + + + True + GTK_BUTTONBOX_END + + + + True + False + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + 0 + + + + + + + True + True + True + gtk-close + True + GTK_RELIEF_NORMAL + True + 0 + + + + + + 0 + False + True + GTK_PACK_END + + + + + + 5 + True + False + 18 + + + + True + False + 6 + + + + True + <b>Progress</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 12 + 0 + + + + True + 3 + 2 + False + 6 + 12 + + + + True + Current Job + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + True + True + True + 0 + + True + * + False + + + 1 + 2 + 0 + 1 + + + + + + + True + False + GTK_PROGRESS_LEFT_TO_RIGHT + 0 + 0.10000000149 + PANGO_ELLIPSIZE_NONE + + + 1 + 2 + 1 + 2 + fill + + + + + + + True + Progress + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 1 + 2 + fill + + + + + + + True + Current Action + False + False + GTK_JUSTIFY_CENTER + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 2 + 3 + fill + + + + + + + True + True + True + True + 0 + + True + * + False + + + 1 + 2 + 2 + 3 + + + + + + + + 0 + True + True + + + + + 0 + False + False + + + + + + True + False + 6 + + + + True + <b>Log Messages</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 12 + 0 + + + + True + GTK_POLICY_AUTOMATIC + GTK_POLICY_AUTOMATIC + GTK_SHADOW_IN + GTK_CORNER_TOP_LEFT + + + + True + True + False + False + True + GTK_JUSTIFY_LEFT + GTK_WRAP_WORD + True + 0 + 0 + 0 + 0 + 0 + 0 + + + + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + True + True + Close when finished + True + GTK_RELIEF_NORMAL + True + True + False + True + + + 0 + False + False + + + + + 0 + True + True + + + + + + + + 5 + Get Transactions Online + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + True + + + + True + False + 2 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + -6 + + + + + + True + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + True + -5 + + + + + 0 + False + True + GTK_PACK_END + + + + + + 5 + True + False + 18 + + + + True + Date range of transactions to retrieve: + False + False + GTK_JUSTIFY_CENTER + True + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + False + 6 + + + + True + <b>From</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 12 + 0 + + + + True + False + 6 + + + + True + True + _Earliest possible date + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + False + False + + + + + + True + True + _Last retrieval date + True + GTK_RELIEF_NORMAL + True + True + False + True + first_button + + + 0 + False + False + + + + + + True + False + 12 + + + + True + True + E_nter date: + True + GTK_RELIEF_NORMAL + True + False + False + True + first_button + + + + 0 + False + False + + + + + + True + False + 0 + + + + + + + 0 + True + True + + + + + 0 + False + False + + + + + + + 0 + True + True + + + + + 0 + False + False + + + + + + True + False + 6 + + + + True + <b>To</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + 0.5 + 0.5 + 1 + 1 + 0 + 0 + 12 + 0 + + + + True + False + 6 + + + + True + True + _Now + True + GTK_RELIEF_NORMAL + True + True + False + True + + + 0 + False + False + + + + + + True + False + 12 + + + + True + True + Ente_r date: + True + GTK_RELIEF_NORMAL + True + False + False + True + now_button + + + + 0 + False + False + + + + + + True + False + 0 + + + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + + 0 + True + True + + + + + 0 + False + False + + + + + 0 + True + True + + + + + + + + 5 + Name for new template + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + True + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + -6 + + + + + + True + True + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + True + -5 + + + + + 0 + False + True + GTK_PACK_END + + + + + + 5 + True + False + 12 + + + + True + Enter name for new template: + False + False + GTK_JUSTIFY_LEFT + False + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + True + True + True + 250 + + True + * + True + + + 0 + False + False + + + + + 0 + True + True + + + + + + + + 5 + Enter Password + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_DIALOG + GDK_GRAVITY_NORTH_WEST + True + True + + + + True + False + 0 + + + + True + GTK_BUTTONBOX_END + + + + True + True + True + gtk-cancel + True + GTK_RELIEF_NORMAL + True + -6 + + + + + + True + True + True + gtk-ok + True + GTK_RELIEF_NORMAL + True + -5 + + + + + 0 + False + True + GTK_PACK_END + + + + + + 5 + True + False + 18 + + + + True + Enter your password + False + False + GTK_JUSTIFY_LEFT + True + False + 0.5 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + False + False + + + + + + True + 3 + 2 + False + 6 + 12 + + + + True + Password: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 0 + 1 + fill + + + + + + + True + Confirm Password: + False + False + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 1 + 1 + 2 + fill + + + + + + + True + True + True + False + 0 + + True + + False + + + 1 + 2 + 0 + 1 + + + + + + + True + True + True + False + 0 + + True + + False + + + 1 + 2 + 1 + 2 + + + + + + + True + True + Remember _PIN + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + 2 + 2 + 3 + fill + + + + + + 0 + True + True + + + + + 0 + True + True + + + + + + + + True + window1 + GTK_WINDOW_TOPLEVEL + GTK_WIN_POS_NONE + False + True + False + True + False + False + GDK_WINDOW_TYPE_HINT_NORMAL + GDK_GRAVITY_NORTH_WEST + True + + + + True + 3 + 4 + False + 0 + 0 + + + + True + <b>Online Banking</b> + False + True + GTK_JUSTIFY_LEFT + False + False + 0 + 0.5 + 0 + 0 + PANGO_ELLIPSIZE_NONE + -1 + False + 0 + + + 0 + 4 + 0 + 1 + fill + + + + + + + True + True + Remember _PIN + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + 4 + 1 + 2 + 12 + fill + + + + + + + True + True + _Verbose debug messages + True + GTK_RELIEF_NORMAL + True + False + False + True + + + 0 + 4 + 2 + 3 + 12 + fill + + + + + + + + diff --git a/src/import-export/aqbanking/dialog-ab-trans.c b/src/import-export/aqbanking/dialog-ab-trans.c new file mode 100644 index 0000000000..d224d06c48 --- /dev/null +++ b/src/import-export/aqbanking/dialog-ab-trans.c @@ -0,0 +1,1000 @@ +/* + * dialog-ab-trans.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 dialog-ab-trans.c + * @brief Templates for AqBanking transactions + * @author Copyright (C) 2002 Christian Stimming + * @author Copyright (C) 2004 Bernd Wagner + * @author Copyright (C) 2006 David Hampton + * @author Copyright (C) 2008 Andreas Koehler + */ + +#include "config.h" + +#include +#if HAVE_KTOBLZCHECK_H +# include +#endif +#include +#include +#include + +#include "dialog-ab-trans.h" +#include "dialog-transfer.h" +#include "dialog-utils.h" +#include "gnc-ab-trans-templ.h" +#include "gnc-ab-utils.h" +#include "gnc-amount-edit.h" +#include "gnc-ui.h" + +/* This static indicates the debugging module that this .o belongs to. */ +static QofLogModule log_module = G_LOG_DOMAIN; + +static void fill_templ_helper(gpointer data, gpointer user_data); +static AB_TRANSACTION *ab_trans_fill_values(GncABTransDialog *td); +static gboolean check_ktoblzcheck(GtkWidget *parent, const GncABTransDialog *td, + const AB_TRANSACTION *trans); +static gboolean clear_templ_helper(GtkTreeModel *model, GtkTreePath *path, + GtkTreeIter *iter, gpointer user_data); +static gboolean get_templ_helper(GtkTreeModel *model, GtkTreePath *path, + GtkTreeIter *iter, gpointer data); +static AB_JOB *get_available_empty_job(AB_ACCOUNT *ab_acc, + GncABTransType trans_type); + +void dat_bankcode_changed_cb(GtkEditable *editable, gpointer user_data); +void templ_list_row_activated_cb(GtkTreeView *view, GtkTreePath *path, + GtkTreeViewColumn *column, gpointer user_data); +static gboolean find_templ_helper(GtkTreeModel *model, GtkTreePath *path, + GtkTreeIter *iter, gpointer user_data); +void dat_add_templ_cb(GtkButton *button, gpointer user_data); +void dat_moveup_templ_cb(GtkButton *button, gpointer user_data); +void dat_movedown_templ_cb(GtkButton *button, gpointer user_data); +void dat_sort_templ_cb(GtkButton *button, gpointer user_data); +void dat_del_templ_cb(GtkButton *button, gpointer user_data); + +enum { + TEMPLATE_NAME, + TEMPLATE_POINTER, + TEMPLATE_NUM_COLUMNS +}; + +struct _GncABTransDialog { + /* The dialog itself */ + GtkWidget *dialog; + GtkWidget *parent; + AB_ACCOUNT *ab_acc; + + /* Whether this is a transfer or a direct debit */ + GncABTransType trans_type; + + /* Recipient */ + GtkWidget *recp_name_entry; + GtkWidget *recp_account_entry; + GtkWidget *recp_bankcode_entry; + + /* Amount */ + GtkWidget *amount_edit; + + /* Purpose, description */ + GtkWidget *purpose_entry; + GtkWidget *purpose_cont_entry; + GtkWidget *purpose_cont2_entry; + GtkWidget *purpose_cont3_entry; + + /* Recipient's bank name (may be filled in automatically sometime later) */ + GtkWidget *recp_bankname_label; + + /* The template choosing GtkTreeView/GtkListStore */ + GtkTreeView *template_gtktreeview; + GtkListStore *template_list_store; + + /* Flag, if template list has been changed */ + gboolean templ_changed; + + /* The aqbanking transaction that got created here */ + AB_TRANSACTION *ab_trans; + + /* The gnucash transaction that got created here */ + Transaction *gnc_trans; + +#if HAVE_KTOBLZCHECK_H + /* object for Account number checking */ + AccountNumberCheck *blzcheck; +#endif +}; + +static void +fill_templ_helper(gpointer data, gpointer user_data) +{ + GncABTransTempl *templ = data; + GtkListStore *store = user_data; + GtkTreeIter iter; + + g_return_if_fail(templ && store); + gtk_list_store_append(store, &iter); + gtk_list_store_set(store, &iter, + TEMPLATE_NAME, gnc_ab_trans_templ_get_name(templ), + TEMPLATE_POINTER, templ, + -1); +} + +/** + * Create a new AB_TRANSACTION, fill the values from the entry fields into it + * and return it. The caller must AB_TRANSACTION_free() it when finished. + */ +static AB_TRANSACTION * +ab_trans_fill_values(GncABTransDialog *td) +{ + /* Fill in the user-entered values */ + AB_TRANSACTION *trans = AB_Transaction_new(); + AB_VALUE *value; + + AB_Transaction_SetLocalBankCode(trans, AB_Account_GetBankCode(td->ab_acc)); + AB_Transaction_SetLocalAccountNumber( + trans, AB_Account_GetAccountNumber(td->ab_acc)); + AB_Transaction_SetLocalCountry(trans, "DE"); + + AB_Transaction_SetRemoteBankCode( + trans, gtk_entry_get_text(GTK_ENTRY(td->recp_bankcode_entry))); + AB_Transaction_SetRemoteAccountNumber( + trans, gtk_entry_get_text(GTK_ENTRY(td->recp_account_entry))); + AB_Transaction_SetRemoteCountry(trans, "DE"); + AB_Transaction_AddRemoteName( + trans, gtk_entry_get_text(GTK_ENTRY(td->recp_name_entry)), FALSE); + + AB_Transaction_AddPurpose( + trans, gtk_entry_get_text(GTK_ENTRY(td->purpose_entry)), FALSE); + AB_Transaction_AddPurpose( + trans, gtk_entry_get_text(GTK_ENTRY(td->purpose_cont_entry)), FALSE); + AB_Transaction_AddPurpose( + trans, gtk_entry_get_text(GTK_ENTRY(td->purpose_cont2_entry)), FALSE); + AB_Transaction_AddPurpose( + trans, gtk_entry_get_text(GTK_ENTRY(td->purpose_cont3_entry)), FALSE); + + value = AB_Value_fromDouble(gnc_amount_edit_get_damount( + GNC_AMOUNT_EDIT(td->amount_edit))); + /* FIXME: Replace "EUR" by account-dependent string here. */ + AB_Value_SetCurrency(value, "EUR"); + AB_Transaction_SetValue(trans, value); + AB_Value_free(value); + + /* If this is a direct debit, a textkey/ "Textschluessel"/transactionCode + * different from the default has to be set. */ + switch (td->trans_type) { + case SINGLE_DEBITNOTE: + /* AB_Transaction_SetTransactionCode (trans, 05); */ + AB_Transaction_SetTextKey(trans, 05); + break; + default: + /* AB_Transaction_SetTransactionCode (trans, 51); */ + AB_Transaction_SetTextKey (trans, 51); + } + + return trans; +} + +GncABTransDialog * +gnc_ab_trans_dialog_new(GtkWidget *parent, AB_ACCOUNT *ab_acc, + gint commodity_scu, GncABTransType trans_type, + GList *templates) +{ + GncABTransDialog *td; + GladeXML *xml; + const gchar *ab_ownername; + const gchar *ab_accountnumber; + const gchar *ab_bankname; + const gchar *ab_bankcode; + GtkWidget *heading_label; + GtkWidget *recp_name_heading; + GtkWidget *recp_account_heading; + GtkWidget *recp_bankcode_heading; + GtkWidget *amount_hbox; + GtkWidget *orig_name_heading; + GtkWidget *orig_name_label; + GtkWidget *orig_account_heading; + GtkWidget *orig_account_label; + GtkWidget *orig_bankname_heading; + GtkWidget *orig_bankname_label; + GtkWidget *orig_bankcode_heading; + GtkWidget *orig_bankcode_label; + GtkCellRenderer *renderer; + GtkTreeViewColumn *column; + + g_return_val_if_fail(ab_acc, NULL); + + ab_ownername = AB_Account_GetOwnerName(ab_acc); + if (!ab_ownername) + ab_ownername = ""; + ab_accountnumber = AB_Account_GetAccountNumber(ab_acc); + ab_bankcode = AB_Account_GetBankCode(ab_acc); + ab_bankname = AB_Account_GetBankName(ab_acc); + if (!ab_bankname || !*ab_bankname) + ab_bankname = _("(unknown)"); + + td = g_new0(GncABTransDialog, 1); + td->parent = parent; + td->ab_acc = ab_acc; + td->trans_type = trans_type; + +#if HAVE_KTOBLZCHECK_H + td->blzcheck = AccountNumberCheck_new(); +#endif + + xml = gnc_glade_xml_new("aqbanking.glade", "Transaction Dialog"); + td->dialog = glade_xml_get_widget(xml, "Transaction Dialog"); + g_object_set_data_full(G_OBJECT(td->dialog), "xml", xml, g_object_unref); + glade_xml_signal_autoconnect_full(xml, gnc_glade_autoconnect_full_func, td); + + if (parent) + gtk_window_set_transient_for(GTK_WINDOW(td->dialog), GTK_WINDOW(parent)); + + /* Extract widgets */ + heading_label = glade_xml_get_widget(xml, "heading_label"); + recp_name_heading = glade_xml_get_widget(xml, "recp_name_heading"); + td->recp_name_entry = glade_xml_get_widget(xml, "recp_name_entry"); + recp_account_heading = glade_xml_get_widget(xml, "recp_account_heading"); + td->recp_account_entry = glade_xml_get_widget(xml, "recp_account_entry"); + recp_bankcode_heading = glade_xml_get_widget(xml, "recp_bankcode_heading"); + td->recp_bankcode_entry = glade_xml_get_widget(xml, "recp_bankcode_entry"); + td->recp_bankname_label = glade_xml_get_widget(xml, "recp_bankname_label"); + amount_hbox = glade_xml_get_widget(xml, "amount_hbox"); + td->purpose_entry = glade_xml_get_widget(xml, "purpose_entry"); + td->purpose_cont_entry = glade_xml_get_widget(xml, "purpose_cont_entry"); + td->purpose_cont2_entry = glade_xml_get_widget(xml, "purpose_cont2_entry"); + td->purpose_cont3_entry = glade_xml_get_widget(xml, "purpose_cont3_entry"); + orig_name_heading = glade_xml_get_widget(xml, "orig_name_heading"); + orig_name_label = glade_xml_get_widget(xml, "orig_name_label"); + orig_account_heading = glade_xml_get_widget(xml, "orig_account_heading"); + orig_account_label = glade_xml_get_widget(xml, "orig_account_label"); + orig_bankname_heading = glade_xml_get_widget(xml, "orig_bankname_heading"); + orig_bankname_label = glade_xml_get_widget(xml, "orig_bankname_label"); + orig_bankcode_heading = glade_xml_get_widget(xml, "orig_bankcode_heading"); + orig_bankcode_label = glade_xml_get_widget(xml, "orig_bankcode_label"); + td->template_gtktreeview = + GTK_TREE_VIEW(glade_xml_get_widget(xml, "template_list")); + + /* Amount edit */ + td->amount_edit = gnc_amount_edit_new(); + gtk_box_pack_start_defaults(GTK_BOX(amount_hbox), td->amount_edit); + gnc_amount_edit_set_evaluate_on_enter(GNC_AMOUNT_EDIT(td->amount_edit), + TRUE); + gnc_amount_edit_set_fraction(GNC_AMOUNT_EDIT(td->amount_edit), + commodity_scu); + + /* Check for what kind of transaction this should be, and change the + * labels accordingly */ + switch (trans_type) { + case SINGLE_TRANSFER: + case SINGLE_INTERNAL_TRANSFER: + /* all labels are already set */ + break; + case SINGLE_DEBITNOTE: + gtk_label_set_text(GTK_LABEL (heading_label), + /* Translators: Strings from this file are + * needed only in countries that have one of + * aqbanking's Online Banking techniques + * available. This is 'OFX DirectConnect' + * (U.S. and others), 'HBCI' (in Germany), + * or 'YellowNet' (Switzerland). If none of + * these techniques are available in your + * country, you may safely ignore strings + * from the import-export/hbci + * subdirectory. */ + _("Enter an Online Direct Debit Note")); + + gtk_label_set_text(GTK_LABEL(recp_name_heading), + _("Debited Account Owner")); + gtk_label_set_text(GTK_LABEL(recp_account_heading), + _("Debited Account Number")); + gtk_label_set_text(GTK_LABEL(recp_bankcode_heading), + _("Debited Account Bank Code")); + + gtk_label_set_text(GTK_LABEL(orig_name_heading), + _("Credited Account Owner")); + gtk_label_set_text(GTK_LABEL(orig_account_heading), + _("Credited Account Number")); + gtk_label_set_text(GTK_LABEL(orig_bankcode_heading), + _("Credited Account Bank Code")); + break; + + default: + g_critical("gnc_ab_trans_dialog_new: Oops, unknown GncABTransType %d", + trans_type); + } + + gtk_label_set_text(GTK_LABEL(orig_name_label), ab_ownername); + gtk_label_set_text(GTK_LABEL(orig_account_label), ab_accountnumber); + gtk_label_set_text(GTK_LABEL(orig_bankname_label), ab_bankname); + gtk_label_set_text (GTK_LABEL (orig_bankcode_label), ab_bankcode); + + /* Fill list for choosing a transaction template */ + td->template_list_store = gtk_list_store_new(TEMPLATE_NUM_COLUMNS, + G_TYPE_STRING, G_TYPE_POINTER); + g_list_foreach(templates, fill_templ_helper, td->template_list_store); + gtk_tree_view_set_model(td->template_gtktreeview, + GTK_TREE_MODEL(td->template_list_store)); + td->templ_changed = FALSE; + /* Keep a reference to the store */ + + /* Show this list */ + renderer = gtk_cell_renderer_text_new(); + column = gtk_tree_view_column_new_with_attributes( + "Template Name", renderer, "text", TEMPLATE_NAME, NULL); + gtk_tree_view_append_column(td->template_gtktreeview, column); + + return td; +} + +static gboolean +check_ktoblzcheck(GtkWidget *parent, const GncABTransDialog *td, + const AB_TRANSACTION *trans) +{ +#ifndef HAVE_KTOBLZCHECK_H + return TRUE; +#else + gint blzresult; + const char *blztext; + gboolean values_ok = TRUE; + + ENTER(" "); + + blzresult = AccountNumberCheck_check( + td->blzcheck, + AB_Transaction_GetRemoteBankCode(trans), + AB_Transaction_GetRemoteAccountNumber(trans)); + switch (blzresult) { + case 2: + gtk_widget_show(parent); + values_ok = gnc_verify_dialog( + parent, TRUE, + _("The internal check of the destination account number '%s' " + "at the specified bank with bank code '%s' failed. This means " + "the account number might contain an error. Should the online " + "transfer job be sent with this account number anyway?"), + AB_Transaction_GetRemoteAccountNumber(trans), + AB_Transaction_GetRemoteBankCode(trans)); + blztext = "Kontonummer wahrscheinlich falsch"; + break; + case 0: + blztext = "Kontonummer ok"; + break; + case 3: + blztext = "bank unbekannt"; + break; + case 1: + default: + blztext = "unbekannt aus unbekanntem grund"; + break; + } + + LEAVE("KtoBlzCheck said check is %d = %s", + blzresult, blztext ? blztext : "(none)"); + + return values_ok; +#endif +} + +gint +gnc_ab_trans_dialog_run_until_ok(GncABTransDialog *td) +{ + gint result; + AB_JOB *job; + const AB_TRANSACTION_LIMITS *joblimits; + guint8 max_purpose_lines; + gboolean values_ok; + gchar *purpose; + gchar *othername; + + /* Check whether the account supports this job */ + job = get_available_empty_job(td->ab_acc, td->trans_type); + if (!job) { + g_warning("gnc_ab_trans_dialog_run_until_ok: Oops, job not available"); + return GTK_RESPONSE_CANCEL; + } + + /* Activate as many purpose entries as available for the job */ + joblimits = AB_JobSingleTransfer_GetFieldLimits(job); + max_purpose_lines = joblimits ? + AB_TransactionLimits_GetMaxLinesPurpose(joblimits) : 2; + gtk_widget_set_sensitive(td->purpose_cont_entry, max_purpose_lines > 1); + gtk_widget_set_sensitive(td->purpose_cont2_entry, max_purpose_lines > 2); + gtk_widget_set_sensitive(td->purpose_cont3_entry, max_purpose_lines > 3); + + /* Show the dialog */ + gtk_widget_show(td->dialog); + + /* Repeat until entered values make sense */ + do { + /* Now run the dialog until it gets closed by a button press */ + result = gtk_dialog_run (GTK_DIALOG (td->dialog)); + + /* Was cancel pressed or dialog closed? + * GNC_RESPONSE_NOW == execute now + * GNC_RESPONSE_LATER == scheduled for later execution (unimplemented) + * GTK_RESPONSE_CANCEL == cancel + * GTK_RESPONSE_DELETE_EVENT == window destroyed */ + if (result != GNC_RESPONSE_NOW && result != GNC_RESPONSE_LATER) { + gtk_widget_destroy(td->dialog); + td->dialog = NULL; + break; + } + + /* Now fill in the values from the entry fields into a new + * AB_TRANSACTION */ + td->ab_trans = ab_trans_fill_values(td); + values_ok = TRUE; + + /* Check transaction value */ + values_ok = + AB_Value_GetValueAsDouble(AB_Transaction_GetValue(td->ab_trans)) + != 0.0; + if (!values_ok) { + gtk_widget_show(td->dialog); + if (gnc_verify_dialog( + td->dialog, TRUE, "%s", + _("The amount is zero or the amount field could not be " + "interpreted correctly. You might have mixed up decimal " + "point and comma, compared to your locale settings. " + "This does not result in a valid online transfer job. \n" + "\n" + "Do you want to enter the job again?"))) { + continue; + } else { + AB_Transaction_free(td->ab_trans); + td->ab_trans = NULL; + result = GTK_RESPONSE_CANCEL; + break; + } + } + + /* Check transaction purpose */ + purpose = gnc_ab_get_purpose(td->ab_trans); + values_ok = *purpose; + g_free(purpose); + if (!values_ok) { + gtk_widget_show(td->dialog); + if (gnc_verify_dialog( + td->dialog, TRUE, "%s", + _("You did not enter any transaction purpose. A purpose is " + "required for an online transfer.\n" + "\n" + "Do you want to enter the job again?"))) { + continue; + } else { + AB_Transaction_free(td->ab_trans); + td->ab_trans = NULL; + result = GTK_RESPONSE_CANCEL; + break; + } + } + + /* Check recipient / remote name */ + othername = gnc_ab_get_remote_name(td->ab_trans); + values_ok = othername && *othername; + g_free(othername); + if (!values_ok) { + gtk_widget_show(td->dialog); + if (gnc_verify_dialog( + td->dialog, TRUE, "%s", + _("You did not enter a recipient name. A recipient name is " + "required for an online transfer.\n" + "\n" + "Do you want to enter the job again?"))) { + continue; + } else { + AB_Transaction_free(td->ab_trans); + td->ab_trans = NULL; + result = GTK_RESPONSE_CANCEL; + break; + } + } + + /* FIXME: If this is a direct debit, set the textkey/ "Textschluessel"/ + * transactionCode according to some GUI selection here!! */ + /*if (td->trans_type == SINGLE_DEBITNOTE) + AB_TRANSACTION_setTextKey (td->hbci_trans, 05); */ + + /* And finally check the account code, if ktoblzcheck is available */ + values_ok = check_ktoblzcheck(td->dialog, td, td->ab_trans); + + } while (!values_ok); + + /* Hide the dialog */ + if (td->dialog) + gtk_widget_hide(td->dialog); + + return result; +} + +static gboolean +clear_templ_helper(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, + gpointer user_data) { + GncABTransTempl *templ; + + g_return_val_if_fail(model && iter, TRUE); + + gtk_tree_model_get(model, iter, TEMPLATE_POINTER, &templ, -1); + gnc_ab_trans_templ_free(templ); + return FALSE; +} + +void +gnc_ab_trans_dialog_free(GncABTransDialog *td) +{ + if (!td) return; + if (td->ab_trans) + AB_Transaction_free(td->ab_trans); + if (td->dialog) + gtk_widget_destroy(td->dialog); + if (td->template_list_store) { + gtk_tree_model_foreach(GTK_TREE_MODEL(td->template_list_store), + clear_templ_helper, NULL); + g_object_unref(td->template_list_store); + } +#if HAVE_KTOBLZCHECK_H + AccountNumberCheck_delete(td->blzcheck); +#endif + g_free(td); +} + +static gboolean +get_templ_helper(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, + gpointer data) +{ + GList **list = data; + GncABTransTempl *templ; + + g_return_val_if_fail(model && iter, TRUE); + + gtk_tree_model_get(model, iter, TEMPLATE_POINTER, &templ, -1); + *list = g_list_prepend(*list, templ); + return FALSE; +} + +GList * +gnc_ab_trans_dialog_get_templ(const GncABTransDialog *td, gboolean *changed) +{ + GList *list = NULL; + + g_return_val_if_fail(td, NULL); + + if (changed) { + *changed = td->templ_changed; + if (!*changed) + return NULL; + } + + gtk_tree_model_foreach(GTK_TREE_MODEL(td->template_list_store), + get_templ_helper, &list); + list = g_list_reverse(list); + return list; +} + +GtkWidget * +gnc_ab_trans_dialog_get_parent(const GncABTransDialog *td) +{ + g_return_val_if_fail(td, NULL); + return td->parent; +} + +const AB_TRANSACTION * +gnc_ab_trans_dialog_get_ab_trans(const GncABTransDialog *td) +{ + g_return_val_if_fail(td, NULL); + return td->ab_trans; +} + +static AB_JOB * +get_available_empty_job(AB_ACCOUNT *ab_acc, GncABTransType trans_type) +{ + AB_JOB *job; + + switch (trans_type) { + case SINGLE_DEBITNOTE: + job = AB_JobSingleDebitNote_new(ab_acc); + break; + case SINGLE_INTERNAL_TRANSFER: + job = AB_JobInternalTransfer_new(ab_acc); + break; + case SINGLE_TRANSFER: + default: + job = AB_JobSingleTransfer_new(ab_acc); + }; + + if (!job || AB_Job_CheckAvailability(job, 0)) { + if (job) AB_Job_free(job); + return NULL; + } + return job; +} + +AB_JOB * +gnc_ab_trans_dialog_get_job(const GncABTransDialog *td) +{ + g_return_val_if_fail(td, NULL); + return gnc_ab_get_trans_job(td->ab_acc, td->ab_trans, td->trans_type); +} + +AB_JOB * +gnc_ab_get_trans_job(AB_ACCOUNT *ab_acc, const AB_TRANSACTION *ab_trans, + GncABTransType trans_type) +{ + AB_JOB *job; + + g_return_val_if_fail(ab_acc && ab_trans, NULL); + + job = get_available_empty_job(ab_acc, trans_type); + if (job) { + switch (trans_type) { + case SINGLE_DEBITNOTE: + AB_JobSingleDebitNote_SetTransaction(job, ab_trans); + break; + case SINGLE_INTERNAL_TRANSFER: + AB_JobInternalTransfer_SetTransaction(job, ab_trans); + break; + case SINGLE_TRANSFER: + default: + AB_JobSingleTransfer_SetTransaction(job, ab_trans); + }; + } + return job; +} + +void +templ_list_row_activated_cb(GtkTreeView *view, GtkTreePath *path, + GtkTreeViewColumn *column, gpointer user_data) +{ + GncABTransDialog *td = user_data; + GtkTreeModel *model; + GtkTreeIter iter; + GncABTransTempl *templ; + const gchar *old_name, *new_name; + const gchar *old_account, *new_account; + const gchar *old_bankcode, *new_bankcode; + const gchar *old_purpose, *new_purpose; + const gchar *old_purpose_cont, *new_purpose_cont; + GtkWidget *amount_widget; + const gchar *old_amount_text; + gnc_numeric old_amount, new_amount; + + g_return_if_fail(td); + + ENTER("td=%p", td); + if (!gtk_tree_model_get_iter(GTK_TREE_MODEL(td->template_list_store), &iter, + path)) { + LEAVE("Could not get iter"); + return; + } + gtk_tree_model_get(GTK_TREE_MODEL(td->template_list_store), &iter, + TEMPLATE_POINTER, &templ, -1); + + /* Get old values */ + old_name = gtk_entry_get_text(GTK_ENTRY(td->recp_name_entry)); + old_account = gtk_entry_get_text(GTK_ENTRY(td->recp_account_entry)); + old_bankcode = gtk_entry_get_text(GTK_ENTRY(td->recp_bankcode_entry)); + old_purpose = gtk_entry_get_text(GTK_ENTRY(td->purpose_entry)); + old_purpose_cont = gtk_entry_get_text(GTK_ENTRY(td->purpose_cont_entry)); + amount_widget = gnc_amount_edit_gtk_entry(GNC_AMOUNT_EDIT(td->amount_edit)); + old_amount_text = gtk_entry_get_text(GTK_ENTRY(amount_widget)); + old_amount = gnc_amount_edit_get_amount(GNC_AMOUNT_EDIT(td->amount_edit)); + + /* Get new values */ + new_name = gnc_ab_trans_templ_get_recp_name(templ); + new_account = gnc_ab_trans_templ_get_recp_account(templ); + new_bankcode = gnc_ab_trans_templ_get_recp_bankcode(templ); + new_purpose = gnc_ab_trans_templ_get_purpose(templ); + new_purpose_cont = gnc_ab_trans_templ_get_purpose_cont(templ); + new_amount = gnc_ab_trans_templ_get_amount(templ); + if (!new_name) new_name = ""; + if (!new_account) new_account = ""; + if (!new_bankcode) new_bankcode = ""; + if (!new_purpose) new_purpose = ""; + if (!new_purpose_cont) new_purpose_cont = ""; + + /* Check for differences to avoid overwriting entered text */ + if ((*old_name && strcmp(old_name, new_name)) + || (*old_account && strcmp(old_account, new_account)) + || (*old_bankcode && strcmp(old_bankcode, new_bankcode)) + || (*old_purpose && strcmp(old_purpose, new_purpose)) + || (*old_purpose_cont && strcmp(old_purpose_cont, new_purpose_cont)) + || (*old_amount_text && !gnc_numeric_equal(old_amount, new_amount))) { + if (!gnc_verify_dialog( + td->parent, FALSE, + _("Do you really want to overwrite your changes with the " + "contents of the template \"%s\"?"), + gnc_ab_trans_templ_get_name(templ))) { + + LEAVE("aborted"); + return; + } + } + + /* Fill in */ + gtk_entry_set_text(GTK_ENTRY(td->recp_name_entry), new_name); + gtk_entry_set_text(GTK_ENTRY(td->recp_account_entry), new_account); + gtk_entry_set_text(GTK_ENTRY(td->recp_bankcode_entry), new_bankcode); + gtk_entry_set_text(GTK_ENTRY(td->purpose_entry), new_purpose); + gtk_entry_set_text(GTK_ENTRY(td->purpose_cont_entry), new_purpose_cont); + gnc_amount_edit_set_amount(GNC_AMOUNT_EDIT(td->amount_edit), new_amount); + LEAVE(" "); +} + +void +dat_bankcode_changed_cb(GtkEditable *editable, gpointer user_data) +{ +#if HAVE_KTOBLZCHECK_H + GncABTransDialog *td = user_data; + const AccountNumberCheck_Record *record; + const gchar *input = gtk_entry_get_text(GTK_ENTRY(td->recp_bankcode_entry)); + + g_return_if_fail(td); + + ENTER("td=%p, input=%s", td, input); + record = AccountNumberCheck_findBank(td->blzcheck, input); + + if (record) { + const char *bankname = AccountNumberCheck_Record_bankName(record); + GError *error = NULL; + const char *ktoblzcheck_encoding = +#ifdef KTOBLZCHECK_VERSION_MAJOR + /* This version number macro has been added in ktoblzcheck-1.10, but + * this function exists already since ktoblzcheck-1.7, so we're on + * the safe side. */ + AccountNumberCheck_stringEncoding() +#else + /* Every ktoblzcheck release before 1.10 is guaranteed to return + * strings only in ISO-8859-15. */ + "ISO-8859-15" +#endif + ; + gchar *utf8_bankname = g_convert(bankname, strlen(bankname), "UTF-8", + ktoblzcheck_encoding, NULL, NULL, + &error); + + if (error) { + g_critical("Error converting bankname \"%s\" to UTF-8", bankname); + g_error_free (error); + /* Conversion was erroneous, so don't use the string */ + utf8_bankname = g_strdup(_("(unknown)")); + } + gtk_label_set_text(GTK_LABEL(td->recp_bankname_label), + *utf8_bankname ? utf8_bankname : _("(unknown)")); + DEBUG("Found: %s", utf8_bankname); + g_free(utf8_bankname); + } else { + gtk_label_set_text(GTK_LABEL(td->recp_bankname_label), _("(unknown)")); + } + LEAVE(" "); +#endif +} + +struct _FindTemplData { + const gchar *name; + const GncABTransTempl *pointer; +}; + +static gboolean +find_templ_helper(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, + gpointer user_data) +{ + struct _FindTemplData *data = user_data; + gchar *name; + GncABTransTempl *templ; + gboolean match; + + g_return_val_if_fail(model && data, TRUE); + gtk_tree_model_get(model, iter, + TEMPLATE_NAME, &name, + TEMPLATE_POINTER, &templ, + -1); + if (data->name) { + /* Search for the template by name */ + g_return_val_if_fail(!data->pointer, TRUE); + match = strcmp(name, data->name) == 0; + if (match) data->pointer = templ; + } else { + /* Search for the template by template pointer */ + g_return_val_if_fail(!data->name, TRUE); + match = templ == data->pointer; + if (match) data->name = g_strdup(name); + } + g_free(name); + return match; +} + +void +dat_add_templ_cb(GtkButton *button, gpointer user_data) +{ + GncABTransDialog *td = user_data; + GladeXML *xml; + GtkWidget *dialog; + GtkWidget *entry; + gint retval; + const gchar *name; + GncABTransTempl *templ; + struct _FindTemplData data; + GtkTreeSelection *selection; + GtkTreeIter cur_iter; + GtkTreeIter new_iter; + + g_return_if_fail(td); + + ENTER("td=%p", td); + xml = gnc_glade_xml_new ("aqbanking.glade", "Template Name Dialog"); + dialog = glade_xml_get_widget(xml, "Template Name Dialog"); + g_object_set_data_full(G_OBJECT(dialog), "xml", xml, g_object_unref); + entry = glade_xml_get_widget(xml, "template_name"); + + /* Suggest recipient name as name of the template */ + gtk_entry_set_text(GTK_ENTRY(entry), + gtk_entry_get_text(GTK_ENTRY(td->recp_name_entry))); + + do { + retval = gtk_dialog_run(GTK_DIALOG(dialog)); + if (retval != GTK_RESPONSE_OK) + break; + + name = gtk_entry_get_text(GTK_ENTRY(entry)); + if (!*name) + break; + + data.name = name; + data.pointer = NULL; + gtk_tree_model_foreach(GTK_TREE_MODEL(td->template_list_store), + find_templ_helper, &data); + if (data.pointer) { + gnc_error_dialog(dialog, + _("A template with the given name already exists. " + "Please enter another name.")); + continue; + } + + /* Create a new template */ + templ = gnc_ab_trans_templ_new_full( + name, + gtk_entry_get_text(GTK_ENTRY(td->recp_name_entry)), + gtk_entry_get_text(GTK_ENTRY(td->recp_account_entry)), + gtk_entry_get_text(GTK_ENTRY(td->recp_bankcode_entry)), + gnc_amount_edit_get_amount(GNC_AMOUNT_EDIT(td->amount_edit)), + gtk_entry_get_text(GTK_ENTRY(td->purpose_entry)), + gtk_entry_get_text (GTK_ENTRY(td->purpose_cont_entry))); + + /* Insert it, either after the selected one or at the end */ + selection = gtk_tree_view_get_selection(td->template_gtktreeview); + if (gtk_tree_selection_get_selected(selection, NULL, &cur_iter)) { + gtk_list_store_insert_after(td->template_list_store, + &new_iter, &cur_iter); + } else { + gtk_list_store_append(td->template_list_store, &new_iter); + } + gtk_list_store_set(td->template_list_store, &new_iter, + TEMPLATE_NAME, name, + TEMPLATE_POINTER, templ, + -1); + td->templ_changed = TRUE; + DEBUG("Added template with name %s", name); + break; + } while (TRUE); + + gtk_widget_destroy(dialog); + + LEAVE(" "); +} + +void +dat_moveup_templ_cb(GtkButton *button, gpointer user_data) +{ + GncABTransDialog *td = user_data; + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + GtkTreePath *prev_path; + GtkTreeIter prev_iter; + + g_return_if_fail(td); + + selection = gtk_tree_view_get_selection(td->template_gtktreeview); + if (!gtk_tree_selection_get_selected(selection, &model, &iter)) + return; + + prev_path = gtk_tree_model_get_path(model, &iter); + if (gtk_tree_path_prev(prev_path)) { + if (gtk_tree_model_get_iter(model, &prev_iter, prev_path)) { + gtk_list_store_move_before(GTK_LIST_STORE(model), &iter, &prev_iter); + td->templ_changed = TRUE; + } + } + gtk_tree_path_free(prev_path); +} + +void +dat_movedown_templ_cb(GtkButton *button, gpointer user_data) +{ + GncABTransDialog *td = user_data; + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + GtkTreeIter next_iter; + + g_return_if_fail(td); + + selection = gtk_tree_view_get_selection(td->template_gtktreeview); + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) + return; + + next_iter = iter; + if (gtk_tree_model_iter_next(model, &next_iter)) { + gtk_list_store_move_after(GTK_LIST_STORE(model), &iter, &next_iter); + td->templ_changed = TRUE; + } +} + +void +dat_sort_templ_cb(GtkButton *button, gpointer user_data) +{ + GncABTransDialog *td = user_data; + + g_return_if_fail(td); + + ENTER("td=%p", td); + gtk_tree_sortable_set_sort_column_id( + GTK_TREE_SORTABLE(td->template_list_store), + TEMPLATE_NAME, GTK_SORT_ASCENDING); + gtk_tree_sortable_set_sort_column_id( + GTK_TREE_SORTABLE(td->template_list_store), + GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID, + GTK_SORT_ASCENDING); + td->templ_changed = TRUE; + LEAVE(" "); +} + +void +dat_del_templ_cb(GtkButton *button, gpointer user_data) +{ + GncABTransDialog *td = user_data; + GtkTreeSelection *selection; + GtkTreeModel *model; + GtkTreeIter iter; + gchar *name; + + g_return_if_fail(td); + + ENTER("td=%p", td); + selection = gtk_tree_view_get_selection(td->template_gtktreeview); + if (!gtk_tree_selection_get_selected (selection, &model, &iter)) { + LEAVE("None selected"); + return; + } + + gtk_tree_model_get(model, &iter, TEMPLATE_NAME, &name, -1); + if (gnc_verify_dialog( + td->parent, FALSE, + _("Do you really want to delete the template with the name \"%s\"?"), + name)) { + gtk_list_store_remove(GTK_LIST_STORE(model), &iter); + td->templ_changed = TRUE; + DEBUG("Deleted template with name %s", name); + } + g_free(name); + LEAVE(" "); +} diff --git a/src/import-export/aqbanking/dialog-ab-trans.h b/src/import-export/aqbanking/dialog-ab-trans.h new file mode 100644 index 0000000000..4b0c867ec2 --- /dev/null +++ b/src/import-export/aqbanking/dialog-ab-trans.h @@ -0,0 +1,143 @@ +/* + * dialog-ab-trans.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 dialog-ab-trans.h + * @brief Dialog for AqBanking transaction data + * @author Copyright (C) 2002 Christian Stimming + * @author Copyright (C) 2004 Bernd Wagner + * @author Copyright (C) 2006 David Hampton + * @author Copyright (C) 2008 Andreas Koehler + */ + +#ifndef DIALOG_AB_TRANS_H +#define DIALOG_AB_TRANS_H + +#include +#include + +#include "Account.h" + +G_BEGIN_DECLS + +#define GNC_RESPONSE_NOW GTK_RESPONSE_YES +#define GNC_RESPONSE_LATER GTK_RESPONSE_NO + +typedef struct _GncABTransDialog GncABTransDialog; + +typedef enum _GncABTransType GncABTransType; +enum _GncABTransType { + SINGLE_TRANSFER = 0, + SINGLE_DEBITNOTE, + SINGLE_INTERNAL_TRANSFER +}; + +/** + * FIXME + * + * @param parent Widget to use as parent, may be NULL + * @param ab_acc FIXME + * @param commodity_scu FIXME + * @param trans_type Type of transaction + * @param templates A GList of template transactions which will become fully + * managed by the dialog, so do not free it and retrieve snapshots via + * gnc_ab_trans_dialog_get_templ() + * @return FIXME + */ +GncABTransDialog *gnc_ab_trans_dialog_new(GtkWidget *parent, AB_ACCOUNT *ab_acc, + gint commodity_scu, + GncABTransType trans_type, + GList *templates); + +/** + * FIXME + * + * @param td Transaction dialog + * @param ab_acc AqBanking account + * @return FIXME + */ +gint gnc_ab_trans_dialog_run_until_ok(GncABTransDialog *td); + +/** + * FIXME + * + * @param td Transaction dialog + */ +void gnc_ab_trans_dialog_free(GncABTransDialog *td); + +/** + * Retrieve the current list of transaction templates from the dialog @a + * td, unless @a changed is a specified location and the templates have + * not been touched by the user. + * + * @param td Transaction dialog + * @param changed Location to store whether the templates have been + * changed, may be NULL + * @return The a newly allocated list of the internal transaction + * templates. Free this one via g_list_free(). + */ +GList *gnc_ab_trans_dialog_get_templ(const GncABTransDialog *td, + gboolean *changed); + +/** + * Retrieve the widget used as parent. + * + * @param td Transaction dialog + * @return The parent + */ +GtkWidget *gnc_ab_trans_dialog_get_parent(const GncABTransDialog *td); + +/** + * FIXME + * + * @param td Transaction dialog + * @return FIXME + */ +const AB_TRANSACTION *gnc_ab_trans_dialog_get_ab_trans( + const GncABTransDialog *td); + +/** + * FIXME + * + * @param td Transaction dialog + * @return FIXME + */ +AB_JOB *gnc_ab_trans_dialog_get_job(const GncABTransDialog *td); + +/** + * FIXME + * + * @param td Transaction dialog + * @return FIXME + */ +AB_JOB *gnc_ab_get_trans_job(AB_ACCOUNT *ab_acc, const AB_TRANSACTION *ab_trans, + GncABTransType trans_type); + +G_END_DECLS + +/** @} */ +/** @} */ + +#endif /* DIALOG_AB_TRANS_H */ diff --git a/src/import-export/aqbanking/dialog-daterange.c b/src/import-export/aqbanking/dialog-daterange.c new file mode 100644 index 0000000000..1689c29017 --- /dev/null +++ b/src/import-export/aqbanking/dialog-daterange.c @@ -0,0 +1,148 @@ +/* + * dialog-daterange.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 dialog-daterange.c + * @brief Dialog for date range entry + * @author Copyright (C) 2002 Christian Stimming + * @author Copyright (C) 2008 Andreas Koehler + */ + +#include "config.h" + +#include "dialog-daterange.h" +#include "dialog-utils.h" +#include "gnc-date-edit.h" + +/* This static indicates the debugging module that this .o belongs to. */ +static QofLogModule log_module = G_LOG_DOMAIN; + +typedef struct _DaterangeInfo DaterangeInfo; + +void ddr_toggled_cb(GtkToggleButton *button, gpointer user_data); + +struct _DaterangeInfo +{ + GtkWidget *enter_from_button; + GtkWidget *enter_to_button; + GtkWidget *from_dateedit; + GtkWidget *to_dateedit; +}; + +gboolean +gnc_ab_enter_daterange(GtkWidget *parent, + const char *heading, + Timespec *from_date, + gboolean *last_retv_date, + gboolean *first_possible_date, + Timespec *to_date, + gboolean *to_now) +{ + GladeXML *xml; + GtkWidget *dialog; + GtkWidget *heading_label; + GtkWidget *first_button; + GtkWidget *last_retrieval_button; + GtkWidget *now_button; + DaterangeInfo info; + gint result; + + xml = gnc_glade_xml_new("aqbanking.glade", "Date Range Dialog"); + + dialog = glade_xml_get_widget(xml, "Date Range Dialog"); + g_object_set_data_full(G_OBJECT(dialog), "xml", xml, g_object_unref); + glade_xml_signal_autoconnect_full(xml, gnc_glade_autoconnect_full_func, + &info); + + if (parent) + gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(parent)); + + heading_label = glade_xml_get_widget(xml, "heading_label"); + first_button = glade_xml_get_widget(xml, "first_button"); + last_retrieval_button = glade_xml_get_widget(xml, "last_retrieval_button"); + info.enter_from_button = glade_xml_get_widget(xml, "enter_from_button"); + now_button = glade_xml_get_widget(xml, "now_button"); + info.enter_to_button = glade_xml_get_widget(xml, "enter_to_button"); + + info.from_dateedit = gnc_date_edit_new_ts(*from_date, FALSE, FALSE); + gtk_container_add(GTK_CONTAINER(glade_xml_get_widget(xml, "enter_from_box")), + info.from_dateedit); + gtk_widget_show(info.from_dateedit); + + info.to_dateedit = gnc_date_edit_new_ts(*to_date, FALSE, FALSE); + gtk_container_add(GTK_CONTAINER(glade_xml_get_widget(xml, "enter_to_box")), + info.to_dateedit); + gtk_widget_show(info.to_dateedit); + + if (*last_retv_date) { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(last_retrieval_button), + TRUE); + } else { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(first_button), TRUE); + gtk_widget_set_sensitive(last_retrieval_button, FALSE); + } + + gtk_widget_set_sensitive(info.from_dateedit, FALSE); + gtk_widget_set_sensitive(info.to_dateedit, FALSE); + + gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK); + + if (heading) + gtk_label_set_text(GTK_LABEL(heading_label), heading); + + gtk_widget_show(dialog); + + result = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_hide(dialog); + + if (result == GTK_RESPONSE_OK) { + *from_date = gnc_date_edit_get_date_ts( + GNC_DATE_EDIT(info.from_dateedit)); + *last_retv_date = gtk_toggle_button_get_active( + GTK_TOGGLE_BUTTON(last_retrieval_button)); + *first_possible_date = gtk_toggle_button_get_active( + GTK_TOGGLE_BUTTON(first_button)); + *to_date = gnc_date_edit_get_date_ts( + GNC_DATE_EDIT(info.to_dateedit)); + *to_now = gtk_toggle_button_get_active( + GTK_TOGGLE_BUTTON(now_button)); + } + + gtk_widget_destroy(dialog); + + return result == GTK_RESPONSE_OK; +} + +void +ddr_toggled_cb(GtkToggleButton *button, gpointer user_data) +{ + DaterangeInfo *info = user_data; + + g_return_if_fail(info); + + gtk_widget_set_sensitive(info->from_dateedit, + gtk_toggle_button_get_active( + GTK_TOGGLE_BUTTON(info->enter_from_button))); + gtk_widget_set_sensitive(info->to_dateedit, + gtk_toggle_button_get_active( + GTK_TOGGLE_BUTTON(info->enter_to_button))); +} diff --git a/src/import-export/aqbanking/dialog-daterange.h b/src/import-export/aqbanking/dialog-daterange.h new file mode 100644 index 0000000000..f37f32d523 --- /dev/null +++ b/src/import-export/aqbanking/dialog-daterange.h @@ -0,0 +1,67 @@ +/* + * dialog-daterange.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 dialog-daterange.h + * @brief Dialog for date range entry + * @author Copyright (C) 2002 Christian Stimming + * @author Copyright (C) 2008 Andreas Koehler + */ + +#ifndef DIALOG_DATERANGE_H +#define DIALOG_DATERANGE_H + +#include + +#include "qof.h" + +G_BEGIN_DECLS + +/** + * Show a dialog to pick a time frame using a sensible set of default options. + * + * @param parent Widget to use as parent, may be NULL + * @param heading Descriptive text showed at the top, may be NULL + * @param from_date Location to read from the initial and write to the final + * value of the from date entry + * @param last_retv_date Location to read from whether the caller knows the last + * retrieval date and write to whether the corresponding button has been chosen + * @param first_possible_date Location to write to whether the earliest possible + * date button has been chosen + * @param to_date Location to read from the initial and write to the final value + * of the to date entry + * @param to_now Location to write to whether the to now button has been chosen + */ +gboolean gnc_ab_enter_daterange(GtkWidget *parent, + const char *heading, + Timespec *from_date, + gboolean *last_retv_date, + gboolean *first_possible_date, + Timespec *to_date, + gboolean *to_now); + +G_END_DECLS + +#endif /* DIALOG_DATERANGE_H */ diff --git a/src/import-export/aqbanking/druid-ab-initial.c b/src/import-export/aqbanking/druid-ab-initial.c new file mode 100644 index 0000000000..3ccd1b8a46 --- /dev/null +++ b/src/import-export/aqbanking/druid-ab-initial.c @@ -0,0 +1,776 @@ +/* + * druid-ab-initial.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 druid-ab-initial.c + * @brief AqBanking setup functionality + * @author Copyright (C) 2002 Christian Stimming + * @author Copyright (C) 2006 David Hampton + * @author Copyright (C) 2008 Andreas Koehler + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "dialog-utils.h" +#include "druid-ab-initial.h" +#include "druid-utils.h" +#include "gnc-ab-kvp.h" +#include "gnc-ab-utils.h" +#include "gnc-component-manager.h" +#include "gnc-glib-utils.h" +#include "gnc-ui.h" +#include "gnc-ui-util.h" +#include "gnc-session.h" +#include "import-account-matcher.h" + +/* This static indicates the debugging module that this .o belongs to. */ +static QofLogModule log_module = G_LOG_DOMAIN; + +#define DRUID_AB_INITIAL_CM_CLASS "druid-ab-initial" + +typedef struct _ABInitialInfo ABInitialInfo; +typedef struct _DeferredInfo DeferredInfo; +typedef struct _AccCbData AccCbData; +typedef struct _RevLookupData RevLookupData; + +gboolean dai_key_press_event_cb(GtkWidget *widget, GdkEventKey *event, gpointer user_data); +void dai_cancel_cb(GnomeDruid *druid, gpointer user_data); +void dai_destroy_cb(GtkObject *object, gpointer user_data); +void dai_wizard_page_prepare_cb(GnomeDruidPage *druid_page, GtkWidget *widget, gpointer user_data); +void dai_wizard_button_clicked_cb(GtkButton *button, gpointer user_data); +void dai_match_page_prepare_cb(GnomeDruidPage *druid_page, GtkWidget *widget, gpointer user_data); +void dai_finish_cb(GnomeDruidPage *druid_page, GtkWidget *widget, gpointer user_data); + +static gboolean banking_has_accounts(AB_BANKING *banking); +static void hash_from_kvp_acc_cb(Account *gnc_acc, gpointer user_data); +static void druid_enable_next_button(ABInitialInfo *info); +static void druid_disable_next_button(ABInitialInfo *info); +static void child_exit_cb(GPid pid, gint status, gpointer data); +static gchar *ab_account_longname(const AB_ACCOUNT *ab_acc); +static AB_ACCOUNT *update_account_list_acc_cb(AB_ACCOUNT *ab_acc, gpointer user_data); +static void update_account_list(ABInitialInfo *info); +static gboolean find_gnc_acc_cb(gpointer key, gpointer value, gpointer user_data); +static gboolean clear_line_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer user_data); +static void account_list_changed_cb(GtkTreeSelection *selection, gpointer user_data); +static void clear_kvp_acc_cb(Account *gnc_acc, gpointer user_data); +static void save_kvp_acc_cb(gpointer key, gpointer value, gpointer user_data); +static void cm_close_handler(gpointer user_data); + +struct _ABInitialInfo { + GtkWidget *window; + GtkWidget *druid; + + /* account match page */ + GtkTreeView *account_view; + GtkListStore *account_store; + + /* managed by child_exit_cb */ + DeferredInfo *deferred_info; + + /* AqBanking stuff */ + AB_BANKING *api; + /* AB_ACCOUNT* -> Account* -- DO NOT DELETE THE KEYS! */ + GHashTable *gnc_hash; +}; + +struct _DeferredInfo { + ABInitialInfo *initial_info; + gchar *wizard_path; + gboolean qt_probably_unavailable; +}; + +struct _AccCbData { + AB_BANKING *api; + GHashTable *hash; +}; + +struct _RevLookupData { + Account *gnc_acc; + AB_ACCOUNT *ab_acc; +}; + +enum account_list_cols { + ACCOUNT_LIST_COL_INDEX = 0, + ACCOUNT_LIST_COL_AB_NAME, + ACCOUNT_LIST_COL_AB_ACCT, + ACCOUNT_LIST_COL_GNC_NAME, + ACCOUNT_LIST_COL_CHECKED, + NUM_ACCOUNT_LIST_COLS +}; + +gboolean +dai_key_press_event_cb(GtkWidget *widget, GdkEventKey *event, gpointer user_data) +{ + if (event->keyval == GDK_Escape) { + gtk_widget_destroy(widget); + return TRUE; + } else { + return FALSE; + } +} + +void +dai_cancel_cb(GnomeDruid *druid, gpointer user_data) +{ + ABInitialInfo *info = user_data; + + gtk_widget_destroy(info->window); +} + +void +dai_destroy_cb(GtkObject *object, gpointer user_data) +{ + ABInitialInfo *info = user_data; + + gnc_unregister_gui_component_by_data(DRUID_AB_INITIAL_CM_CLASS, info); + + if (info->deferred_info) { + g_message("Online Banking druid is being closed but the wizard is still " + "running. Inoring."); + + /* Tell child_exit_cb() that there is no druid anymore */ + info->deferred_info->initial_info = NULL; + } + + if (info->gnc_hash) { + AB_Banking_OnlineFini(info->api); + g_hash_table_destroy(info->gnc_hash); + info->gnc_hash = NULL; + } + + if (info->api) { + gnc_AB_BANKING_delete(info->api); + info->api = NULL; + } + + gtk_widget_destroy(info->window); + info->window = NULL; + + g_free(info); +} + +void +dai_wizard_page_prepare_cb(GnomeDruidPage *druid_page, GtkWidget *widget, + gpointer user_data) +{ + ABInitialInfo *info = user_data; + + g_return_if_fail(info->api); + + if (banking_has_accounts(info->api)) + druid_enable_next_button(info); + else + druid_disable_next_button(info); +} + +void +dai_wizard_button_clicked_cb(GtkButton *button, gpointer user_data) +{ + ABInitialInfo *info = user_data; + AB_BANKING *banking = info->api; + GWEN_BUFFER *buf; + gboolean wizard_exists; + const gchar *wizard_path; + gboolean qt_probably_unavailable = FALSE; + + g_return_if_fail(banking); + + ENTER("user_data: %p", user_data); + + if (info->deferred_info) { + LEAVE("Wizard is still running"); + return; + } + + /* This is the point where we look for and start an external + * application shipped with aqbanking that contains the setup druid + * for AqBanking related stuff. It requires qt (but not kde). This + * application contains the very verbose step-by-step setup wizard + * for the AqBanking account, and the application is shared with + * other AqBanking-based financial managers that offer the AqBanking + * features (e.g. KMyMoney). See gnucash-devel discussion here + * https://lists.gnucash.org/pipermail/gnucash-devel/2004-December/012351.html + */ + buf = GWEN_Buffer_new(NULL, 300, 0, 0); + AB_Banking_FindWizard(banking, "", NULL, buf); + wizard_exists = *GWEN_Buffer_GetStart(buf) != 0; + wizard_path = GWEN_Buffer_GetStart(buf); + + if (wizard_exists) { + /* Really check whether the file exists */ + gint fd = g_open(wizard_path, O_RDONLY, 0); + if (fd == -1) + wizard_exists = FALSE; + else + close(fd); + } + +#ifdef G_OS_WIN32 + { + const char *check_file = "qtdemo.exe"; + gchar *found_program = g_find_program_in_path(check_file); + if (found_program) { + g_debug("Yes, we found the Qt demo program in %s\n", found_program); + g_free(found_program); + } else { + g_warning("Ouch, no Qt demo program was found. Qt not installed?\n"); + qt_probably_unavailable = TRUE; + } + } +#endif + + druid_disable_next_button(info); + + if (wizard_exists) { + /* Call the qt wizard. See the note above about why this + * approach is chosen. */ + + GPid pid; + GError *error = NULL; + gchar *argv[2]; + gboolean spawned; + + argv[0] = g_strdup (wizard_path); + argv[1] = NULL; + spawned = g_spawn_async (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, + NULL, NULL, &pid, &error); + g_free (argv[0]); + + if (error) + g_critical( + "Error on starting AqBanking setup wizard: Code %d: %s", + error->code, error->message ? error->message : "(null)"); + + if (!spawned) { + g_critical("Could not start AqBanking setup wizard: %s", + error->message ? error->message : "(null)"); + g_error_free (error); + } else { + /* Keep a reference to info that can survive info */ + info->deferred_info = g_new0(DeferredInfo, 1); + info->deferred_info->initial_info = info; + info->deferred_info->wizard_path = g_strdup(wizard_path); + info->deferred_info->qt_probably_unavailable = + qt_probably_unavailable; + + g_child_watch_add (pid, child_exit_cb, info->deferred_info); + } + } else { + g_warning("on_aqhbci_button: Oops, no aqhbci setup wizard found."); + gnc_error_dialog + (info->window, + _("The external program \"AqBanking Setup Wizard\" has not " + "been found. \n\n" + "The %s package should include the " + "program \"qt3-wizard\". Please check your installation to " + "ensure this program is present. On some distributions this " + "may require installing additional packages."), + QT3_WIZARD_PACKAGE); + druid_disable_next_button(info); + } + + GWEN_Buffer_free(buf); + + LEAVE(" "); +} + +void +dai_match_page_prepare_cb(GnomeDruidPage *druid_page, GtkWidget *widget, + gpointer user_data) +{ + ABInitialInfo *info = user_data; + Account *root; + AccCbData data; + + + g_return_if_fail(info && info->api); + + /* No way back */ + gnome_druid_set_buttons_sensitive(GNOME_DRUID(info->druid), + FALSE, TRUE, TRUE, TRUE); + + /* Load aqbanking accounts */ + AB_Banking_OnlineInit(info->api); + + /* Determine current mapping */ + root = gnc_book_get_root_account(gnc_get_current_book()); + info->gnc_hash = g_hash_table_new(&g_direct_hash, &g_direct_equal); + data.api = info->api; + data.hash = info->gnc_hash; + gnc_account_foreach_descendant( + root, (AccountCb) hash_from_kvp_acc_cb, &data); + + /* Update the graphical representation */ + update_account_list(info); +} + +void +dai_finish_cb(GnomeDruidPage *druid_page, GtkWidget *widget, + gpointer user_data) +{ + ABInitialInfo *info = user_data; + Account *root; + + g_return_if_fail(info && info->gnc_hash); + + /* Commit the changes */ + root = gnc_book_get_root_account(gnc_get_current_book()); + gnc_account_foreach_descendant(root, (AccountCb) clear_kvp_acc_cb, NULL); + g_hash_table_foreach(info->gnc_hash, (GHFunc) save_kvp_acc_cb, NULL); + + gtk_widget_destroy(info->window); +} + +static gboolean +banking_has_accounts(AB_BANKING *banking) +{ + AB_ACCOUNT_LIST2 *accl; + gboolean result; + + g_return_val_if_fail(banking, FALSE); + + AB_Banking_OnlineInit(banking); + + accl = AB_Banking_GetAccounts(banking); + if (accl && (AB_Account_List2_GetSize(accl) > 0)) + result = TRUE; + else + result = FALSE; + + if (accl) + AB_Account_List2_free(accl); + + AB_Banking_OnlineFini(banking); + + return result; +} + +static void +hash_from_kvp_acc_cb(Account *gnc_acc, gpointer user_data) +{ + AccCbData *data = user_data; + AB_ACCOUNT *ab_acc; + + ab_acc = gnc_ab_get_ab_account(data->api, gnc_acc); + if (ab_acc) + g_hash_table_insert(data->hash, ab_acc, gnc_acc); +} + +static void +druid_enable_next_button(ABInitialInfo *info) +{ + g_return_if_fail(info); + gnome_druid_set_buttons_sensitive(GNOME_DRUID(info->druid), + TRUE, TRUE, TRUE, TRUE); +} + +static void +druid_disable_next_button(ABInitialInfo *info) +{ + g_return_if_fail(info); + gnome_druid_set_buttons_sensitive(GNOME_DRUID(info->druid), + TRUE, FALSE, TRUE, TRUE); +} + +static void +child_exit_cb(GPid pid, gint status, gpointer data) +{ + DeferredInfo *deferred_info = data; + ABInitialInfo *info = deferred_info->initial_info; + gint exit_status; + +#ifdef G_OS_WIN32 + exit_status = status; +#else + exit_status = WEXITSTATUS(status); +#endif + + g_spawn_close_pid(pid); + + if (!info) { + g_message("Online Banking wizard exited, but the druid has been " + "destroyed already"); + goto cleanup_child_exit_cb; + } + + if (exit_status == 0) { + druid_enable_next_button(info); + } else { + if (deferred_info->qt_probably_unavailable) { + g_warning("on_aqhbci_button: Oops, aqhbci wizard return nonzero " + "value: %d. The called program was \"%s\".\n", + exit_status, deferred_info->wizard_path); + gnc_error_dialog + (info->window, + _("The external program \"AqBanking Setup Wizard\" failed " + "to run successfully because the " + "additional software \"Qt\" was not found. " + "Please install the \"Qt/Windows Open Source Edition\" " + "from Trolltech by downloading it from www.trolltech.com" + "\n\n" + "If you have installed Qt already, you will have to adapt " + "the PATH variable of your system appropriately. " + "Contact the GnuCash developers if you need further " + "assistance on how to install Qt correctly." + "\n\n" + "Online Banking cannot be setup without Qt. Press \"Close\" " + "now, then \"Cancel\" to cancel the Online Banking setup.")); + } else { + g_warning("on_aqhbci_button: Oops, aqhbci wizard return nonzero " + "value: %d. The called program was \"%s\".\n", + exit_status, deferred_info->wizard_path); + gnc_error_dialog + (info->window, + _("The external program \"AqBanking Setup Wizard\" failed " + "to run successfully. Online Banking can only be setup " + "if this wizard has run successfully. " + "Please try running the \"AqBanking Setup Wizard\" again.")); + } + druid_disable_next_button(info); + } + +cleanup_child_exit_cb: + g_free(deferred_info->wizard_path); + g_free(deferred_info); + if (info) + info->deferred_info = NULL; +} + +static gchar * +ab_account_longname(const AB_ACCOUNT *ab_acc) +{ + gchar *bankname; + gchar *result; + const char *bankcode; + + g_return_val_if_fail(ab_acc, NULL); + + bankname = gnc_utf8_strip_invalid_strdup(AB_Account_GetBankName(ab_acc)); + bankcode = AB_Account_GetBankCode(ab_acc); + + /* Translators: Strings are 1. Account code, 2. Bank name, 3. Bank code. */ + if (bankname && *bankname) + result = g_strdup_printf(_("%s at %s (code %s)"), + AB_Account_GetAccountNumber(ab_acc), + bankname, + bankcode); + else + result = g_strdup_printf(_("%s at bank code %s"), + AB_Account_GetAccountNumber(ab_acc), + bankcode); + g_free(bankname); + + return result; + +} + +static AB_ACCOUNT * +update_account_list_acc_cb(AB_ACCOUNT *ab_acc, gpointer user_data) +{ + ABInitialInfo *info = user_data; + gchar *gnc_name, *ab_name; + Account *gnc_acc; + GtkTreeIter iter; + + g_return_val_if_fail(ab_acc && info, NULL); + + ab_name = ab_account_longname(ab_acc); + + /* Get corresponding gnucash account */ + gnc_acc = g_hash_table_lookup(info->gnc_hash, ab_acc); + + /* Build the text for the gnucash account. */ + if (gnc_acc) + gnc_name = xaccAccountGetFullName(gnc_acc); + else + gnc_name = g_strdup(""); + + /* Add item to the list store */ + gtk_list_store_append(info->account_store, &iter); + gtk_list_store_set(info->account_store, &iter, + ACCOUNT_LIST_COL_AB_NAME, ab_name, + ACCOUNT_LIST_COL_AB_ACCT, ab_acc, + ACCOUNT_LIST_COL_GNC_NAME, gnc_name, + ACCOUNT_LIST_COL_CHECKED, FALSE, + -1); + + g_free(gnc_name); + g_free(ab_name); + return NULL; +} + +static void +update_account_list(ABInitialInfo *info) +{ + AB_ACCOUNT_LIST2 *acclist; + + g_return_if_fail(info && info->api && info->gnc_hash); + + /* Detach model from view while updating */ + g_object_ref(info->account_store); + gtk_tree_view_set_model(info->account_view, NULL); + + /* Refill the list */ + gtk_list_store_clear(info->account_store); + acclist = AB_Banking_GetAccounts(info->api); + if (acclist) + AB_Account_List2_ForEach(acclist, update_account_list_acc_cb, info); + else + g_warning("update_account_list: Oops, account list from AB_Banking " + "is NULL"); + + /* Attach model to view again */ + gtk_tree_view_set_model(info->account_view, + GTK_TREE_MODEL(info->account_store)); + g_object_unref(info->account_store); +} + +static gboolean +find_gnc_acc_cb(gpointer key, gpointer value, gpointer user_data) +{ + RevLookupData *data = user_data; + + g_return_val_if_fail(data, TRUE); + + if (value == data->gnc_acc) { + data->ab_acc = (AB_ACCOUNT*) key; + return TRUE; + } + return FALSE; +} + +static gboolean +clear_line_cb(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, + gpointer user_data) +{ + RevLookupData *data = user_data; + GtkListStore *store = GTK_LIST_STORE(model); + gpointer ab_acc; + + g_return_val_if_fail(data && store, FALSE); + + gtk_tree_model_get(model, iter, ACCOUNT_LIST_COL_AB_ACCT, &ab_acc, -1); + + if (ab_acc == data->ab_acc) { + gtk_list_store_set(store, iter, ACCOUNT_LIST_COL_GNC_NAME, "", + ACCOUNT_LIST_COL_CHECKED, TRUE, -1); + return TRUE; + } + return FALSE; +} + +static void +account_list_changed_cb(GtkTreeSelection *selection, gpointer user_data) +{ + ABInitialInfo *info = user_data; + GtkTreeModel *model; + GtkTreeIter iter; + AB_ACCOUNT *ab_acc; + gchar *longname, *gnc_name; + Account *old_value, *gnc_acc; + const gchar *currency; + gnc_commodity *commodity = NULL; + gboolean ok_pressed; + + g_return_if_fail(info); + + if (!gtk_tree_selection_get_selected(selection, &model, &iter)) + return; + gtk_tree_model_get(model, &iter, ACCOUNT_LIST_COL_AB_ACCT, &ab_acc, -1); + + /* Avoid recursion when unselecting the item again */ + g_signal_handlers_block_by_func(selection, account_list_changed_cb, info); + gtk_tree_selection_unselect_iter(selection, &iter); + g_signal_handlers_unblock_by_func(selection, account_list_changed_cb, info); + + if (ab_acc) { + old_value = g_hash_table_lookup(info->gnc_hash, ab_acc); + + longname = ab_account_longname(ab_acc); + currency = AB_Account_GetCurrency(ab_acc); + if (currency && *currency) { + commodity = gnc_commodity_table_lookup( + gnc_commodity_table_get_table(gnc_get_current_book()), + GNC_COMMODITY_NS_CURRENCY, + currency); + } + + gnc_acc = gnc_import_select_account(info->window, NULL, TRUE, + longname, commodity, ACCT_TYPE_BANK, + old_value, &ok_pressed); + g_free(longname); + + if (ok_pressed && old_value != gnc_acc) { + if (gnc_acc) { + RevLookupData data; + + /* Lookup and clear other mappings to gnc_acc */ + data.gnc_acc = gnc_acc; + data.ab_acc = NULL; + g_hash_table_find(info->gnc_hash, (GHRFunc) find_gnc_acc_cb, + &data); + if (data.ab_acc) { + g_hash_table_remove(info->gnc_hash, data.ab_acc); + gtk_tree_model_foreach( + GTK_TREE_MODEL(info->account_store), + (GtkTreeModelForeachFunc) clear_line_cb, + &data); + } + + /* Map ab_acc to gnc_acc */ + g_hash_table_insert(info->gnc_hash, ab_acc, gnc_acc); + gnc_name = xaccAccountGetFullName(gnc_acc); + gtk_list_store_set(info->account_store, &iter, + ACCOUNT_LIST_COL_GNC_NAME, gnc_name, + ACCOUNT_LIST_COL_CHECKED, TRUE, + -1); + g_free(gnc_name); + + } else { + g_hash_table_remove(info->gnc_hash, ab_acc); + gtk_list_store_set(info->account_store, &iter, + ACCOUNT_LIST_COL_GNC_NAME, "", + ACCOUNT_LIST_COL_CHECKED, TRUE, + -1); + } + } + } +} + +static void +clear_kvp_acc_cb(Account *gnc_acc, gpointer user_data) +{ + if (gnc_ab_get_account_uid(gnc_acc)) + gnc_ab_set_account_uid(gnc_acc, 0); + if (gnc_ab_get_account_accountid(gnc_acc)) + gnc_ab_set_account_accountid(gnc_acc, ""); + if (gnc_ab_get_account_bankcode(gnc_acc)) + gnc_ab_set_account_bankcode(gnc_acc, ""); +} + +static void +save_kvp_acc_cb(gpointer key, gpointer value, gpointer user_data) +{ + AB_ACCOUNT *ab_acc = key; + Account *gnc_acc = value; + guint32 ab_account_uid; + const gchar *ab_accountid, *gnc_accountid; + const gchar *ab_bankcode, *gnc_bankcode; + + g_return_if_fail(ab_acc && gnc_acc); + + ab_account_uid = AB_Account_GetUniqueId(ab_acc); + if (gnc_ab_get_account_uid(gnc_acc) != ab_account_uid) + gnc_ab_set_account_uid(gnc_acc, ab_account_uid); + + ab_accountid = AB_Account_GetAccountNumber(ab_acc); + gnc_accountid = gnc_ab_get_account_accountid(gnc_acc); + if (ab_accountid + && (!gnc_accountid + || (strcmp(ab_accountid, gnc_accountid) != 0))) + gnc_ab_set_account_accountid(gnc_acc, ab_accountid); + + ab_bankcode = AB_Account_GetBankCode(ab_acc); + gnc_bankcode = gnc_ab_get_account_bankcode(gnc_acc); + if (ab_bankcode + && (!gnc_bankcode + || (strcmp(gnc_bankcode, ab_bankcode) != 0))) + gnc_ab_set_account_bankcode(gnc_acc, ab_bankcode); +} + +static void +cm_close_handler(gpointer user_data) +{ + ABInitialInfo *info = user_data; + + gtk_widget_destroy(info->window); +} + +void +gnc_ab_initial_druid(void) +{ + ABInitialInfo *info; + GladeXML *xml; + GtkTreeViewColumn *column; + GtkTreeSelection *selection; + gint component_id; + + info = g_new0(ABInitialInfo, 1); + + xml = gnc_glade_xml_new("aqbanking.glade", "AqBanking Init Druid"); + + info->window = glade_xml_get_widget(xml, "AqBanking Init Druid"); + g_object_set_data_full(G_OBJECT(info->window), "xml", xml, g_object_unref); + glade_xml_signal_autoconnect_full(xml, gnc_glade_autoconnect_full_func, + info); + + info->druid = glade_xml_get_widget(xml, "ab_init_druid"); + gnc_druid_set_colors(GNOME_DRUID(info->druid)); + + info->api = gnc_AB_BANKING_new(); + info->deferred_info = NULL; + info->gnc_hash = NULL; + + info->account_view = + GTK_TREE_VIEW(glade_xml_get_widget(xml, "account_page_view")); + info->account_store = gtk_list_store_new(NUM_ACCOUNT_LIST_COLS, + G_TYPE_INT, G_TYPE_STRING, + G_TYPE_POINTER, G_TYPE_STRING, + G_TYPE_BOOLEAN); + gtk_tree_view_set_model(info->account_view, + GTK_TREE_MODEL(info->account_store)); + g_object_unref(info->account_store); + + column = gtk_tree_view_column_new_with_attributes( + _("Online Banking Account Name"), gtk_cell_renderer_text_new(), + "text", ACCOUNT_LIST_COL_AB_NAME, (gchar*) NULL); + gtk_tree_view_append_column(info->account_view, column); + + column = gtk_tree_view_column_new_with_attributes( + _("GnuCash Account Name"), gtk_cell_renderer_text_new(), + "text", ACCOUNT_LIST_COL_GNC_NAME, (gchar*) NULL); + gtk_tree_view_column_set_expand(column, TRUE); + gtk_tree_view_append_column(info->account_view, column); + + column = gtk_tree_view_column_new_with_attributes( + _("New?"), gtk_cell_renderer_toggle_new(), + "active", ACCOUNT_LIST_COL_CHECKED, (gchar*) NULL); + gtk_tree_view_append_column(info->account_view, column); + + selection = gtk_tree_view_get_selection(info->account_view); + g_signal_connect(selection, "changed", + G_CALLBACK(account_list_changed_cb), info); + + component_id = gnc_register_gui_component(DRUID_AB_INITIAL_CM_CLASS, + NULL, cm_close_handler, info); + gnc_gui_component_set_session(component_id, gnc_get_current_session()); + + gtk_widget_show(info->window); +} diff --git a/src/import-export/aqbanking/druid-ab-initial.h b/src/import-export/aqbanking/druid-ab-initial.h new file mode 100644 index 0000000000..144709a95f --- /dev/null +++ b/src/import-export/aqbanking/druid-ab-initial.h @@ -0,0 +1,51 @@ +/* + * druid-ab-initial.h -- aqbanking creation functionality + * + * + * 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 druid-ab-initial.h + * @brief AqBanking setup functionality + * @author Copyright (C) 2002 Christian Stimming + * @author Copyright (C) 2008 Andreas Koehler + */ + +#ifndef DRUID_AB_INITIAL_H +#define DRUID_AB_INITIAL_H + +#include + +G_BEGIN_DECLS + +/** + * Create and show a druid for the aqbanking setup. + */ +void gnc_ab_initial_druid(void); + +G_END_DECLS + +/** @} */ +/** @} */ + +#endif /* DRUID_AB_INITIAL_H */ diff --git a/src/import-export/aqbanking/gnc-ab-getbalance.c b/src/import-export/aqbanking/gnc-ab-getbalance.c new file mode 100644 index 0000000000..d345f55cef --- /dev/null +++ b/src/import-export/aqbanking/gnc-ab-getbalance.c @@ -0,0 +1,251 @@ +/* + * gnc-ab-getbalance.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-ab-getbalance.c + * @brief AqBanking getbalance functions + * @author Copyright (C) 2002 Christian Stimming + * @author Copyright (C) 2008 Andreas Koehler + */ + +#include "config.h" + +#include +#include +#include + +#include "gnc-ab-getbalance.h" +#include "gnc-ab-kvp.h" +#include "gnc-ab-utils.h" +#include "gnc-gwen-gui.h" +#include "gnc-ui.h" +#include "RecnWindow.h" + +/* This static indicates the debugging module that this .o belongs to. */ +static QofLogModule log_module = G_LOG_DOMAIN; + +void +gnc_ab_getbalance(GtkWidget *parent, Account *gnc_acc) +{ + AB_BANKING *api; + gboolean online = FALSE; + AB_ACCOUNT *ab_acc; + AB_JOB *job = NULL; + AB_JOB_LIST2 *job_list = NULL; + GncGWENGui *gui = NULL; + AB_IMEXPORTER_CONTEXT *context = NULL; + AB_IMEXPORTER_ACCOUNTINFO *acc_info = NULL; + AB_ACCOUNT_STATUS *status = NULL; + const AB_BALANCE *booked_bal, *noted_bal; + const AB_VALUE *booked_val = NULL, *noted_val = NULL; + gdouble booked_value, noted_value; + gnc_numeric value; + time_t booked_tt = 0; + GtkWidget *dialog; + gboolean show_recn_window = FALSE; + + g_return_if_fail(parent && gnc_acc); + + /* Get the API */ + api = gnc_AB_BANKING_new(); + if (!api) { + g_warning("gnc_ab_gettrans: Couldn't get AqBanking API"); + return; + } + if (AB_Banking_OnlineInit(api) != 0) { + g_warning("gnc_ab_gettrans: Couldn't initialize AqBanking API"); + goto cleanup; + } + online = TRUE; + + /* Get the AqBanking Account */ + ab_acc = gnc_ab_get_ab_account(api, gnc_acc); + if (!ab_acc) { + g_warning("gnc_ab_getbalance: No AqBanking account found"); + goto cleanup; + } + + /* Get a GetBalance job and enqueue it */ + job = AB_JobGetBalance_new(ab_acc); + if (!job || AB_Job_CheckAvailability(job, 0)) { + g_warning("gnc_ab_getbalance: JobGetBalance not available for this " + "account"); + goto cleanup; + } + job_list = AB_Job_List2_new(); + AB_Job_List2_PushBack(job_list, job); + + /* Get a GUI object */ + gui = gnc_GWEN_Gui_get(parent); + if (!gui) { + g_warning("gnc_ab_getbalance: Couldn't initialize Gwenhywfar GUI"); + goto cleanup; + } + + /* Create a context to store the results */ + context = AB_ImExporterContext_new(); + + /* Execute the job */ + if (AB_Banking_ExecuteJobs(api, job_list, context, 0)) { + g_warning("gnc_ab_getbalance: Error on executing job"); + goto cleanup; + } + + /* Lookup account in context */ + acc_info = AB_ImExporterContext_FindAccountInfo( + context, gnc_ab_get_account_bankcode(gnc_acc), + gnc_ab_get_account_accountid(gnc_acc)); + if (!acc_info) { + g_warning("gnc_ab_getbalance: No accountinfo result for this account"); + goto cleanup; + } + + /* Lookup newest data */ + status = gnc_ab_get_best_accountstatus(acc_info); + if (!status) { + g_warning("gnc_ab_getbalance: No accountstatus result for this account"); + goto cleanup; + } + + /* Lookup booked balance and time */ + booked_bal = AB_AccountStatus_GetBookedBalance(status); + if (booked_bal) { + const GWEN_TIME *ti = AB_Balance_GetTime(booked_bal); + if (ti) { + booked_tt = GWEN_Time_toTime_t(ti); + } else { + /* No time found? Use today because the HBCI query asked for today's + * balance. */ + booked_tt = gnc_timet_get_day_start(time(NULL)); + } + booked_val = AB_Balance_GetValue(booked_bal); + if (booked_val) { + booked_value = AB_Value_GetValueAsDouble(booked_val); + } else { + g_warning("gnc_ab_getbalance: booked_val == NULL. Assuming 0"); + booked_value = 0.0; + } + } else { + g_warning("gnc_ab_getbalance: booked_bal == NULL. Assuming 0"); + booked_tt = 0; + booked_value = 0.0; + } + + /* Lookup noted balance */ + noted_bal = AB_AccountStatus_GetNotedBalance(status); + if (noted_bal) { + noted_val = AB_Balance_GetValue(noted_bal); + if (noted_val) + noted_value = AB_Value_GetValueAsDouble(noted_val); + else { + g_warning("gnc_ab_getbalance: noted_val == NULL. Assuming 0"); + noted_value = 0.0; + } + } else { + g_warning("gnc_ab_getbalance: noted_bal == NULL. Assuming 0"); + noted_value = 0.0; + } + + value = double_to_gnc_numeric(booked_value, + xaccAccountGetCommoditySCU(gnc_acc), + GNC_RND_ROUND); + if (noted_value == 0.0 && booked_value == 0.0) { + dialog = gtk_message_dialog_new( + GTK_WINDOW(parent), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_OK, + "%s", + /* Translators: Strings from this file are needed only in + * countries that have one of aqbanking's Online Banking + * techniques available. This is 'OFX DirectConnect' + * (U.S. and others), 'HBCI' (in Germany), or 'YellowNet' + * (Switzerland). If none of these techniques are available + * in your country, you may safely ignore strings from the + * import-export/hbci subdirectory. */ + _("The downloaded Online Banking Balance was zero.\n\n" + "Either this is the correct balance, or your bank does not " + "support Balance download in this Online Banking version. " + "In the latter case you should choose a different " + "Online Banking version number in the Online Banking " + "(AqBanking or HBCI) Setup. After that, try again to " + "download the Online Banking Balance.")); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + + } else { + gnc_numeric reconc_balance = xaccAccountGetReconciledBalance(gnc_acc); + + gchar *booked_str = gnc_AB_VALUE_to_readable_string(booked_val); + gchar *message1 = g_strdup_printf( + _("Result of Online Banking job: \n" + "Account booked balance is %s"), + booked_str); + gchar *message2 = + (noted_value == 0.0) ? + g_strdup("") : + g_strdup_printf(_("For your information: This account also " + "has a noted balance of %s\n"), + gnc_AB_VALUE_to_readable_string(noted_val)); + + if (gnc_numeric_equal(value, reconc_balance)) { + const gchar *message3 = + _("The booked balance is identical to the current " + "reconciled balance of the account."); + dialog = gtk_message_dialog_new( + GTK_WINDOW(parent), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_OK, + "%s\n%s\n%s", + message1, message2, message3); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(GTK_WIDGET(dialog)); + + } else { + const char *message3 = _("Reconcile account now?"); + + show_recn_window = gnc_verify_dialog(parent,TRUE, "%s\n%s\n%s", + message1, message2, message3); + } + g_free(booked_str); + g_free(message1); + g_free(message2); + } + + /* Show reconciliation window */ + if (show_recn_window) + recnWindowWithBalance(parent, gnc_acc, value, booked_tt); + +cleanup: + if (context) + AB_ImExporterContext_free(context); + if (gui) + gnc_GWEN_Gui_release(gui); + if (job_list) + AB_Job_List2_free(job_list); + if (job) + AB_Job_free(job); + if (online) + AB_Banking_OnlineFini(api); + gnc_AB_BANKING_fini(api); +} diff --git a/src/import-export/aqbanking/gnc-ab-getbalance.h b/src/import-export/aqbanking/gnc-ab-getbalance.h new file mode 100644 index 0000000000..e960a059f8 --- /dev/null +++ b/src/import-export/aqbanking/gnc-ab-getbalance.h @@ -0,0 +1,53 @@ +/* + * gnc-ab-get-balance.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-ab-getbalance.h + * @brief AqBanking getbalance functions + * @author Copyright (C) 2002 Christian Stimming + * @author Copyright (C) 2008 Andreas Koehler + */ + +#ifndef GNC_AB_GETBALANCE_H +#define GNC_AB_GETBALANCE_H + +#include + +#include "Account.h" + +G_BEGIN_DECLS + +/** + * Execute a GetBalance job, show the resulting balance and offer to reconcile + * the GnuCash account. + * + * @param parent Widget to use as parent, may be NULL + * @param gnc_acc GnuCash account to fetch balance for + */ +void gnc_ab_getbalance(GtkWidget *parent, Account *gnc_acc); + +G_END_DECLS + +#endif /* GNC_AB_GETBALANCE_H */ diff --git a/src/import-export/aqbanking/gnc-ab-gettrans.c b/src/import-export/aqbanking/gnc-ab-gettrans.c new file mode 100644 index 0000000000..a128f63944 --- /dev/null +++ b/src/import-export/aqbanking/gnc-ab-gettrans.c @@ -0,0 +1,245 @@ +/* + * gnc-ab-gettrans.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-ab-gettrans.c + * @brief AqBanking get transactions functions + * @author Copyright (C) 2002 Christian Stimming + * @author Copyright (C) 2008 Andreas Koehler + */ + +#include "config.h" + +#include +#include +#include + +#include "Account.h" +#include "dialog-daterange.h" +#include "gnc-ab-gettrans.h" +#include "gnc-ab-kvp.h" +#include "gnc-ab-utils.h" +#include "gnc-gwen-gui.h" +#include "import-main-matcher.h" + +/* This static indicates the debugging module that this .o belongs to. */ +static QofLogModule log_module = G_LOG_DOMAIN; + +typedef struct _TransListData TransListData; + +static gboolean gettrans_dates(GtkWidget *parent, Account *gnc_acc, GWEN_TIME **from_date, GWEN_TIME **to_date); +static const AB_TRANSACTION *transaction_cb(const AB_TRANSACTION *ab_trans, gpointer user_data); + +struct _TransListData { + Account *gnc_acc; + GNCImportMainMatcher *importer_generic; +}; + +static gboolean +gettrans_dates(GtkWidget *parent, Account *gnc_acc, + GWEN_TIME **from_date, GWEN_TIME **to_date) +{ + Timespec last_timespec, until_timespec; + time_t now = time(NULL); + gboolean use_last_date = TRUE; + gboolean use_earliest_date = TRUE; + gboolean use_until_now = TRUE; + + g_return_val_if_fail(from_date && to_date, FALSE); + + /* Get time of last retrieval */ + last_timespec = gnc_ab_get_account_trans_retrieval(gnc_acc); + if (last_timespec.tv_sec == 0) { + use_last_date = FALSE; + timespecFromTime_t(&last_timespec, now); + } + timespecFromTime_t(&until_timespec, now); + + /* Let the user choose the date range of retrieval */ + if (!gnc_ab_enter_daterange(parent, NULL, + &last_timespec, + &use_last_date, &use_earliest_date, + &until_timespec, &use_until_now)) + return FALSE; + + /* Now calculate from date */ + if (use_earliest_date) { + *from_date = NULL; + } else { + if (use_last_date) + last_timespec = gnc_ab_get_account_trans_retrieval(gnc_acc); + *from_date = GWEN_Time_fromSeconds(timespecToTime_t(last_timespec)); + } + + /* Now calculate to date */ + if (use_until_now) + timespecFromTime_t(&until_timespec, now); + *to_date = GWEN_Time_fromSeconds(timespecToTime_t(until_timespec)); + + return TRUE; +} + +/** + * Callback function for AB_ImExporterAccountInfo_TransactionsForEach(). The + * conversion from AqBanking to GnuCash transaction is done here, once for each + * AB_TRANSACTION. + */ +static const AB_TRANSACTION * +transaction_cb(const AB_TRANSACTION *ab_trans, gpointer user_data) +{ + TransListData *data = user_data; + Transaction *gnc_trans; + + g_return_val_if_fail(ab_trans && data, NULL); + + /* Create a GnuCash transaction from ab_trans */ + gnc_trans = gnc_ab_trans_to_gnc(ab_trans, data->gnc_acc); + + /* Instead of xaccTransCommitEdit(gnc_trans) */ + gnc_gen_trans_list_add_trans(data->importer_generic, gnc_trans); + + return NULL; +} + +void +gnc_ab_gettrans(GtkWidget *parent, Account *gnc_acc) +{ + AB_BANKING *api; + gboolean online = FALSE; + AB_ACCOUNT *ab_acc; + GWEN_TIME *from_date = NULL, *to_date = NULL; + Timespec until_timespec; + AB_JOB *job = NULL; + AB_JOB_LIST2 *job_list = NULL; + GncGWENGui *gui = NULL; + AB_IMEXPORTER_CONTEXT *context = NULL; + AB_IMEXPORTER_ACCOUNTINFO *acc_info = NULL; + + g_return_if_fail(parent && gnc_acc); + + /* Get the API */ + api = gnc_AB_BANKING_new(); + if (!api) { + g_warning("gnc_ab_gettrans: Couldn't get AqBanking API"); + return; + } + if (AB_Banking_OnlineInit(api) != 0) { + g_warning("gnc_ab_gettrans: Couldn't initialize AqBanking API"); + goto cleanup; + } + online = TRUE; + + /* Get the AqBanking Account */ + ab_acc = gnc_ab_get_ab_account(api, gnc_acc); + if (!ab_acc) { + g_warning("gnc_ab_gettrans: No AqBanking account found"); + goto cleanup; + } + + /* Get the start and end dates for the GetTransactions job. */ + if (!gettrans_dates(parent, gnc_acc, &from_date, &to_date)) { + g_debug("gnc_ab_gettrans: gettrans_dates aborted"); + goto cleanup; + } + /* Use this as a local storage for the until_time below. */ + timespecFromTime_t(&until_timespec, GWEN_Time_toTime_t(to_date)); + + /* Get a GetTransactions job and enqueue it */ + job = AB_JobGetTransactions_new(ab_acc); + if (!job || AB_Job_CheckAvailability(job, 0)) { + g_warning("gnc_ab_gettrans: JobGetTransactions not available for this " + "account"); + goto cleanup; + } + AB_JobGetTransactions_SetFromTime(job, from_date); + AB_JobGetTransactions_SetToTime(job, to_date); + job_list = AB_Job_List2_new(); + AB_Job_List2_PushBack(job_list, job); + + /* Get a GUI object */ + gui = gnc_GWEN_Gui_get(parent); + if (!gui) { + g_warning("gnc_ab_gettrans: Couldn't initialize Gwenhywfar GUI"); + goto cleanup; + } + + /* Create a context to store the results */ + context = AB_ImExporterContext_new(); + + /* Execute the job */ + if (AB_Banking_ExecuteJobs(api, job_list, context, 0)) { + g_warning("gnc_ab_gettrans: Error on executing job"); + goto cleanup; + } + + /* Lookup account in context */ + acc_info = AB_ImExporterContext_FindAccountInfo( + context, gnc_ab_get_account_bankcode(gnc_acc), + gnc_ab_get_account_accountid(gnc_acc)); + if (!acc_info) { + g_warning("gnc_ab_gettrans: No accountinfo result for this account"); + goto cleanup; + } + + if (AB_ImExporterAccountInfo_GetFirstTransaction(acc_info)) { + /* Import transactions */ + + TransListData data; + data.importer_generic = gnc_gen_trans_list_new(parent, NULL, TRUE, 14); + data.gnc_acc = gnc_acc; + + AB_ImExporterAccountInfo_TransactionsForEach(acc_info, transaction_cb, + &data); + } else { + /* No transaction found */ + GtkWidget *dialog = gtk_message_dialog_new( + GTK_WINDOW(parent), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_OK, + "%s", + _("The Online Banking import returned no transactions " + "for the selected time period.")); + gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + } + + /* Store the date of this retrieval */ + gnc_ab_set_account_trans_retrieval(gnc_acc, until_timespec); + +cleanup: + if (context) + AB_ImExporterContext_free(context); + if (gui) + gnc_GWEN_Gui_release(gui); + if (job_list) + AB_Job_List2_free(job_list); + if (job) + AB_Job_free(job); + if (to_date) + GWEN_Time_free(to_date); + if (from_date) + GWEN_Time_free(from_date); + if (online) + AB_Banking_OnlineFini(api); + gnc_AB_BANKING_fini(api); +} diff --git a/src/import-export/aqbanking/gnc-ab-gettrans.h b/src/import-export/aqbanking/gnc-ab-gettrans.h new file mode 100644 index 0000000000..8767da21eb --- /dev/null +++ b/src/import-export/aqbanking/gnc-ab-gettrans.h @@ -0,0 +1,50 @@ +/* + * gnc-ab-get-balance.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-ab-getbalance.h + * @brief AqBanking getbalance functions + * @author Copyright (C) 2002 Christian Stimming + * @author Copyright (C) 2008 Andreas Koehler + */ + +#ifndef GNC_AB_GETTRANS_H +#define GNC_AB_GETTRANS_H + +#include + +G_BEGIN_DECLS + +/** + * Execute a GetTransactions job. + * + * @param parent Widget to use as parent, may be NULL + * @param gnc_acc GnuCash account to fetch transactions for + */ +void gnc_ab_gettrans(GtkWidget *parent, Account *gnc_acc); + +G_END_DECLS + +#endif /* GNC_AB_GETTRANS_H */ diff --git a/src/import-export/aqbanking/gnc-ab-kvp.c b/src/import-export/aqbanking/gnc-ab-kvp.c new file mode 100644 index 0000000000..1eaf7ca084 --- /dev/null +++ b/src/import-export/aqbanking/gnc-ab-kvp.c @@ -0,0 +1,176 @@ +/* + * gnc-ab-kvp.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-ab-kvp.c + * @brief AqBanking KVP handling + * @author Copyright (C) 2002 Christian Stimming + * @author Copyright (C) 2008 Andreas Koehler + */ + +#include "config.h" + +#include "gnc-ab-kvp.h" + +#define AB_KEY "hbci" +#define AB_ACCOUNT_ID "account-id" +#define AB_ACCOUNT_UID "account-uid" +#define AB_BANK_CODE "bank-code" +#define AB_TRANS_RETRIEVAL "trans-retrieval" +#define AB_TEMPLATES "template-list" + +/* This static indicates the debugging module that this .o belongs to. */ +static QofLogModule log_module = G_LOG_DOMAIN; + +static void force_account_dirty(Account *acct); +static kvp_frame *gnc_ab_get_account_kvp(const Account *a, gboolean create); +static kvp_frame *gnc_ab_get_book_kvp(QofBook *b, gboolean create); + +G_CONST_RETURN gchar * +gnc_ab_get_account_accountid(const Account *a) +{ + kvp_frame *frame = gnc_ab_get_account_kvp(a, FALSE); + kvp_value *value = kvp_frame_get_slot(frame, AB_ACCOUNT_ID); + return kvp_value_get_string(value); +} + +void +gnc_ab_set_account_accountid(Account *a, const gchar *id) +{ + kvp_frame *frame = gnc_ab_get_account_kvp(a, TRUE); + kvp_value *value = kvp_value_new_string(id); + xaccAccountBeginEdit(a); + kvp_frame_set_slot_nc(frame, AB_ACCOUNT_ID, value); + force_account_dirty(a); + xaccAccountCommitEdit(a); +} + +G_CONST_RETURN gchar * +gnc_ab_get_account_bankcode(const Account *a) +{ + kvp_frame *frame = gnc_ab_get_account_kvp(a, FALSE); + kvp_value *value = kvp_frame_get_slot(frame, AB_BANK_CODE); + return kvp_value_get_string(value); +} + +void +gnc_ab_set_account_bankcode(Account *a, const gchar *code) +{ + kvp_frame *frame = gnc_ab_get_account_kvp(a, TRUE); + kvp_value *value = kvp_value_new_string(code); + xaccAccountBeginEdit(a); + kvp_frame_set_slot_nc(frame, AB_BANK_CODE, value); + force_account_dirty(a); + xaccAccountCommitEdit(a); +} + +guint32 +gnc_ab_get_account_uid(const Account *a) +{ + kvp_frame *frame = gnc_ab_get_account_kvp(a, FALSE); + kvp_value *value = kvp_frame_get_slot(frame, AB_ACCOUNT_UID); + return (guint32) kvp_value_get_gint64(value); +} + +void +gnc_ab_set_account_uid(Account *a, guint32 uid) +{ + kvp_frame *frame = gnc_ab_get_account_kvp(a, TRUE); + kvp_value *value = kvp_value_new_gint64(uid); + xaccAccountBeginEdit(a); + kvp_frame_set_slot_nc(frame, AB_ACCOUNT_UID, value); + force_account_dirty(a); + xaccAccountCommitEdit(a); +} + +Timespec +gnc_ab_get_account_trans_retrieval(const Account *a) +{ + kvp_frame *frame = gnc_ab_get_account_kvp(a, FALSE); + kvp_value *value = kvp_frame_get_slot(frame, AB_TRANS_RETRIEVAL); + return kvp_value_get_timespec(value); +} + +void +gnc_ab_set_account_trans_retrieval(Account *a, Timespec time) +{ + kvp_frame *frame = gnc_ab_get_account_kvp(a, TRUE); + kvp_value *value = kvp_value_new_timespec(time); + xaccAccountBeginEdit(a); + kvp_frame_set_slot_nc(frame, AB_TRANS_RETRIEVAL, value); + force_account_dirty(a); + xaccAccountCommitEdit(a); +} + +GList * +gnc_ab_get_book_template_list(QofBook *b) +{ + kvp_frame *frame = gnc_ab_get_book_kvp(b, FALSE); + kvp_value *value = kvp_frame_get_slot(frame, AB_TEMPLATES); + return kvp_value_get_glist(value); +} + +void +gnc_ab_set_book_template_list(QofBook *b, GList *template_list) +{ + kvp_frame *frame = gnc_ab_get_book_kvp(b, TRUE); + kvp_value *value = kvp_value_new_glist_nc(template_list); + kvp_frame_set_slot_nc(frame, AB_TEMPLATES, value); + qof_book_kvp_changed(b); +} + +static void +force_account_dirty(Account *acct) +{ + gchar *name = g_strdup(xaccAccountGetName(acct)); + + /* This is necessary because modifying the KvpFrames doesn't mark + * accounts dirty, which means the changes wont be propagated to the + * backend. + */ + xaccAccountSetName(acct, name); + g_free(name); +} + +static kvp_frame * +gnc_ab_get_account_kvp(const Account *a, gboolean create) +{ + kvp_frame *toplevel = xaccAccountGetSlots(a); + kvp_frame *result = kvp_frame_get_frame(toplevel, AB_KEY); + if (!result && create) { + result = kvp_frame_new(); + kvp_frame_add_frame_nc(toplevel, AB_KEY, result); + } + return result; +} + +static kvp_frame * +gnc_ab_get_book_kvp(QofBook *b, gboolean create) +{ + kvp_frame *toplevel = qof_book_get_slots(b); + kvp_frame *result = kvp_frame_get_frame(toplevel, AB_KEY); + if (!result && create) { + result = kvp_frame_new(); + kvp_frame_add_frame_nc(toplevel, AB_KEY, result); + } + return result; +} diff --git a/src/import-export/aqbanking/gnc-ab-kvp.h b/src/import-export/aqbanking/gnc-ab-kvp.h new file mode 100644 index 0000000000..a17b800218 --- /dev/null +++ b/src/import-export/aqbanking/gnc-ab-kvp.h @@ -0,0 +1,148 @@ +/* + * gnc-ab-kvp.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-ab-kvp.h + * @brief AqBanking KVP handling + * @author Copyright (C) 2002 Christian Stimming + * @author Copyright (C) 2008 Andreas Koehler + */ + +#ifndef GNC_AB_KVP_H +#define GNC_AB_KVP_H + +#include + +#include "Account.h" + +G_BEGIN_DECLS + +/** @name Account + * @{ */ + +/** + * Return a non-copied pointer to the accountid string in the Account @a a. + * The gchar* is still owned by the kvp_frame, so don't free it until you want + * to delete the whole kvp_frame. + * + * @param a Account + * @return Account ID + */ +const gchar *gnc_ab_get_account_accountid(const Account *a); + +/** + * Set the accountid string in the Account @a a to @a id. A copy of the string + * will be stored. The Account will be marked as "dirty". + * + * @param a Account + * @param id Account ID + */ +void gnc_ab_set_account_accountid(Account *a, const gchar *id); + +/** + * Return a non-copied pointer to the bankcode string in the Account @a a. The + * gchar* is still owned by the kvp_frame, so don't free it until you want to + * delete the whole kvp_frame. + * + * @param a Account + * @return Bank code + */ +const gchar *gnc_ab_get_account_bankcode(const Account *a); + +/** + * Set the bankcode string in the Account @a a to @a code. A copy of the string + * will be stored. The Account will be marked as "dirty". + * + * @param a Account + * @param code Bank code + */ +void gnc_ab_set_account_bankcode(Account *a, const gchar *code); + +/** + * Return the unique id for the AB_BANKING account in the Account @a a. + * + * @param a Account + * @return Unique ID + */ +guint32 gnc_ab_get_account_uid(const Account *a); + +/** + * Set the unique id for the AB_BANKING account in the Account @a a to @a uid. + * The Account will be marked as "dirty". + * + * @param a Account + * @param uid Unique ID + */ +void gnc_ab_set_account_uid(Account *a, guint32 uid); + +/** + * Return the time of last online transaction retrieval for Account @a a. + * + * @param a Account + * @return Retrieval time + */ +Timespec gnc_ab_get_account_trans_retrieval(const Account *a); + +/** + * Set the time of last online transaction retrieval for Account @a a. The + * account will be marked as "dirty". + * + * @param a Account + * @param time Retrieval time + */ +void gnc_ab_set_account_trans_retrieval(Account *a, Timespec time); + +/** @} */ + +/** @name Book + * @{ */ + +/** + * Return a non-copied pointer to the GList of kvp_frames which eventually are + * the template transactions, stored in the given book. + * + * @param b Book + * @return Template list + */ +GList *gnc_ab_get_book_template_list(QofBook *b); + +/** + * Set the GList of kvp_frames of template transactions in the Book @a b to @a + * template_list. No copy of the GList will be stored, the callee becomes the + * owner and the caller must not free it. The book will be marked "dirty". + * + * @param b Book + * @param template_list Template list + */ +void gnc_ab_set_book_template_list(QofBook *b, GList *template_list); + +/** @} */ + +G_END_DECLS + +/** @} */ +/** @} */ + +#endif /* GNC_AB_KVP_H */ diff --git a/src/import-export/aqbanking/gnc-ab-trans-templ.c b/src/import-export/aqbanking/gnc-ab-trans-templ.c new file mode 100644 index 0000000000..96d70c7aca --- /dev/null +++ b/src/import-export/aqbanking/gnc-ab-trans-templ.c @@ -0,0 +1,285 @@ +/* + * gnc-ab-trans-templ.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-ab-trans-templ.c + * @brief Templates for AqBanking transactions + * @author Copyright (C) 2002 Christian Stimming + * @author Copyright (C) 2008 Andreas Koehler + */ + +#include "config.h" + +#include "gnc-ab-trans-templ.h" + +/* This static indicates the debugging module that this .o belongs to. */ +static QofLogModule log_module = G_LOG_DOMAIN; + +/* kvp_frame slot names */ +#define TT_NAME "name" +#define TT_RNAME "rnam" +#define TT_RACC "racc" +#define TT_RBCODE "rbcd" +#define TT_PURPOS "purp" +#define TT_PURPOSCT "purc" +#define TT_AMOUNT "amou" + +struct _GncABTransTempl +{ + /* Name of this Template */ + gchar *name; + gchar *name_key; /* Collation key */ + + /* Recipient */ + gchar *recp_name; + gchar *recp_account; + gchar *recp_bankcode; + + /* Amount */ + gnc_numeric amount; + + /* Purpose, description */ + gchar *purpose; + gchar *purpose_cont; +}; + + +GncABTransTempl * +gnc_ab_trans_templ_new(void) +{ + return gnc_ab_trans_templ_new_full(NULL, NULL, NULL, NULL, + gnc_numeric_zero(), NULL, NULL); +} + +GncABTransTempl * +gnc_ab_trans_templ_new_full(const char *name, const char *recp_name, + const char *recp_account, const char *recp_bankcode, + gnc_numeric amount, const char *purpose, + const char *purpose_cont) +{ + GncABTransTempl *r = g_new(GncABTransTempl, 1); + r->name = g_strdup(name); + r->name_key = g_utf8_collate_key(name, -1); + r->recp_name = g_strdup(recp_name); + r->recp_account = g_strdup(recp_account); + r->recp_bankcode = g_strdup(recp_bankcode); + r->amount = amount; + r->purpose = g_strdup(purpose); + r->purpose_cont = g_strdup(purpose_cont); + + return r; +} + +GncABTransTempl * +gnc_ab_trans_templ_new_from_kvp(const kvp_frame *k) +{ + g_return_val_if_fail(k, NULL); + + return gnc_ab_trans_templ_new_full( + kvp_value_get_string(kvp_frame_get_slot(k, TT_NAME)), + kvp_value_get_string(kvp_frame_get_slot(k, TT_RNAME)), + kvp_value_get_string(kvp_frame_get_slot(k, TT_RACC)), + kvp_value_get_string(kvp_frame_get_slot(k, TT_RBCODE)), + kvp_value_get_numeric(kvp_frame_get_slot(k, TT_AMOUNT)), + kvp_value_get_string(kvp_frame_get_slot(k, TT_PURPOS)), + kvp_value_get_string(kvp_frame_get_slot(k, TT_PURPOSCT))); +} + +GList * +gnc_ab_trans_templ_list_new_from_kvp_list(GList *v) +{ + GList *res = NULL; + GList *iter; + + for (iter = v; iter; iter = iter->next) { + kvp_frame *frame = kvp_value_get_frame((kvp_value*) iter->data); + res = g_list_prepend(res, gnc_ab_trans_templ_new_from_kvp(frame)); + } + res = g_list_reverse(res); + + return res; +} + +void +gnc_ab_trans_templ_free(GncABTransTempl *t) +{ + if (!t) return; + g_free(t->name); + g_free(t->name_key); + g_free(t->recp_name); + g_free(t->recp_account); + g_free(t->recp_bankcode); + g_free(t->purpose); + g_free(t->purpose_cont); + g_free(t); +} + +void +gnc_ab_trans_templ_list_free(GList *l) +{ + GList *iter; + for (iter = l; iter; iter = iter->next) + gnc_ab_trans_templ_free((GncABTransTempl*) iter->data); + g_list_free(l); +} + +kvp_frame * +gnc_ab_trans_templ_to_kvp(const GncABTransTempl *t) +{ + kvp_frame *k; + + g_return_val_if_fail(t, NULL); + + k = kvp_frame_new(); + kvp_frame_set_slot(k, TT_NAME, kvp_value_new_string(t->name)); + kvp_frame_set_slot(k, TT_RNAME, kvp_value_new_string(t->recp_name)); + kvp_frame_set_slot(k, TT_RACC, kvp_value_new_string(t->recp_account)); + kvp_frame_set_slot(k, TT_RBCODE, kvp_value_new_string(t->recp_bankcode)); + kvp_frame_set_slot(k, TT_AMOUNT, kvp_value_new_gnc_numeric(t->amount)); + kvp_frame_set_slot(k, TT_PURPOS, kvp_value_new_string(t->purpose)); + kvp_frame_set_slot(k, TT_PURPOSCT, kvp_value_new_string(t->purpose_cont)); + + return k; +} + +GList * +gnc_ab_trans_templ_list_to_kvp_list(GList *k) +{ + GList *res = NULL; + GList *iter; + + for (iter = k; iter; iter = iter->next) { + GncABTransTempl *t = (GncABTransTempl*) iter->data; + kvp_value *value = kvp_value_new_frame_nc(gnc_ab_trans_templ_to_kvp(t)); + res = g_list_prepend(res, value); + } + res = g_list_reverse(res); + + return res; +} + +const gchar * +gnc_ab_trans_templ_get_name(const GncABTransTempl *t) +{ + g_return_val_if_fail(t, NULL); + return t->name; +} + +const gchar * +gnc_ab_trans_templ_get_recp_name(const GncABTransTempl *t) +{ + g_return_val_if_fail(t, NULL); + return t->recp_name; +} + +const gchar * +gnc_ab_trans_templ_get_recp_account(const GncABTransTempl *t) +{ + g_return_val_if_fail(t, NULL); + return t->recp_account; +} + +const gchar * +gnc_ab_trans_templ_get_recp_bankcode(const GncABTransTempl *t) +{ + g_return_val_if_fail(t, NULL); + return t->recp_bankcode; +} + +gnc_numeric +gnc_ab_trans_templ_get_amount(const GncABTransTempl *t) +{ + g_return_val_if_fail(t, gnc_numeric_zero()); + return t->amount; +} + +const gchar * +gnc_ab_trans_templ_get_purpose(const GncABTransTempl *t) +{ + g_return_val_if_fail(t, NULL); + return t->purpose; +} + +const gchar * +gnc_ab_trans_templ_get_purpose_cont(const GncABTransTempl *t) +{ + g_return_val_if_fail(t, NULL); + return t->purpose_cont; +} + +void +gnc_ab_trans_templ_set_name(GncABTransTempl *t, const gchar *name) +{ + g_return_if_fail(t); + g_free(t->name); + t->name = g_strdup(name); +} + +void +gnc_ab_trans_templ_set_recp_name(GncABTransTempl *t, const gchar *recp_name) +{ + g_return_if_fail(t); + g_free(t->recp_name); + t->recp_name = g_strdup(recp_name); +} + +void +gnc_ab_trans_templ_set_recp_account(GncABTransTempl *t, + const gchar *recp_account) +{ + g_return_if_fail(t); + g_free(t->recp_account); + t->recp_account = g_strdup(recp_account); +} + +void +gnc_ab_trans_templ_set_recp_bankcode(GncABTransTempl *t, + const gchar *recp_bankcode) +{ + g_return_if_fail(t); + g_free(t->recp_bankcode); + t->recp_bankcode = g_strdup(recp_bankcode); +} + +void +gnc_ab_trans_templ_set_amount(GncABTransTempl *t, gnc_numeric amount) +{ + g_return_if_fail(t); + t->amount = amount; +} + +void +gnc_ab_trans_templ_set_purpose(GncABTransTempl *t, const gchar *purpose) +{ + g_return_if_fail(t); + g_free(t->purpose); + t->purpose = g_strdup(purpose); +} + +void +gnc_ab_trans_templ_set_purpose_cont(GncABTransTempl *t, + const gchar *purpose_cont) +{ + g_return_if_fail(t); + g_free(t->purpose_cont); + t->purpose_cont = g_strdup(purpose_cont); +} diff --git a/src/import-export/aqbanking/gnc-ab-trans-templ.h b/src/import-export/aqbanking/gnc-ab-trans-templ.h new file mode 100644 index 0000000000..bb28c19c25 --- /dev/null +++ b/src/import-export/aqbanking/gnc-ab-trans-templ.h @@ -0,0 +1,221 @@ +/* + * gnc-ab-trans-templ.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-ab-trans-templ.h + * @brief Templates for AqBanking transactions + * @author Copyright (C) 2003 Christian Stimming + * @author Copyright (C) 2008 Andreas Koehler + */ + +#ifndef GNC_AB_TRANS_TEMPL_H +#define GNC_AB_TRANS_TEMPL_H + +#include + +#include "qof.h" + +G_BEGIN_DECLS + +/** A template for an AqBanking transaction */ +typedef struct _GncABTransTempl GncABTransTempl; + +/** + * Create a template with unset contents. + * + * @return A newly allocated GncABTransTempl + */ +GncABTransTempl *gnc_ab_trans_templ_new(void); + +/** + * Create a template with given contents. + * + * @param name Name of the template + * @param recp_name Name of the recipient + * @param recp_account Account Number of the recipient + * @param recp_bankcode Bank Code of the recipient + * @param amount Amount + * @param purpose First purpose line + * @param purpose_cont Second purpose line + * @return A newly allocated GncABTransTempl + */ +GncABTransTempl *gnc_ab_trans_templ_new_full( + const gchar *name, const gchar *recp_name, const gchar *recp_account, + const gchar *recp_bankcode, gnc_numeric amount, const gchar *purpose, + const gchar *purpose_cont); + +/** + * Create a template, taking the values from a kvp_frame. + * + * @param k kvp_frame + * @return A newly allocated GncABTransTempl + */ +GncABTransTempl *gnc_ab_trans_templ_new_from_kvp(const kvp_frame *k); + +/** + * Create a list of templates from a list of kvp_values which in turn + * contain a kvp_frame. + * + * @param v GList of kvp_values + * @return A GList of newly allocated GncABTransTempls + */ +GList *gnc_ab_trans_templ_list_new_from_kvp_list(GList *v); + +/** + * Free the memory used by a template. + * + * @param t GncABTransTempl to be freed + */ +void gnc_ab_trans_templ_free(GncABTransTempl *t); + +/** + * Free the memory used by a list of templates, including the list itself. + * + * @param l GList of GncABTransTempl + */ +void gnc_ab_trans_templ_list_free(GList *l); + +/** + * Create a kvp_frame a given template. + * + * @param t Template + * @return A newly allocated kvp_frame + */ +kvp_frame *gnc_ab_trans_templ_to_kvp(const GncABTransTempl *t); + +/** + * Create a list of kvp_values, which in turn contain a kvp_frame, from a list + * of templates. + * + * @param k GList of GncABTransTempls + * @return GList of newly allocated kvp_values + */ +GList *gnc_ab_trans_templ_list_to_kvp_list(GList *k); + +/** + * @param t Template + * @return Name of the template, an internal string + */ +const gchar *gnc_ab_trans_templ_get_name(const GncABTransTempl *t); + +/** + * @param t Template + * @return Name of the recipient, an internal string + */ +const gchar *gnc_ab_trans_templ_get_recp_name(const GncABTransTempl *t); + +/** + * @param t Template + * @return Account Number of the recipient, an internal string + */ +const gchar *gnc_ab_trans_templ_get_recp_account(const GncABTransTempl *t); + +/** + * @param t Template + * @return Bank Code of the recipient, an internal string + */ +const gchar *gnc_ab_trans_templ_get_recp_bankcode(const GncABTransTempl *t); + +/** + * @param t Template + * @return Amount + */ +gnc_numeric gnc_ab_trans_templ_get_amount(const GncABTransTempl *t); + +/** + * @param t Template + * @return First purpose line, an internal string + */ +const gchar *gnc_ab_trans_templ_get_purpose(const GncABTransTempl *t); + +/** + * @param t Template + * @return Second purpose line, an internal string + */ +const gchar *gnc_ab_trans_templ_get_purpose_cont(const GncABTransTempl *t); + +/** + * Set the name of a template. + * + * @param t Template + * @param name Name + */ +void gnc_ab_trans_templ_set_name(GncABTransTempl *t, const gchar *name); + +/** + * Replace the Account Number of the recipient stored in a template. + * + * @param t Template + * @param recp_name Account Number of the recipient + */ +void gnc_ab_trans_templ_set_recp_name(GncABTransTempl *t, + const gchar *recp_name); + +/** + * Replace the Account Number of the recipient stored in a template. + * + * @param t Template + * @param recp_account Account Number of the recipient + */ +void gnc_ab_trans_templ_set_recp_account(GncABTransTempl *t, + const gchar *recp_account); + +/** + * Replace the Bank Code of the recipient stored in a template. + * + * @param t Template + * @param recp_bankcode Bank Code of the recipient + */ +void gnc_ab_trans_templ_set_recp_bankcode(GncABTransTempl *t, + const gchar *recp_bankcode); + +/** + * Replace the amount stored in a template. + * + * @param t Template + * @param amount Amount + */ +void gnc_ab_trans_templ_set_amount(GncABTransTempl *t, gnc_numeric amount); + +/** + * Replace the first purpose line stored in a template. + * + * @param t Template + * @param purpose First purpose line + */ +void gnc_ab_trans_templ_set_purpose(GncABTransTempl *t, const gchar *purpose); + +/** + * Replace the second purpose line stored in a template. + * + * @param t Template + * @param purpose_cont Second purpose line + */ +void gnc_ab_trans_templ_set_purpose_cont(GncABTransTempl *t, + const gchar *purpose_cont); + +G_END_DECLS + +#endif /* GNC_AB_TRANS_TEMPL_H */ diff --git a/src/import-export/aqbanking/gnc-ab-transfer.c b/src/import-export/aqbanking/gnc-ab-transfer.c new file mode 100644 index 0000000000..c918f30499 --- /dev/null +++ b/src/import-export/aqbanking/gnc-ab-transfer.c @@ -0,0 +1,283 @@ +/* + * gnc-ab-transfer.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-ab-utils.c + * @brief AqBanking transfer functions + * @author Copyright (C) 2002 Christian Stimming + * @author Copyright (C) 2004 Bernd Wagner + * @author Copyright (C) 2006 David Hampton + * @author Copyright (C) 2008 Andreas Koehler + */ + +#include "config.h" + +#include +#include +#include + +#include "Transaction.h" +#include "dialog-transfer.h" +#include "gnc-ab-transfer.h" +#include "gnc-ab-kvp.h" +#include "gnc-ab-utils.h" +#include "gnc-ab-trans-templ.h" +#include "gnc-gwen-gui.h" +#include "gnc-ui.h" + +/* This static indicates the debugging module that this .o belongs to. */ +static QofLogModule log_module = G_LOG_DOMAIN; + +static void save_templates(GtkWidget *parent, Account *gnc_acc, GList *templates, + gboolean dont_ask); +static void txn_created_cb(Transaction *trans, gpointer user_data); + +static void +save_templates(GtkWidget *parent, Account *gnc_acc, GList *templates, + gboolean dont_ask) +{ + g_return_if_fail(gnc_acc); + if (dont_ask || gnc_verify_dialog( + parent, FALSE, "%s", + _("You have changed the list of online transfer templates, " + "but you cancelled the transfer dialog. " + "Do you nevertheless want to store the changes?"))) { + GList *kvp_list = gnc_ab_trans_templ_list_to_kvp_list(templates); + gnc_ab_set_book_template_list(gnc_account_get_book(gnc_acc), kvp_list); + } +} + +static void +txn_created_cb(Transaction *trans, gpointer user_data) +{ + Transaction **trans_loc = user_data; + + if (!trans) return; + g_return_if_fail(trans_loc); + *trans_loc = trans; +} + +void +gnc_ab_maketrans(GtkWidget *parent, Account *gnc_acc, + GncABTransType trans_type) +{ + AB_BANKING *api; + gboolean online = FALSE; + AB_ACCOUNT *ab_acc; + GncABTransDialog *dialog = NULL; + GList *templates = NULL; + GncABTransDialog *td = NULL; + gboolean successful; + gboolean aborted = FALSE; + + g_return_if_fail(parent && gnc_acc); + + /* Get the API */ + api = gnc_AB_BANKING_new(); + if (!api) { + g_warning("gnc_ab_maketrans: Couldn't get AqBanking API"); + return; + } + if (AB_Banking_OnlineInit(api) != 0) { + g_warning("gnc_ab_maketrans: Couldn't initialize AqBanking API"); + goto cleanup; + } + online = TRUE; + + /* Get the AqBanking Account */ + ab_acc = gnc_ab_get_ab_account(api, gnc_acc); + if (!ab_acc) { + g_warning("gnc_ab_gettrans: No AqBanking account found"); + goto cleanup; + } + + /* Get list of template transactions */ + templates = gnc_ab_trans_templ_list_new_from_kvp_list( + gnc_ab_get_book_template_list(gnc_account_get_book(gnc_acc))); + + /* Create new ABTransDialog */ + td = gnc_ab_trans_dialog_new(parent, ab_acc, + xaccAccountGetCommoditySCU(gnc_acc), + trans_type, templates); + templates = NULL; + + /* Repeat until AqBanking action was successful or user pressed cancel */ + do { + GncGWENGui *gui = NULL; + gint result; + gboolean changed; + const AB_TRANSACTION *ab_trans; + AB_JOB *job = NULL; + AB_JOB_LIST2 *job_list = NULL; + XferDialog *xfer_dialog = NULL; + gnc_numeric amount; + gchar *description; + gchar *memo; + Transaction *gnc_trans = NULL; + + /* Get a GUI object */ + gui = gnc_GWEN_Gui_get(parent); + if (!gui) { + g_warning("gnc_ab_maketrans: Couldn't initialize Gwenhywfar GUI"); + aborted = TRUE; + goto repeat; + } + + /* Let the user enter the values */ + result = gnc_ab_trans_dialog_run_until_ok(td); + + if (result != GNC_RESPONSE_NOW && result != GNC_RESPONSE_LATER) { + aborted = TRUE; + goto repeat; + } + + /* Save the templates */ + templates = gnc_ab_trans_dialog_get_templ(td, &changed); + if (changed) + save_templates(parent, gnc_acc, templates, + (result == GNC_RESPONSE_NOW)); + g_list_free(templates); + templates = NULL; + + /* Get a job and enqueue it */ + ab_trans = gnc_ab_trans_dialog_get_ab_trans(td); + job = gnc_ab_trans_dialog_get_job(td); + if (!job || AB_Job_CheckAvailability(job, 0)) { + if (!gnc_verify_dialog( + parent, FALSE, "%s", + _("The backend found an error during the preparation " + "of the job. It is not possible to execute this job. \n" + "\n" + "Most probable the bank does not support your chosen " + "job or your Online Banking account does not have the permission " + "to execute this job. More error messages might be " + "visible on your console log.\n" + "\n" + "Do you want to enter the job again?"))) + aborted = TRUE; + goto repeat; + } + job_list = AB_Job_List2_new(); + AB_Job_List2_PushBack(job_list, job); + + /* Setup a Transfer Dialog for the GnuCash transaction */ + xfer_dialog = gnc_xfer_dialog(gnc_ab_trans_dialog_get_parent(td), + gnc_acc); + switch (trans_type) { + case SINGLE_DEBITNOTE: + gnc_xfer_dialog_set_title( + xfer_dialog, _("Online Banking Direct Debit Note")); + gnc_xfer_dialog_lock_to_account_tree(xfer_dialog); + break; + case SINGLE_INTERNAL_TRANSFER: + gnc_xfer_dialog_set_title( + xfer_dialog, _("Online Banking Bank-Internal Transfer")); + gnc_xfer_dialog_lock_from_account_tree(xfer_dialog); + break; + case SINGLE_TRANSFER: + default: + gnc_xfer_dialog_set_title( + xfer_dialog, _("Online Banking Transaction")); + gnc_xfer_dialog_lock_from_account_tree(xfer_dialog); + } + + amount = double_to_gnc_numeric( + AB_Value_GetValueAsDouble(AB_Transaction_GetValue(ab_trans)), + xaccAccountGetCommoditySCU(gnc_acc), + GNC_RND_ROUND); + gnc_xfer_dialog_set_amount(xfer_dialog, amount); + + description = gnc_ab_description_to_gnc(ab_trans); + gnc_xfer_dialog_set_description(xfer_dialog, description); + g_free(description); + + memo = gnc_ab_memo_to_gnc(ab_trans); + gnc_xfer_dialog_set_memo(xfer_dialog, memo); + g_free(memo); + + gnc_xfer_dialog_set_txn_cb(xfer_dialog, txn_created_cb, &gnc_trans); + + /* And run it */ + successful = gnc_xfer_dialog_run_until_done(xfer_dialog); + + /* On cancel, go back to the AB transaction dialog */ + if (!successful || !gnc_trans) { + successful = FALSE; + goto repeat; + } + + if (result == GNC_RESPONSE_NOW) { + /* Finally, execute the job */ + successful = AB_Banking_ExecuteJobs(api, job_list, NULL, 0) == 0; + + if (!successful + || AB_Job_GetStatus(job) != AB_Job_StatusFinished) { + successful = FALSE; + if (!gnc_verify_dialog( + parent, FALSE, "%s", + _("An error occurred while executing the job. Please check " + "the log window for the exact error message.\n" + "\n" + "Do you want to enter the job again?"))) { + /* _("The job was sent to the bank successfully, but the " */ + /* "bank is refusing to execute the job. Please check " */ + /* "the log window for the exact error message of the " */ + /* "bank. The line with the error message contains a " */ + /* "code number that is greater than 9000.\n" */ + /* "\n" */ + /* "Do you want to enter the job again?"))) { */ + aborted = TRUE; + } + } + } + /* Simply ignore any other case */ + + repeat: + /* Clean up */ + if (gnc_trans && !successful) { + xaccTransBeginEdit(gnc_trans); + xaccTransDestroy(gnc_trans); + xaccTransCommitEdit(gnc_trans); + gnc_trans = NULL; + } + if (job_list) { + AB_Job_List2_free(job_list); + job_list = NULL; + } + if (job) { + AB_Job_free(job); + job = NULL; + } + if (gui) { + gnc_GWEN_Gui_release(gui); + gui = NULL; + } + + } while (!successful && !aborted); + +cleanup: + if (td) + gnc_ab_trans_dialog_free(td); + if (online) + AB_Banking_OnlineFini(api); + gnc_AB_BANKING_fini(api); +} diff --git a/src/import-export/aqbanking/gnc-ab-transfer.h b/src/import-export/aqbanking/gnc-ab-transfer.h new file mode 100644 index 0000000000..9f57a147ef --- /dev/null +++ b/src/import-export/aqbanking/gnc-ab-transfer.h @@ -0,0 +1,58 @@ +/* + * gnc-ab-transfer.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-ab-transfer.h + * @brief Dialog for AqBanking transaction data + * @author Copyright (C) 2002 Christian Stimming + * @author Copyright (C) 2008 Andreas Koehler + */ + +#ifndef GNC_AB_TRANSFER_H +#define GNC_AB_TRANSFER_H + +#include + +#include "Account.h" +#include "dialog-ab-trans.h" + +G_BEGIN_DECLS + +/** + * FIXME + * + * @param parent Widget to use as parent, may be NULL + * @param gnc_acc GnuCash account to fetch balance for + * @param trans_type Type of transaction + */ +void gnc_ab_maketrans(GtkWidget *parent, Account *gnc_acc, + GncABTransType trans_type); + +G_END_DECLS + +/** @} */ +/** @} */ + +#endif /* GNC_AB_TRANSFER_H */ diff --git a/src/import-export/aqbanking/gnc-ab-utils.c b/src/import-export/aqbanking/gnc-ab-utils.c new file mode 100644 index 0000000000..289bb9121d --- /dev/null +++ b/src/import-export/aqbanking/gnc-ab-utils.c @@ -0,0 +1,414 @@ +/* + * gnc-ab-utils.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-ab-utils.c + * @brief AqBanking utility functions + * @author Copyright (C) 2002 Christian Stimming + * @author Copyright (C) 2008 Andreas Koehler + */ + +#include "config.h" + +#include +#include +#include + +#include "Transaction.h" +#include "gnc-ab-kvp.h" +#include "gnc-ab-utils.h" +#include "gnc-glib-utils.h" +#include "gnc-gwen-gui.h" +#include "import-utilities.h" +#include "qof.h" + +/* This static indicates the debugging module that this .o belongs to. */ +static QofLogModule log_module = G_LOG_DOMAIN; + +/* Global variables for AB_BANKING caching. */ +static AB_BANKING *gnc_AB_BANKING = NULL; +static gint gnc_AB_BANKING_refcount = 0; + +static gpointer join_ab_strings_cb(const gchar *str, gpointer user_data); + +void +gnc_GWEN_Init(void) +{ + gint i; + + /* Initialize gwen library */ + GWEN_Init(); + + /* Initialize gwen logging */ + GWEN_Logger_SetLevel(NULL, GWEN_LoggerLevel_Debug); + GWEN_Logger_SetLevel(GWEN_LOGDOMAIN, GWEN_LoggerLevel_Debug); + GWEN_Logger_SetLevel(AQBANKING_LOGDOMAIN, GWEN_LoggerLevel_Debug); + gnc_GWEN_Gui_log_init(); +} + +void +gnc_GWEN_Fini(void) +{ + /* Shutdown the GWEN_GUIs */ + gnc_GWEN_Gui_shutdown(); + GWEN_Logger_SetLevel(NULL, GWEN_LoggerLevel_Warning); + GWEN_Logger_SetLevel(GWEN_LOGDOMAIN, GWEN_LoggerLevel_Warning); + GWEN_Logger_SetLevel(AQBANKING_LOGDOMAIN, GWEN_LoggerLevel_Warning); + + /* Finalize gwen library */ + GWEN_Fini(); +} + +AB_BANKING * +gnc_AB_BANKING_new(void) +{ + AB_BANKING *api; + + if (gnc_AB_BANKING) { + /* API cached. */ + api = gnc_AB_BANKING; + + /* Init the API again. */ + if (gnc_AB_BANKING_refcount == 0) + g_return_val_if_fail(AB_Banking_Init(api) == 0, NULL); + + } else { + api = AB_Banking_new("gnucash", NULL, 0); + g_return_val_if_fail(api, NULL); + + /* Init the API */ + g_return_val_if_fail(AB_Banking_Init(api) == 0, NULL); + + /* Cache it */ + gnc_AB_BANKING = api; + gnc_AB_BANKING_refcount = 0; + } + + gnc_AB_BANKING_refcount++; + + return api; +} + +void +gnc_AB_BANKING_delete(AB_BANKING *api) +{ + if (!api) + api = gnc_AB_BANKING; + + if (api) { + if (api == gnc_AB_BANKING) { + gnc_AB_BANKING = NULL; + if (gnc_AB_BANKING_refcount > 0) + AB_Banking_Fini(api); + } + + AB_Banking_free(api); + } +} + + +gint +gnc_AB_BANKING_fini(AB_BANKING *api) +{ + if (api == gnc_AB_BANKING) { + if (--gnc_AB_BANKING_refcount == 0) + return AB_Banking_Fini(api); + } else { + return AB_Banking_Fini(api); + } + return 0; +} + +AB_ACCOUNT * +gnc_ab_get_ab_account(const AB_BANKING *api, Account *gnc_acc) +{ + AB_ACCOUNT *ab_account = NULL; + const gchar *bankcode = NULL; + const gchar *accountid = NULL; + guint32 account_uid = 0; + + bankcode = gnc_ab_get_account_bankcode(gnc_acc); + accountid = gnc_ab_get_account_accountid(gnc_acc); + account_uid = gnc_ab_get_account_uid (gnc_acc); + + if (account_uid > 0) { + ab_account = AB_Banking_GetAccount(api, account_uid); + + if (!ab_account && bankcode && *bankcode && accountid && *accountid) { + g_message("gnc_ab_get_ab_account: No AB_ACCOUNT found for UID %d, " + "trying bank code\n", account_uid); + ab_account = AB_Banking_GetAccountByCodeAndNumber(api, bankcode, + accountid); + } + return ab_account; + + } else if (bankcode && *bankcode && accountid && *accountid) { + ab_account = AB_Banking_GetAccountByCodeAndNumber(api, bankcode, + accountid); + return ab_account; + } + + return NULL; +} + +gchar * +gnc_AB_VALUE_to_readable_string(const AB_VALUE *value) +{ + if (value) + return g_strdup_printf("%.2f %s", + AB_Value_GetValueAsDouble(value), + AB_Value_GetCurrency(value)); + else + return g_strdup_printf("%.2f", 0.0); +} + +/** + * Take a string from a GWEN_STRINGLIST, strip invalid utf8 and join it + * to the rest. + */ +static gpointer +join_ab_strings_cb(const gchar *str, gpointer user_data) +{ + gchar **acc = user_data; + gchar *tmp; + + if (!str || !*str) + return NULL; + + tmp = g_strdup(str); + g_strstrip(tmp); + gnc_utf8_strip_invalid(tmp); + + if (*acc) { + gchar *join = g_strjoin(" ", *acc, tmp, (gchar*) NULL); + g_free(*acc); + g_free(tmp); + *acc = join; + } else { + *acc = tmp; + } + return NULL; +} + +gchar * +gnc_ab_get_remote_name(const AB_TRANSACTION *ab_trans) +{ + const GWEN_STRINGLIST *ab_remote_name; + gchar *gnc_other_name = NULL; + + g_return_val_if_fail(ab_trans, NULL); + + ab_remote_name = AB_Transaction_GetPurpose(ab_trans); + if (ab_remote_name) + GWEN_StringList_ForEach(ab_remote_name, join_ab_strings_cb, + &gnc_other_name); + + if (!gnc_other_name || !*gnc_other_name) { + g_free(gnc_other_name); + gnc_other_name = NULL; + } + + return gnc_other_name; +} + +gchar * +gnc_ab_get_purpose(const AB_TRANSACTION *ab_trans) +{ + const GWEN_STRINGLIST *ab_purpose; + gchar *gnc_description = NULL; + + g_return_val_if_fail(ab_trans, g_strdup("")); + + ab_purpose = AB_Transaction_GetPurpose(ab_trans); + if (ab_purpose) + GWEN_StringList_ForEach(ab_purpose, join_ab_strings_cb, + &gnc_description); + + if (!gnc_description) + gnc_description = g_strdup(""); + + return gnc_description; +} + +gchar * +gnc_ab_description_to_gnc(const AB_TRANSACTION *ab_trans) +{ + /* Description */ + gchar *description = gnc_ab_get_purpose(ab_trans); + gchar *other_name = gnc_ab_get_remote_name(ab_trans); + gchar *retval; + + if (other_name) { + if (description && *description) { + retval = g_strdup_printf("%s; %s", description, other_name); + } else { + retval = g_strdup(other_name); + } + } else { + if (description && *description) { + retval = g_strdup(description); + } else { + retval = g_strdup(_("Unspecified")); + } + } + g_free(description); + g_free(other_name); + + return retval; +} + +gchar * +gnc_ab_memo_to_gnc(const AB_TRANSACTION *ab_trans) +{ + const gchar *ab_remote_accountnumber = + AB_Transaction_GetRemoteAccountNumber(ab_trans); + const gchar *ab_remote_bankcode = + AB_Transaction_GetRemoteBankCode(ab_trans); + gchar *ab_other_accountid = + g_strdup(ab_remote_accountnumber ? ab_remote_accountnumber + : _("unknown")); + gchar *ab_other_bankcode = + g_strdup(ab_remote_bankcode ? ab_remote_bankcode + : _("unknown")); + gchar *retval; + + g_strstrip(ab_other_accountid); + g_strstrip(ab_other_bankcode); + /* Ensure string is in utf8 */ + gnc_utf8_strip_invalid(ab_other_accountid); + gnc_utf8_strip_invalid(ab_other_bankcode); + + if (ab_other_accountid && *ab_other_accountid) { + retval = g_strdup_printf("%s %s %s %s", + _("Account"), ab_other_accountid, + _("Bank"), ab_other_bankcode); + } else { + retval = g_strdup(""); + } + g_free(ab_other_accountid); + g_free(ab_other_bankcode); + + return retval; +} + +Transaction * +gnc_ab_trans_to_gnc(const AB_TRANSACTION *ab_trans, Account *gnc_acc) +{ + QofBook *book; + Transaction *gnc_trans; + const gchar *fitid; + const GWEN_TIME *valuta_date; + time_t current_time; + const char *custref; + gchar *description; + Split *split; + const AB_VALUE *ab_value; + gnc_numeric gnc_amount; + gchar *memo; + + g_return_val_if_fail(ab_trans && gnc_acc, NULL); + + /* Create new GnuCash transaction for the given AqBanking one */ + book = gnc_account_get_book(gnc_acc); + gnc_trans = xaccMallocTransaction(book); + xaccTransBeginEdit(gnc_trans); + + /* Set OFX unique transaction ID */ + fitid = AB_Transaction_GetFiId(ab_trans); + if (fitid && *fitid) + gnc_import_set_trans_online_id(gnc_trans, fitid); + + /* Date / Time */ + valuta_date = AB_Transaction_GetValutaDate(ab_trans); + if (!valuta_date) { + const GWEN_TIME *normal_date = AB_Transaction_GetDate(ab_trans); + if (normal_date) + valuta_date = normal_date; + } + if (valuta_date) + xaccTransSetDateSecs(gnc_trans, GWEN_Time_toTime_t(valuta_date)); + else + g_warning("transaction_cb: Oops, date 'valuta_date' was NULL"); + + current_time = time(NULL); + xaccTransSetDateEnteredSecs(gnc_trans, mktime(localtime(¤t_time))); + + /* Currency. We take simply the default currency of the gnucash account */ + xaccTransSetCurrency(gnc_trans, xaccAccountGetCommodity(gnc_acc)); + + /* Number. We use the "customer reference", if there is one. */ + custref = AB_Transaction_GetCustomerReference(ab_trans); + if (custref && *custref + && g_ascii_strncasecmp(custref, "NONREF", 6) != 0) + xaccTransSetNum(gnc_trans, custref); + + /* Description */ + description = gnc_ab_description_to_gnc(ab_trans); + xaccTransSetDescription(gnc_trans, description); + g_free(description); + + /* Notes. */ + /* xaccTransSetNotes(gnc_trans, g_notes); */ + /* But Nobody ever uses the Notes field? */ + + /* Add one split */ + split = xaccMallocSplit(book); + xaccSplitSetParent(split, gnc_trans); + xaccSplitSetAccount(split, gnc_acc); + + /* Amount into the split */ + ab_value = AB_Transaction_GetValue(ab_trans); + gnc_amount = double_to_gnc_numeric( + ab_value ? AB_Value_GetValueAsDouble(ab_value) : 0.0, + xaccAccountGetCommoditySCU(gnc_acc), + GNC_RND_ROUND); + if (!ab_value) + g_warning("transaction_cb: Oops, value was NULL. Using 0"); + xaccSplitSetBaseValue(split, gnc_amount, xaccAccountGetCommodity(gnc_acc)); + + /* Memo in the Split. */ + memo = gnc_ab_memo_to_gnc(ab_trans); + xaccSplitSetMemo(split, memo); + g_free(memo); + + return gnc_trans; +} + +AB_ACCOUNT_STATUS * +gnc_ab_get_best_accountstatus(AB_IMEXPORTER_ACCOUNTINFO *acc_info) +{ + AB_ACCOUNT_STATUS *item, *best = NULL; + const GWEN_TIME *best_time; + + g_return_val_if_fail(acc_info, NULL); + + item = AB_ImExporterAccountInfo_GetFirstAccountStatus(acc_info); + while (item) { + const GWEN_TIME *item_time = AB_AccountStatus_GetTime(item); + if (!best || GWEN_Time_Diff(best_time, item_time) < 0.0) { + best = item; + best_time = item_time; + } + item = AB_ImExporterAccountInfo_GetNextAccountStatus(acc_info); + } + return best; +} diff --git a/src/import-export/aqbanking/gnc-ab-utils.h b/src/import-export/aqbanking/gnc-ab-utils.h new file mode 100644 index 0000000000..5811cf1698 --- /dev/null +++ b/src/import-export/aqbanking/gnc-ab-utils.h @@ -0,0 +1,174 @@ +/* + * gnc-ab-utils.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-ab-utils.h + * @brief AqBanking utility functions + * @author Copyright (C) 2002 Christian Stimming + * @author Copyright (C) 2008 Andreas Koehler + */ + +#ifndef GNC_AB_UTILS_H +#define GNC_AB_UTILS_H + +#include +#include + +#include "Account.h" + +G_BEGIN_DECLS + +#define GCONF_SECTION_AQBANKING "dialogs/import/hbci" +#define KEY_FORMAT_SWIFT940 "format_swift_mt940" +#define KEY_FORMAT_SWIFT942 "format_swift_mt942" +#define KEY_FORMAT_DTAUS "format_dtaus" + +/** + * Initialize the gwenhywfar library by calling GWEN_Init() and setting up + * gwenhywfar logging. + */ +void gnc_GWEN_Init(void); + +/** + * Finalize the gwenhywfar library. + */ +void gnc_GWEN_Fini(void); + +/** + * If there is a cached AB_BANKING object, return it initialized. Otherwise, + * create a new AB_BANKING, let it load its environment from its default + * configuration and cache it. + * + * @return The AB_BANKING object + */ +AB_BANKING *gnc_AB_BANKING_new(void); + +/** + * Delete the AB_BANKING @a api. If this is also the one that was cached by + * gnc_AB_BANKING_new(), then all references are deleted, too. + * + * @param api AB_BANKING or NULL for the cached AB_BANKING object + */ +void gnc_AB_BANKING_delete(AB_BANKING *api); + +/** + * Finish the AB_BANKING @a api. If this is also the one that was cached by + * gnc_AB_BANKING_new(), then finish only if the decremented reference count + * reaches zero. After this call, you may only call gnc_AB_BANKING_new() to get + * the api again in a properly initialized state. + * + * @param api AB_BANKING object + * @return Zero on success + */ +gint gnc_AB_BANKING_fini(AB_BANKING *api); + +/** + * Get the corresponding AqBanking account to the GnuCash account @a gnc_acc. + * Of course this only works after the GnuCash account has been set up for + * AqBanking use, i.e. the kvp_frame "hbci/..." has been filled with + * information. + * + * @param api The AB_BANKING to get the AB_ACCOUNT from + * @param gnc_acc The GnuCash account to query for AB_ACCOUNT reference data + * @return The AB_ACCOUNT found or NULL otherwise + */ +AB_ACCOUNT *gnc_ab_get_ab_account(const AB_BANKING *api, Account *gnc_acc); + +/** + * Print the value of @a value with two decimal places and @a value's + * currency appended, or 0.0 otherwise + * + * @param value AB_VALUE or NULL + * @return A newly allocated string + */ +gchar *gnc_AB_VALUE_to_readable_string(const AB_VALUE *value); + +/** + * Retrieve the merged "remote name" fields from a transaction. The returned + * string must be g_free'd by the caller. If there was no "remote name" field, + * NULL (!) is returned. + * + * @param ab_trans AqBanking transaction + * @return A newly allocated string or NULL otherwise + */ +gchar *gnc_ab_get_remote_name(const AB_TRANSACTION *ab_trans); + +/** + * Retrieve the merged purpose fields from a transaction. The returned string + * must be g_free'd by the caller. If there was no purpose, an empty (but + * allocated) string is returned. + * + * @param ab_trans AqBanking transaction + * @return A newly allocated string, may be "" + */ +gchar *gnc_ab_get_purpose(const AB_TRANSACTION *ab_trans); + +/** + * Create the appropriate description field for a GnuCash Transaction by the + * information given in the AB_TRANSACTION @a ab_trans. The returned string + * must be g_free'd by the caller. + * + * @param ab_trans AqBanking transaction + * @return A newly allocated string, may be "" + */ +gchar *gnc_ab_description_to_gnc(const AB_TRANSACTION *ab_trans); + +/** + * Create the appropriate memo field for a GnuCash Split by the information + * given in the AB_TRANSACTION @a ab_trans. The returned string must be + * g_free'd by the caller. + * + * @param ab_trans AqBanking transaction + * @return A newly allocated string, may be "" + */ +gchar *gnc_ab_memo_to_gnc(const AB_TRANSACTION *ab_trans); + +/** + * Create an unbalanced and dirty GnuCash transaction with a split to @a gnc_acc + * from the information available in the AqBanking transaction @a ab_trans. + * + * @param ab_trans AqBanking transaction + * @param gnc_acc Account of to use for the split + * @return A dirty GnuCash transaction or NULL otherwise + */ +Transaction *gnc_ab_trans_to_gnc(const AB_TRANSACTION *ab_trans, Account *gnc_acc); + +/** + * Lookup the most recent ACCOUNT_STATUS available in an ACCOUNTINFO as + * extracted from an IMEXPORTER_CONTEXT. This can be used to determine the + * reported account balance most up-to-date. + * + * @param acc_info ACCOUNTINFO + * @return An AB_ACCOUNT_STATUS internal to @a acc_info, or NULL otherwise + */ +AB_ACCOUNT_STATUS *gnc_ab_get_best_accountstatus( + AB_IMEXPORTER_ACCOUNTINFO *acc_info); + +G_END_DECLS + +/** @} */ +/** @} */ + +#endif /* GNC_AB_UTILS_H */ diff --git a/src/import-export/aqbanking/gnc-file-aqb-import.c b/src/import-export/aqbanking/gnc-file-aqb-import.c new file mode 100644 index 0000000000..9027ef3729 --- /dev/null +++ b/src/import-export/aqbanking/gnc-file-aqb-import.c @@ -0,0 +1,344 @@ +/* + * gnc-file-aqb-import.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-file-aqb-import.c + * @brief DTAUS import module code + * @author Copyright (C) 2002 Benoit Grégoire + * @author Copyright (C) 2003 Jan-Pascal van Best + * @author Copyright (C) 2006 Florian Steinel + * @author Copyright (C) 2006 Christian Stimming + * @author Copyright (C) 2008 Andreas Koehler + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include "dialog-ab-trans.h" +#include "gnc-ab-utils.h" +#include "gnc-file.h" +#include "gnc-file-aqb-import.h" +#include "gnc-gwen-gui.h" +#include "gnc-ui.h" +#include "gnc-ui-util.h" +#include "import-account-matcher.h" +#include "import-main-matcher.h" + +/* This static indicates the debugging module that this .o belongs to. */ +static QofLogModule log_module = GNC_MOD_IMPORT; + +typedef struct _ImportData ImportData; + +static const AB_TRANSACTION *transaction_cb( + const AB_TRANSACTION *element, gpointer user_data); +static AB_IMEXPORTER_ACCOUNTINFO *accountinfo_cb( + AB_IMEXPORTER_ACCOUNTINFO *element, gpointer user_data); +static AB_JOB_LIST2 *import_context( + AB_BANKING *api, AB_IMEXPORTER_CONTEXT *context, + GNCImportMainMatcher *importer_generic_gui, gboolean execute_transactions); + +struct _ImportData { + AB_BANKING *api; + GNCImportMainMatcher *importer_generic; + gboolean execute_transactions; + AB_JOB_LIST2 *job_list; + Account *gnc_acc; + AB_ACCOUNT *ab_acc; +}; + +static const AB_TRANSACTION * +transaction_cb(const AB_TRANSACTION *element, gpointer user_data) +{ + ImportData *data = user_data; + Transaction *gnc_trans; + AB_JOB *job; + + g_return_val_if_fail(element && data, NULL); + + /* Create a GnuCash transaction from ab_trans */ + gnc_trans = gnc_ab_trans_to_gnc(element, data->gnc_acc); + + /* Instead of xaccTransCommitEdit(gnc_trans) */ + gnc_gen_trans_list_add_trans(data->importer_generic, gnc_trans); + + if (data->ab_acc) { + AB_TRANSACTION *ab_trans = AB_Transaction_dup(element); + + /* NEW: The imported transaction has been imported into gnucash. + * Now also add it as a job to aqbanking */ + AB_Transaction_SetLocalBankCode( + ab_trans, AB_Account_GetBankCode(data->ab_acc)); + AB_Transaction_SetLocalAccountNumber( + ab_trans, AB_Account_GetAccountNumber(data->ab_acc)); + AB_Transaction_SetLocalCountry(ab_trans, "DE"); + + job = gnc_ab_get_trans_job(data->ab_acc, ab_trans, SINGLE_DEBITNOTE); + + /* Check whether we really got a job */ + if (!job) { + /* Oops, no job, probably not supported by bank */ + if (gnc_verify_dialog( + NULL, FALSE, "%s", + _("The backend found an error during the preparation " + "of the job. It is not possible to execute this job. \n" + "\n" + "Most probable the bank does not support your chosen " + "job or your Online Banking account does not have the permission " + "to execute this job. More error messages might be " + "visible on your console log.\n" + "\n" + "Do you want to enter the job again?"))) { + gnc_error_dialog(NULL, "Sorry, not implemented yet."); + } + /* else */ + } + AB_Job_List2_PushBack(data->job_list, job); + + AB_Transaction_free(ab_trans); + } + + return NULL; +} + +static AB_IMEXPORTER_ACCOUNTINFO * +accountinfo_cb(AB_IMEXPORTER_ACCOUNTINFO *element, gpointer user_data) +{ + Account *gnc_acc; + ImportData *data = user_data; + const gchar *bank_code = + AB_ImExporterAccountInfo_GetBankCode(element); + const gchar *account_number = + AB_ImExporterAccountInfo_GetAccountNumber(element); + const gchar *account_name = + AB_ImExporterAccountInfo_GetAccountName(element); + gchar *online_id; + + g_return_val_if_fail(element && data, NULL); + + online_id = g_strconcat(bank_code, account_number, (gchar*)NULL); + gnc_acc = gnc_import_select_account(NULL, online_id, 1, account_name, NULL, + ACCT_TYPE_NONE, NULL, NULL); + g_free(online_id); + + if (gnc_acc) { + /* Store chosen gnucash account in callback data */ + data->gnc_acc = gnc_acc; + + if (data->execute_transactions) { + /* Retrieve the aqbanking account that belongs to this gnucash + * account */ + data->ab_acc = gnc_ab_get_ab_account(data->api, gnc_acc); + if (!data->ab_acc) { + gnc_error_dialog(NULL, "%s", + _("No Online Banking account found for this " + "gnucash account. These transactions will " + "not be executed by Online Banking.")); + } + } else { + data->ab_acc = NULL; + } + + /* Iterate through all transactions. */ + AB_ImExporterAccountInfo_TransactionsForEach(element, transaction_cb, + data); + } + return NULL; +} + +static AB_JOB_LIST2 * +import_context(AB_BANKING *api, AB_IMEXPORTER_CONTEXT *context, + GNCImportMainMatcher *importer_generic_gui, + gboolean execute_transactions) +{ + ImportData data; + + g_return_val_if_fail(api && context && importer_generic_gui, NULL); + data.api = api; + data.importer_generic = importer_generic_gui; + data.execute_transactions = execute_transactions; + data.job_list = NULL; + + /* Iterate through all accounts */ + AB_ImExporterContext_AccountInfoForEach(context, accountinfo_cb, &data); + + return data.job_list; +} + +void +gnc_file_aqbanking_import(const gchar *aqbanking_importername, + const gchar *aqbanking_profilename, + gboolean execute_transactions) +{ + gchar *default_dir; + gchar *selected_filename = NULL; + gint dtaus_fd = -1; + AB_BANKING *api = NULL; + gboolean online = FALSE; + GncGWENGui *gui = NULL; + AB_IMEXPORTER *importer; + GWEN_DB_NODE *db_profiles = NULL; + GWEN_DB_NODE *db_profile; + AB_IMEXPORTER_CONTEXT *context = NULL; + GWEN_IO_LAYER *io, *buffio; + GNCImportMainMatcher *importer_generic_gui = NULL; + AB_JOB_LIST2 *job_list = NULL; + + /* Select a file */ + default_dir = gnc_get_default_directory(GCONF_SECTION_AQBANKING); + selected_filename = gnc_file_dialog(_("Select a file to import"), + NULL, default_dir, + GNC_FILE_DIALOG_IMPORT); + g_free(default_dir); + + if (!selected_filename) + goto cleanup; + DEBUG("filename: %s", selected_filename); + + /* Remember the directory as the default */ + default_dir = g_path_get_dirname(selected_filename); + gnc_set_default_directory(GCONF_SECTION_AQBANKING, default_dir); + g_free(default_dir); + + dtaus_fd = g_open(selected_filename, O_RDONLY, 0); + if (dtaus_fd == -1) { + DEBUG("Could not open file %s", selected_filename); + goto cleanup; + } + + /* Get the API */ + api = gnc_AB_BANKING_new(); + if (!api) { + g_warning("gnc_file_aqbanking_import: Couldn't get AqBanking API"); + goto cleanup; + } + if (AB_Banking_OnlineInit(api) != 0) { + g_warning("gnc_file_aqbanking_import: " + "Couldn't initialize AqBanking API"); + goto cleanup; + } + online = TRUE; + + /* Get a GUI object */ + gui = gnc_GWEN_Gui_get(NULL); + if (!gui) { + g_warning("gnc_ab_getbalance: Couldn't initialize Gwenhywfar GUI"); + goto cleanup; + } + + /* Get import module */ + importer = AB_Banking_GetImExporter(api, aqbanking_importername); + if (!importer) { + g_warning("Import module %s not found", aqbanking_importername); + gnc_error_dialog(NULL, "%s", + _("Import module for DTAUS import not found.")); + goto cleanup; + } + + /* Load the import profile */ + db_profiles = AB_Banking_GetImExporterProfiles(api, aqbanking_importername); + + /* Select profile */ + db_profile = GWEN_DB_GetFirstGroup(db_profiles); + while (db_profile) { + const gchar *name; + + name = GWEN_DB_GetCharValue(db_profile, "name", 0, 0); + g_return_if_fail(name); + if (g_ascii_strcasecmp(name, aqbanking_profilename)==0) + break; + db_profile = GWEN_DB_GetNextGroup(db_profile); + } + if (!db_profile) { + g_warning("Profile \"%s\" for importer \"%s\" not found", + aqbanking_profilename, aqbanking_importername); + /* For debugging: Print those available names that have been found */ + db_profile = GWEN_DB_GetFirstGroup(db_profiles); + while (db_profile) { + const char *name = GWEN_DB_GetCharValue(db_profile, "name", 0, 0); + g_warning("Only found profile \"%s\"\n", name ? name : "(null)"); + db_profile = GWEN_DB_GetNextGroup(db_profile); + } + goto cleanup; + } + + /* Create a context to store the results */ + context = AB_ImExporterContext_new(); + + /* Wrap file in buffered gwen io */ + io = GWEN_Io_LayerFile_new(dtaus_fd, -1); + dtaus_fd = -1; + buffio = GWEN_Io_LayerBuffered_new(io); + if (GWEN_Io_Manager_RegisterLayer(buffio)) { + g_warning("gnc_file_aqbanking_import: Failed to wrap file"); + goto cleanup; + } + + /* Run the import */ + if (AB_ImExporter_Import(importer, context, buffio, db_profile, 0)) { + g_warning("gnc_file_aqbanking_import: Error on import"); + goto cleanup; + } + + /* Close the file */ + GWEN_Io_Layer_free(buffio); + + /* Create importer GUI */ + importer_generic_gui = gnc_gen_trans_list_new(NULL, NULL, TRUE, 14); + + /* Import the transactions from the context into gnucash */ + job_list = import_context(api, context, importer_generic_gui, + execute_transactions); + + if (execute_transactions) { + if (gnc_gen_trans_list_run(importer_generic_gui)) { + /* FIXME */ + /* gnc_hbci_multijob_execute(NULL, api, job_list, gui); */ + } + } + +cleanup: + if (job_list) + AB_Job_List2_free(job_list); + if (importer_generic_gui) + gnc_gen_trans_list_delete(importer_generic_gui); + if (context) + AB_ImExporterContext_free(context); + if (db_profiles) + GWEN_DB_Group_free(db_profiles); + if (gui) + gnc_GWEN_Gui_release(gui); + if (online) + AB_Banking_OnlineFini(api); + if (api) + gnc_AB_BANKING_fini(api); + if (dtaus_fd != -1) + close(dtaus_fd); + if (selected_filename) + g_free(selected_filename); +} diff --git a/src/import-export/aqbanking/gnc-file-aqb-import.h b/src/import-export/aqbanking/gnc-file-aqb-import.h new file mode 100644 index 0000000000..382ca4fa69 --- /dev/null +++ b/src/import-export/aqbanking/gnc-file-aqb-import.h @@ -0,0 +1,69 @@ +/* + * gnc-file-aqb-import.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-file-aqb-import.h + * @brief DTAUS import module interface + * @author Copyright (C) 2002 Benoit Grégoire + * @author Copyright (C) 2008 Andreas Koehler + */ + +#ifndef GNC_FILE_AQB_IMPORT_H +#define GNC_FILE_AQB_IMPORT_H + +#include + +G_BEGIN_DECLS + +/** + * This routine will pop up a standard file selection dialog asking the user to + * pick a file to import. This file will be opened and read. Its contents will + * be imported into the current book, using the import matcher from + * import-main-matcher.h. + * + * @param aqbanking_importername The aqbanking importer module that should be + * used. Possible values: "dtaus", "csv", "swift", or more. + * + * @param aqbanking_formatname In aqbanking, each importer has one or more data + * formats available which define the actual data fields that should be used. + * In aqbanking, such a different format is called a "profile". Possible values + * for swift: "swift-mt940" or "swift-mt942", but for all others: "default", or + * more precisely: Look into $datadir/aqbanking/imexporters and look into the + * "name" field of the foo.conf files. + * + * @param exec_as_aqbanking_jobs If TRUE, additionally queue the imported + * transactions as online jobs over aqbanking/HBCI. If FALSE, just import the + * transactions and that's it. + */ +void gnc_file_aqbanking_import (const gchar *aqbanking_importername, + const gchar *aqbanking_formatname, + gboolean exec_as_aqbanking_jobs); + +G_END_DECLS + +/** @} */ +/** @} */ + +#endif /* GNC_FILE_AQB_IMPORT_H */ diff --git a/src/import-export/aqbanking/gnc-gwen-gui.c b/src/import-export/aqbanking/gnc-gwen-gui.c new file mode 100644 index 0000000000..8612a252ce --- /dev/null +++ b/src/import-export/aqbanking/gnc-gwen-gui.c @@ -0,0 +1,1331 @@ +/* + * gnc-gwen-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-gwen-gui.c + * @brief GUI callbacks for AqBanking + * @author Copyright (C) 2002 Christian Stimming + * @author Copyright (C) 2006 David Hampton + * @author Copyright (C) 2008 Andreas Koehler + */ + +#include "config.h" + +#include +#include +#include +#include + +#include "dialog-utils.h" +#include "gnc-ab-utils.h" +#include "gnc-component-manager.h" +#include "gnc-gconf-utils.h" +#include "gnc-gwen-gui.h" +#include "gnc-session.h" +#include "gnc-ui.h" +#include "md5.h" +#include "qof.h" + +/* This static indicates the debugging module that this .o belongs to. */ +static QofLogModule log_module = G_LOG_DOMAIN; + +/* A unique full-blown GUI, featuring */ +static GncGWENGui *full_gui = NULL; + +/* A unique Gwenhywfar GUI for hooking our logging into the gwenhywfar logging + * framework */ +static GWEN_GUI *log_gwen_gui = NULL; + +/* A mapping from gwenhywfar log levels to glib ones */ +static GLogLevelFlags log_levels[] = { + G_LOG_LEVEL_ERROR, /* GWEN_LoggerLevel_Emergency */ + G_LOG_LEVEL_ERROR, /* GWEN_LoggerLevel_Alert */ + G_LOG_LEVEL_CRITICAL, /* GWEN_LoggerLevel_Critical */ + G_LOG_LEVEL_CRITICAL, /* GWEN_LoggerLevel_Error */ + G_LOG_LEVEL_WARNING, /* GWEN_LoggerLevel_Warning */ + G_LOG_LEVEL_MESSAGE, /* GWEN_LoggerLevel_Notice */ + G_LOG_LEVEL_INFO, /* GWEN_LoggerLevel_Info */ + G_LOG_LEVEL_DEBUG, /* GWEN_LoggerLevel_Debug */ + G_LOG_LEVEL_DEBUG /* GWEN_LoggerLevel_Verbous */ +}; +static guint8 n_log_levels = G_N_ELEMENTS(log_levels); + +/* Macros to determine the GncGWENGui* from a GWEN_GUI* */ +GWEN_INHERIT(GWEN_GUI, GncGWENGui) +#define SETDATA_GUI(gwen_gui, gui) GWEN_INHERIT_SETDATA(GWEN_GUI, GncGWENGui, \ + (gwen_gui), (gui), NULL) +#define GETDATA_GUI(gwen_gui) GWEN_INHERIT_GETDATA(GWEN_GUI, GncGWENGui, (gwen_gui)) + +#define GWEN_GUI_CM_CLASS "dialog-hbcilog" +#define GCONF_SECTION_CONNECTION GCONF_SECTION_AQBANKING "/connection_dialog" +#define KEY_CLOSE_ON_FINISH "close_on_finish" +#define KEY_REMEMBER_PIN "remember_pin" + +#define OTHER_ENTRIES_ROW_OFFSET 3 + +typedef struct _Progress Progress; +typedef enum _GuiState GuiState; + +static void register_callbacks(GncGWENGui *gui); +static void unregister_callbacks(GncGWENGui *gui); +static void setup_dialog(GncGWENGui *gui); +static void enable_password_cache(GncGWENGui *gui, gboolean enabled); +static void reset_dialog(GncGWENGui *gui); +static void set_runing(GncGWENGui *gui); +static void set_finished(GncGWENGui *gui); +static void set_aborted(GncGWENGui *gui); +static void show_dialog(GncGWENGui *gui, gboolean clear_log); +static void hide_dialog(GncGWENGui *gui); +static gboolean show_progress_cb(gpointer user_data); +static void show_progress(GncGWENGui *gui, Progress *progress); +static void hide_progress(GncGWENGui *gui, Progress *progress); +static void free_progress(Progress *progress, gpointer unused); +static gboolean keep_alive(GncGWENGui *gui); +static void cm_close_handler(gpointer user_data); +static void erase_password(gchar *password); +static gchar *strip_html(gchar *text); +static void get_input(GncGWENGui *gui, guint32 flags, const gchar *title, + const gchar *text, gchar **input, gint min_len, + gint max_len); +static gint messagebox_cb(GWEN_GUI *gwen_gui, guint32 flags, const gchar *title, + const gchar *text, const gchar *b1,const gchar *b2, + const gchar *b3, guint32 guiid); +static gint inputbox_cb(GWEN_GUI *gwen_gui, guint32 flags, const gchar *title, + const gchar *text, gchar *buffer, gint min_len, + gint max_len, guint32 guiid); +static guint32 showbox_cb(GWEN_GUI *gwen_gui, guint32 flags, const gchar *title, + const gchar *text, guint32 guiid); +static void hidebox_cb(GWEN_GUI *gwen_gui, guint32 id); +static guint32 progress_start_cb(GWEN_GUI *gwen_gui, guint32 progressFlags, + const gchar *title, const gchar *text, + guint64 total, guint32 guiid); +static gint progress_advance_cb(GWEN_GUI *gwen_gui, guint32 id, + guint64 new_progress); +static gint progress_log_cb(GWEN_GUI *gwen_gui, guint32 id, + GWEN_LOGGER_LEVEL level, const gchar *text); +static gint progress_end_cb(GWEN_GUI *gwen_gui, guint32 id); +static gint getpassword_cb(GWEN_GUI *gwen_gui, guint32 flags, const gchar *token, + const gchar *title, const gchar *text, gchar *buffer, + gint min_len, gint max_len, guint32 guiid); +static gint setpasswordstatus_cb(GWEN_GUI *gwen_gui, const gchar *token, + const gchar *pin, + GWEN_GUI_PASSWORD_STATUS status, guint32 guiid); +static gint loghook_cb(GWEN_GUI *gwen_gui, const gchar *log_domain, + GWEN_LOGGER_LEVEL priority, const gchar *text); +static gint checkcert_cb(GWEN_GUI *gwen_gui, const GWEN_SSLCERTDESCR *cert, + GWEN_IO_LAYER *io, guint32 guiid); + +gboolean ggg_delete_event_cb(GtkWidget *widget, GdkEvent *event, + gpointer user_data); +void ggg_abort_clicked_cb(GtkButton *button, gpointer user_data); +void ggg_close_clicked_cb(GtkButton *button, gpointer user_data); + +enum _GuiState { + INIT, + RUNNING, + FINISHED, + ABORTED, + HIDDEN +}; + +struct _GncGWENGui { + GWEN_GUI *gwen_gui; + GtkWidget *parent; + GtkWidget *dialog; + + /* Progress bars */ + GtkWidget *entries_table; + GtkWidget *top_entry; + GtkWidget *top_progress; + GtkWidget *second_entry; + GtkWidget *other_entries_box; + + /* Stack of nested Progresses */ + GList *progresses; + + /* Number of steps in top-level progress or -1 */ + guint64 max_actions; + guint64 current_action; + + /* Log window */ + GtkWidget *log_text; + + /* Buttons */ + GtkWidget *abort_button; + GtkWidget *close_button; + GtkWidget *close_checkbutton; + + /* Flags to keep track on whether an HBCI action is running or not */ + gboolean keep_alive; + GuiState state; + + /* Password caching */ + gboolean cache_passwords; + GHashTable *passwords; + + /* Certificates handling */ + GHashTable *accepted_certs; + GWEN_GUI_CHECKCERT_FN builtin_checkcert; + + /* Dialogs */ + guint showbox_id; + GHashTable *showbox_hash; + GtkWidget *showbox_last; + + /* Cache the lowest loglevel, corresponding to the most serious warning */ + GWEN_LOGGER_LEVEL min_loglevel; +}; + +struct _Progress { + GncGWENGui *gui; + + /* Title of the process */ + gchar *title; + + /* Event source id for showing delayed */ + guint source; +}; + +void +gnc_GWEN_Gui_log_init(void) +{ + if (!log_gwen_gui) { + log_gwen_gui = GWEN_Gui_new(); + + /* Always use our own logging */ + GWEN_Gui_SetLogHookFn(log_gwen_gui, loghook_cb); + + /* Keep a reference so that the GWEN_GUI survives a GUI switch */ + GWEN_Gui_Attach(log_gwen_gui); + } + GWEN_Gui_SetGui(log_gwen_gui); +} + +GncGWENGui * +gnc_GWEN_Gui_get(GtkWidget *parent) +{ + GncGWENGui *gui; + + ENTER("parent=%p", parent); + + if (full_gui) { + if (full_gui->state == INIT || full_gui->state == RUNNING) { + LEAVE("full_gui in use, state=%d", full_gui->state); + return NULL; + } + + gui = full_gui; + gui->parent = parent; + reset_dialog(gui); + register_callbacks(gui); + + LEAVE("gui=%p", gui); + return gui; + } + + gui = g_new0(GncGWENGui, 1); + gui->parent = parent; + setup_dialog(gui); + register_callbacks(gui); + + full_gui = gui; + + LEAVE("new gui=%p", gui); + return gui; +} + +void +gnc_GWEN_Gui_release(GncGWENGui *gui) +{ + g_return_if_fail(gui && gui == full_gui); + + /* Currently a no-op */ + ENTER("gui=%p", gui); + LEAVE(" "); +} + +void +gnc_GWEN_Gui_shutdown(void) +{ + GncGWENGui *gui = full_gui; + + ENTER(" "); + + if (log_gwen_gui) { + GWEN_Gui_free(log_gwen_gui); + log_gwen_gui = NULL; + } + GWEN_Gui_SetGui(NULL); + + if (!gui) + return; + + gui->parent = NULL; + reset_dialog(gui); + if (gui->passwords) + g_hash_table_destroy(gui->passwords); + if (gui->showbox_hash) + g_hash_table_destroy(gui->showbox_hash); + if (gui->accepted_certs) + g_hash_table_destroy(gui->accepted_certs); + gtk_widget_destroy(gui->dialog); + g_free(gui); + + full_gui = NULL; + + LEAVE(" "); +} + +static void +register_callbacks(GncGWENGui *gui) +{ + GWEN_GUI *gwen_gui; + + g_return_if_fail(gui && !gui->gwen_gui); + + ENTER("gui=%p", gui); + + gui->gwen_gui = gwen_gui = GWEN_Gui_new(); + + GWEN_Gui_SetMessageBoxFn(gwen_gui, messagebox_cb); + GWEN_Gui_SetInputBoxFn(gwen_gui, inputbox_cb); + GWEN_Gui_SetShowBoxFn(gwen_gui, showbox_cb); + GWEN_Gui_SetHideBoxFn(gwen_gui, hidebox_cb); + GWEN_Gui_SetProgressStartFn(gwen_gui, progress_start_cb); + GWEN_Gui_SetProgressAdvanceFn(gwen_gui, progress_advance_cb); + GWEN_Gui_SetProgressLogFn(gwen_gui, progress_log_cb); + GWEN_Gui_SetProgressEndFn(gwen_gui, progress_end_cb); + GWEN_Gui_SetGetPasswordFn(gwen_gui, getpassword_cb); + GWEN_Gui_SetSetPasswordStatusFn(gwen_gui, setpasswordstatus_cb); + GWEN_Gui_SetLogHookFn(gwen_gui, loghook_cb); + gui->builtin_checkcert = GWEN_Gui_SetCheckCertFn(gwen_gui, checkcert_cb); + + GWEN_Gui_SetGui(gwen_gui); + SETDATA_GUI(gwen_gui, gui); + + LEAVE(" "); +} + +static void +unregister_callbacks(GncGWENGui *gui) +{ + g_return_if_fail(gui); + + ENTER("gui=%p", gui); + + if (!gui->gwen_gui) { + LEAVE("already unregistered"); + return; + } + + /* Switch to log_gwen_gui and free gui->gwen_gui */ + gnc_GWEN_Gui_log_init(); + + gui->gwen_gui = NULL; + + LEAVE(" "); +} + +static void +setup_dialog(GncGWENGui *gui) +{ + GladeXML *xml; + gint component_id; + + g_return_if_fail(gui); + + ENTER("gui=%p", gui); + + xml = gnc_glade_xml_new("aqbanking.glade", "Connection Dialog"); + + gui->dialog = glade_xml_get_widget(xml, "Connection Dialog"); + g_object_set_data_full(G_OBJECT(gui->dialog), "xml", xml, g_object_unref); + glade_xml_signal_autoconnect_full(xml, gnc_glade_autoconnect_full_func, gui); + gui->entries_table = glade_xml_get_widget(xml, "entries_table"); + gui->top_entry = glade_xml_get_widget(xml, "top_entry"); + gui->top_progress = glade_xml_get_widget(xml, "top_progress"); + gui->second_entry = glade_xml_get_widget(xml, "second_entry"); + gui->other_entries_box = NULL; + gui->progresses = NULL; + gui->log_text = glade_xml_get_widget(xml, "log_text"); + gui->abort_button = glade_xml_get_widget(xml, "abort_button"); + gui->close_button = glade_xml_get_widget(xml, "close_button"); + gui->close_checkbutton = glade_xml_get_widget(xml, "close_checkbutton"); + gui->accepted_certs = NULL; + gui->showbox_hash = NULL; + gui->showbox_id = 1; + + gtk_toggle_button_set_active( + GTK_TOGGLE_BUTTON(gui->close_checkbutton), + gnc_gconf_get_bool(GCONF_SECTION_AQBANKING, KEY_CLOSE_ON_FINISH, NULL)); + + component_id = gnc_register_gui_component(GWEN_GUI_CM_CLASS, NULL, + cm_close_handler, gui); + gnc_gui_component_set_session(component_id, gnc_get_current_session()); + + reset_dialog(gui); + + LEAVE(" "); +} + +static void +enable_password_cache(GncGWENGui *gui, gboolean enabled) +{ + g_return_if_fail(gui); + + if (enabled && !gui->passwords) { + /* Remember passwords in memory, mapping tokens to passwords */ + gui->passwords = g_hash_table_new_full( + g_str_hash, g_str_equal, (GDestroyNotify) g_free, + (GDestroyNotify) erase_password); + } else if (!enabled && gui->passwords) { + /* Erase and free remembered passwords from memory */ + g_hash_table_destroy(gui->passwords); + gui->passwords = NULL; + } + gui->cache_passwords = enabled; +} + +static void +reset_dialog(GncGWENGui *gui) +{ + gboolean cache_passwords; + + g_return_if_fail(gui); + + ENTER("gui=%p", gui); + + gtk_entry_set_text(GTK_ENTRY(gui->top_entry), ""); + gtk_entry_set_text(GTK_ENTRY(gui->second_entry), ""); + g_list_foreach(gui->progresses, (GFunc) free_progress, NULL); + g_list_free(gui->progresses); + gui->progresses = NULL; + + if (gui->other_entries_box) { + gtk_table_resize(GTK_TABLE(gui->entries_table), + OTHER_ENTRIES_ROW_OFFSET, 2); + gtk_widget_destroy(gui->other_entries_box); + gui->other_entries_box = NULL; + } + if (gui->showbox_hash) + g_hash_table_destroy(gui->showbox_hash); + gui->showbox_last = NULL; + gui->showbox_hash = g_hash_table_new_full( + NULL, NULL, NULL, (GDestroyNotify) gtk_widget_destroy); + + if (gui->parent) + gtk_window_set_transient_for(GTK_WINDOW(gui->dialog), + GTK_WINDOW(gui->parent)); + gnc_restore_window_size(GCONF_SECTION_CONNECTION, GTK_WINDOW(gui->dialog)); + + gui->keep_alive = TRUE; + gui->state = INIT; + gui->min_loglevel = GWEN_LoggerLevel_Verbous; + + cache_passwords = gnc_gconf_get_bool(GCONF_SECTION_AQBANKING, + KEY_REMEMBER_PIN, NULL); + enable_password_cache(gui, cache_passwords); + + if (!gui->accepted_certs) + gui->accepted_certs = g_hash_table_new_full( + g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL); + + LEAVE(" "); +} + +static void +set_running(GncGWENGui *gui) +{ + g_return_if_fail(gui); + + ENTER("gui=%p", gui); + + gui->state = RUNNING; + gtk_widget_set_sensitive(gui->abort_button, TRUE); + gtk_widget_set_sensitive(gui->close_button, FALSE); + gui->keep_alive = TRUE; + + LEAVE(" "); +} + +static void +set_finished(GncGWENGui *gui) +{ + g_return_if_fail(gui); + + ENTER("gui=%p", gui); + + /* Do not serve as GUI anymore */ + gui->state = FINISHED; + unregister_callbacks(gui); + + gtk_widget_set_sensitive(gui->abort_button, FALSE); + gtk_widget_set_sensitive(gui->close_button, TRUE); + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gui->close_checkbutton))) + hide_dialog(gui); + + LEAVE(" "); +} + +static void +set_aborted(GncGWENGui *gui) +{ + g_return_if_fail(gui); + + ENTER("gui=%p", gui); + + /* Do not serve as GUI anymore */ + gui->state = ABORTED; + unregister_callbacks(gui); + + gtk_widget_set_sensitive(gui->abort_button, FALSE); + gtk_widget_set_sensitive(gui->close_button, TRUE); + gui->keep_alive = FALSE; + + LEAVE(" "); +} + +static void +show_dialog(GncGWENGui *gui, gboolean clear_log) +{ + gboolean cache_pin; + + g_return_if_fail(gui); + + ENTER("gui=%p, clear_log=%d", gui, clear_log); + + gtk_widget_show(gui->dialog); + + /* Clear the log window */ + if (clear_log) { + gtk_text_buffer_set_text( + gtk_text_view_get_buffer(GTK_TEXT_VIEW(gui->log_text)), "", 0); + } + + LEAVE(" "); +} + +static void +hide_dialog(GncGWENGui *gui) +{ + g_return_if_fail(gui); + + ENTER("gui=%p", gui); + + /* Hide the dialog */ + gtk_widget_hide(gui->dialog); + + /* Remember whether the dialog is to be closed when finished */ + gnc_gconf_set_bool( + GCONF_SECTION_AQBANKING, KEY_CLOSE_ON_FINISH, + gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(gui->close_checkbutton)), + NULL); + + /* Remember size and position of the dialog */ + gnc_save_window_size(GCONF_SECTION_CONNECTION, GTK_WINDOW(gui->dialog)); + + /* Do not serve as GUI anymore */ + gui->state = HIDDEN; + unregister_callbacks(gui); + + LEAVE(" "); +} + +static gboolean +show_progress_cb(gpointer user_data) +{ + Progress *progress = user_data; + GncGWENGui *gui; + GList *item; + + g_return_val_if_fail(progress, FALSE); + + ENTER("progress=%p", progress); + + show_progress(progress->gui, progress); + + LEAVE(" "); + return FALSE; +} + +/** + * Show all processes down to and including @a progress. + */ +static void +show_progress(GncGWENGui *gui, Progress *progress) +{ + GList *item; + Progress *current; + + g_return_if_fail(gui); + + ENTER("gui=%p, progress=%p", gui, progress); + + for (item = g_list_last(gui->progresses); item; item = item->prev) { + current = (Progress*) item->data; + + if (!current->source + && current != progress) + /* Already showed */ + continue; + + /* Show it */ + if (!item->next) { + /* Top-level progress */ + show_dialog(gui, TRUE); + gtk_entry_set_text(GTK_ENTRY(gui->top_entry), current->title); + } else if (!item->next->next) { + /* Second-level progress */ + gtk_entry_set_text(GTK_ENTRY(gui->second_entry), current->title); + } else { + /* Other progress */ + GtkWidget *entry = gtk_entry_new(); + GtkWidget *box = gui->other_entries_box; + gboolean new_box = box == NULL; + + gtk_entry_set_text(GTK_ENTRY(entry), current->title); + if (new_box) + gui->other_entries_box = box = gtk_vbox_new(TRUE, 6); + gtk_box_pack_start_defaults(GTK_BOX(box), entry); + gtk_widget_show(entry); + if (new_box) { + gtk_table_resize(GTK_TABLE(gui->entries_table), + OTHER_ENTRIES_ROW_OFFSET + 1, 2); + gtk_table_attach_defaults( + GTK_TABLE(gui->entries_table), box, 1, 2, + OTHER_ENTRIES_ROW_OFFSET, OTHER_ENTRIES_ROW_OFFSET + 1); + gtk_widget_show(box); + } + } + + if (current->source) { + /* Stop delayed call */ + g_source_remove(current->source); + current->source = 0; + } + + if (current == progress) + break; + } + + LEAVE(" "); +} + +/** + * Hide all processes up to and including @a progress. + */ +static void +hide_progress(GncGWENGui *gui, Progress *progress) +{ + GList *item; + Progress *current; + + g_return_if_fail(gui); + + ENTER("gui=%p, progress=%p", gui, progress); + + for (item = gui->progresses; item; item = item->next) { + current = (Progress*) item->data; + + if (current->source) { + /* Not yet showed */ + g_source_remove(current->source); + current->source = 0; + if (current == progress) + break; + else + continue; + } + + /* Hide it */ + if (!item->next) { + /* Top-level progress */ + gtk_entry_set_text(GTK_ENTRY(gui->second_entry), ""); + } else if (!item->next->next) { + /* Second-level progress */ + gtk_entry_set_text(GTK_ENTRY(gui->second_entry), ""); + } else { + /* Other progress */ + GtkWidget *box = gui->other_entries_box; + GList *entries; + + g_return_if_fail(box); + entries = gtk_container_get_children(GTK_CONTAINER(box)); + g_return_if_fail(entries); + if (entries->next) { + /* Another progress is still to be showed */ + gtk_widget_destroy(GTK_WIDGET(g_list_last(entries)->data)); + } else { + /* Last other progress to be hided */ + gtk_table_resize(GTK_TABLE(gui->entries_table), + OTHER_ENTRIES_ROW_OFFSET, 2); + gtk_widget_destroy(box); + gui->other_entries_box = NULL; + } + g_list_free(entries); + } + + if (current == progress) + break; + } + + LEAVE(" "); +} + +static void +free_progress(Progress *progress, gpointer unused) +{ + if (progress->source) + g_source_remove(progress->source); + g_free(progress->title); + g_free(progress); +} + +static gboolean +keep_alive(GncGWENGui *gui) +{ + g_return_val_if_fail(gui, FALSE); + + ENTER("gui=%p", gui); + + /* Let the widgets be redrawn */ + while (g_main_context_iteration(NULL, FALSE)); + + LEAVE("alive=%d", gui->keep_alive); + return gui->keep_alive; +} + +static void +cm_close_handler(gpointer user_data) +{ + GncGWENGui *gui = user_data; + + g_return_if_fail(gui); + + ENTER("gui=%p", gui); + + /* FIXME */ + set_aborted(gui); + + LEAVE(" "); +} + +static void +erase_password(gchar *password) +{ + g_return_if_fail(password); + + ENTER(" "); + + memset(password, 0, strlen(password)); + g_free(password); + + LEAVE(" "); +} + +/** + * Find first <[Hh][Tt][Mm][Ll]> and cut off the string there. + */ +static gchar * +strip_html(gchar *text) +{ + gchar *p, *q; + + if (!text) + return NULL; + + p = text; + while (strchr(p, '<')) { + q = p + 1; + if (*q && toupper(*q++) == 'H' + && *q && toupper(*q++) == 'T' + && *q && toupper(*q++) == 'M' + && *q && toupper(*q) == 'L') { + *p = '\0'; + return text; + } + p++; + } + return text; +} + +static void +get_input(GncGWENGui *gui, guint32 flags, const gchar *title, const gchar *text, + gchar **input, gint min_len, gint max_len) +{ + GladeXML *xml; + GtkWidget *dialog; + GtkWidget *heading_label; + GtkWidget *input_entry; + GtkWidget *confirm_entry; + GtkWidget *confirm_label; + GtkWidget *remember_pin_checkbutton; + const gchar *internal_input, *internal_confirmed; + gboolean confirm = (flags & GWEN_GUI_INPUT_FLAGS_CONFIRM) != 0; + gboolean hidden = (flags & GWEN_GUI_INPUT_FLAGS_SHOW) == 0; + gboolean is_tan = (flags & GWEN_GUI_INPUT_FLAGS_TAN) != 0; + gint retval; + + g_return_if_fail(input); + g_return_if_fail(max_len >= min_len && max_len > 0); + + ENTER(" "); + + /* Set up dialog */ + xml = gnc_glade_xml_new("aqbanking.glade", "Password Dialog"); + dialog = glade_xml_get_widget(xml, "Password Dialog"); + g_object_set_data_full(G_OBJECT(dialog), "xml", xml, g_object_unref); + + heading_label = glade_xml_get_widget(xml, "heading_label"); + input_entry = glade_xml_get_widget(xml, "input_entry"); + confirm_entry = glade_xml_get_widget(xml, "confirm_entry"); + confirm_label = glade_xml_get_widget(xml, "confirm_label"); + remember_pin_checkbutton = glade_xml_get_widget(xml, "remember_pin"); + if (is_tan) { + gtk_widget_hide(remember_pin_checkbutton); + } else { + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(remember_pin_checkbutton), + gui->cache_passwords); + } + + if (gui->parent) + gtk_window_set_transient_for(GTK_WINDOW(dialog), + GTK_WINDOW(gui->parent)); + if (title) + gtk_window_set_title(GTK_WINDOW(dialog), title); + + if (text) { + gchar *raw_text = strip_html(g_strdup(text)); + gtk_label_set_text(GTK_LABEL(heading_label), raw_text); + g_free(raw_text); + } + + if (*input) { + gtk_entry_set_text(GTK_ENTRY(input_entry), *input); + erase_password(*input); + *input = NULL; + } + + if (confirm) { + gtk_entry_set_activates_default(GTK_ENTRY(input_entry), FALSE); + gtk_entry_set_activates_default(GTK_ENTRY(confirm_entry), TRUE); + gtk_entry_set_max_length(GTK_ENTRY(input_entry), max_len); + gtk_entry_set_max_length(GTK_ENTRY(confirm_entry), max_len); + } else { + gtk_entry_set_activates_default(GTK_ENTRY(input_entry), TRUE); + gtk_entry_set_max_length(GTK_ENTRY(input_entry), max_len); + gtk_widget_hide(confirm_entry); + gtk_widget_hide(confirm_label); + } + gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK); + + /* Ask the user until he enters a valid input or cancels */ + while (TRUE) { + gboolean remember_pin; + + if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_OK) + break; + + if (!is_tan) { + /* Enable or disable the password cache */ + remember_pin = gtk_toggle_button_get_active( + GTK_TOGGLE_BUTTON(remember_pin_checkbutton)); + enable_password_cache(gui, remember_pin); + gnc_gconf_set_bool(GCONF_SECTION_AQBANKING, KEY_REMEMBER_PIN, + remember_pin, NULL); + } + + internal_input = gtk_entry_get_text(GTK_ENTRY(input_entry)); + if (strlen(internal_input) < min_len) { + gboolean retval; + gchar *msg = g_strdup_printf( + _("The PIN needs to be at least %d characters \n" + "long. Do you want to try again?"), min_len); + retval = gnc_verify_dialog(gui->parent, TRUE, "%s", msg); + g_free(msg); + if (!retval) + break; + continue; + } + + if (!confirm) { + *input = g_strdup(internal_input); + break; + } + + internal_confirmed = gtk_entry_get_text(GTK_ENTRY(confirm_entry)); + if (strcmp(internal_input, internal_confirmed) == 0) { + *input = g_strdup(internal_input); + break; + } + } + + /* This trashes passwords in the entries' memory as well */ + gtk_widget_destroy(dialog); + + LEAVE("input %s", *input ? "non-NULL" : "NULL"); +} + +static gint +messagebox_cb(GWEN_GUI *gwen_gui, guint32 flags, const gchar *title, + const gchar *text, const gchar *b1,const gchar *b2, + const gchar *b3, guint32 guiid) +{ + GncGWENGui *gui = GETDATA_GUI(gwen_gui); + GtkWidget *dialog; + GtkWidget *vbox; + GtkWidget *label; + gchar *raw_text; + gint result; + + ENTER("gui=%p, flags=%d, title=%s, b1=%s, b2=%s, b3=%s", gui, flags, + title ? title : "(null)", b1 ? b1 : "(null)", b2 ? b2 : "(null)", + b3 ? b3 : "(null)"); + + dialog = gtk_dialog_new_with_buttons( + title, gui->parent ? GTK_WINDOW(gui->parent) : NULL, + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + b1, 1, b2, 2, b3, 3, (gchar*) NULL); + + raw_text = strip_html(g_strdup(text)); + label = gtk_label_new(raw_text); + g_free(raw_text); + gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT); + vbox = gtk_vbox_new(TRUE, 0); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + gtk_container_add(GTK_CONTAINER(vbox), label); + gtk_container_set_border_width(GTK_CONTAINER(dialog), 5); + gtk_container_add(GTK_CONTAINER(GTK_DIALOG(dialog)->vbox), vbox); + gtk_widget_show_all(dialog); + + result = gtk_dialog_run(GTK_DIALOG(dialog)); + gtk_widget_destroy(dialog); + + if (result<1 || result>3) { + g_warning("messagebox_cb: Bad result %d", result); + result = 0; + } + + LEAVE("result=%d", result); + return result; +} + +static gint +inputbox_cb(GWEN_GUI *gwen_gui, guint32 flags, const gchar *title, + const gchar *text, gchar *buffer, gint min_len, gint max_len, + guint32 guiid) +{ + GncGWENGui *gui = GETDATA_GUI(gwen_gui); + gchar *input = NULL; + + g_return_val_if_fail(gui, -1); + + ENTER("gui=%p, flags=%d", gui, flags); + + get_input(gui, flags, title, text, &input, min_len, max_len); + + if (input) { + /* Copy the input to the result buffer */ + strncpy(buffer, input, max_len); + buffer[max_len-1] = '\0'; + } + + LEAVE(" "); + return input ? 0 : -1; +} + +static guint32 +showbox_cb(GWEN_GUI *gwen_gui, guint32 flags, const gchar *title, + const gchar *text, guint32 guiid) +{ + GncGWENGui *gui = GETDATA_GUI(gwen_gui); + GtkWidget *dialog; + + g_return_val_if_fail(gui, -1); + + ENTER("gui=%p, flags=%d, title=%s", gui, flags, title ? title : "(null)"); + + dialog = gtk_message_dialog_new( + gui->parent ? GTK_WINDOW(gui->parent) : NULL, 0, GTK_MESSAGE_INFO, + GTK_BUTTONS_OK, "%s", text); + + if (title) + gtk_window_set_title(GTK_WINDOW(dialog), title); + + g_signal_connect(dialog, "response", G_CALLBACK(gtk_widget_hide), NULL); + gtk_widget_show_all(dialog); + + g_hash_table_insert(gui->showbox_hash, GUINT_TO_POINTER(gui->showbox_id), + dialog); + gui->showbox_id++; + gui->showbox_last = dialog; + + LEAVE(" "); + return 0; +} + +static void +hidebox_cb(GWEN_GUI *gwen_gui, guint32 id) +{ + GncGWENGui *gui = GETDATA_GUI(gwen_gui); + GtkWidget *dialog; + + g_return_if_fail(gui && gui->showbox_hash); + + ENTER("gui=%p, id=%d", gui, id); + + if (id == 0) { + if (gui->showbox_last) { + g_hash_table_remove(gui->showbox_hash, + GUINT_TO_POINTER(gui->showbox_id)); + gui->showbox_last = NULL; + } else { + g_warning("hidebox_cb: Last showed message box already destroyed"); + } + } else { + gpointer p_var; + p_var = g_hash_table_lookup(gui->showbox_hash, GUINT_TO_POINTER(id)); + if (p_var) { + g_hash_table_remove(gui->showbox_hash, GUINT_TO_POINTER(id)); + if (p_var == gui->showbox_last) + gui->showbox_last = NULL; + } else { + g_warning("hidebox_cb: Message box %d could not been found", id); + } + } + + LEAVE(" "); +} + +static guint32 +progress_start_cb(GWEN_GUI *gwen_gui, guint32 progressFlags, const gchar *title, + const gchar *text, guint64 total, guint32 guiid) +{ + GncGWENGui *gui = GETDATA_GUI(gwen_gui); + Progress *progress; + + g_return_val_if_fail(gui, -1); + + ENTER("gui=%p, flags=%d, title=%s, total=%" G_GUINT64_FORMAT, gui, + progressFlags, title ? title : "(null)", total); + + if (!gui->progresses) { + /* Top-level progress */ + if (progressFlags & GWEN_GUI_PROGRESS_SHOW_PROGRESS) { + gtk_widget_set_sensitive(gui->top_progress, TRUE); + gtk_progress_bar_set_fraction( + GTK_PROGRESS_BAR(gui->top_progress), 0.0); + gui->max_actions = total; + } else { + gtk_widget_set_sensitive(gui->top_progress, FALSE); + gui->max_actions = -1; + } + set_running(gui); + } + + /* Put progress onto the stack */ + progress = g_new0(Progress, 1); + progress->gui = gui; + progress->title = title ? g_strdup(title) : ""; + gui->progresses = g_list_prepend(gui->progresses, progress); + + if (progressFlags & GWEN_GUI_PROGRESS_DELAY) { + /* Show progress later */ + progress->source = g_timeout_add(GWEN_GUI_DELAY_SECS * 1000, + (GSourceFunc) show_progress_cb, + progress); + } else { + /* Show it now */ + progress->source = 0; + show_progress(gui, progress); + } + + LEAVE(" "); + return g_list_length(gui->progresses); +} + +static gint +progress_advance_cb(GWEN_GUI *gwen_gui, guint32 id, guint64 progress) +{ + GncGWENGui *gui = GETDATA_GUI(gwen_gui); + + g_return_val_if_fail(gui, -1); + + ENTER("gui=%p, progress=%" G_GUINT64_FORMAT, gui, progress); + + if (id == 1 /* top-level progress */ + && gui->max_actions > 0 /* progressbar active */ + && progress != GWEN_GUI_PROGRESS_NONE) { /* progressbar update needed */ + if (progress == GWEN_GUI_PROGRESS_ONE) + gui->current_action++; + else + gui->current_action = progress; + + gtk_progress_bar_set_fraction( + GTK_PROGRESS_BAR(gui->top_progress), + ((gdouble) gui->current_action) / ((gdouble) gui->max_actions)); + } + + LEAVE(" "); + return !keep_alive(gui); +} + +static gint +progress_log_cb(GWEN_GUI *gwen_gui, guint32 id, GWEN_LOGGER_LEVEL level, + const gchar *text) +{ + GncGWENGui *gui = GETDATA_GUI(gwen_gui); + GtkTextBuffer *tb; + GtkTextView *tv; + + g_return_val_if_fail(gui, -1); + + ENTER("gui=%p, text=%s", gui, text ? text : "(null)"); + + tv = GTK_TEXT_VIEW(gui->log_text); + tb = gtk_text_view_get_buffer(tv); + gtk_text_buffer_insert_at_cursor(tb, text, -1); + gtk_text_buffer_insert_at_cursor(tb, "\n", -1); + + /* Scroll to the end of the buffer */ + gtk_text_view_scroll_to_mark(tv, gtk_text_buffer_get_insert(tb), + 0.0, FALSE, 0.0, 0.0); + + /* Cache loglevel */ + if (level < gui->min_loglevel) + gui->min_loglevel = level; + + LEAVE(" "); + return !keep_alive(gui); +} + +static gint +progress_end_cb(GWEN_GUI *gwen_gui, guint32 id) +{ + GncGWENGui *gui = GETDATA_GUI(gwen_gui); + Progress *progress; + + g_return_val_if_fail(gui, -1); + g_return_val_if_fail(id == g_list_length(gui->progresses), -1); + + ENTER("gui=%p, id=%d", gui, id); + + if (gui->state != RUNNING) { + /* Ignore finishes of progresses we do not track */ + LEAVE("not running anymore"); + return 0; + } + + /* Hide progress */ + progress = (Progress*) gui->progresses->data; + hide_progress(gui, progress); + + /* Remove progress from stack and free memory */ + gui->progresses = g_list_delete_link(gui->progresses, gui->progresses); + free_progress(progress, NULL); + + if (!gui->progresses) { + /* top-level progress finished */ + set_finished(gui); + } + + LEAVE(" "); + return 0; +} + +static gint +getpassword_cb(GWEN_GUI *gwen_gui, guint32 flags, const gchar *token, + const gchar *title, const gchar *text, gchar *buffer, + gint min_len, gint max_len, guint32 guiid) +{ + GncGWENGui *gui = GETDATA_GUI(gwen_gui); + gchar *password = NULL; + gboolean is_tan = (flags & GWEN_GUI_INPUT_FLAGS_TAN) != 0; + + g_return_val_if_fail(gui, -1); + + ENTER("gui=%p, flags=%d, token=%s", gui, flags, token ? token : "(null"); + + /* Check remembered passwords, excluding TANs */ + if (!is_tan && gui->cache_passwords && gui->passwords && token) { + if (flags & GWEN_GUI_INPUT_FLAGS_RETRY) { + /* If remembered, remove password from memory */ + g_hash_table_remove(gui->passwords, token); + } else { + gpointer p_var; + if (g_hash_table_lookup_extended(gui->passwords, token, NULL, + &p_var)) { + /* Copy the password to the result buffer */ + password = p_var; + strncpy(buffer, password, max_len); + buffer[max_len-1] = '\0'; + + LEAVE("chose remembered password"); + return 0; + } + } + } + + get_input(gui, flags, title, text, &password, min_len, max_len); + + if (password) { + /* Copy the password to the result buffer */ + strncpy(buffer, password, max_len); + buffer[max_len-1] = '\0'; + + if (!is_tan && token) { + if (gui->cache_passwords && gui->passwords) { + /* Remember password */ + DEBUG("Remember password, token=%s", token); + g_hash_table_insert(gui->passwords, g_strdup(token), password); + } else { + /* Remove the password from memory */ + DEBUG("Forget password, token=%s", token); + erase_password(password); + } + } + } + + LEAVE(" "); + return password ? 0 : -1; +} + +static gint +setpasswordstatus_cb(GWEN_GUI *gwen_gui, const gchar *token, const gchar *pin, + GWEN_GUI_PASSWORD_STATUS status, guint32 guiid) +{ + GncGWENGui *gui = GETDATA_GUI(gwen_gui); + + g_return_val_if_fail(gui, -1); + + ENTER("gui=%p, token=%s, status=%d", gui, token ? token : "(null)", status); + + if (gui->passwords && status != GWEN_Gui_PasswordStatus_Ok) { + /* If remembered, remove password from memory */ + g_hash_table_remove(gui->passwords, token); + } + + LEAVE(" "); + return 0; +} + +static gint +loghook_cb(GWEN_GUI *gwen_gui, const gchar *log_domain, + GWEN_LOGGER_LEVEL priority, const gchar *text) +{ + if (G_LIKELY(priority < n_log_levels)) + g_log(log_domain, log_levels[priority], "%s", text); + + return 1; +} + +static gint +checkcert_cb(GWEN_GUI *gwen_gui, const GWEN_SSLCERTDESCR *cert, + GWEN_IO_LAYER *io, guint32 guiid) +{ + GncGWENGui *gui = GETDATA_GUI(gwen_gui); + const gchar *hash, *status; + struct md5_ctx md5_context; + gchar cert_hash[16]; + gint retval; + + g_return_val_if_fail(gui && gui->accepted_certs, -1); + + ENTER("gui=%p, cert=%p", gui, cert); + + hash = GWEN_SslCertDescr_GetFingerPrint(cert); + status = GWEN_SslCertDescr_GetStatusText(cert); + + /* Operate on an md5sum of the pair of hash and status */ + md5_init_ctx(&md5_context); + md5_process_bytes(hash, strlen(hash), &md5_context); + md5_process_bytes(status, strlen(status), &md5_context); + md5_finish_ctx(&md5_context, cert_hash); + + if (g_hash_table_lookup(gui->accepted_certs, cert_hash)) { + /* Certificate has been accepted before */ + LEAVE("Automatically accepting certificate"); + return 0; + } + + retval = gui->builtin_checkcert(gwen_gui, cert, io, guiid); + if (retval == 0) { + /* Certificate has been accepted */ + g_hash_table_insert(gui->accepted_certs, g_strdup(cert_hash), cert_hash); + } + + LEAVE("retval=%d", retval); + return retval; +} + +gboolean +ggg_delete_event_cb(GtkWidget *widget, GdkEvent *event, gpointer user_data){ + GncGWENGui *gui = user_data; + + g_return_val_if_fail(gui, FALSE); + + ENTER("gui=%p, state=%d", gui, gui->state); + + if (gui->state == RUNNING) { + const char *still_running_msg = + _("The Online Banking job is still running; are you " + "sure you want to cancel?"); + if (!gnc_verify_dialog(gui->dialog, FALSE, "%s", still_running_msg)) + return FALSE; + + set_aborted(gui); + } + + hide_dialog(gui); + + LEAVE(" "); + return TRUE; +} + +void +ggg_abort_clicked_cb(GtkButton *button, gpointer user_data) +{ + GncGWENGui *gui = user_data; + + g_return_if_fail(gui && gui->state == RUNNING); + + ENTER("gui=%p", gui); + + set_aborted(gui); + + LEAVE(" "); +} + +void +ggg_close_clicked_cb(GtkButton *button, gpointer user_data) +{ + GncGWENGui *gui = user_data; + + g_return_if_fail(gui); + g_return_if_fail(gui->state == FINISHED || gui->state == ABORTED); + + ENTER("gui=%p", gui); + + hide_dialog(gui); + + LEAVE(" "); +} diff --git a/src/import-export/aqbanking/gnc-gwen-gui.h b/src/import-export/aqbanking/gnc-gwen-gui.h new file mode 100644 index 0000000000..39fff7b695 --- /dev/null +++ b/src/import-export/aqbanking/gnc-gwen-gui.h @@ -0,0 +1,80 @@ +/* + * gnc-gwen-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-gwen-gui.h + * @brief GUI callbacks for AqBanking + * @author Copyright (C) 2002 Christian Stimming + * @author Copyright (C) 2008 Andreas Koehler + */ + +#ifndef GNC_GWEN_GUI_H +#define GNC_GWEN_GUI_H + +#include + +G_BEGIN_DECLS + +typedef struct _GncGWENGui GncGWENGui; + +/** + * Hook our logging into the gwenhywfar logging framework by creating a + * minimalistic GWEN_GUI with only a callback for Gwen_Gui_LogHook(). This + * function can be called more than once, it will unref and replace the + * currently set GWEN_GUI though. + */ +void gnc_GWEN_Gui_log_init(void); + +/** + * When called for the first time, create a unique GncGWENGui object featuring a + * GWEN_GUI with all necessary callbacks, which can serve as a user interface + * for AqBanking jobs. On later calls, return the object only when it is not + * active and save to use. Typically, you only need to call + * gnc_GWEN_Gui_release() once your job has finished. + * + * @param parent Widget to set new dialogs transient for, may be NULL + * @return The unique GncGWENGui object or NULL otherwise + */ +GncGWENGui *gnc_GWEN_Gui_get(GtkWidget *parent); + +/** + * Currently a no-op. The GncGWENGui will not be freed and it is considered + * finished once the first tracked progress has ended. + * + * @param gui The GncGwenGUI returned by gnc_GWEN_Gui_get() + */ +void gnc_GWEN_Gui_release(GncGWENGui *gui); + +/** + * Free all memory related to both the full-blown and minimalistic GUI objects. + */ +void gnc_GWEN_Gui_shutdown(void); + +G_END_DECLS + +/** @} */ +/** @} */ + +#endif /* GNC_GWEN_GUI_H */ diff --git a/src/import-export/aqbanking/gnc-plugin-aqbanking-ui.xml b/src/import-export/aqbanking/gnc-plugin-aqbanking-ui.xml new file mode 100644 index 0000000000..9b51002361 --- /dev/null +++ b/src/import-export/aqbanking/gnc-plugin-aqbanking-ui.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/import-export/aqbanking/gnc-plugin-aqbanking.c b/src/import-export/aqbanking/gnc-plugin-aqbanking.c new file mode 100644 index 0000000000..0dd0301777 --- /dev/null +++ b/src/import-export/aqbanking/gnc-plugin-aqbanking.c @@ -0,0 +1,472 @@ +/* + * gnc-plugin-aqbanking.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-plugin-aqbanking.c + * @brief Plugin registration of the AqBanking module + * @author Copyright (C) 2002 Christian Stimming + * @author Copyright (C) 2003 David Hampton + * @author Copyright (C) 2008 Andreas Koehler + */ + +#include "config.h" + +#include + +#include "Account.h" +#include "dialog-ab-trans.h" +#include "druid-ab-initial.h" +#include "gnc-ab-getbalance.h" +#include "gnc-ab-gettrans.h" +#include "gnc-ab-transfer.h" +#include "gnc-ab-utils.h" +#include "gnc-file-aqb-import.h" +#include "gnc-gconf-utils.h" +#include "gnc-plugin-aqbanking.h" +#include "gnc-plugin-manager.h" +#include "gnc-plugin-page-account-tree.h" +#include "gnc-plugin-page-register.h" + +/* This static indicates the debugging module that this .o belongs to. */ +static QofLogModule log_module = G_LOG_DOMAIN; + +static void gnc_plugin_aqbanking_class_init(GncPluginAqBankingClass *klass); +static void gnc_plugin_aqbanking_init(GncPluginAqBanking *plugin); +static void gnc_plugin_aqbanking_add_to_window(GncPlugin *plugin, GncMainWindow *window, GQuark type); +static void gnc_plugin_aqbanking_remove_from_window(GncPlugin *plugin, GncMainWindow *window, GQuark type); + +/* Object callbacks */ +static void gnc_plugin_ab_main_window_page_added(GncMainWindow *window, GncPluginPage *page, gpointer user_data); +static void gnc_plugin_ab_main_window_page_changed(GncMainWindow *window, GncPluginPage *page, gpointer user_data); +static void gnc_plugin_ab_account_selected(GncPluginPage *plugin_page, Account *account, gpointer user_data); + +/* Auxiliary functions */ +static Account *main_window_to_account(GncMainWindow *window); + +/* Command callbacks */ +static void gnc_plugin_ab_cmd_setup(GtkAction *action, GncMainWindowActionData *data); +static void gnc_plugin_ab_cmd_get_balance(GtkAction *action, GncMainWindowActionData *data); +static void gnc_plugin_ab_cmd_get_transactions(GtkAction *action, GncMainWindowActionData *data); +static void gnc_plugin_ab_cmd_issue_transaction(GtkAction *action, GncMainWindowActionData *data); +static void gnc_plugin_ab_cmd_issue_inttransaction(GtkAction *action, GncMainWindowActionData *data); +static void gnc_plugin_ab_cmd_issue_direct_debit(GtkAction *action, GncMainWindowActionData *data); +static void gnc_plugin_ab_cmd_mt940_import(GtkAction *action, GncMainWindowActionData *data); +static void gnc_plugin_ab_cmd_mt942_import(GtkAction *action, GncMainWindowActionData *data); +static void gnc_plugin_ab_cmd_dtaus_import(GtkAction *action, GncMainWindowActionData *data); +static void gnc_plugin_ab_cmd_dtaus_importsend(GtkAction *action, GncMainWindowActionData *data); + +#define PLUGIN_ACTIONS_NAME "gnc-plugin-aqbanking-actions" +#define PLUGIN_UI_FILENAME "gnc-plugin-aqbanking-ui.xml" + +static GtkActionEntry gnc_plugin_actions [] = { + /* Menus */ + { "OnlineActionsAction", NULL, N_("_Online Actions"), NULL, NULL, NULL }, + + /* Menu Items */ + { "ABSetupAction", NULL, N_("_Online Banking Setup..."), NULL, + N_("Initial setup of Online Banking access (HBCI, or OFX DirectConnect, using AqBanking)"), + G_CALLBACK(gnc_plugin_ab_cmd_setup) }, + { "ABGetBalanceAction", NULL, N_("Get _Balance"), NULL, + N_("Get the account balance online through Online Banking"), + G_CALLBACK(gnc_plugin_ab_cmd_get_balance) }, + { "ABGetTransAction", NULL, N_("Get _Transactions..."), NULL, + N_("Get the transactions online through Online Banking"), + G_CALLBACK(gnc_plugin_ab_cmd_get_transactions) }, + { "ABIssueTransAction", NULL, N_("_Issue Transaction..."), NULL, + N_("Issue a new transaction online through Online Banking"), + G_CALLBACK(gnc_plugin_ab_cmd_issue_transaction) }, + { "ABIssueIntTransAction", NULL, N_("I_nternal Transaction..."), NULL, + N_("Issue a new bank-internal transaction online through Online Banking"), + G_CALLBACK(gnc_plugin_ab_cmd_issue_inttransaction) }, + { "ABIssueDirectDebitAction", NULL, N_("_Direct Debit..."), NULL, + N_("Issue a new direct debit note online through Online Banking"), + G_CALLBACK(gnc_plugin_ab_cmd_issue_direct_debit) }, + + /* File -> Import menu item */ + { "Mt940ImportAction", GTK_STOCK_CONVERT, N_("Import _MT940"), NULL, + N_("Import a MT940 file into GnuCash"), + G_CALLBACK(gnc_plugin_ab_cmd_mt940_import) }, + { "Mt942ImportAction", GTK_STOCK_CONVERT, N_("Import MT94_2"), NULL, + N_("Import a MT942 file into GnuCash"), + G_CALLBACK(gnc_plugin_ab_cmd_mt942_import) }, + { "DtausImportAction", GTK_STOCK_CONVERT, N_("Import _DTAUS"), NULL, + N_("Import a DTAUS file into GnuCash"), + G_CALLBACK(gnc_plugin_ab_cmd_dtaus_import) }, +/* #ifdef CSV_IMPORT_FUNCTIONAL */ +/* { "CsvImportAction", GTK_STOCK_CONVERT, N_("Import _CSV"), NULL, */ +/* N_("Import a CSV file into GnuCash"), */ +/* G_CALLBACK(gnc_plugin_ab_cmd_csv_import) }, */ +/* { "CsvImportSendAction", GTK_STOCK_CONVERT, N_("Import CSV and s_end..."), NULL, */ +/* N_("Import a CSV file into GnuCash and send the transfers online through Online Banking"), */ +/* G_CALLBACK(gnc_plugin_ab_cmd_csv_importsend) }, */ +/* #endif */ + { "DtausImportSendAction", GTK_STOCK_CONVERT, N_("Import DTAUS and _send..."), NULL, + N_("Import a DTAUS file into GnuCash and send the transfers online through Online Banking"), + G_CALLBACK(gnc_plugin_ab_cmd_dtaus_importsend) }, +}; +static guint gnc_plugin_n_actions = G_N_ELEMENTS(gnc_plugin_actions); + +static const gchar *need_account_actions[] = { + "ABGetBalanceAction", + "ABGetTransAction", + "ABIssueTransAction", + "ABIssueIntTransAction", + "ABIssueDirectDebitAction", + NULL +}; + +/************************************************************ + * Object Implementation * + ************************************************************/ + +G_DEFINE_TYPE(GncPluginAqBanking, gnc_plugin_aqbanking, GNC_TYPE_PLUGIN) + +GncPlugin * +gnc_plugin_aqbanking_new(void) +{ + return GNC_PLUGIN(g_object_new(GNC_TYPE_PLUGIN_AQBANKING, (gchar*) NULL)); +} + +static void +gnc_plugin_aqbanking_class_init(GncPluginAqBankingClass *klass) +{ + GncPluginClass *plugin_class = GNC_PLUGIN_CLASS(klass); + + /* plugin info */ + plugin_class->plugin_name = GNC_PLUGIN_AQBANKING_NAME; + + /* widget addition/removal */ + plugin_class->actions_name = PLUGIN_ACTIONS_NAME; + plugin_class->actions = gnc_plugin_actions; + plugin_class->n_actions = gnc_plugin_n_actions; + plugin_class->ui_filename = PLUGIN_UI_FILENAME; + plugin_class->add_to_window = gnc_plugin_aqbanking_add_to_window; + plugin_class->remove_from_window = gnc_plugin_aqbanking_remove_from_window; +} + +static void +gnc_plugin_aqbanking_init(GncPluginAqBanking *plugin) +{ +} + +/** + * Called when this plugin is added to a main window. Connect a few callbacks + * here to track page changes. + */ +static void +gnc_plugin_aqbanking_add_to_window(GncPlugin *plugin, GncMainWindow *window, + GQuark type) +{ + g_signal_connect(window, "page_added", + G_CALLBACK(gnc_plugin_ab_main_window_page_added), + plugin); + g_signal_connect(window, "page_changed", + G_CALLBACK(gnc_plugin_ab_main_window_page_changed), + plugin); +} + +static void +gnc_plugin_aqbanking_remove_from_window(GncPlugin *plugin, GncMainWindow *window, + GQuark type) +{ + g_signal_handlers_disconnect_by_func( + window, G_CALLBACK(gnc_plugin_ab_main_window_page_changed), plugin); + g_signal_handlers_disconnect_by_func( + window, G_CALLBACK(gnc_plugin_ab_main_window_page_added), plugin); +} + +/************************************************************ + * Object Callbacks * + ************************************************************/ + +/** + * A new page has been added to a main window. Connect a signal to it so that + * we can track when accounts are selected. + */ +static void +gnc_plugin_ab_main_window_page_added(GncMainWindow *window, GncPluginPage *page, + gpointer user_data) +{ + const gchar *page_name; + + ENTER("main window %p, page %p", window, page); + if (!GNC_IS_PLUGIN_PAGE(page)) { + LEAVE("no plugin_page"); + return; + } + + page_name = gnc_plugin_page_get_plugin_name(page); + if (!page_name) { + LEAVE("no page_name of plugin_page"); + return; + } + + if (strcmp(page_name, GNC_PLUGIN_PAGE_ACCOUNT_TREE_NAME) == 0) { + DEBUG("account tree page, adding signal"); + g_signal_connect(page, "account_selected", + G_CALLBACK(gnc_plugin_ab_account_selected), NULL); + } + LEAVE(" "); +} + +/** + * Whenever the current page has changed, update the aqbanking menus based upon + * the page that is currently selected. + */ +static void +gnc_plugin_ab_main_window_page_changed(GncMainWindow *window, + GncPluginPage *page, gpointer user_data) +{ +} + +/** + * An account had been (de)selected in an "account tree" page. Update the hbci + * menus appropriately. + */ +static void +gnc_plugin_ab_account_selected(GncPluginPage *plugin_page, Account *account, + gpointer user_data) +{ + GtkActionGroup *action_group; + GncMainWindow *window; + + g_return_if_fail(GNC_IS_PLUGIN_PAGE(plugin_page)); + window = GNC_MAIN_WINDOW(plugin_page->window); + g_return_if_fail(GNC_IS_MAIN_WINDOW(window)); + action_group = gnc_main_window_get_action_group(window, PLUGIN_ACTIONS_NAME); + g_return_if_fail(GTK_IS_ACTION_GROUP(action_group)); + gnc_plugin_update_actions(action_group, need_account_actions, + "sensitive", account != NULL); + +} + +/************************************************************ + * Auxiliary Functions * + ************************************************************/ + +/** + * Given a pointer to a main window, try and extract an Account from it. If the + * current page is an "account tree" page, get the account corresponding to the + * selected account. (What if multiple accounts are selected?) If the current + * page is a "register" page, get the head account for the register. (Returns + * NULL for a general ledger or search register.) + * + * @param window A pointer to a GncMainWindow object. + * @return A pointer to an account, if one can be determined from the current + * page. NULL otherwise. + */ +static Account * +main_window_to_account(GncMainWindow *window) +{ + GncPluginPage *page; + const gchar *page_name; + Account *account = NULL; + const gchar *account_name; + + ENTER("main window %p", window); + if (!GNC_IS_MAIN_WINDOW(window)) { + LEAVE("no main_window"); + return NULL; + } + + page = gnc_main_window_get_current_page(window); + if (!GNC_IS_PLUGIN_PAGE(page)) { + LEAVE("no plugin_page"); + return NULL; + } + page_name = gnc_plugin_page_get_plugin_name(page); + if (!page_name) { + LEAVE("no page_name of plugin_page"); + return NULL; + } + + if (strcmp(page_name, GNC_PLUGIN_PAGE_REGISTER_NAME) == 0) { + DEBUG("register page"); + account = gnc_plugin_page_register_get_account( + GNC_PLUGIN_PAGE_REGISTER(page)); + } else if (strcmp(page_name, GNC_PLUGIN_PAGE_ACCOUNT_TREE_NAME) == 0) { + DEBUG("account tree page"); + account = gnc_plugin_page_account_tree_get_current_account( + GNC_PLUGIN_PAGE_ACCOUNT_TREE(page)); + } else { + account = NULL; + } + account_name = account ? xaccAccountGetName(account) : NULL; + LEAVE("account %s(%p)", account_name ? account_name : "(null)", account); + return account; +} + +/************************************************************ + * Command Callbacks * + ************************************************************/ + +static void +gnc_plugin_ab_cmd_setup(GtkAction *action, GncMainWindowActionData *data) +{ + ENTER("action %p, main window data %p", action, data); + gnc_ab_initial_druid(); + LEAVE(" "); +} + +static void +gnc_plugin_ab_cmd_get_balance(GtkAction *action, GncMainWindowActionData *data) +{ + Account *account; + + ENTER("action %p, main window data %p", action, data); + account = main_window_to_account(data->window); + if (account == NULL) { + g_message("No AqBanking account selected"); + LEAVE("no account"); + return; + } + + gnc_ab_getbalance(GTK_WIDGET(data->window), account); + + LEAVE(" "); +} + +static void +gnc_plugin_ab_cmd_get_transactions(GtkAction *action, + GncMainWindowActionData *data) +{ + Account *account; + + ENTER("action %p, main window data %p", action, data); + account = main_window_to_account(data->window); + if (account == NULL) { + g_message("No AqBanking account selected"); + LEAVE("no account"); + return; + } + + gnc_ab_gettrans(GTK_WIDGET(data->window), account); + + LEAVE(" "); +} + +static void +gnc_plugin_ab_cmd_issue_transaction(GtkAction *action, + GncMainWindowActionData *data) +{ + Account *account; + + ENTER("action %p, main window data %p", action, data); + account = main_window_to_account(data->window); + if (account == NULL) { + g_message("No AqBanking account selected"); + LEAVE("no account"); + return; + } + + gnc_ab_maketrans(GTK_WIDGET(data->window), account, SINGLE_TRANSFER); + + LEAVE(" "); +} + +static void +gnc_plugin_ab_cmd_issue_inttransaction(GtkAction *action, + GncMainWindowActionData *data) +{ + Account *account; + + ENTER("action %p, main window data %p", action, data); + account = main_window_to_account(data->window); + if (account == NULL) { + g_message("No AqBanking account selected"); + LEAVE("no account"); + return; + } + + gnc_ab_maketrans(GTK_WIDGET(data->window), account, + SINGLE_INTERNAL_TRANSFER); + + LEAVE(" "); +} + +static void +gnc_plugin_ab_cmd_issue_direct_debit(GtkAction *action, + GncMainWindowActionData *data) +{ + Account *account; + + ENTER("action %p, main window data %p", action, data); + account = main_window_to_account(data->window); + if (account == NULL) { + g_message("No AqBanking account selected"); + LEAVE("no account"); + return; + } + + gnc_ab_maketrans(GTK_WIDGET(data->window), account, SINGLE_DEBITNOTE); + + LEAVE(" "); +} + +static void +gnc_plugin_ab_cmd_mt940_import(GtkAction *action, GncMainWindowActionData *data) +{ + gchar *format = gnc_gconf_get_string(GCONF_SECTION_AQBANKING, + KEY_FORMAT_SWIFT940, NULL); + gnc_file_aqbanking_import("swift", format ? format : "swift-mt940", FALSE); + g_free(format); +} + +static void +gnc_plugin_ab_cmd_mt942_import(GtkAction *action, GncMainWindowActionData *data) +{ + gchar *format = gnc_gconf_get_string(GCONF_SECTION_AQBANKING, + KEY_FORMAT_SWIFT942, NULL); + gnc_file_aqbanking_import("swift", format ? format : "swift-mt942", FALSE); + g_free(format); +} + +static void +gnc_plugin_ab_cmd_dtaus_import(GtkAction *action, GncMainWindowActionData *data) +{ + gchar *format = gnc_gconf_get_string(GCONF_SECTION_AQBANKING, + KEY_FORMAT_DTAUS, NULL); + gnc_file_aqbanking_import("dtaus", format ? format : "default", FALSE); + g_free(format); +} + +static void +gnc_plugin_ab_cmd_dtaus_importsend(GtkAction *action, + GncMainWindowActionData *data) +{ + gchar *format = gnc_gconf_get_string(GCONF_SECTION_AQBANKING, + KEY_FORMAT_DTAUS, NULL); + gnc_file_aqbanking_import("dtaus", format ? format : "default", TRUE); + g_free(format); +} + +/************************************************************ + * Plugin Bootstrapping * + ************************************************************/ + +void +gnc_plugin_aqbanking_create_plugin(void) +{ + GncPlugin *plugin = gnc_plugin_aqbanking_new(); + + gnc_plugin_manager_add_plugin(gnc_plugin_manager_get(), plugin); +} diff --git a/src/import-export/aqbanking/gnc-plugin-aqbanking.h b/src/import-export/aqbanking/gnc-plugin-aqbanking.h new file mode 100644 index 0000000000..62c8bec4cb --- /dev/null +++ b/src/import-export/aqbanking/gnc-plugin-aqbanking.h @@ -0,0 +1,83 @@ +/* + * gnc-plugin-aqbanking.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-plugin-aqbanking.h + * @brief Plugin registration of the AqBanking module + * @author Copyright (C) 2003 David Hampton + * @author Copyright (C) 2008 Andreas Koehler + */ + +#ifndef GNC_PLUGIN_AQBANKING_H +#define GNC_PLUGIN_AQBANKING_H + +#include + +#include "gnc-plugin.h" + +G_BEGIN_DECLS + +/* type macros */ +#define GNC_TYPE_PLUGIN_AQBANKING (gnc_plugin_aqbanking_get_type()) +#define GNC_PLUGIN_AQBANKING(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GNC_TYPE_PLUGIN_AQBANKING, GncPluginAqBanking)) +#define GNC_PLUGIN_AQBANKING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GNC_TYPE_PLUGIN_AQBANKING, GncPluginAqBankingClass)) +#define GNC_IS_PLUGIN_AQBANKING(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GNC_TYPE_PLUGIN_AQBANKING)) +#define GNC_IS_PLUGIN_AQBANKING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GNC_TYPE_PLUGIN_AQBANKING)) +#define GNC_PLUGIN_AQBANKING_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GNC_TYPE_PLUGIN_AQBANKING, GncPluginAqBankingClass)) + +#define GNC_PLUGIN_AQBANKING_NAME "gnc-plugin-aqbanking" + +/* typedefs & structures */ +typedef struct { + GncPlugin gnc_plugin; +} GncPluginAqBanking; + +typedef struct { + GncPluginClass gnc_plugin; +} GncPluginAqBankingClass; + +/* function prototypes */ + +/** + * @return The glib runtime type of an aqbanking plugin page + **/ +GType gnc_plugin_aqbanking_get_type(void); + +/** + * @return A new GncPluginAqBanking object + */ +GncPlugin* gnc_plugin_aqbanking_new(void); + +/** + * Create a new GncPluginAqBanking object and register it. + */ +void gnc_plugin_aqbanking_create_plugin(void); + +G_END_DECLS + +/** @} */ +/** @} */ + +#endif /* GNC_PLUGIN_AQBANKING_H */ diff --git a/src/import-export/aqbanking/gncmod-aqbanking.c b/src/import-export/aqbanking/gncmod-aqbanking.c new file mode 100644 index 0000000000..587ea88f07 --- /dev/null +++ b/src/import-export/aqbanking/gncmod-aqbanking.c @@ -0,0 +1,91 @@ +/* + * gncmod-aqbanking.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 gncmod-aqbanking.c + * @brief Module definition/initialization for AqBanking support + * @author Copyright (C) 2002 Christian Stimming + * @author Copyright (C) 2008 Andreas Koehler + */ + +#include "config.h" + +#include "gnc-ab-utils.h" +#include "gnc-module.h" +#include "gnc-module-api.h" +#include "gnc-plugin-aqbanking.h" +#include "dialog-preferences.h" + +GNC_MODULE_API_DECL(libgncmod_aqbanking) + +/* version of the gnc module system interface we require */ +gint libgncmod_aqbanking_gnc_module_system_interface = 0; + +/* module versioning uses libtool semantics. */ +gint libgncmod_aqbanking_gnc_module_current = 0; +gint libgncmod_aqbanking_gnc_module_revision = 0; +gint libgncmod_aqbanking_gnc_module_age = 0; + +gchar * +libgncmod_aqbanking_gnc_module_path(void) +{ + return g_strdup("gnucash/import-export/aqbanking"); +} + +gchar * +libgncmod_aqbanking_gnc_module_description(void) { + return g_strdup("Support for Online Banking protocols"); +} + +gint +libgncmod_aqbanking_gnc_module_init(gint refcount) +{ + /* Load modules we depend on */ + if(!gnc_module_load("gnucash/engine", 0) + || !gnc_module_load("gnucash/app-utils", 0) + || !gnc_module_load("gnucash/gnome-utils", 0) + || !gnc_module_load("gnucash/import-export", 0)) { + return FALSE; + } + + /* Add menu items with C callbacks */ + gnc_plugin_aqbanking_create_plugin(); + + gnc_preferences_add_to_page("aqbanking.glade", "aqbanking_prefs", + "Online Banking"); + + /* Initialize gwen library */ + gnc_GWEN_Init(); + + return 1; +} + +gint +libgncmod_aqbanking_gnc_module_end(gint refcount) { + /* Delete the shared AB_BANKING object */ + gnc_AB_BANKING_delete(NULL); + + /* Finalize gwen library */ + gnc_GWEN_Fini(); + + return 1; +} diff --git a/src/import-export/aqbanking/schemas/Makefile.am b/src/import-export/aqbanking/schemas/Makefile.am new file mode 100644 index 0000000000..2ea2b95f3f --- /dev/null +++ b/src/import-export/aqbanking/schemas/Makefile.am @@ -0,0 +1,21 @@ +schemadir = @GCONF_SCHEMA_FILE_DIR@ +schemas_in_files = \ + apps_gnucash_dialog_hbci.schemas.in +schema_DATA = $(schemas_in_files:.schemas.in=.schemas) + +@INTLTOOL_SCHEMAS_RULE@ + +EXTRA_DIST = $(schemas_in_files) + +CLEANFILES = $(schema_DATA) + +install-data-local: +if GCONF_SCHEMAS_INSTALL + -mkdir -p $(DESTDIR)$(GCONF_SCHEMA_CONFIG_SOURCE_DIRONLY) + GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $(schema_DATA) +endif + +uninstall-local: +if GCONF_SCHEMAS_INSTALL + GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-uninstall-rule $(schema_DATA) +endif diff --git a/src/import-export/aqbanking/schemas/apps_gnucash_dialog_hbci.schemas.in b/src/import-export/aqbanking/schemas/apps_gnucash_dialog_hbci.schemas.in new file mode 100644 index 0000000000..a33eca54f2 --- /dev/null +++ b/src/import-export/aqbanking/schemas/apps_gnucash_dialog_hbci.schemas.in @@ -0,0 +1,143 @@ + + + + + + /schemas/apps/gnucash/dialogs/import/hbci/position + /apps/gnucash/dialogs/import/hbci/connection_dialog/window_position + gnucash + list + int + + Window position + + The X,Y coordinates of the top left corner of the dialog + when it was last closed. + + + + + + /schemas/apps/gnucash/dialogs/import/hbci/geometry + /apps/gnucash/dialogs/import/hbci/connection_dialog/window_geometry + gnucash + list + int + + Window geometry + + The width and size of the dialog when it was last closed. + + + + + + /schemas/apps/gnucash/dialogs/import/hbci/close_on_finish + /apps/gnucash/dialogs/import/hbci/close_on_finish + gnucash + bool + True + + Close dialog when finished + + If active, the window will be closed automatically when you + finish the HBCI/AqBanking import process. Otherwise it will + stay open. + + + + + + /schemas/apps/gnucash/dialogs/import/hbci/remember_pin + /apps/gnucash/dialogs/import/hbci/remember_pin + gnucash + bool + False + + Remember the PIN in memory + If active, the PIN for HBCI/AqBanking actions will be + remembered in memory during a session. Otherwise it will have + to be entered again each time during a session when it is + needed. + + + + + + /schemas/apps/gnucash/dialogs/import/hbci/verbose_debug + /apps/gnucash/dialogs/import/hbci/verbose_debug + gnucash + bool + False + + Verbose HBCI debug messages + Enables verbose debug messages for HBCI/AqBanking Online Banking. + + + + + /schemas/apps/gnucash/dialogs/import/hbci/format_dtaus + /apps/gnucash/dialogs/import/hbci/format_dtaus + gnucash + string + default + + DTAUS import data format + + This setting specifies the data format when importing DTAUS + files. The AqBanking library offers various import formats + (called "profiles") of which you can choose one here. + + + + + + /schemas/apps/gnucash/dialogs/import/hbci/format_csv + /apps/gnucash/dialogs/import/hbci/format_csv + gnucash + string + default + + CSV import data format + + This setting specifies the data format when importing CSV + files. The AqBanking library offers various import formats + (called "profiles") of which you can choose one here. + + + + + + /schemas/apps/gnucash/dialogs/import/hbci/format_swift_mt940 + /apps/gnucash/dialogs/import/hbci/format_swift_mt940 + gnucash + string + swift-mt940 + + SWIFT MT940 import data format + + This setting specifies the data format when importing SWIFT + MT940 files. The AqBanking library offers various import + formats (called "profiles") of which you can choose one here. + + + + + + /schemas/apps/gnucash/dialogs/import/hbci/format_swift_mt942 + /apps/gnucash/dialogs/import/hbci/format_swift_mt942 + gnucash + string + swift-mt942 + + SWIFT MT942 import data format + + This setting specifies the data format when importing SWIFT + MT942 files. The AqBanking library offers various import + formats (called "profiles") of which you can choose one here. + + + + + + diff --git a/src/import-export/hbci/Makefile.am b/src/import-export/hbci/Makefile.am index a53eaa8492..d999610a7e 100644 --- a/src/import-export/hbci/Makefile.am +++ b/src/import-export/hbci/Makefile.am @@ -56,7 +56,7 @@ libgncmod_hbci_la_LIBADD = \ ${GLADE_LIBS} \ ${QOF_LIBS} \ ${GLIB_LIBS} \ - ${HBCI_LIBS} + ${AQBANKING_LIBS} AM_CFLAGS = \ -I${top_srcdir}/src \ @@ -77,7 +77,7 @@ AM_CFLAGS = \ ${GLADE_CFLAGS} \ ${QOF_CFLAGS} \ ${GLIB_CFLAGS} \ - ${HBCI_CFLAGS} + ${AQBANKING_CFLAGS} #gladedir = $(GNC_GLADE_DIR) #glade_DATA =