1 /*
2  * gnc-ab-utils.c --
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, contact:
16  *
17  * Free Software Foundation           Voice:  +1-617-542-5942
18  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652
19  * Boston, MA  02110-1301,  USA       gnu@gnu.org
20  */
21 
22 /**
23  * @internal
24  * @file gnc-ab-utils.c
25  * @brief AqBanking utility functions
26  * @author Copyright (C) 2002 Christian Stimming <stimming@tuhh.de>
27  * @author Copyright (C) 2008 Andreas Koehler <andi5.py@gmx.net>
28  */
29 
30 #include <config.h>
31 
32 #include "gnc-ab-utils.h"
33 
34 #include <glib/gi18n.h>
35 #include <gwenhywfar/gwenhywfar.h>
36 #include <aqbanking/banking.h>
37 #ifdef AQBANKING6
38 #include <aqbanking/types/balance.h>
39 #if (AQBANKING_VERSION_INT >= 60400)
40 #include <aqbanking/types/refaccount.h>
41 #include <gnc-aqbanking-templates.h>
42 #endif
43 #endif
44 #include "window-reconcile.h"
45 #include "Transaction.h"
46 #include "dialog-ab-trans.h"
47 #include "gnc-ab-kvp.h"
48 #include "gnc-glib-utils.h"
49 #include "gnc-gwen-gui.h"
50 #include "gnc-prefs.h"
51 #include "gnc-ui.h"
52 #include "import-account-matcher.h"
53 #include "import-main-matcher.h"
54 #include "import-utilities.h"
55 #include "qof.h"
56 #include "engine-helpers.h"
57 #ifdef AQBANKING6
58 # include <aqbanking/gui/abgui.h>
59 #else
60 # include <aqbanking/abgui.h>
61 #endif
62 
63 /* This static indicates the debugging module that this .o belongs to.  */
64 G_GNUC_UNUSED static QofLogModule log_module = G_LOG_DOMAIN;
65 
66 /* Global variables for AB_BANKING caching. */
67 static AB_BANKING *gnc_AB_BANKING = NULL;
68 static gint gnc_AB_BANKING_refcount = 0;
69 
70 static gpointer join_ab_strings_cb(const gchar *str, gpointer user_data);
71 static Account *gnc_ab_accinfo_to_gnc_acc(GtkWidget *parent,
72     AB_IMEXPORTER_ACCOUNTINFO *account_info);
73 static Account *gnc_ab_txn_to_gnc_acc(GtkWidget *parent,
74     const AB_TRANSACTION *transaction);
75 static const AB_TRANSACTION *txn_transaction_cb(
76     const AB_TRANSACTION *element, gpointer user_data);
77 static AB_IMEXPORTER_ACCOUNTINFO *txn_accountinfo_cb(
78     AB_IMEXPORTER_ACCOUNTINFO *element, gpointer user_data);
79 static AB_IMEXPORTER_ACCOUNTINFO *bal_accountinfo_cb(
80     AB_IMEXPORTER_ACCOUNTINFO *element, gpointer user_data);
81 
82 struct _GncABImExContextImport
83 {
84     guint awaiting;
85     gboolean txn_found;
86     Account *gnc_acc;
87     GNC_AB_ACCOUNT_SPEC *ab_acc;
88     gboolean execute_txns;
89     AB_BANKING *api;
90     GtkWidget *parent;
91     GNC_AB_JOB_LIST2 *job_list;
92     GNCImportMainMatcher *generic_importer;
93     GData *tmp_job_list;
94 };
95 
96 static inline time64
gnc_gwen_date_to_time64(const GNC_GWEN_DATE * date)97 gnc_gwen_date_to_time64 (const GNC_GWEN_DATE* date)
98 {
99 #if AQBANKING_VERSION_INT >= 59900
100     return gnc_dmy2time64_neutral(GWEN_Date_GetDay(date),
101                                   GWEN_Date_GetMonth(date),
102                                   GWEN_Date_GetYear(date));
103 #else
104     int month, day, year;
105     GWEN_Time_GetBrokenDownDate(date, &day, &month, &year);
106     /* GWEN_Time_GetBrokenDownDate returns localtime(3) format; month is [0..11] */
107     return gnc_dmy2time64_neutral(day, month + 1, year);
108 #endif
109 }
110 
111 void
gnc_GWEN_Init(void)112 gnc_GWEN_Init(void)
113 {
114     gchar* gwen_logging = g_strdup(g_getenv("GWEN_LOGLEVEL"));
115     gchar* aqb_logging = g_strdup(g_getenv("AQBANKING_LOGLEVEL"));
116 
117     /* Initialize gwen library */
118     GWEN_Init();
119 
120     /* Initialize gwen logging */
121     if (gnc_prefs_get_bool(GNC_PREFS_GROUP_AQBANKING, GNC_PREF_VERBOSE_DEBUG))
122     {
123         if (!gwen_logging)
124         {
125             GWEN_Logger_SetLevel(NULL, GWEN_LoggerLevel_Info);
126             GWEN_Logger_SetLevel(GWEN_LOGDOMAIN, GWEN_LoggerLevel_Info);
127         }
128         if (!aqb_logging)
129             GWEN_Logger_SetLevel(AQBANKING_LOGDOMAIN, GWEN_LoggerLevel_Debug);
130     }
131     else
132     {
133         if (!gwen_logging)
134         {
135             GWEN_Logger_SetLevel(NULL, GWEN_LoggerLevel_Error);
136             GWEN_Logger_SetLevel(GWEN_LOGDOMAIN, GWEN_LoggerLevel_Error);
137         }
138         if (!aqb_logging)
139             GWEN_Logger_SetLevel(AQBANKING_LOGDOMAIN, GWEN_LoggerLevel_Warning);
140     }
141     g_free(gwen_logging);
142     g_free(aqb_logging);
143     gnc_GWEN_Gui_log_init();
144 }
145 
146 void
gnc_GWEN_Fini(void)147 gnc_GWEN_Fini(void)
148 {
149     /* Shutdown the GWEN_GUIs */
150     gnc_GWEN_Gui_shutdown();
151     GWEN_Logger_SetLevel(NULL, GWEN_LoggerLevel_Error);
152     GWEN_Logger_SetLevel(GWEN_LOGDOMAIN, GWEN_LoggerLevel_Warning);
153     GWEN_Logger_SetLevel(AQBANKING_LOGDOMAIN, GWEN_LoggerLevel_Warning);
154 
155     /* Finalize gwen library */
156     GWEN_Fini();
157 }
158 
159 static GWEN_GUI *gnc_gwengui_extended_by_ABBanking;
160 
161 AB_BANKING *
gnc_AB_BANKING_new(void)162 gnc_AB_BANKING_new(void)
163 {
164     AB_BANKING *api;
165 
166     if (gnc_AB_BANKING)
167     {
168         /* API cached. */
169         api = gnc_AB_BANKING;
170 
171         /* Init the API again. */
172         if (gnc_AB_BANKING_refcount == 0)
173             g_return_val_if_fail(AB_Banking_Init(api) == 0, NULL);
174 
175     }
176     else
177     {
178         api = AB_Banking_new("gnucash", NULL, 0);
179         g_return_val_if_fail(api, NULL);
180 
181 #if AQBANKING_VERSION_INT >= 59925 \
182     || (AQBANKING_VERSION_INT >= 50709 && AQBANKING_VERSION_INT < 59900)
183         /* These two values must be set because newest bank regulation requires
184         the bank servers to require it. The string itself results from our
185         registration with the German bank association at
186         https://www.hbci-zka.de/register/prod_register.htm (where the
187         registration was requested and is managed by cstim). The function call was
188         introduced in aqbanking-5.99.25 and aqbanking-5.7.9. */
189         AB_Banking_RuntimeConfig_SetCharValue(api, "fintsRegistrationKey", "412748A1836CDD07181CE1910");
190         AB_Banking_RuntimeConfig_SetCharValue(api, "fintsApplicationVersionString", PROJECT_VERSION);
191 #endif
192 
193 #ifndef AQBANKING6
194         /* Check for config migration */
195         if (AB_Banking_HasConf4(api) != 0)
196         {
197             if (AB_Banking_HasConf3(api) == 0)
198             {
199                 PINFO("gnc_AB_BANKING_new: importing aqbanking3 configuration\n");
200                 if (AB_Banking_ImportConf3(api) < 0)
201                 {
202                     PINFO("gnc_AB_BANKING_new: unable to import aqbanking3 configuration\n");
203                 }
204             }
205             else if (AB_Banking_HasConf2(api) == 0)
206             {
207                 PINFO("gnc_AB_BANKING_new: importing aqbanking2 configuration\n");
208                 if (AB_Banking_ImportConf2(api) < 0)
209                 {
210                     PINFO("gnc_AB_BANKING_new: unable to import aqbanking2 configuration\n");
211                 }
212             }
213         }
214 #endif
215 
216         /* Init the API */
217         g_return_val_if_fail(AB_Banking_Init(api) == 0, NULL);
218         gnc_gwengui_extended_by_ABBanking = GWEN_Gui_GetGui();
219         AB_Gui_Extend(gnc_gwengui_extended_by_ABBanking, api);
220 
221         /* Cache it */
222         gnc_AB_BANKING = api;
223         gnc_AB_BANKING_refcount = 0;
224     }
225 
226     gnc_AB_BANKING_refcount++;
227 
228     return api;
229 }
230 
231 void
gnc_AB_BANKING_delete(AB_BANKING * api)232 gnc_AB_BANKING_delete(AB_BANKING *api)
233 {
234     if (!api)
235         api = gnc_AB_BANKING;
236 
237     if (api)
238     {
239         if (api == gnc_AB_BANKING)
240         {
241             gnc_AB_BANKING = NULL;
242             gnc_AB_BANKING_fini(api);
243         }
244 
245         AB_Banking_free(api);
246     }
247 }
248 
249 
250 gint
gnc_AB_BANKING_fini(AB_BANKING * api)251 gnc_AB_BANKING_fini(AB_BANKING *api)
252 {
253     if (api == gnc_AB_BANKING)
254     {
255         if (--gnc_AB_BANKING_refcount == 0)
256         {
257             if (gnc_gwengui_extended_by_ABBanking)
258                 AB_Gui_Unextend(gnc_gwengui_extended_by_ABBanking);
259             gnc_gwengui_extended_by_ABBanking = NULL;
260             return AB_Banking_Fini(api);
261         }
262     }
263     else
264     {
265         if (gnc_gwengui_extended_by_ABBanking)
266             AB_Gui_Unextend(gnc_gwengui_extended_by_ABBanking);
267         gnc_gwengui_extended_by_ABBanking = NULL;
268         return AB_Banking_Fini(api);
269     }
270     return 0;
271 }
272 
273 GNC_AB_ACCOUNT_SPEC *
gnc_ab_get_ab_account(const AB_BANKING * api,Account * gnc_acc)274 gnc_ab_get_ab_account(const AB_BANKING *api, Account *gnc_acc)
275 {
276     GNC_AB_ACCOUNT_SPEC *ab_account = NULL;
277     const gchar *bankcode = NULL;
278     const gchar *accountid = NULL;
279     guint32 account_uid = 0;
280 
281     bankcode = gnc_ab_get_account_bankcode(gnc_acc);
282     accountid = gnc_ab_get_account_accountid(gnc_acc);
283     account_uid = gnc_ab_get_account_uid (gnc_acc);
284 
285     if (account_uid > 0)
286     {
287 #ifdef AQBANKING6
288         gint rv;
289 
290         rv = AB_Banking_GetAccountSpecByUniqueId(api, account_uid, &ab_account);
291 
292         if ( (rv<0 || !ab_account) && bankcode && *bankcode &&
293              accountid && *accountid)
294         {
295 /* Finding the account by code and number is suspended in AQBANKING 6 pending
296  * implementation of a replacement for AB_Banking_GetAccountByCodeAndNumber.
297  */
298             PINFO("gnc_ab_get_ab_account: No AB_ACCOUNT found for UID %d, "
299                       "trying bank code\n", account_uid);
300             return NULL;
301         }
302         return ab_account;
303 #else
304         ab_account = AB_Banking_GetAccount(api, account_uid);
305 
306         if (!ab_account && bankcode && *bankcode && accountid && *accountid)
307         {
308             PINFO("gnc_ab_get_ab_account: No AB_ACCOUNT found for UID %d, "
309                       "trying bank code\n", account_uid);
310             ab_account = AB_Banking_GetAccountByCodeAndNumber(api, bankcode,
311                                                               accountid);
312         }
313         return ab_account;
314 
315     }
316     else if (bankcode && *bankcode && accountid && *accountid)
317     {
318         ab_account = AB_Banking_GetAccountByCodeAndNumber(api, bankcode,
319                      accountid);
320         return ab_account;
321 #endif
322     }
323 
324     return NULL;
325 }
326 
327 gchar *
gnc_AB_VALUE_to_readable_string(const AB_VALUE * value)328 gnc_AB_VALUE_to_readable_string(const AB_VALUE *value)
329 {
330     if (value)
331         return g_strdup_printf("%.2f %s",
332                                AB_Value_GetValueAsDouble(value),
333                                AB_Value_GetCurrency(value));
334     else
335         return g_strdup_printf("%.2f", 0.0);
336 }
337 
338 
339 gchar*
gnc_ab_create_online_id(const gchar * bankcode,const gchar * accountnumber)340 gnc_ab_create_online_id(const gchar *bankcode, const gchar *accountnumber)
341 {
342     gchar *online_id;
343 
344     /* The accountnumber may have leading zeros, depending on where them
345      * accountnumber is came from, e.g. the accountnumber of accountinfo
346      * has no leading zeros while the (local)accountnumber of a transaction
347      * has leading zeros.
348      * So remove all leading '0', to get a consistent online_id.
349      */
350     while (accountnumber && *accountnumber == '0')
351         accountnumber++;
352 
353     online_id = g_strconcat(bankcode ? bankcode : "",
354                             accountnumber ? accountnumber : "",
355                             (gchar*)NULL);
356 
357     return online_id;
358 }
359 
360 /**
361  * Take a string from a GWEN_STRINGLIST, strip invalid utf8 and join it
362  * to the rest.
363  */
364 static gpointer
join_ab_strings_cb(const gchar * str,gpointer user_data)365 join_ab_strings_cb(const gchar *str, gpointer user_data)
366 {
367     gchar **acc = user_data;
368     gchar *tmp;
369 
370     if (!str || !*str)
371         return NULL;
372 
373     tmp = g_strdup(str);
374     g_strstrip(tmp);
375     gnc_utf8_strip_invalid_and_controls(tmp);
376 
377     if (*acc)
378     {
379         gchar *join = g_strjoin(" ", *acc, tmp, (gchar*) NULL);
380         g_free(*acc);
381         g_free(tmp);
382         *acc = join;
383     }
384     else
385     {
386         *acc = tmp;
387     }
388     return NULL;
389 }
390 
391 gchar *
gnc_ab_get_remote_name(const AB_TRANSACTION * ab_trans)392 gnc_ab_get_remote_name(const AB_TRANSACTION *ab_trans)
393 {
394 #ifdef AQBANKING6
395     const char* ab_remote_name;
396 #else
397     const GWEN_STRINGLIST *ab_remote_name;
398 #endif
399     gchar *gnc_other_name = NULL;
400 
401     g_return_val_if_fail(ab_trans, NULL);
402 
403     ab_remote_name = AB_Transaction_GetRemoteName(ab_trans);
404     if (ab_remote_name)
405 #ifdef AQBANKING6
406         gnc_other_name = g_strdup(ab_remote_name);
407 #else
408         GWEN_StringList_ForEach(ab_remote_name, join_ab_strings_cb,
409                                 &gnc_other_name);
410 #endif
411     if (!gnc_other_name || !*gnc_other_name)
412     {
413         g_free(gnc_other_name);
414         gnc_other_name = NULL;
415     }
416 
417     return gnc_other_name;
418 }
419 
420 gchar *
gnc_ab_get_purpose(const AB_TRANSACTION * ab_trans,gboolean is_ofx)421 gnc_ab_get_purpose(const AB_TRANSACTION *ab_trans, gboolean is_ofx)
422 {
423 #ifdef AQBANKING6
424 #  if AQBANKING_VERSION_INT < 59929
425 #    error "You are using an old beta version of aqbanking > 5.99.0 but < 5.99.29, please upgrade to the latest 5.99.29 or newer."
426 #  endif
427 #else
428     const /* only const in aqbanking < 5.99 */
429 #endif
430             GWEN_STRINGLIST *ab_purpose;
431     const char *ab_transactionText = NULL;
432     gchar *gnc_description = NULL;
433 
434     g_return_val_if_fail(ab_trans, g_strdup(""));
435 
436     if (!is_ofx && gnc_prefs_get_bool(GNC_PREFS_GROUP_AQBANKING, GNC_PREF_USE_TRANSACTION_TXT))
437     {
438         /* According to AqBanking, some of the non-swift lines have a special
439          * meaning. Some banks place valuable text into the transaction text,
440          * hence we put this text in front of the purpose. */
441         ab_transactionText = AB_Transaction_GetTransactionText(ab_trans);
442         if (ab_transactionText)
443             gnc_description = g_strdup(ab_transactionText);
444     }
445 
446     ab_purpose =
447 #ifdef AQBANKING6
448             /* With aqbanking-5.99.29, the identical function as before is now available under this new name. */
449             AB_Transaction_GetPurposeAsStringList
450 #else
451             AB_Transaction_GetPurpose
452 #endif
453             (ab_trans);
454     if (ab_purpose)
455         GWEN_StringList_ForEach(ab_purpose, join_ab_strings_cb,
456                                 &gnc_description);
457 
458 #ifdef AQBANKING6
459     /* With aqbanking>=5.99, the return value must now be free'd */
460     GWEN_StringList_free(ab_purpose);
461 #endif
462 
463     if (!gnc_description)
464         gnc_description = g_strdup("");
465 
466     return gnc_description;
467 }
468 
469 gchar *
gnc_ab_description_to_gnc(const AB_TRANSACTION * ab_trans,gboolean is_ofx)470 gnc_ab_description_to_gnc(const AB_TRANSACTION *ab_trans, gboolean is_ofx)
471 {
472     /* Description */
473     gchar *description = gnc_ab_get_purpose(ab_trans, is_ofx);
474     gchar *other_name = gnc_ab_get_remote_name(ab_trans);
475     gchar *retval;
476 
477     if (other_name)
478     {
479         if (description && *description)
480         {
481             retval = g_strdup_printf("%s; %s", description, other_name);
482         }
483         else
484         {
485             retval = g_strdup(other_name);
486         }
487     }
488     else
489     {
490         if (description && *description)
491         {
492             retval = g_strdup(description);
493         }
494         else
495         {
496             retval = g_strdup(_("Unspecified"));
497         }
498     }
499     g_free(description);
500     g_free(other_name);
501 
502     return retval;
503 }
504 
505 gchar *
gnc_ab_memo_to_gnc(const AB_TRANSACTION * ab_trans)506 gnc_ab_memo_to_gnc(const AB_TRANSACTION *ab_trans)
507 {
508     const gchar *ab_remote_accountnumber =
509         AB_Transaction_GetRemoteAccountNumber(ab_trans);
510     const gchar *ab_remote_bankcode =
511         AB_Transaction_GetRemoteBankCode(ab_trans);
512 
513     gchar *ab_other_accountid;
514     gchar *ab_other_bankcode;
515 
516     gboolean have_accountid;
517     gboolean have_bankcode;
518 
519     gchar *retval;
520 
521     // For SEPA transactions, we need to ask for something different here
522     if (!ab_remote_accountnumber)
523         ab_remote_accountnumber = AB_Transaction_GetRemoteIban(ab_trans);
524     if (!ab_remote_bankcode)
525         ab_remote_bankcode = AB_Transaction_GetRemoteBic(ab_trans);
526 
527     ab_other_accountid = g_strdup(ab_remote_accountnumber ? ab_remote_accountnumber : "");
528     ab_other_bankcode = g_strdup(ab_remote_bankcode ? ab_remote_bankcode : "");
529 
530     /* Ensure string is in utf8 */
531     gnc_utf8_strip_invalid(ab_other_accountid);
532     gnc_utf8_strip_invalid(ab_other_bankcode);
533 
534     /* and -then- trim it */
535     g_strstrip(ab_other_accountid);
536     g_strstrip(ab_other_bankcode);
537 
538 
539     have_accountid = ab_other_accountid && *ab_other_accountid;
540     have_bankcode = ab_other_bankcode && *ab_other_bankcode;
541 
542     if ( have_accountid || have_bankcode )
543     {
544         retval = g_strdup_printf("%s %s %s %s",
545                                  have_accountid ? _("Account") : "",
546                                  have_accountid ? ab_other_accountid : "",
547                                  have_bankcode  ? _("Bank") : "",
548                                  have_bankcode  ? ab_other_bankcode : ""
549                                 );
550         g_strstrip(retval);
551     }
552     else
553     {
554         retval = g_strdup("");
555     }
556 
557     g_free(ab_other_accountid);
558     g_free(ab_other_bankcode);
559 
560     return retval;
561 }
562 
563 Transaction *
gnc_ab_trans_to_gnc(const AB_TRANSACTION * ab_trans,Account * gnc_acc)564 gnc_ab_trans_to_gnc(const AB_TRANSACTION *ab_trans, Account *gnc_acc)
565 {
566     QofBook *book;
567     Transaction *gnc_trans;
568     const gchar *fitid;
569     const GNC_GWEN_DATE *valuta_date;
570     time64 current_time;
571     const char *custref;
572     gchar *description;
573     Split *split;
574     gchar *memo;
575 
576     g_return_val_if_fail(ab_trans && gnc_acc, NULL);
577 
578     /* Create new GnuCash transaction for the given AqBanking one */
579     book = gnc_account_get_book(gnc_acc);
580     gnc_trans = xaccMallocTransaction(book);
581     xaccTransBeginEdit(gnc_trans);
582 
583     /* Date / Time */
584     valuta_date = AB_Transaction_GetValutaDate(ab_trans);
585     if (!valuta_date)
586     {
587         const GNC_GWEN_DATE *normal_date = AB_Transaction_GetDate(ab_trans);
588         if (normal_date)
589             valuta_date = normal_date;
590     }
591     if (valuta_date)
592     {
593         time64 secs = gnc_gwen_date_to_time64(valuta_date);
594         xaccTransSetDatePostedSecsNormalized(gnc_trans, secs);
595     }
596     else
597     {
598         g_warning("transaction_cb: Oops, date 'valuta_date' was NULL");
599     }
600     xaccTransSetDateEnteredSecs(gnc_trans, gnc_time (NULL));
601 
602     /* Currency.  We take simply the default currency of the gnucash account */
603     xaccTransSetCurrency(gnc_trans, xaccAccountGetCommodity(gnc_acc));
604 
605     /* Trans-Num or Split-Action set with gnc_set_num_action below per book
606      * option */
607 
608     fitid = AB_Transaction_GetFiId(ab_trans);
609 
610     /* Description */
611     description = gnc_ab_description_to_gnc(ab_trans, (fitid && *fitid));
612     xaccTransSetDescription(gnc_trans, description);
613     g_free(description);
614 
615     /* Notes. */
616     /* xaccTransSetNotes(gnc_trans, g_notes); */
617     /* But Nobody ever uses the Notes field? */
618 
619     /* Add one split */
620     split = xaccMallocSplit(book);
621     xaccSplitSetParent(split, gnc_trans);
622     xaccSplitSetAccount(split, gnc_acc);
623 
624     /* Set the transaction number or split action field based on book option.
625      * We use the "customer reference", if there is one. */
626     custref = AB_Transaction_GetCustomerReference(ab_trans);
627     if (custref && *custref
628             && g_ascii_strncasecmp(custref, "NONREF", 6) != 0)
629         gnc_set_num_action (gnc_trans, split, custref, NULL);
630 
631     /* Set OFX unique transaction ID */
632     if (fitid && *fitid)
633         gnc_import_set_split_online_id(split, fitid);
634 
635     /* FIXME: Extract function */
636     {
637         /* Amount into the split */
638         const AB_VALUE *ab_value = AB_Transaction_GetValue(ab_trans);
639         double d_value = ab_value ? AB_Value_GetValueAsDouble (ab_value) : 0.0;
640         AB_TRANSACTION_TYPE ab_type = AB_Transaction_GetType (ab_trans);
641         gnc_numeric gnc_amount;
642 
643         /*printf("Transaction with value %f has type %d\n", d_value, ab_type);*/
644         /* If the value is positive, but the transaction type says the
645            money is transferred away from our account (Transfer instead of
646            DebitNote), we switch the value to negative. */
647         if (d_value > 0.0 && ab_type == AB_Transaction_TypeTransfer)
648             d_value = -d_value;
649 
650         gnc_amount = double_to_gnc_numeric(
651                          d_value,
652                          xaccAccountGetCommoditySCU(gnc_acc),
653                          GNC_HOW_RND_ROUND_HALF_UP);
654         if (!ab_value)
655             g_warning("transaction_cb: Oops, value was NULL.  Using 0");
656         xaccSplitSetBaseValue(split, gnc_amount, xaccAccountGetCommodity(gnc_acc));
657     }
658 
659     /* Memo in the Split. */
660     memo = gnc_ab_memo_to_gnc(ab_trans);
661     xaccSplitSetMemo(split, memo);
662     g_free(memo);
663 
664     return gnc_trans;
665 }
666 
667 /**
668  * Call gnc_import_select_account() on the online id constructed using
669  * the information in @a acc_info.
670  *
671  * @param parent Parent Widget
672  * @param acc_info AB_IMEXPORTER_ACCOUNTINFO
673  * @return A GnuCash account, or NULL otherwise
674  */
675 static Account *
gnc_ab_accinfo_to_gnc_acc(GtkWidget * parent,AB_IMEXPORTER_ACCOUNTINFO * acc_info)676 gnc_ab_accinfo_to_gnc_acc(GtkWidget *parent, AB_IMEXPORTER_ACCOUNTINFO *acc_info)
677 {
678     const gchar *bankcode, *accountnumber;
679     gchar *online_id;
680     Account *gnc_acc;
681 
682     g_return_val_if_fail(acc_info, NULL);
683 
684     bankcode = AB_ImExporterAccountInfo_GetBankCode(acc_info);
685     accountnumber = AB_ImExporterAccountInfo_GetAccountNumber(acc_info);
686     online_id = gnc_ab_create_online_id(bankcode, accountnumber);
687     gnc_acc = gnc_import_select_account(
688                   parent, online_id, 1, AB_ImExporterAccountInfo_GetAccountName(acc_info),
689                   NULL, ACCT_TYPE_NONE, NULL, NULL);
690     if (!gnc_acc)
691     {
692         g_warning("gnc_ab_accinfo_to_gnc_acc: Could not determine source account"
693                   " for online_id %s", online_id);
694     }
695     g_free(online_id);
696 
697     return gnc_acc;
698 }
699 
700 
701 /**
702  * Call gnc_import_select_account() on the online id constructed using
703  * the local information in @a transaction.
704  *
705  * @param parent Parent Widget
706  * @param transaction AB_TRANSACTION
707  * @return A GnuCash account, or NULL otherwise
708  */
709 static Account *
gnc_ab_txn_to_gnc_acc(GtkWidget * parent,const AB_TRANSACTION * transaction)710 gnc_ab_txn_to_gnc_acc(GtkWidget *parent, const AB_TRANSACTION *transaction)
711 {
712     const gchar *bankcode, *accountnumber;
713     gchar *online_id;
714     Account *gnc_acc;
715 
716     g_return_val_if_fail(transaction, NULL);
717 
718     bankcode = AB_Transaction_GetLocalBankCode(transaction);
719     accountnumber = AB_Transaction_GetLocalAccountNumber(transaction);
720     if (!bankcode && !accountnumber)
721     {
722         return NULL;
723     }
724 
725     online_id = gnc_ab_create_online_id(bankcode, accountnumber);
726     gnc_acc = gnc_import_select_account(
727                   parent, online_id, 1, AB_Transaction_GetLocalName(transaction),
728                   NULL, ACCT_TYPE_NONE, NULL, NULL);
729     if (!gnc_acc)
730     {
731         g_warning("gnc_ab_txn_to_gnc_acc: Could not determine source account"
732                   " for online_id %s", online_id);
733     }
734     g_free(online_id);
735 
736     return gnc_acc;
737 }
738 
739 static const AB_TRANSACTION *
txn_transaction_cb(const AB_TRANSACTION * element,gpointer user_data)740 txn_transaction_cb(const AB_TRANSACTION *element, gpointer user_data)
741 {
742     GncABImExContextImport *data = user_data;
743     Transaction *gnc_trans;
744     GncABTransType trans_type;
745     Account* txnacc;
746 
747     g_return_val_if_fail(element && data, NULL);
748 
749     /* Create a GnuCash transaction from ab_trans */
750     txnacc = gnc_ab_txn_to_gnc_acc(GTK_WIDGET(data->parent), element);
751     gnc_trans = gnc_ab_trans_to_gnc(element, txnacc ? txnacc : data->gnc_acc);
752 
753     if (data->execute_txns && data->ab_acc)
754     {
755         AB_TRANSACTION *ab_trans = AB_Transaction_dup(element);
756         GNC_AB_JOB *job;
757 
758         /* NEW: The imported transaction has been imported into gnucash.
759          * Now also add it as a job to aqbanking */
760 #ifdef AQBANKING6
761         AB_Transaction_SetLocalBankCode(
762             ab_trans, AB_AccountSpec_GetBankCode(data->ab_acc));
763         AB_Transaction_SetLocalAccountNumber(
764             ab_trans, AB_AccountSpec_GetAccountNumber(data->ab_acc));
765 #else
766         AB_Transaction_SetLocalBankCode(
767             ab_trans, AB_Account_GetBankCode(data->ab_acc));
768         AB_Transaction_SetLocalAccountNumber(
769             ab_trans, AB_Account_GetAccountNumber(data->ab_acc));
770 #endif
771         AB_Transaction_SetLocalCountry(ab_trans, "DE");
772 
773 
774         switch (AB_Transaction_GetType(ab_trans))
775         {
776         case AB_Transaction_TypeDebitNote:
777             trans_type = SINGLE_DEBITNOTE;
778             break;
779         case AB_Transaction_TypeTransaction:
780             /* trans_type = SINGLE_INTERNAL_TRANSFER;
781              * break; */
782         case AB_Transaction_TypeTransfer:
783 #ifndef AQBANKING6
784         case AB_Transaction_TypeEuTransfer:
785 #endif
786         default:
787             trans_type = SEPA_TRANSFER;
788             break;
789         } /* switch */
790 
791         job = gnc_ab_get_trans_job(data->ab_acc, ab_trans, trans_type);
792 
793         /* Check whether we really got a job */
794 #ifdef AQBANKING6
795         if (!job || AB_AccountSpec_GetTransactionLimitsForCommand(data->ab_acc, AB_Transaction_GetCommand(job))==NULL)
796 #else
797         if (!job || AB_Job_CheckAvailability(job))
798 #endif
799         {
800             /* Oops, no job, probably not supported by bank */
801             if (gnc_verify_dialog(
802                         GTK_WINDOW (data->parent), FALSE, "%s",
803                         _("The backend found an error during the preparation "
804                           "of the job. It is not possible to execute this job.\n"
805                           "\n"
806                           "Most probably the bank does not support your chosen "
807                           "job or your Online Banking account does not have the permission "
808                           "to execute this job. More error messages might be "
809                           "visible on your console log.\n"
810                           "\n"
811                           "Do you want to enter the job again?")))
812             {
813                 gnc_error_dialog (GTK_WINDOW (data->parent),
814                                   "Sorry, not implemented yet. Please check the console or trace file logs to see which job was rejected.");
815             }
816         }
817         else
818         {
819             gnc_gen_trans_list_add_trans_with_ref_id(data->generic_importer,
820                                                      gnc_trans,
821 #ifdef AQBANKING6
822                                                      AB_Transaction_GetUniqueId(job));
823 #else
824                                                      AB_Job_GetJobId(job));
825 #endif
826             /* AB_Job_List2_PushBack(data->job_list, job); -> delayed until trans is successfully imported */
827             g_datalist_set_data(&data->tmp_job_list, gnc_AB_JOB_to_readable_string(job), job);
828         }
829         AB_Transaction_free(ab_trans);
830     }
831     else
832     {
833         /* Instead of xaccTransCommitEdit(gnc_trans)  */
834         gnc_gen_trans_list_add_trans(data->generic_importer, gnc_trans);
835     }
836 
837     return NULL;
838 }
839 
gnc_ab_trans_processed_cb(GNCImportTransInfo * trans_info,gboolean imported,gpointer user_data)840 static void gnc_ab_trans_processed_cb(GNCImportTransInfo *trans_info,
841                                       gboolean imported,
842                                       gpointer user_data)
843 {
844     GncABImExContextImport *data = user_data;
845     gchar *jobname = gnc_AB_JOB_ID_to_string(gnc_import_TransInfo_get_ref_id(trans_info));
846     GNC_AB_JOB *job = g_datalist_get_data(&data->tmp_job_list, jobname);
847 
848     if (imported)
849     {
850 #ifdef AQBANKING6
851         AB_Transaction_List2_PushBack(data->job_list, job);
852 #else
853         AB_Job_List2_PushBack(data->job_list, job);
854 #endif
855     }
856     else
857     {
858 #ifdef AQBANKING6
859         AB_Transaction_free(job);
860 #else
861         AB_Job_free(job);
862 #endif
863     }
864 
865     g_datalist_remove_data(&data->tmp_job_list, jobname);
866 }
867 
868 gchar *
gnc_AB_JOB_to_readable_string(const GNC_AB_JOB * job)869 gnc_AB_JOB_to_readable_string(const GNC_AB_JOB *job)
870 {
871     if (job)
872     {
873 #ifdef AQBANKING6
874         return gnc_AB_JOB_ID_to_string(AB_Transaction_GetUniqueId(job));
875 #else
876         return gnc_AB_JOB_ID_to_string(AB_Job_GetJobId(job));
877 #endif
878     }
879     else
880     {
881         return gnc_AB_JOB_ID_to_string(0);
882     }
883 }
884 gchar *
gnc_AB_JOB_ID_to_string(gulong job_id)885 gnc_AB_JOB_ID_to_string(gulong job_id)
886 {
887     return g_strdup_printf("job_%lu", job_id);
888 }
889 
890 
891 
892 static AB_IMEXPORTER_ACCOUNTINFO *
txn_accountinfo_cb(AB_IMEXPORTER_ACCOUNTINFO * element,gpointer user_data)893 txn_accountinfo_cb(AB_IMEXPORTER_ACCOUNTINFO *element, gpointer user_data)
894 {
895     GncABImExContextImport *data = user_data;
896     Account *gnc_acc;
897 
898     g_return_val_if_fail(element && data, NULL);
899 
900     if (data->awaiting & IGNORE_TRANSACTIONS)
901         /* Ignore them */
902         return NULL;
903 
904 #ifdef AQBANKING6
905     if (!AB_ImExporterAccountInfo_GetFirstTransaction(element, AB_Transaction_TypeStatement, 0))
906 #else
907     if (!AB_ImExporterAccountInfo_GetFirstTransaction(element))
908 #endif
909 /* No transaction found */
910         return NULL;
911     else
912         data->awaiting |= FOUND_TRANSACTIONS;
913 
914     if (!(data->awaiting & AWAIT_TRANSACTIONS))
915     {
916         if (gnc_verify_dialog (GTK_WINDOW (data->parent), TRUE, "%s",
917                               _("The bank has sent transaction information "
918                                 "in its response."
919                                 "\n"
920                                 "Do you want to import it?")))
921         {
922             data->awaiting |= AWAIT_TRANSACTIONS;
923         }
924         else
925         {
926             data->awaiting |= IGNORE_TRANSACTIONS;
927             return NULL;
928         }
929     }
930 
931     /* Lookup the corresponding gnucash account */
932     gnc_acc = gnc_ab_accinfo_to_gnc_acc(GTK_WIDGET(data->parent), element);
933     if (!gnc_acc) return NULL;
934     data->gnc_acc = gnc_acc;
935 
936     if (data->execute_txns)
937     {
938         /* Retrieve the aqbanking account that belongs to this gnucash
939          * account */
940         data->ab_acc = gnc_ab_get_ab_account(data->api, gnc_acc);
941         if (!data->ab_acc)
942         {
943             gnc_error_dialog(GTK_WINDOW (data->parent), "%s",
944                              _("No Online Banking account found for this "
945                                "gnucash account. These transactions will "
946                                "not be executed by Online Banking."));
947         }
948     }
949     else
950     {
951         data->ab_acc = NULL;
952     }
953 
954     if (!data->generic_importer)
955     {
956         data->generic_importer = gnc_gen_trans_list_new(data->parent, NULL,
957                                  TRUE, 14, TRUE);
958         if (data->execute_txns)
959         {
960             gnc_gen_trans_list_add_tp_cb(data->generic_importer,
961                                          gnc_ab_trans_processed_cb, data);
962         }
963     }
964 
965     /* Iterate through all transactions */
966 #ifdef AQBANKING6
967     {
968         AB_TRANSACTION_LIST *ab_trans_list = AB_ImExporterAccountInfo_GetTransactionList(element);
969         if (ab_trans_list)
970             AB_Transaction_List_ForEachByType(ab_trans_list,
971                                               txn_transaction_cb, data,
972                                               AB_Transaction_TypeStatement, 0);
973     }
974 #else
975     AB_ImExporterAccountInfo_TransactionsForEach(element, txn_transaction_cb,
976                                                  data);
977 #endif
978     return NULL;
979 }
980 
981 static AB_IMEXPORTER_ACCOUNTINFO *
bal_accountinfo_cb(AB_IMEXPORTER_ACCOUNTINFO * element,gpointer user_data)982 bal_accountinfo_cb(AB_IMEXPORTER_ACCOUNTINFO *element, gpointer user_data)
983 {
984     GncABImExContextImport *data = user_data;
985     Account *gnc_acc;
986     const AB_BALANCE *booked_bal, *noted_bal;
987     const AB_VALUE *booked_val = NULL, *noted_val = NULL;
988     gdouble booked_value, noted_value;
989     gnc_numeric value;
990     time64 booked_tt = 0;
991     GtkWidget *dialog;
992     gboolean show_recn_window = FALSE;
993 #ifndef AQBANKING6
994     AB_ACCOUNT_STATUS *best = NULL;
995 #endif
996 
997     g_return_val_if_fail(element && data, NULL);
998 
999     if (data->awaiting & IGNORE_BALANCES)
1000         /* Ignore them */
1001         return NULL;
1002 
1003 #ifdef AQBANKING6
1004     if (!AB_ImExporterAccountInfo_GetFirstBalance(element))
1005 #else
1006     if (!AB_ImExporterAccountInfo_GetFirstAccountStatus(element))
1007 #endif
1008         /* No balance found */
1009         return NULL;
1010     else
1011         data->awaiting |= FOUND_BALANCES;
1012 
1013 #ifdef AQBANKING6
1014     /* Lookup the most recent BALANCE available */
1015     booked_bal=AB_Balance_List_GetLatestByType(AB_ImExporterAccountInfo_GetBalanceList(element),
1016                                                AB_Balance_TypeBooked);
1017 #else
1018     {
1019         AB_ACCOUNT_STATUS *item = NULL;
1020         const GWEN_TIME *best_time = NULL;
1021         /* Lookup the most recent ACCOUNT_STATUS available */
1022         item = AB_ImExporterAccountInfo_GetFirstAccountStatus(element);
1023         while (item)
1024         {
1025             const GWEN_TIME *item_time = AB_AccountStatus_GetTime(item);
1026             if (!best || GWEN_Time_Diff(best_time, item_time) < 0.0)
1027             {
1028                 best = item;
1029                 best_time = item_time;
1030             }
1031             item = AB_ImExporterAccountInfo_GetNextAccountStatus(element);
1032         }
1033 
1034         booked_bal = AB_AccountStatus_GetBookedBalance(best);
1035     }
1036 #endif
1037 
1038     if (!(data->awaiting & AWAIT_BALANCES))
1039     {
1040          GtkWindow *parent = data->generic_importer ?
1041               GTK_WINDOW(data->generic_importer) :
1042               GTK_WINDOW(data->parent);
1043          const char* balance_msg =
1044               _("The bank has sent balance information in its response.\n"
1045                 "Do you want to import it?");
1046         /* Ignore zero balances if we don't await a balance */
1047         if (!booked_bal || AB_Value_IsZero(AB_Balance_GetValue(booked_bal)))
1048             return NULL;
1049 
1050         /* Ask the user whether to import unawaited non-zero balance */
1051         if (gnc_verify_dialog (parent, TRUE, "%s", balance_msg))
1052         {
1053             data->awaiting |= AWAIT_BALANCES;
1054         }
1055         else
1056         {
1057             data->awaiting |= IGNORE_BALANCES;
1058             return NULL;
1059         }
1060     }
1061 
1062     /* Lookup the corresponding gnucash account */
1063     gnc_acc = gnc_ab_accinfo_to_gnc_acc(GTK_WIDGET (data->parent), element);
1064     if (!gnc_acc) return NULL;
1065     data->gnc_acc = gnc_acc;
1066 
1067     /* Lookup booked balance and time */
1068     if (booked_bal)
1069     {
1070 #ifdef AQBANKING6
1071         const GWEN_DATE *ti = AB_Balance_GetDate(booked_bal);
1072 #else
1073         const GNC_GWEN_DATE *ti = AB_Balance_GetTime(booked_bal);
1074 #endif
1075         if (ti)
1076         {
1077             booked_tt = gnc_gwen_date_to_time64(ti);
1078         }
1079         else
1080         {
1081             /* No time found? Use today because the HBCI query asked for today's
1082              * balance. */
1083             booked_tt = gnc_time64_get_day_neutral(gnc_time(NULL));
1084         }
1085         booked_val = AB_Balance_GetValue(booked_bal);
1086         if (booked_val)
1087         {
1088             booked_value = AB_Value_GetValueAsDouble(booked_val);
1089         }
1090         else
1091         {
1092             g_warning("bal_accountinfo_cb: booked_val == NULL.  Assuming 0");
1093             booked_value = 0.0;
1094         }
1095     }
1096     else
1097     {
1098         g_warning("bal_accountinfo_cb: booked_bal == NULL.  Assuming 0");
1099         booked_tt = 0;
1100         booked_value = 0.0;
1101     }
1102 
1103     /* Lookup noted balance */
1104 #ifdef AQBANKING6
1105     noted_bal = AB_Balance_List_GetLatestByType(AB_ImExporterAccountInfo_GetBalanceList(element),
1106                                                 AB_Balance_TypeNoted);
1107 #else
1108     noted_bal = AB_AccountStatus_GetNotedBalance(best);
1109 #endif
1110     if (noted_bal)
1111     {
1112         noted_val = AB_Balance_GetValue(noted_bal);
1113         if (noted_val)
1114             noted_value = AB_Value_GetValueAsDouble(noted_val);
1115         else
1116         {
1117             g_warning("bal_accountinfo_cb: noted_val == NULL.  Assuming 0");
1118             noted_value = 0.0;
1119         }
1120     }
1121     else
1122     {
1123         g_warning("bal_accountinfo_cb: noted_bal == NULL.  Assuming 0");
1124         noted_value = 0.0;
1125     }
1126 
1127     value = double_to_gnc_numeric(booked_value,
1128                                   xaccAccountGetCommoditySCU(gnc_acc),
1129                                   GNC_HOW_RND_ROUND_HALF_UP);
1130     if (noted_value == 0.0 && booked_value == 0.0)
1131     {
1132         dialog = gtk_message_dialog_new(
1133                      GTK_WINDOW(data->parent),
1134                      GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1135                      GTK_MESSAGE_INFO,
1136                      GTK_BUTTONS_OK,
1137                      "%s",
1138                      /* Translators: Strings from this file are needed only in
1139                         countries that have one of aqbanking's Online Banking
1140                         techniques available. This is 'OFX DirectConnect'
1141                         (U.S. and others), 'HBCI' (in Germany), or 'YellowNet'
1142                         (Switzerland). If none of these techniques are available
1143                         in your country, you may safely ignore strings from the
1144                         import-export/hbci subdirectory. */
1145                      _("The downloaded Online Banking Balance was zero.\n\n"
1146                        "Either this is the correct balance, or your bank does not "
1147                        "support Balance download in this Online Banking version. "
1148                        "In the latter case you should choose a different "
1149                        "Online Banking version number in the Online Banking "
1150                        "(AqBanking or HBCI) Setup. After that, try again to "
1151                        "download the Online Banking Balance."));
1152         gtk_dialog_run(GTK_DIALOG(dialog));
1153         gtk_widget_destroy(dialog);
1154 
1155     }
1156     else
1157     {
1158         gnc_numeric reconc_balance = xaccAccountGetReconciledBalance(gnc_acc);
1159 
1160         gchar *booked_str = gnc_AB_VALUE_to_readable_string(booked_val);
1161         gchar *message1 = g_strdup_printf(
1162                               _("Result of Online Banking job:\n"
1163                                 "Account booked balance is %s"),
1164                               booked_str);
1165         gchar *message2 =
1166             (noted_value == 0.0) ?
1167             g_strdup("") :
1168             g_strdup_printf(_("For your information: This account also "
1169                               "has a noted balance of %s\n"),
1170                             gnc_AB_VALUE_to_readable_string(noted_val));
1171 
1172         if (gnc_numeric_equal(value, reconc_balance))
1173         {
1174             const gchar *message3 =
1175                 _("The booked balance is identical to the current "
1176                   "reconciled balance of the account.");
1177             dialog = gtk_message_dialog_new(
1178                          GTK_WINDOW(data->parent),
1179                          GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
1180                          GTK_MESSAGE_INFO,
1181                          GTK_BUTTONS_OK,
1182                          "%s\n%s\n%s",
1183                          message1, message2, message3);
1184             gtk_dialog_run(GTK_DIALOG(dialog));
1185             gtk_widget_destroy(GTK_WIDGET(dialog));
1186 
1187         }
1188         else
1189         {
1190             const char *message3 = _("Reconcile account now?");
1191 
1192             show_recn_window = gnc_verify_dialog (GTK_WINDOW (data->parent), TRUE, "%s\n%s\n%s",
1193                                                  message1, message2, message3);
1194         }
1195         g_free(booked_str);
1196         g_free(message1);
1197         g_free(message2);
1198     }
1199 
1200     /* Show reconciliation window */
1201     if (show_recn_window)
1202         recnWindowWithBalance(GTK_WIDGET (data->parent), gnc_acc, value, booked_tt);
1203 
1204     return NULL;
1205 }
1206 
1207 GncABImExContextImport *
gnc_ab_import_context(AB_IMEXPORTER_CONTEXT * context,guint awaiting,gboolean execute_txns,AB_BANKING * api,GtkWidget * parent)1208 gnc_ab_import_context(AB_IMEXPORTER_CONTEXT *context,
1209                       guint awaiting, gboolean execute_txns,
1210                       AB_BANKING *api, GtkWidget *parent)
1211 {
1212     GncABImExContextImport *data = g_new(GncABImExContextImport, 1);
1213 #ifdef AQBANKING6
1214     AB_IMEXPORTER_ACCOUNTINFO_LIST *ab_ail;
1215 #endif
1216     g_return_val_if_fail(context, NULL);
1217     /* Do not await and ignore at the same time */
1218     g_return_val_if_fail(!(awaiting & AWAIT_BALANCES)
1219                          || !(awaiting & IGNORE_BALANCES),
1220                          NULL);
1221     g_return_val_if_fail(!(awaiting & AWAIT_TRANSACTIONS)
1222                          || !(awaiting & IGNORE_TRANSACTIONS),
1223                          NULL);
1224     /* execute_txns must be FALSE if txns are not awaited */
1225     g_return_val_if_fail(awaiting & AWAIT_TRANSACTIONS || !execute_txns, NULL);
1226     /* An api is needed for the jobs */
1227     g_return_val_if_fail(!execute_txns || api, NULL);
1228 
1229     data->awaiting = awaiting;
1230     data->txn_found = FALSE;
1231     data->execute_txns = execute_txns;
1232     data->api = api;
1233     data->parent = parent;
1234 #ifdef AQBANKING6
1235     data->job_list = AB_Transaction_List2_new();
1236 #else
1237     data->job_list = AB_Job_List2_new();
1238 #endif
1239     data->tmp_job_list = NULL;
1240     data->generic_importer = NULL;
1241 
1242     g_datalist_init(&data->tmp_job_list);
1243 
1244     /* Import transactions */
1245 #ifdef AQBANKING6
1246     ab_ail = AB_ImExporterContext_GetAccountInfoList(context);
1247     if (ab_ail && AB_ImExporterAccountInfo_List_GetCount(ab_ail))
1248     {
1249         if (!(awaiting & IGNORE_TRANSACTIONS))
1250             AB_ImExporterAccountInfo_List_ForEach(ab_ail, txn_accountinfo_cb,
1251                                                   data);
1252 
1253         /* populate and display the matching window */
1254         if (data->generic_importer)
1255             gnc_gen_trans_list_show_all(data->generic_importer);
1256 
1257         /* Check balances */
1258         if (!(awaiting & IGNORE_BALANCES))
1259             AB_ImExporterAccountInfo_List_ForEach(ab_ail, bal_accountinfo_cb,
1260                                                   data);
1261     }
1262 #else
1263     if (!(awaiting & IGNORE_TRANSACTIONS))
1264         AB_ImExporterContext_AccountInfoForEach(context, txn_accountinfo_cb,
1265                                                 data);
1266 
1267     /* populate and display the matching window */
1268     if (data->generic_importer)
1269         gnc_gen_trans_list_show_all(data->generic_importer);
1270 
1271     /* Check balances */
1272     if (!(awaiting & IGNORE_BALANCES))
1273         AB_ImExporterContext_AccountInfoForEach(context, bal_accountinfo_cb,
1274                                                 data);
1275 #endif
1276 
1277     /* Check bank-messages */
1278     {
1279         AB_MESSAGE * bankmsg = AB_ImExporterContext_GetFirstMessage(context);
1280         while (bankmsg)
1281         {
1282             const char* subject = AB_Message_GetSubject(bankmsg);
1283             const char* text = AB_Message_GetText(bankmsg);
1284             gnc_info_dialog(GTK_WINDOW (data->parent), "%s\n%s %s\n%s",
1285                             _("The bank has sent a message in its response."),
1286                             _("Subject:"),
1287                             subject,
1288                             text);
1289 
1290 #ifdef AQBANKING6
1291             bankmsg = AB_Message_List_Next(bankmsg);
1292 #else
1293             bankmsg = AB_ImExporterContext_GetNextMessage(context); // The iterator is incremented within aqbanking
1294 #endif
1295         }
1296     }
1297 
1298     return data;
1299 }
1300 
1301 guint
gnc_ab_ieci_get_found(GncABImExContextImport * ieci)1302 gnc_ab_ieci_get_found(GncABImExContextImport *ieci)
1303 {
1304     g_return_val_if_fail(ieci, 0);
1305 
1306     return ieci->awaiting;
1307 }
1308 
1309 GNC_AB_JOB_LIST2 *
gnc_ab_ieci_get_job_list(GncABImExContextImport * ieci)1310 gnc_ab_ieci_get_job_list(GncABImExContextImport *ieci)
1311 {
1312     g_return_val_if_fail(ieci, NULL);
1313 
1314     return ieci->job_list;
1315 }
1316 
1317 gboolean
gnc_ab_ieci_run_matcher(GncABImExContextImport * ieci)1318 gnc_ab_ieci_run_matcher(GncABImExContextImport *ieci)
1319 {
1320     g_return_val_if_fail(ieci, FALSE);
1321 
1322     return gnc_gen_trans_list_run(ieci->generic_importer);
1323 }
1324 
1325 GWEN_DB_NODE *
gnc_ab_get_permanent_certs(void)1326 gnc_ab_get_permanent_certs(void)
1327 {
1328     int rv;
1329     GWEN_DB_NODE *perm_certs = NULL;
1330     AB_BANKING *banking = gnc_AB_BANKING_new();
1331 
1332     g_return_val_if_fail(banking, NULL);
1333     rv = AB_Banking_LoadSharedConfig(banking, "certs", &perm_certs);
1334     gnc_AB_BANKING_fini(banking);
1335     g_return_val_if_fail(rv >= 0, NULL);
1336     return perm_certs;
1337 }
1338 
1339 #if (AQBANKING_VERSION_INT >= 60400)
1340 GList*
gnc_ab_trans_templ_list_new_from_ref_accounts(GNC_AB_ACCOUNT_SPEC * ab_acc)1341 gnc_ab_trans_templ_list_new_from_ref_accounts(GNC_AB_ACCOUNT_SPEC *ab_acc)
1342 {
1343     GList *retval = NULL;
1344     AB_REFERENCE_ACCOUNT *ra;
1345     AB_REFERENCE_ACCOUNT_LIST *ral;
1346     GWEN_BUFFER *accNameForTemplate = GWEN_Buffer_new(0,120,0,0);
1347     gnc_numeric zero = gnc_numeric_zero();
1348 
1349     /* get the target account list */
1350     ral = AB_AccountSpec_GetRefAccountList(ab_acc);
1351     ra = AB_ReferenceAccount_List_First(ral);
1352 
1353     /* fill the template list with the target accounts */
1354     while (ra)
1355     {
1356         GncABTransTempl *new_templ = gnc_ab_trans_templ_new();
1357         const char *iban = AB_ReferenceAccount_GetIban(ra);
1358 	const char *accName = AB_ReferenceAccount_GetAccountName(ra);
1359 	GWEN_Buffer_Reset(accNameForTemplate);
1360 	if (accName)
1361 	{
1362 	    GWEN_Buffer_AppendString(accNameForTemplate, accName);
1363 	    GWEN_Buffer_AppendString(accNameForTemplate, ": ");
1364 	}
1365 	GWEN_Buffer_AppendString(accNameForTemplate, iban);
1366 	gnc_ab_trans_templ_set_name(new_templ, GWEN_Buffer_GetStart(accNameForTemplate));
1367 	gnc_ab_trans_templ_set_recp_name(new_templ, AB_ReferenceAccount_GetOwnerName(ra));
1368 	gnc_ab_trans_templ_set_recp_account(new_templ, AB_ReferenceAccount_GetIban(ra));
1369 	gnc_ab_trans_templ_set_recp_bankcode(new_templ, AB_ReferenceAccount_GetBic(ra));
1370 	gnc_ab_trans_templ_set_amount(new_templ, zero);
1371 	retval = g_list_prepend (retval, new_templ);
1372 	ra = AB_ReferenceAccount_List_Next(ra);
1373     }
1374     retval = g_list_reverse (retval);
1375 
1376     GWEN_Buffer_free(accNameForTemplate);
1377 
1378     return retval;
1379 }
1380 #endif
1381