[neon/backports-focal/libaqbanking/Neon/release] /: New upstream version 6.3.1

Micha Lenk null at kde.org
Mon Sep 27 15:37:28 BST 2021


Git commit d260acfb674fb90a098dcdfc4ad0e5f08c6a58f8 by Micha Lenk.
Committed on 11/09/2021 at 19:10.
Pushed by jriddell into branch 'Neon/release'.

New upstream version 6.3.1

M  +71   -30   ChangeLog
M  +1    -1    Makefile.in
M  +3    -3    aqbanking.iss
M  +1    -1    aqbanking.spec
M  +2    -2    configure
M  +2    -2    configure.ac
M  +1    -1    mksymlinks.sh
M  +1    -1    src/libs/aqbanking/backendsupport/swiftdescr.c
M  +2    -2    src/libs/aqbanking/backendsupport/swiftdescr.xml
M  +1    -1    src/libs/aqbanking/banking_imex.c
M  +55   -0    src/libs/aqbanking/types/transaction.c
M  +27   -0    src/libs/aqbanking/types/transaction.h
M  +14   -0    src/libs/aqbanking/types/transaction.xml
M  +1    -0    src/libs/aqbanking/types/transaction_p.h
M  +4    -4    src/libs/aqbanking/version.h
M  +1    -1    src/libs/plugins/backends/aqfints/libaqfints/parser/segment.h
M  +6    -6    src/libs/plugins/backends/aqfints/libaqfints/service/bpd/bpd.h
M  +1    -1    src/libs/plugins/backends/aqfints/libaqfints/service/bpd/bpdaddr.h
M  +1    -1    src/libs/plugins/backends/aqfints/libaqfints/service/bpd/taninfo.h
M  +1    -1    src/libs/plugins/backends/aqfints/libaqfints/service/upd/accountdata.h
M  +1    -1    src/libs/plugins/backends/aqfints/libaqfints/service/upd/userdata.h
M  +12   -0    src/libs/plugins/backends/aqhbci/ajobs/jobgetestatements.c
M  +101  -8    src/libs/plugins/backends/aqhbci/applayer/cbox_queue.c
M  +1    -0    src/libs/plugins/backends/aqhbci/joblayer/job_l.h
M  +6    -6    src/libs/plugins/backends/aqhbci/joblayer/job_swift.c
M  +1    -1    src/libs/plugins/backends/aqhbci/joblayer/jobqueue_addjob.c
M  +20   -1    src/libs/plugins/backends/aqhbci/joblayer/jobqueue_dispatch.c
M  +2    -0    src/tools/aqbanking-cli/globals.h
M  +17   -4    src/tools/aqbanking-cli/request.c
M  +12   -5    src/tools/aqbanking-cli/util.c

https://invent.kde.org/neon/backports-focal/libaqbanking/commit/d260acfb674fb90a098dcdfc4ad0e5f08c6a58f8

diff --git a/ChangeLog b/ChangeLog
index a289cdc..94870a5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,74 @@
+------------------------------------------------------------------
+2021-09-10 14:17:52 +0200 Martin Preuss
+Prepared release 6.3.1.
+
+------------------------------------------------------------------
+2021-07-14 18:56:58 +0200 Martin Preuss
+Decreased verbosity.
+
+------------------------------------------------------------------
+2021-04-01 16:04:13 +0200 Tobias Deiminger
+Send acknowledgements (HKQTG)
+FinTS 3.0 defines an acknowledge workflow (C.9.4, "Empfangsquittung"):
+> By sending this segment, the customer acknowledges they have
+> correctly received a bank response. The acknowledgement always
+> relates to the direclty preceding bank response.
+> Optionally, the acknowledgement can be supplemented by a code
+> ("Quittungscode", e.g. a hash value), which allows the bank to draw
+> addtional conclusion about the job to be acknowledged.
+
+In practice, this means you can mark documents in the inbox of a
+banking web client as "read", and prevent your bank from sending
+you printed documents by post.
+
+FinTS defines acknwoledgement only for a subset of jobs
+- HIEKA "Quittungscode"
+  BPD HIEKAS "Parameter Kontoauszug":"Quittierung benoetig"
+- HIECA "Quittungscode"
+  BPD HIEKAS "Parameter Kontoauszug camt":"Quittierung benoetig"
+- HIEKP "Quittungscode"
+  BPD HIEKPS "Parameter Kontoauszug PDF":"Quittierung benoetig"
+- HIKAA "Quittungscode"
+  BPD HIKAA "Postfach Nachricht abrufen":"Quittierung (fallweise)
+  benoetigt"
+
+This commit adds some generic handling, and fully enables acknowledgment
+for HIEKA and HIEKP, i.e. AB_Transaction_CommandGetEStatements.
+
+Users can enable acknowledgement with a new CLI option for the request
+command:
+$ aqbanking-cli -P /tmp/pinfile request --estatements -a 1234567 -c est.ctx --fromdate=20200101 --docnumber=10 --acknowledge
+
+or they enable it via API by
+AB_Transaction_SetAcknowledge(myTransaction, AB_Transaction_AckJobsWithAckCode).
+
+Disclaimer: I don't understand the spec in how "preceding response" is
+supposed to be interpreted for multi-segment responses and if the optional
+acknowledge code was not sent by the bank. Seems the spec leaves some doubt
+there, it could mean
+- ack all segments from the preceding multi-segment response
+- ack only the first segment from the preceding multi-segment response
+- ack only the last segement
+- ... whatever, you get it
+
+Therefore I'm only implementing cases where an acknowledgement code was
+given, because it allows to definitely identify the segment we mean.
+
+------------------------------------------------------------------
+2021-06-06 19:01:53 +0200 Martin Preuss
+aqbanking-cli: Fixed argument for document number
+- minnum and maxnum specify the minimum and maximum *occurrence* of an
+  argument, not the allowed range for values
+- changed argument name to "--docnumber=xxx"
+
+------------------------------------------------------------------
+2021-06-06 18:53:40 +0200 Martin Preuss
+aqbanking-cli: Fixed a bug.
+
+------------------------------------------------------------------
+2021-05-05 17:31:21 +0200 Martin Preuss
+Prepared release 6.3.0
+
 ------------------------------------------------------------------
 2021-05-05 16:37:57 +0200 Martin Preuss
 Prepared release 6.3.0stable.
@@ -478,33 +549,3 @@ This is much easier than the old OFX v1 importer which will soon be removed.
 Adding the ability to read new OFX structures to the old parser is extremely
 painful, this is now much much easier with the generic XML importer (which
 wasn't available when the old OFX parser was created).
-
-------------------------------------------------------------------
-2021-02-14 20:41:40 +0100 Martin Preuss
-Fixed a bug.
-
-------------------------------------------------------------------
-2021-02-14 18:22:25 +0100 Christian Stimming
-i18n: Update German translation
-Still 83f, 314u to go, though.
-
-------------------------------------------------------------------
-2021-02-14 18:03:42 +0100 Christian Stimming
-AqHBCI: Reduce log level of non-error messages back to "notice"
-
-------------------------------------------------------------------
-2021-02-13 02:12:35 +0100 Martin Preuss
-Released version 6.2.6.
-
-------------------------------------------------------------------
-2021-02-13 01:06:23 +0100 Martin Preuss
-Prepared release 6.2.6.
-
-------------------------------------------------------------------
-2021-02-10 18:06:44 +0100 Thomas Baumgart
-Provide setting of includedir
-Set includedir to AqBanking value because it it is not declared in
-aqbanking-config.cmake cmake will pick up the one defined in
-gwenhywfar's.
-
-Patch provided by Dawid Wróbel
diff --git a/Makefile.in b/Makefile.in
index 1d62fc3..cad4a27 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1087,8 +1087,8 @@ maintainer-clean-generic:
 	@echo "This command is intended for maintainers to use"
 	@echo "it deletes files that may require special tools to rebuild."
 	-test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
- at IF_MAKE_I18N_FILES_FALSE@install-data-local:
 @IF_MAKE_I18N_FILES_FALSE at uninstall-local:
+ at IF_MAKE_I18N_FILES_FALSE@install-data-local:
 clean: clean-recursive
 
 clean-am: clean-generic clean-libtool mostlyclean-am
diff --git a/aqbanking.iss b/aqbanking.iss
index 7eff101..1e23dc7 100644
--- a/aqbanking.iss
+++ b/aqbanking.iss
@@ -8,7 +8,7 @@
 [Setup]
 ; Using the name here directly because we want it capitalized
 AppName=AqBanking
-AppVerName=AqBanking 6.3.0
+AppVerName=AqBanking 6.3.1
 AppPublisher=AqBanking Development Team
 AppPublisherURL=http://sourceforge.net/projects/aqbanking
 AppSupportURL=http://sourceforge.net/support/getsupport.php?group_id=115695
@@ -18,7 +18,7 @@ DefaultDirName={pf}\aqbanking
 DirExistsWarning=no
 InfoAfterFile=README
 LicenseFile=COPYING
-OutputBaseFilename=aqbanking-6.3.0-setup
+OutputBaseFilename=aqbanking-6.3.1-setup
 OutputDir=.
 UninstallFilesDir={app}\uninstall\aqbanking
 
@@ -151,7 +151,7 @@ begin
   StringChange(FileString, '@'+'aqbanking_pkgdatadir@', pkgdatadir);
   StringChange(FileString, '@'+'AQBANKING_VERSION_MAJOR@', '6');
   StringChange(FileString, '@'+'AQBANKING_VERSION_MINOR@', '3');
-  StringChange(FileString, '@'+'AQBANKING_VERSION_PATCHLEVEL@', '0');
+  StringChange(FileString, '@'+'AQBANKING_VERSION_PATCHLEVEL@', '1');
   StringChange(FileString, '@'+'AQBANKING_VERSION_BUILD@', '0');
   StringChange(FileString, '@'+'AQBANKING_VERSION_TAG@', 'stable');
 
diff --git a/aqbanking.spec b/aqbanking.spec
index d641145..a05f44d 100644
--- a/aqbanking.spec
+++ b/aqbanking.spec
@@ -2,7 +2,7 @@
 # neededforbuild gwenhywfar gwenhywfar-devel python python-ctypes pyyxml libchipcard2-devel libchipcard2 pkgconfig gettext-devel libacl-devel libacl libattr-devel libattr
 
 %define name aqbanking
-%define version 6.3.0
+%define version 6.3.1
 
 %define dist    Ubuntu
 %define disttag ubuntu
diff --git a/configure b/configure
index 559a798..5c5002e 100755
--- a/configure
+++ b/configure
@@ -2678,7 +2678,7 @@ ac_config_headers="$ac_config_headers config.h"
 
 AQBANKING_VERSION_MAJOR=6
 AQBANKING_VERSION_MINOR=3
-AQBANKING_VERSION_PATCHLEVEL=0
+AQBANKING_VERSION_PATCHLEVEL=1
 AQBANKING_VERSION_BUILD=0
 AQBANKING_VERSION_TAG="stable"
 
@@ -2695,7 +2695,7 @@ AQBANKING_VERSION_TAG="stable"
 
 AQBANKING_SO_CURRENT=47
 AQBANKING_SO_AGE=3
-AQBANKING_SO_REVISION=0
+AQBANKING_SO_REVISION=1
 AQBANKING_SO_EFFECTIVE="`echo \$(($AQBANKING_SO_CURRENT-$AQBANKING_SO_AGE))`"
 
 
diff --git a/configure.ac b/configure.ac
index 36e4024..24e256c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -16,7 +16,7 @@ AC_CONFIG_HEADERS([config.h])
 
 AQBANKING_VERSION_MAJOR=6
 AQBANKING_VERSION_MINOR=3
-AQBANKING_VERSION_PATCHLEVEL=0
+AQBANKING_VERSION_PATCHLEVEL=1
 AQBANKING_VERSION_BUILD=0
 dnl "stable", "rcX", "betaX", "svn"
 AQBANKING_VERSION_TAG="stable"
@@ -34,7 +34,7 @@ AQBANKING_VERSION_TAG="stable"
 
 AQBANKING_SO_CURRENT=47
 AQBANKING_SO_AGE=3
-AQBANKING_SO_REVISION=0
+AQBANKING_SO_REVISION=1
 AQBANKING_SO_EFFECTIVE="`echo \$(($AQBANKING_SO_CURRENT-$AQBANKING_SO_AGE))`"
 
 
diff --git a/mksymlinks.sh b/mksymlinks.sh
index 1e65c43..63bb71d 100644
--- a/mksymlinks.sh
+++ b/mksymlinks.sh
@@ -91,7 +91,7 @@ symlinkFolder () {
 #symlinkFolder "src/libs/aqbankingpp" "aqbanking6/aqbankingpp"
 
 # symlink all headers from src/libs/plugins/backends/
-#dirlist='aqhbci aqofxconnect aqebics aqpaypal'  # list might be empty
+#dirlist='aqfints aqhbci aqofxconnect aqnone aqpaypal aqebics'  # list might be empty
 dirlist='aqebics aqofxconnect aqpaypal'
 for backend in ${dirlist} ; do
   mkdir -p aqbanking6/${backend}
diff --git a/src/libs/aqbanking/backendsupport/swiftdescr.c b/src/libs/aqbanking/backendsupport/swiftdescr.c
index 3e1cf37..656b12f 100644
--- a/src/libs/aqbanking/backendsupport/swiftdescr.c
+++ b/src/libs/aqbanking/backendsupport/swiftdescr.c
@@ -424,7 +424,7 @@ int AB_SwiftDescr_Matches(const AB_SWIFT_DESCR *d, const char *wantedFamily, int
 AB_SWIFT_DESCR *AB_SwiftDescr_List__FindInternal(AB_SWIFT_DESCR *d, const char *wantedFamily, int wantedVersion1, int wantedVersion2, int wantedVersion3){ if (!wantedFamily) wantedFamily="*"; while(d) { if (1==AB_SwiftDescr_Matches(d, wantedFamily, wantedVersion1, wantedVersion2, wantedVersion3)) break; d=AB_SwiftDescr_List_Next(d); } /* while */ return d; }
 AB_SWIFT_DESCR *AB_SwiftDescr_List_FindFirst(const AB_SWIFT_DESCR_LIST *dl, const char *wantedFamily, int wantedVersion1, int wantedVersion2, int wantedVersion3) { AB_SWIFT_DESCR *d; if (AB_SwiftDescr_List_GetCount(dl)==0) { DBG_INFO(AQBANKING_LOGDOMAIN, "empty list"); return NULL; } d=AB_SwiftDescr_List_First(dl); assert(d); return AB_SwiftDescr_List__FindInternal(d, wantedFamily, wantedVersion1, wantedVersion2, wantedVersion3); }
 AB_SWIFT_DESCR *AB_SwiftDescr_List_FindNext(AB_SWIFT_DESCR *d, const char *wantedFamily, int wantedVersion1, int wantedVersion2, int wantedVersion3){ assert(d); d=AB_SwiftDescr_List_Next(d); if (d==NULL) { DBG_INFO(AQBANKING_LOGDOMAIN, "No more entries in list"); return NULL; } return AB_SwiftDescr_List__FindInternal(d, wantedFamily, wantedVersion1, wantedVersion2, wantedVersion3); }
-AB_SWIFT_DESCR *AB_SwiftDescr_FromString(const char *inputName) { GWEN_STRINGLIST *slist; int count; /* add delimiters here if needed */ slist=GWEN_StringList_fromString(inputName, ":._- \t", 0); if (slist==NULL) { DBG_ERROR(AQBANKING_LOGDOMAIN, "Could not parse string [%s] into list", inputName); return NULL; } count=GWEN_StringList_Count(slist); if (count>2) { int i; for (i=count-1; i>=0; i--) { const char *s; s=GWEN_StringList_StringAt(slist, i); DBG_DEBUG(AQBANKING_LOGDOMAIN, "Handling string[%d of %d]: \"%s\"", i, count, s?s:"<empty>"); if (s && (strcasecmp(s, "camt")==0 || strcasecmp(s, "pain")==0)) { if ((count-i)<4) { DBG_ERROR(AQBANKING_LOGDOMAIN, "Too few entries left in string list (source: [%s])", inputName); break; } else { const char *family; int version1; int version2; int version3; AB_SWIFT_DESCR *d; family=s; i++; s=GWEN_StringList_StringAt(slist, i); if (!(s && *s && 1==sscanf(s, "%d", &version1))) { DBG_ERROR(AQBANKING_LOGDOMAIN, "No valid string for version1 [%s] ", s?s:"<empty>"); GWEN_StringList_free(slist); return NULL; } i++; s=GWEN_StringList_StringAt(slist, i); if (!(s && *s && 1==sscanf(s, "%d", &version2))) { DBG_ERROR(AQBANKING_LOGDOMAIN, "No valid string for version2 [%s] ", s?s:"<empty>"); GWEN_StringList_free(slist); return NULL; } i++; s=GWEN_StringList_StringAt(slist, i); if (!(s && *s && 1==sscanf(s, "%d", &version3))) { DBG_ERROR(AQBANKING_LOGDOMAIN, "No valid string for version3 [%s] ", s?s:"<empty>"); GWEN_StringList_free(slist); return NULL; } i++; DBG_INFO(AQBANKING_LOGDOMAIN, "Creating descriptor %s.%03d.%03d.%02d", family?family:"<empty>", version1, version2, version3); d=AB_SwiftDescr_new(); AB_SwiftDescr_SetFamily(d, family); AB_SwiftDescr_SetVersion1(d, version1); AB_SwiftDescr_SetVersion2(d, version2); AB_SwiftDescr_SetVersion3(d, version3); GWEN_StringList_free(slist); return d; } } /* if camt or pain */ } /* for */ } /* if enough entries in string list to be a valid descriptor */ else { DBG_ERROR(AQBANKING_LOGDOMAIN, "Too few entries in string list (source: [%s])", inputName); } GWEN_StringList_free(slist); return NULL; }
+AB_SWIFT_DESCR *AB_SwiftDescr_FromString(const char *inputName) { GWEN_STRINGLIST *slist; int count; /* add delimiters here if needed */ slist=GWEN_StringList_fromString(inputName, ":._- \t", 0); if (slist==NULL) { DBG_ERROR(AQBANKING_LOGDOMAIN, "Could not parse string [%s] into list", inputName); return NULL; } count=GWEN_StringList_Count(slist); if (count>2) { int i; for (i=count-1; i>=0; i--) { const char *s; s=GWEN_StringList_StringAt(slist, i); DBG_DEBUG(AQBANKING_LOGDOMAIN, "Handling string[%d of %d]: \"%s\"", i, count, s?s:"<empty>"); if (s && (strcasecmp(s, "camt")==0 || strcasecmp(s, "pain")==0)) { if ((count-i)<4) { DBG_INFO(AQBANKING_LOGDOMAIN, "Too few entries left in string list (source: [%s])", inputName); break; } else { const char *family; int version1; int version2; int version3; AB_SWIFT_DESCR *d; family=s; i++; s=GWEN_StringList_StringAt(slist, i); if (!(s && *s && 1==sscanf(s, "%d", &version1))) { DBG_ERROR(AQBANKING_LOGDOMAIN, "No valid string for version1 [%s] ", s?s:"<empty>"); GWEN_StringList_free(slist); return NULL; } i++; s=GWEN_StringList_StringAt(slist, i); if (!(s && *s && 1==sscanf(s, "%d", &version2))) { DBG_ERROR(AQBANKING_LOGDOMAIN, "No valid string for version2 [%s] ", s?s:"<empty>"); GWEN_StringList_free(slist); return NULL; } i++; s=GWEN_StringList_StringAt(slist, i); if (!(s && *s && 1==sscanf(s, "%d", &version3))) { DBG_ERROR(AQBANKING_LOGDOMAIN, "No valid string for version3 [%s] ", s?s:"<empty>"); GWEN_StringList_free(slist); return NULL; } i++; DBG_INFO(AQBANKING_LOGDOMAIN, "Creating descriptor %s.%03d.%03d.%02d", family?family:"<empty>", version1, version2, version3); d=AB_SwiftDescr_new(); AB_SwiftDescr_SetFamily(d, family); AB_SwiftDescr_SetVersion1(d, version1); AB_SwiftDescr_SetVersion2(d, version2); AB_SwiftDescr_SetVersion3(d, version3); GWEN_StringList_free(slist); return d; } } /* if camt or pain */ } /* for */ } /* if enough entries in string list to be a valid descriptor */ else { DBG_INFO(AQBANKING_LOGDOMAIN, "Too few entries in string list (source: [%s])", inputName); } GWEN_StringList_free(slist); return NULL; }
 
 /* code headers */
 
diff --git a/src/libs/aqbanking/backendsupport/swiftdescr.xml b/src/libs/aqbanking/backendsupport/swiftdescr.xml
index d38216a..a8d6c99 100644
--- a/src/libs/aqbanking/backendsupport/swiftdescr.xml
+++ b/src/libs/aqbanking/backendsupport/swiftdescr.xml
@@ -289,7 +289,7 @@
                    DBG_DEBUG(AQBANKING_LOGDOMAIN, "Handling string[%d of %d]: \"%s\"", i, count, s?s:"<empty>");
                    if (s && (strcasecmp(s, "camt")==0 || strcasecmp(s, "pain")==0)) {
                      if ((count-i)<4) {
-                       DBG_ERROR(AQBANKING_LOGDOMAIN, "Too few entries left in string list (source: [%s])", inputName);
+                       DBG_INFO(AQBANKING_LOGDOMAIN, "Too few entries left in string list (source: [%s])", inputName);
                        break;
                      }
                      else {
@@ -341,7 +341,7 @@
                  
                } /* if enough entries in string list to be a valid descriptor */
                else {
-                 DBG_ERROR(AQBANKING_LOGDOMAIN, "Too few entries in string list (source: [%s])", inputName);
+                 DBG_INFO(AQBANKING_LOGDOMAIN, "Too few entries in string list (source: [%s])", inputName);
                }
                
                GWEN_StringList_free(slist);
diff --git a/src/libs/aqbanking/banking_imex.c b/src/libs/aqbanking/banking_imex.c
index b4be5ea..7056382 100644
--- a/src/libs/aqbanking/banking_imex.c
+++ b/src/libs/aqbanking/banking_imex.c
@@ -1169,7 +1169,7 @@ AB_SWIFT_DESCR_LIST *AB_Banking_GetSwiftDescriptorsForImExporter(AB_BANKING *ab,
 
       descr=AB_SwiftDescr_FromString(name);
       if (descr) {
-        DBG_ERROR(AQBANKING_LOGDOMAIN, "Adding matching profile [%s]", name);
+        DBG_INFO(AQBANKING_LOGDOMAIN, "Adding matching profile [%s]", name);
         AB_SwiftDescr_SetAlias1(descr, name);
         AB_SwiftDescr_List_Add(descr, descrList);
       }
diff --git a/src/libs/aqbanking/types/transaction.c b/src/libs/aqbanking/types/transaction.c
index 94de690..87cd129 100644
--- a/src/libs/aqbanking/types/transaction.c
+++ b/src/libs/aqbanking/types/transaction.c
@@ -212,6 +212,16 @@ AB_TRANSACTION_SEQUENCE AB_Transaction_Sequence_fromString(const char *p_s) {
   return AB_Transaction_SequenceUnknown;
 }
 
+AB_TRANSACTION_ACK AB_Transaction_Ack_fromString(const char *p_s) {
+  if (p_s && *p_s) {
+    if (strcasecmp(p_s, "never")==0)
+      return AB_Transaction_AckNever;
+    else if (strcasecmp(p_s, "jobsWithAckCode")==0)
+      return AB_Transaction_AckJobsWithAckCode;
+  }
+  return AB_Transaction_AckUnknown;
+}
+
 const char *AB_Transaction_Type_toString(AB_TRANSACTION_TYPE p_i) {
   switch(p_i) {
     case AB_Transaction_TypeNone: return "none";
@@ -335,6 +345,15 @@ const char *AB_Transaction_Sequence_toString(AB_TRANSACTION_SEQUENCE p_i) {
   }
 }
 
+const char *AB_Transaction_Ack_toString(AB_TRANSACTION_ACK p_i) {
+  switch(p_i) {
+    case AB_Transaction_AckNever: return "never";
+    case AB_Transaction_AckJobsWithAckCode: return "jobsWithAckCode";
+    case AB_Transaction_AckUnknown:
+    default: return "unknown";
+  }
+}
+
 AB_TRANSACTION *AB_Transaction_new(void) {
   AB_TRANSACTION *p_struct;
 
@@ -347,6 +366,7 @@ AB_TRANSACTION *AB_Transaction_new(void) {
   p_struct->command=AB_Transaction_CommandNone;
   p_struct->status=AB_Transaction_StatusUnknown;
   p_struct->uniqueAccountId=0;
+  p_struct->acknowledge=AB_Transaction_AckNever;
   p_struct->uniqueId=0;
   p_struct->refUniqueId=0;
   p_struct->idForApplication=0;
@@ -517,6 +537,9 @@ AB_TRANSACTION *AB_Transaction_dup(const AB_TRANSACTION *p_src) {
   /* member "uniqueAccountId" */
   p_struct->uniqueAccountId=p_src->uniqueAccountId;
 
+  /* member "acknowledge" */
+  p_struct->acknowledge=p_src->acknowledge;
+
   /* member "uniqueId" */
   p_struct->uniqueId=p_src->uniqueId;
 
@@ -1081,6 +1104,9 @@ AB_TRANSACTION *AB_Transaction_copy(AB_TRANSACTION *p_struct, const AB_TRANSACTI
   /* member "uniqueAccountId" */
   p_struct->uniqueAccountId=p_src->uniqueAccountId;
 
+  /* member "acknowledge" */
+  p_struct->acknowledge=p_src->acknowledge;
+
   /* member "uniqueId" */
   p_struct->uniqueId=p_src->uniqueId;
 
@@ -1652,6 +1678,11 @@ uint32_t AB_Transaction_GetUniqueAccountId(const AB_TRANSACTION *p_struct) {
   return p_struct->uniqueAccountId;
 }
 
+AB_TRANSACTION_ACK AB_Transaction_GetAcknowledge(const AB_TRANSACTION *p_struct) {
+  assert(p_struct);
+  return p_struct->acknowledge;
+}
+
 uint32_t AB_Transaction_GetUniqueId(const AB_TRANSACTION *p_struct) {
   assert(p_struct);
   return p_struct->uniqueId;
@@ -2027,6 +2058,11 @@ void AB_Transaction_SetUniqueAccountId(AB_TRANSACTION *p_struct, uint32_t p_src)
   p_struct->uniqueAccountId=p_src;
 }
 
+void AB_Transaction_SetAcknowledge(AB_TRANSACTION *p_struct, AB_TRANSACTION_ACK  p_src) {
+  assert(p_struct);
+  p_struct->acknowledge=p_src;
+}
+
 void AB_Transaction_SetUniqueId(AB_TRANSACTION *p_struct, uint32_t p_src) {
   assert(p_struct);
   p_struct->uniqueId=p_src;
@@ -2858,6 +2894,9 @@ void AB_Transaction_ReadDb(AB_TRANSACTION *p_struct, GWEN_DB_NODE *p_db) {
   /* member "uniqueAccountId" */
   p_struct->uniqueAccountId=GWEN_DB_GetIntValue(p_db, "uniqueAccountId", 0, 0);
 
+  /* member "acknowledge" */
+  { const char *s; s=GWEN_DB_GetCharValue(p_db, "acknowledge", 0, NULL); if (s) p_struct->acknowledge=AB_Transaction_Ack_fromString(s); else p_struct->acknowledge=AB_Transaction_AckNever; }
+
   /* member "uniqueId" */
   p_struct->uniqueId=GWEN_DB_GetIntValue(p_db, "uniqueId", 0, 0);
 
@@ -3385,6 +3424,13 @@ int AB_Transaction_WriteDb(const AB_TRANSACTION *p_struct, GWEN_DB_NODE *p_db) {
     return p_rv;
   }
 
+  /* member "acknowledge" */
+  p_rv=GWEN_DB_SetCharValue(p_db, GWEN_DB_FLAGS_OVERWRITE_VARS, "acknowledge", AB_Transaction_Ack_toString(p_struct->acknowledge));
+  if (p_rv<0) {
+    DBG_INFO(GWEN_LOGDOMAIN, "here (%d)\n", p_rv);
+    return p_rv;
+  }
+
   /* member "uniqueId" */
   p_rv=GWEN_DB_SetIntValue(p_db, GWEN_DB_FLAGS_OVERWRITE_VARS, "uniqueId", p_struct->uniqueId);
   if (p_rv<0) {
@@ -3901,6 +3947,9 @@ void AB_Transaction_ReadXml(AB_TRANSACTION *p_struct, GWEN_XMLNODE *p_db) {
   /* member "uniqueAccountId" */
   p_struct->uniqueAccountId=GWEN_XMLNode_GetIntValue(p_db, "uniqueAccountId", 0);
 
+  /* member "acknowledge" */
+  { const char *s; s=GWEN_XMLNode_GetCharValue(p_db, "acknowledge", NULL); if (s) p_struct->acknowledge=AB_Transaction_Ack_fromString(s); else p_struct->acknowledge=AB_Transaction_AckNever; }
+
   /* member "uniqueId" */
   p_struct->uniqueId=GWEN_XMLNode_GetIntValue(p_db, "uniqueId", 0);
 
@@ -4461,6 +4510,9 @@ void AB_Transaction_WriteXml(const AB_TRANSACTION *p_struct, GWEN_XMLNODE *p_db)
   /* member "uniqueAccountId" */
   GWEN_XMLNode_SetIntValue(p_db, "uniqueAccountId", p_struct->uniqueAccountId);
 
+  /* member "acknowledge" */
+  GWEN_XMLNode_SetCharValue(p_db, "acknowledge", AB_Transaction_Ack_toString(p_struct->acknowledge));
+
   /* member "uniqueId" */
   GWEN_XMLNode_SetIntValue(p_db, "uniqueId", p_struct->uniqueId);
 
@@ -4748,6 +4800,9 @@ void AB_Transaction_toHashString(const AB_TRANSACTION *p_struct, GWEN_BUFFER *p_
   /* member "uniqueAccountId" */
   { char numbuf[32]; snprintf(numbuf, sizeof(numbuf)-1, "%d", p_struct->uniqueAccountId); numbuf[sizeof(numbuf)-1]=0; GWEN_Buffer_AppendString(p_buffer, numbuf); }
   GWEN_Buffer_AppendByte(p_buffer, ':');
+  /* member "acknowledge" */
+  { char numbuf[32]; snprintf(numbuf, sizeof(numbuf)-1, "%d", p_struct->acknowledge); numbuf[sizeof(numbuf)-1]=0; GWEN_Buffer_AppendString(p_buffer, numbuf); }
+  GWEN_Buffer_AppendByte(p_buffer, ':');
   /* member "uniqueId" */
   { char numbuf[32]; snprintf(numbuf, sizeof(numbuf)-1, "%d", p_struct->uniqueId); numbuf[sizeof(numbuf)-1]=0; GWEN_Buffer_AppendString(p_buffer, numbuf); }
   GWEN_Buffer_AppendByte(p_buffer, ':');
diff --git a/src/libs/aqbanking/types/transaction.h b/src/libs/aqbanking/types/transaction.h
index 748c2cb..64df6d0 100644
--- a/src/libs/aqbanking/types/transaction.h
+++ b/src/libs/aqbanking/types/transaction.h
@@ -71,6 +71,12 @@ This is a unique id of the local account for banking commands.
 <p>Set this property with @ref AB_Transaction_SetUniqueAccountId(), get it with @ref AB_Transaction_GetUniqueAccountId().</p>
 
 
+ at anchor AB_TRANSACTION_acknowledge
+<h3>acknowledge</h3>
+
+<p>Set this property with @ref AB_Transaction_SetAcknowledge(), get it with @ref AB_Transaction_GetAcknowledge().</p>
+
+
 <h2>Identifiers</h2>
 
 
@@ -777,6 +783,13 @@ typedef enum {
 } AB_TRANSACTION_SEQUENCE;
 
 
+typedef enum {
+  AB_Transaction_AckUnknown = -1,
+  AB_Transaction_AckNever = 0,
+  AB_Transaction_AckJobsWithAckCode
+} AB_TRANSACTION_ACK;
+
+
 /* post-headers */
 
 
@@ -794,6 +807,8 @@ AQBANKING_API AB_TRANSACTION_CHARGE AB_Transaction_Charge_fromString(const char
 
 AQBANKING_API AB_TRANSACTION_SEQUENCE AB_Transaction_Sequence_fromString(const char *p_s);
 
+AQBANKING_API AB_TRANSACTION_ACK AB_Transaction_Ack_fromString(const char *p_s);
+
 AQBANKING_API const char *AB_Transaction_Type_toString(AB_TRANSACTION_TYPE p_i);
 
 AQBANKING_API const char *AB_Transaction_SubType_toString(AB_TRANSACTION_SUBTYPE p_i);
@@ -808,6 +823,8 @@ AQBANKING_API const char *AB_Transaction_Charge_toString(AB_TRANSACTION_CHARGE p
 
 AQBANKING_API const char *AB_Transaction_Sequence_toString(AB_TRANSACTION_SEQUENCE p_i);
 
+AQBANKING_API const char *AB_Transaction_Ack_toString(AB_TRANSACTION_ACK p_i);
+
 /** Constructor. */
 AQBANKING_API AB_TRANSACTION *AB_Transaction_new(void);
 
@@ -845,6 +862,11 @@ AQBANKING_API AB_TRANSACTION_STATUS AB_Transaction_GetStatus(const AB_TRANSACTIO
 */
 AQBANKING_API uint32_t AB_Transaction_GetUniqueAccountId(const AB_TRANSACTION *p_struct);
 
+/** Getter.
+ * Use this function to get the member "acknowledge" (see @ref AB_TRANSACTION_acknowledge)
+*/
+AQBANKING_API AB_TRANSACTION_ACK AB_Transaction_GetAcknowledge(const AB_TRANSACTION *p_struct);
+
 /** Getter.
  * Use this function to get the member "uniqueId" (see @ref AB_TRANSACTION_uniqueId)
 */
@@ -1220,6 +1242,11 @@ AQBANKING_API void AB_Transaction_SetStatus(AB_TRANSACTION *p_struct, AB_TRANSAC
 */
 AQBANKING_API void AB_Transaction_SetUniqueAccountId(AB_TRANSACTION *p_struct, uint32_t p_src);
 
+/** Setter.
+ * Use this function to set the member "acknowledge" (see @ref AB_TRANSACTION_acknowledge)
+*/
+AQBANKING_API void AB_Transaction_SetAcknowledge(AB_TRANSACTION *p_struct, AB_TRANSACTION_ACK  p_src);
+
 /** Setter.
  * Use this function to set the member "uniqueId" (see @ref AB_TRANSACTION_uniqueId)
 */
diff --git a/src/libs/aqbanking/types/transaction.xml b/src/libs/aqbanking/types/transaction.xml
index a3c268f..2b07609 100644
--- a/src/libs/aqbanking/types/transaction.xml
+++ b/src/libs/aqbanking/types/transaction.xml
@@ -908,6 +908,11 @@
         <item name="final"/>
       </enum>
 
+      <enum id="AB_TRANSACTION_ACK" prefix="AB_Transaction_Ack" type="AB_TRANSACTION_ACK">
+        <item name="never" value="0"/>
+        <item name="jobsWithAckCode"/>
+      </enum>
+
     </enums>
 
     <defines>
@@ -971,6 +976,15 @@
           </descr>
         </member>
 
+        <member name="acknowledge" type="int" maxlen="32" enum="AB_TRANSACTION_ACK" >
+          <default>AB_Transaction_AckNever</default>
+          <preset>AB_Transaction_AckNever</preset>
+          <access>public</access>
+          <flags>enum with_hash</flags>
+          <setflags>none</setflags>
+          <getflags>none</getflags>
+        </member>
+
       </group>
 
 
diff --git a/src/libs/aqbanking/types/transaction_p.h b/src/libs/aqbanking/types/transaction_p.h
index 17d9af1..e9dd39c 100644
--- a/src/libs/aqbanking/types/transaction_p.h
+++ b/src/libs/aqbanking/types/transaction_p.h
@@ -23,6 +23,7 @@ struct AB_TRANSACTION {
   AB_TRANSACTION_COMMAND command;
   AB_TRANSACTION_STATUS status;
   uint32_t uniqueAccountId;
+  AB_TRANSACTION_ACK acknowledge;
   uint32_t uniqueId;
   uint32_t refUniqueId;
   uint32_t idForApplication;
diff --git a/src/libs/aqbanking/version.h b/src/libs/aqbanking/version.h
index eee7abb..8c0d430 100644
--- a/src/libs/aqbanking/version.h
+++ b/src/libs/aqbanking/version.h
@@ -13,15 +13,15 @@
 
 #define AQBANKING_VERSION_MAJOR 6
 #define AQBANKING_VERSION_MINOR 3
-#define AQBANKING_VERSION_PATCHLEVEL 0
+#define AQBANKING_VERSION_PATCHLEVEL 1
 #define AQBANKING_VERSION_BUILD 0
 #define AQBANKING_VERSION_TAG "stable"
-#define AQBANKING_VERSION_FULL_STRING "6.3.0.0stable"
-#define AQBANKING_VERSION_STRING "6.3.0"
+#define AQBANKING_VERSION_FULL_STRING "6.3.1.0stable"
+#define AQBANKING_VERSION_STRING "6.3.1"
 
 
 #define AQBANKING_SO_CURRENT 47
-#define AQBANKING_SO_REVISION 0
+#define AQBANKING_SO_REVISION 1
 #define AQBANKING_SO_AGE 3
 #define AQBANKING_SO_EFFECTIVE 44
 
diff --git a/src/libs/plugins/backends/aqfints/libaqfints/parser/segment.h b/src/libs/plugins/backends/aqfints/libaqfints/parser/segment.h
index 4007755..1a09704 100644
--- a/src/libs/plugins/backends/aqfints/libaqfints/parser/segment.h
+++ b/src/libs/plugins/backends/aqfints/libaqfints/parser/segment.h
@@ -119,7 +119,7 @@ GWEN_LIST_FUNCTION_DEFS(AQFINTS_SEGMENT, AQFINTS_Segment)
 
 
 /* post-headers */
-#include "parser/element.h"
+#include "libaqfints/parser/element.h"
 
 
 /** Constructor. */
diff --git a/src/libs/plugins/backends/aqfints/libaqfints/service/bpd/bpd.h b/src/libs/plugins/backends/aqfints/libaqfints/service/bpd/bpd.h
index ab417a9..b9efda9 100644
--- a/src/libs/plugins/backends/aqfints/libaqfints/service/bpd/bpd.h
+++ b/src/libs/plugins/backends/aqfints/libaqfints/service/bpd/bpd.h
@@ -85,12 +85,12 @@ GWEN_LIST_FUNCTION_DEFS(AQFINTS_BPD, AQFINTS_Bpd)
 
 
 /* post-headers */
-#include "service/bpd/bankdata.h"
-#include "service/bpd/bpdjob.h"
-#include "service/bpd/bpdaddr.h"
-#include "service/bpd/bpdsecprofile.h"
-#include "service/bpd/taninfo.h"
-#include "service/bpd/tanmethod.h"
+#include "libaqfints/service/bpd/bankdata.h"
+#include "libaqfints/service/bpd/bpdjob.h"
+#include "libaqfints/service/bpd/bpdaddr.h"
+#include "libaqfints/service/bpd/bpdsecprofile.h"
+#include "libaqfints/service/bpd/taninfo.h"
+#include "libaqfints/service/bpd/tanmethod.h"
 
 
 /** Constructor. */
diff --git a/src/libs/plugins/backends/aqfints/libaqfints/service/bpd/bpdaddr.h b/src/libs/plugins/backends/aqfints/libaqfints/service/bpd/bpdaddr.h
index 883f558..22d3d03 100644
--- a/src/libs/plugins/backends/aqfints/libaqfints/service/bpd/bpdaddr.h
+++ b/src/libs/plugins/backends/aqfints/libaqfints/service/bpd/bpdaddr.h
@@ -73,7 +73,7 @@ GWEN_LIST_FUNCTION_DEFS(AQFINTS_BPDADDR, AQFINTS_BpdAddr)
 
 
 /* post-headers */
-#include "service/bpd/bpdaddrservice.h"
+#include "libaqfints/service/bpd/bpdaddrservice.h"
 
 
 /** Constructor. */
diff --git a/src/libs/plugins/backends/aqfints/libaqfints/service/bpd/taninfo.h b/src/libs/plugins/backends/aqfints/libaqfints/service/bpd/taninfo.h
index 2443494..474cab3 100644
--- a/src/libs/plugins/backends/aqfints/libaqfints/service/bpd/taninfo.h
+++ b/src/libs/plugins/backends/aqfints/libaqfints/service/bpd/taninfo.h
@@ -104,7 +104,7 @@ GWEN_LIST_FUNCTION_DEFS(AQFINTS_TANINFO, AQFINTS_TanInfo)
 
 
 /* post-headers */
-#include "service/bpd/tanjobinfo.h"
+#include "libaqfints/service/bpd/tanjobinfo.h"
 
 
 /** Constructor. */
diff --git a/src/libs/plugins/backends/aqfints/libaqfints/service/upd/accountdata.h b/src/libs/plugins/backends/aqfints/libaqfints/service/upd/accountdata.h
index c02bad7..f07a404 100644
--- a/src/libs/plugins/backends/aqfints/libaqfints/service/upd/accountdata.h
+++ b/src/libs/plugins/backends/aqfints/libaqfints/service/upd/accountdata.h
@@ -145,7 +145,7 @@ GWEN_LIST_FUNCTION_DEFS(AQFINTS_ACCOUNTDATA, AQFINTS_AccountData)
 
 
 /* post-headers */
-#include "service/upd/updjob.h"
+#include "libaqfints/service/upd/updjob.h"
 
 
 /** Constructor. */
diff --git a/src/libs/plugins/backends/aqfints/libaqfints/service/upd/userdata.h b/src/libs/plugins/backends/aqfints/libaqfints/service/upd/userdata.h
index 04a6e6c..c5ae010 100644
--- a/src/libs/plugins/backends/aqfints/libaqfints/service/upd/userdata.h
+++ b/src/libs/plugins/backends/aqfints/libaqfints/service/upd/userdata.h
@@ -85,7 +85,7 @@ GWEN_LIST_FUNCTION_DEFS(AQFINTS_USERDATA, AQFINTS_UserData)
 
 
 /* post-headers */
-#include "service/upd/accountdata.h"
+#include "libaqfints/service/upd/accountdata.h"
 
 
 /** Constructor. */
diff --git a/src/libs/plugins/backends/aqhbci/ajobs/jobgetestatements.c b/src/libs/plugins/backends/aqhbci/ajobs/jobgetestatements.c
index 4794fc9..a8300fe 100644
--- a/src/libs/plugins/backends/aqhbci/ajobs/jobgetestatements.c
+++ b/src/libs/plugins/backends/aqhbci/ajobs/jobgetestatements.c
@@ -111,6 +111,18 @@ static int AH_Job_GetEstatements_HandleCommand(AH_JOB *j, const AB_TRANSACTION *
       GWEN_DB_SetIntValue(dbArgs, GWEN_DB_FLAGS_DEFAULT, "maxEntries", maxEntries);
     }
   }
+
+  /*
+   * If the user reqeusted to acknowledge this job,
+   * and the bank also wants to acknowledge the job, flag it for acknowledgement.
+   */
+  if (AB_Transaction_GetAcknowledge(t) == AB_Transaction_AckJobsWithAckCode) {
+    s=GWEN_DB_GetCharValue(dbParams, "ackNeeded", 0, 0);
+    if (s && !strcmp(s, "J")) {
+      AH_Job_AddFlags(j, AH_JOB_FLAGS_ACKNOWLEDGE);
+    }
+  }
+
   return 0;
 }
 
diff --git a/src/libs/plugins/backends/aqhbci/applayer/cbox_queue.c b/src/libs/plugins/backends/aqhbci/applayer/cbox_queue.c
index 34d7cc8..8c32044 100644
--- a/src/libs/plugins/backends/aqhbci/applayer/cbox_queue.c
+++ b/src/libs/plugins/backends/aqhbci/applayer/cbox_queue.c
@@ -15,6 +15,7 @@
 
 #include "cbox_queue.h"
 
+#include "aqhbci/admjobs/jobacknowledge_l.h"
 #include "aqhbci/admjobs/jobtan_l.h"
 
 #include "aqhbci/applayer/cbox_send.h"
@@ -33,6 +34,7 @@
  * ------------------------------------------------------------------------------------------------
  */
 
+static AH_JOBQUEUE *_createAckQueueFromTodoList(AB_USER *user, AH_JOB_LIST *jl, uint32_t jqFlags);
 static AH_JOBQUEUE *_createNextQueueFromTodoList(AB_USER *user, AH_JOB_LIST *jl, uint32_t jqFlags,
                                                  AH_JOB_LIST *finishedJobs);
 static int _performQueue(AH_OUTBOX_CBOX *cbox, AH_DIALOG *dlg, AH_JOBQUEUE *jq);
@@ -131,33 +133,124 @@ int _performQueue(AH_OUTBOX_CBOX *cbox, AH_DIALOG *dlg, AH_JOBQUEUE *jq)
   finishedJobs=AH_OutboxCBox_GetFinishedJobs(cbox);
 
   for (;;) {
+    AH_JOBQUEUE *jqAck;
     AH_JOBQUEUE *jqTodo;
     AH_JOB_LIST *jl;
 
     jl=AH_JobQueue_TakeJobList(jq);
     assert(jl);
 
+    jqAck=_createAckQueueFromTodoList(user, jl, AH_JobQueue_GetFlags(jq));
     jqTodo=_createNextQueueFromTodoList(user, jl, AH_JobQueue_GetFlags(jq), finishedJobs);
     AH_Job_List_free(jl);
     AH_JobQueue_free(jq);
+
+    if (jqAck != NULL) {
+      rv=AH_OutboxCBox_SendAndRecvQueue(cbox, dlg, jqAck);
+      if (rv) {
+        _handleQueueError(cbox, jqAck, "Error performing acknowledge queue");
+        return rv;
+      } /* if error during acknowledgement (jqAck freed by _handleQueueError */
+      AH_JobQueue_free(jqAck);
+    }
+
     if (jqTodo==NULL) {
       DBG_INFO(AQHBCI_LOGDOMAIN, "No more jobs left");
       break;
     }
-    jq=jqTodo;
-
-    /* jq now contains all jobs to be executed */
-    rv=AH_OutboxCBox_SendAndRecvQueue(cbox, dlg, jq);
-    if (rv) {
-      _handleQueueError(cbox, jq, "Error performing queue"); /* frees jobQueue */
-      return rv;
-    } /* if error */
+    else { 
+      jq=jqTodo;
+      /* jq now contains all jobs to be executed */
+      // Execute NEXT send-recv round, syhcnrounously.
+      rv=AH_OutboxCBox_SendAndRecvQueue(cbox, dlg, jq);
+      if (rv) {
+        _handleQueueError(cbox, jq, "Error performing queue"); /* frees jobQueue */
+        return rv;
+      } /* if error */
+    }
   } /* for */
 
   return 0;
 }
 
 
+AH_JOBQUEUE *_createAckQueueFromTodoList(AB_USER *user, AH_JOB_LIST *jl, uint32_t jqFlags)
+{
+  AH_JOB *j;
+  AH_JOBQUEUE *jqAck;
+
+  jqAck=AH_JobQueue_new(user);
+  /* copy some flags */
+  jqFlags&=~(AH_JOBQUEUE_FLAGS_CRYPT |
+             AH_JOBQUEUE_FLAGS_SIGN |
+             AH_JOBQUEUE_FLAGS_NOSYSID |
+             AH_JOBQUEUE_FLAGS_NOITAN);
+  AH_JobQueue_SetFlags(jqAck, (jqFlags&AH_JOBQUEUE_FLAGS_COPYMASK));
+
+  /* insert intermediate round for possible acknowledgements */
+  j=AH_Job_List_First(jl);
+  while (j) {
+    const char *jobName;
+
+    jobName=AH_Job_GetName(j);
+    if (!(jobName && *jobName))
+      jobName="<unnamed>";
+
+    if (AH_Job_GetStatus(j)==AH_JobStatusAnswered) {
+      /* Should we send an acknowledgement for the previously executed job? */
+      const void* ackCode = NULL;
+      AH_JOB* jAck = NULL;
+      unsigned int lenAckCode = 0;
+      GWEN_DB_NODE *args = AH_Job_GetArguments(j);
+
+      DBG_INFO(AQHBCI_LOGDOMAIN,
+               "Job \"%s\" with status \"answered\", checking whether it needs acknowledgement",
+               jobName);
+      ackCode = GWEN_DB_GetBinValue(args, "_tmpAckCode", 0, 0, 0, &lenAckCode);
+      if (ackCode != NULL && lenAckCode > 0) {
+         jAck = AH_Job_Acknowledge_new(AH_Job_GetProvider(j), AH_Job_GetUser(j), ackCode, lenAckCode);
+         DBG_NOTICE(AQHBCI_LOGDOMAIN, "Job \"%s\" received acknowledge code, prepare acknowledge job", jobName);
+         if (GWEN_DB_DeleteVar(args, "_tmpAckCode")) {
+           DBG_DEBUG(AQHBCI_LOGDOMAIN, "Temporary acknowledge code removed");
+         }
+      }
+      else {
+        DBG_DEBUG(AQHBCI_LOGDOMAIN, "Job \"%s\" didn't receive an acknowledge code, no acknowledge job needed.", jobName);
+      }
+
+      /* Job received acknowledge code in previous response and acknowledge is allowed by BPD and user wants to acknowledge - so do it. */
+      if (jAck != NULL) {
+        /* copy signers to new job */
+        if (AH_Job_GetFlags(j) & AH_JOB_FLAGS_SIGN) {
+          GWEN_STRINGLISTENTRY *se;
+          se=GWEN_StringList_FirstEntry(AH_Job_GetSigners(j));
+          while (se) {
+            AH_Job_AddSigner(jAck, GWEN_StringListEntry_Data(se));
+            se=GWEN_StringListEntry_Next(se);
+          } /* while */
+        }
+
+        if (AH_JobQueue_AddJob(jqAck, jAck)!=AH_JobQueueAddResultOk) {
+          DBG_DEBUG(AQHBCI_LOGDOMAIN, "Couldn't add ack job to todo list.");
+          AH_Job_SetStatus(j, AH_JobStatusError);
+        }
+        else {
+          AH_Job_Log(j, GWEN_LoggerLevel_Info, "Acknwoledge Job enqueued");
+        }
+      }
+    }
+    j=AH_Job_List_Next(j);
+  }
+
+  if (AH_JobQueue_GetCount(jqAck)==0) {
+    DBG_INFO(AQHBCI_LOGDOMAIN, "No acknwoledge jobs enqueued.");
+    AH_JobQueue_free(jqAck);
+    return NULL;
+  }
+
+  return jqAck;
+}
+
 
 AH_JOBQUEUE *_createNextQueueFromTodoList(AB_USER *user, AH_JOB_LIST *jl, uint32_t jqFlags, AH_JOB_LIST *finishedJobs)
 {
diff --git a/src/libs/plugins/backends/aqhbci/joblayer/job_l.h b/src/libs/plugins/backends/aqhbci/joblayer/job_l.h
index 0abd307..41f31c1 100644
--- a/src/libs/plugins/backends/aqhbci/joblayer/job_l.h
+++ b/src/libs/plugins/backends/aqhbci/joblayer/job_l.h
@@ -13,6 +13,7 @@
 
 typedef struct AH_JOB AH_JOB;
 
+#define AH_JOB_FLAGS_ACKNOWLEDGE          0x00000200
 #define AH_JOB_FLAGS_IGNOREACCOUNTS       0x00000400
 #define AH_JOB_FLAGS_SIGNSEQONE           0x00000800
 #define AH_JOB_FLAGS_IGNORE_ERROR         0x00001000
diff --git a/src/libs/plugins/backends/aqhbci/joblayer/job_swift.c b/src/libs/plugins/backends/aqhbci/joblayer/job_swift.c
index d737fbe..08c8786 100644
--- a/src/libs/plugins/backends/aqhbci/joblayer/job_swift.c
+++ b/src/libs/plugins/backends/aqhbci/joblayer/job_swift.c
@@ -187,7 +187,7 @@ AB_SWIFT_DESCR_LIST *AH_Job_GetSwiftDescriptorsSupportedByUser(AH_JOB *j, const
     if (s && *s) {
       AB_SWIFT_DESCR *tmpDescr;
 
-      DBG_ERROR(AQHBCI_LOGDOMAIN, "Checking user supported param [%s] (job \"%s\")", s, AH_Job_GetName(j));
+      DBG_INFO(AQHBCI_LOGDOMAIN, "Checking user supported param [%s] (job \"%s\")", s, AH_Job_GetName(j));
       tmpDescr=AB_SwiftDescr_FromString(s);
       if (tmpDescr) {
         if (AB_SwiftDescr_Matches(tmpDescr, family, version1, 0, 0)) {
@@ -204,17 +204,17 @@ AB_SWIFT_DESCR_LIST *AH_Job_GetSwiftDescriptorsSupportedByUser(AH_JOB *j, const
 
             /* store name of selected profile */
             AB_SwiftDescr_SetAlias2(descrFromList, s);
-            DBG_ERROR(AQHBCI_LOGDOMAIN,
-                      "Adding matching profile [%s] (%s)",
-                      AB_SwiftDescr_GetAlias1(descrFromList),
-                      AB_SwiftDescr_GetAlias2(descrFromList));
+            DBG_INFO(AQHBCI_LOGDOMAIN,
+                     "Adding matching profile [%s] (%s)",
+                     AB_SwiftDescr_GetAlias1(descrFromList),
+                     AB_SwiftDescr_GetAlias2(descrFromList));
             /* copy to return list */
             descrCopy=AB_SwiftDescr_dup(descrFromList);
             AB_SwiftDescr_List_Add(descrCopy, returnDescrList);
           }
         }
         else {
-          DBG_ERROR(AQHBCI_LOGDOMAIN, "Param [%s] does not match family %s.%03d", s, family, version1);
+          DBG_INFO(AQHBCI_LOGDOMAIN, "Param [%s] does not match family %s.%03d", s, family, version1);
         }
       }
       else {
diff --git a/src/libs/plugins/backends/aqhbci/joblayer/jobqueue_addjob.c b/src/libs/plugins/backends/aqhbci/joblayer/jobqueue_addjob.c
index 8b716a7..4244f8f 100644
--- a/src/libs/plugins/backends/aqhbci/joblayer/jobqueue_addjob.c
+++ b/src/libs/plugins/backends/aqhbci/joblayer/jobqueue_addjob.c
@@ -229,7 +229,7 @@ int _countJobsOtherThanTan(const AH_JOBQUEUE *jq)
 
 AH_JOBQUEUE_ADDRESULT _checkJobFlags(AH_JOBQUEUE *jq, AH_JOB *jobToAdd)
 {
-  if (strcasecmp(AH_Job_GetName(jobToAdd), "JobTan")!=0) {
+  if (strcasecmp(AH_Job_GetName(jobToAdd), "JobTan")!=0 && strcasecmp(AH_Job_GetName(jobToAdd), "JobAcknowledge")!=0) {
     uint32_t flagsInJobToAdd;
     uint32_t flagsInFirstJob;
     AH_JOB *firstJob;
diff --git a/src/libs/plugins/backends/aqhbci/joblayer/jobqueue_dispatch.c b/src/libs/plugins/backends/aqhbci/joblayer/jobqueue_dispatch.c
index dae6705..9a7cf0e 100644
--- a/src/libs/plugins/backends/aqhbci/joblayer/jobqueue_dispatch.c
+++ b/src/libs/plugins/backends/aqhbci/joblayer/jobqueue_dispatch.c
@@ -34,6 +34,7 @@ static void _removeAttachPoints(const AH_JOBQUEUE *jq);
 static void _setUsedTanStatusInJobs(const AH_JOBQUEUE *jq);
 static void _adjustSystemTanStatus(AH_JOBQUEUE *jq, uint32_t guiid);
 static AH_JOB *_findReferencedJob(AH_JOBQUEUE *jq, int refMsgNum, int refSegNum);
+static void _possiblyExtractJobAckCode(AH_JOB *j, GWEN_DB_NODE *dbSegment);
 static void _possiblyExtractAttachPoint(AH_JOB *j, GWEN_DB_NODE *dbSegment);
 static void _handleSegmentResultForAllJobs(AH_JOBQUEUE *jq, GWEN_DB_NODE *dbSegment);
 static void _handleSegmentResult(AH_JOBQUEUE *jq, AH_JOB *j, GWEN_DB_NODE *dbSegment);
@@ -371,6 +372,22 @@ AH_JOB *_findReferencedJob(AH_JOBQUEUE *jq, int refMsgNum, int refSegNum)
 }
 
 
+void _possiblyExtractJobAckCode(AH_JOB *j, GWEN_DB_NODE *dbSegment) {
+  if (AH_Job_GetFlags(j) & AH_JOB_FLAGS_ACKNOWLEDGE) {
+    const char *responseName=AH_Job_GetResponseName(j);
+    if (strcasecmp(GWEN_DB_GroupName(dbSegment), responseName)==0) {
+      unsigned int byteSize = 0;
+      const void* ackCode;
+      ackCode = GWEN_DB_GetBinValue(dbSegment, "ackCode", 0, NULL, 0, &byteSize);
+      if (ackCode) {
+        GWEN_DB_NODE *args = AH_Job_GetArguments(j);
+        GWEN_DB_SetBinValue(args, GWEN_DB_FLAGS_OVERWRITE_VARS, "_tmpAckCode", ackCode, byteSize);
+        DBG_DEBUG(AQHBCI_LOGDOMAIN, "Found acknoledge code in job response, storing it.");
+      }
+    }
+  }
+}
+
 
 void _possiblyExtractAttachPoint(AH_JOB *j, GWEN_DB_NODE *dbSegment)
 {
@@ -527,7 +544,9 @@ void _handleResponseSegments(AH_JOBQUEUE *jq, AH_MSG *msg, GWEN_DB_NODE *db, GWE
 		 GWEN_DB_GroupName(dbCurr),
 		 AH_Msg_GetMsgRef(msg),
 		 refSegNum);
-	_possiblyExtractAttachPoint(j, dbCurr);
+
+        _possiblyExtractJobAckCode(j, dbCurr);
+        _possiblyExtractAttachPoint(j, dbCurr);
 
         /* check for segment results */
         if (strcasecmp(GWEN_DB_GroupName(dbCurr), "SegResult")==0)
diff --git a/src/tools/aqbanking-cli/globals.h b/src/tools/aqbanking-cli/globals.h
index ffb34e0..c026223 100644
--- a/src/tools/aqbanking-cli/globals.h
+++ b/src/tools/aqbanking-cli/globals.h
@@ -49,6 +49,7 @@ typedef enum {
 #define AQBANKING_TOOL_REQUEST_ESTATEMENTS   0x0008
 #define AQBANKING_TOOL_REQUEST_DEPOT         0x0010
 
+#define AQBANKING_TOOL_REQUEST_ACKNOWLEDGE   0x4000
 #define AQBANKING_TOOL_REQUEST_IGNORE_UNSUP  0x8000
 
 
@@ -106,6 +107,7 @@ int createAndAddRequest(AB_BANKING *ab,
                         const GWEN_DATE *fromDate,
                         const GWEN_DATE *toDate,
                         int ignoreUnsupported,
+                        AB_TRANSACTION_ACK ackMethod,
                         uint32_t number);
 
 /**
diff --git a/src/tools/aqbanking-cli/request.c b/src/tools/aqbanking-cli/request.c
index 98acaab..cbaef6c 100644
--- a/src/tools/aqbanking-cli/request.c
+++ b/src/tools/aqbanking-cli/request.c
@@ -68,6 +68,8 @@ int request(AB_BANKING *ab, GWEN_DB_NODE *dbArgs, int argc, char **argv)
     requestFlags|=AQBANKING_TOOL_REQUEST_DEPOT;
   if (GWEN_DB_GetIntValue(db, "ignoreUnsupported", 0, 0))
     requestFlags|=AQBANKING_TOOL_REQUEST_IGNORE_UNSUP;
+  if (GWEN_DB_GetIntValue(db, "acknowledge", 0, 0))
+    requestFlags|=AQBANKING_TOOL_REQUEST_ACKNOWLEDGE;
 
   /* read command line arguments */
   ctxFile=GWEN_DB_GetCharValue(db, "ctxfile", 0, 0);
@@ -359,6 +361,17 @@ GWEN_DB_NODE *_readCommandLine(GWEN_DB_NODE *dbArgs, int argc, char **argv)
       "Request depot (security list)", /* short description */
       "Request depot (security list)"  /* long description */
     },
+    {
+      0,                              /* flags */
+      GWEN_ArgsType_Int,              /* type */
+      "acknowledge",                  /* name */
+      0,                              /* minnum */
+      1,                              /* maxnum */
+      0,                              /* short option */
+      "acknowledge",                  /* long option */
+      "Acknowledge jobs",             /* short description */
+      "Acknowledge each job where the bank supports."   /* long description */
+    },
     {
       0,
       GWEN_ArgsType_Int,
@@ -396,11 +409,11 @@ GWEN_DB_NODE *_readCommandLine(GWEN_DB_NODE *dbArgs, int argc, char **argv)
       GWEN_ARGS_FLAGS_HAS_ARGUMENT, /* flags */
       GWEN_ArgsType_Int,            /* type */
       "number",                     /* name */
-      1,                            /* minnum */
-      99999,                        /* maxnum */
+      0,                            /* minnum */
+      0,                            /* maxnum */
       0,                            /* short option */
-      "number",                     /* long option */
-      "Document number",           /* short description */
+      "docnumber",                  /* long option */
+      "Document number",            /* short description */
       "Fetch a specific document number"  /* long description */
     },
 
diff --git a/src/tools/aqbanking-cli/util.c b/src/tools/aqbanking-cli/util.c
index 0ea1471..fe896d2 100644
--- a/src/tools/aqbanking-cli/util.c
+++ b/src/tools/aqbanking-cli/util.c
@@ -981,6 +981,7 @@ int createAndAddRequest(AB_BANKING *ab,
                         const GWEN_DATE *fromDate,
                         const GWEN_DATE *toDate,
                         int ignoreUnsupported,
+                        AB_TRANSACTION_ACK ackMethod,
                         uint32_t number)
 {
   uint32_t aid;
@@ -1003,6 +1004,7 @@ int createAndAddRequest(AB_BANKING *ab,
       if (number>0)
         AB_Transaction_SetEstatementNumber(j, number);
     }
+    AB_Transaction_SetAcknowledge(j, ackMethod);
     AB_Transaction_List2_PushBack(tList, j);
     return 0;
   }
@@ -1038,39 +1040,44 @@ int createAndAddRequests(AB_BANKING *ab,
                          uint32_t number)
 {
   int ignoreUnsupported=requestFlags & AQBANKING_TOOL_REQUEST_IGNORE_UNSUP;
+  int ackMethod=AB_Transaction_AckNever;
   int rv;
 
   assert(ab);
   assert(tList);
   assert(as);
 
+  if (requestFlags & AQBANKING_TOOL_REQUEST_ACKNOWLEDGE) {
+    ackMethod=AB_Transaction_AckJobsWithAckCode;
+  }
+
   /* create and add requests */
   if (requestFlags & AQBANKING_TOOL_REQUEST_BALANCE) {
-    rv=createAndAddRequest(ab, tList, as, AB_Transaction_CommandGetBalance, fromDate, toDate, ignoreUnsupported, number);
+    rv=createAndAddRequest(ab, tList, as, AB_Transaction_CommandGetBalance, fromDate, toDate, ignoreUnsupported, ackMethod, number);
     if (rv)
       return rv;
   }
 
   if (requestFlags & AQBANKING_TOOL_REQUEST_STATEMENTS) {
-    rv=createAndAddRequest(ab, tList, as, AB_Transaction_CommandGetTransactions, fromDate, toDate, ignoreUnsupported, number);
+    rv=createAndAddRequest(ab, tList, as, AB_Transaction_CommandGetTransactions, fromDate, toDate, ignoreUnsupported, ackMethod, number);
     if (rv)
       return rv;
   }
 
   if (requestFlags & AQBANKING_TOOL_REQUEST_SEPASTO) {
-    rv=createAndAddRequest(ab, tList, as, AB_Transaction_CommandSepaGetStandingOrders, fromDate, toDate, ignoreUnsupported, number);
+    rv=createAndAddRequest(ab, tList, as, AB_Transaction_CommandSepaGetStandingOrders, fromDate, toDate, ignoreUnsupported, ackMethod, number);
     if (rv)
       return rv;
   }
 
   if (requestFlags & AQBANKING_TOOL_REQUEST_ESTATEMENTS) {
-    rv=createAndAddRequest(ab, tList, as, AB_Transaction_CommandGetEStatements, fromDate, toDate, ignoreUnsupported, number);
+    rv=createAndAddRequest(ab, tList, as, AB_Transaction_CommandGetEStatements, fromDate, toDate, ignoreUnsupported, ackMethod, number);
     if (rv)
       return rv;
   }
 
   if (requestFlags & AQBANKING_TOOL_REQUEST_DEPOT) {
-    rv=createAndAddRequest(ab, tList, as, AB_Transaction_CommandGetDepot, fromDate, toDate, ignoreUnsupported, number);
+    rv=createAndAddRequest(ab, tList, as, AB_Transaction_CommandGetDepot, fromDate, toDate, ignoreUnsupported, ackMethod, number);
     if (rv)
       return rv;
   }



More information about the Neon-commits mailing list