1 /***************************************************************************
2     begin       : Mon Mar 01 2004
3     copyright   : (C) 2019 by Martin Preuss
4     email       : martin@libchipcard.de
5 
6  ***************************************************************************
7  *          Please see toplevel file COPYING for license details           *
8  ***************************************************************************/
9 
10 #ifdef HAVE_CONFIG_H
11 # include <config.h>
12 #endif
13 
14 
15 #include "r_hkd_htd_l.h"
16 #include "aqebics/client/provider_l.h"
17 #include "aqebics/aqebics_l.h"
18 #include "aqebics/client/account_l.h"
19 
20 #include "aqebics/msg/msg.h"
21 #include "aqebics/msg/keys.h"
22 #include "aqebics/msg/zip.h"
23 #include "aqebics/msg/xml.h"
24 #include "aqebics/client/user_l.h"
25 
26 #include "aqebics/requests/r_download_l.h"
27 
28 #include <gwenhywfar/base64.h>
29 #include <gwenhywfar/gui.h>
30 
31 
32 /* -------------------------------------------------------------------------------------------------------------------------
33  * forward declarations
34  * -------------------------------------------------------------------------------------------------------------------------
35  */
36 
37 static int _xchgHkdRequest(AB_PROVIDER *pro, GWEN_HTTP_SESSION *sess, AB_USER *u, const char *requestName);
38 
39 static void _sampleAccounts(xmlNodePtr node, GWEN_DB_NODE *dbAll);
40 static AB_ACCOUNT_LIST *_readAccounts(AB_PROVIDER *pro, GWEN_DB_NODE *dbAll);
41 static AB_ACCOUNT *_readAccount(AB_PROVIDER *pro, GWEN_DB_NODE *db);
42 static void _removeEmptyAccountsFromList(AB_ACCOUNT_LIST *accList);
43 static void _assignIdsOfStoredAccounts(AB_PROVIDER *pro, AB_ACCOUNT_LIST *accountList);
44 static void _addOrModifyAccounts(AB_PROVIDER *pro, AB_USER *user, AB_ACCOUNT_LIST *accountList);
45 static int _modifyExistingAccount(AB_PROVIDER *pro, AB_USER *user, AB_ACCOUNT *account);
46 static int _addAccount(AB_PROVIDER *pro, AB_USER *user, AB_ACCOUNT *account);
47 
48 
49 
50 /* -------------------------------------------------------------------------------------------------------------------------
51  * code
52  * --------------------------------------------------------------------------------------------------------------------------
53  */
54 
55 
56 
EBC_Provider_XchgHkdRequest(AB_PROVIDER * pro,GWEN_HTTP_SESSION * sess,AB_USER * u)57 int EBC_Provider_XchgHkdRequest(AB_PROVIDER *pro, GWEN_HTTP_SESSION *sess, AB_USER *u)
58 {
59   int rv;
60 
61   rv=_xchgHkdRequest(pro, sess, u, "HKD");
62   if (rv<0) {
63     DBG_INFO(AQEBICS_LOGDOMAIN, "here (%d)", rv);
64     return rv;
65   }
66 
67   return 0;
68 }
69 
70 
71 
EBC_Provider_XchgHtdRequest(AB_PROVIDER * pro,GWEN_HTTP_SESSION * sess,AB_USER * u)72 int EBC_Provider_XchgHtdRequest(AB_PROVIDER *pro, GWEN_HTTP_SESSION *sess, AB_USER *u)
73 {
74   int rv;
75 
76   rv=_xchgHkdRequest(pro, sess, u, "HTD");
77   if (rv<0) {
78     DBG_INFO(AQEBICS_LOGDOMAIN, "here (%d)", rv);
79     return rv;
80   }
81 
82   return 0;
83 }
84 
85 
86 
87 
_xchgHkdRequest(AB_PROVIDER * pro,GWEN_HTTP_SESSION * sess,AB_USER * u,const char * requestName)88 int _xchgHkdRequest(AB_PROVIDER *pro, GWEN_HTTP_SESSION *sess, AB_USER *u, const char *requestName)
89 {
90   int rv;
91   GWEN_BUFFER *buf;
92 
93   buf=GWEN_Buffer_new(0, 1024, 0, 1);
94   rv=EBC_Provider_XchgDownloadRequest(pro, sess, u, requestName, buf, 0, NULL, NULL);
95   if (rv<0 || rv>=300) {
96     DBG_INFO(AQEBICS_LOGDOMAIN, "here (%d)", rv);
97     GWEN_Buffer_free(buf);
98     return rv;
99   }
100   else {
101     xmlDocPtr orderDoc=NULL;
102     xmlNodePtr root_node=NULL;
103     xmlNodePtr node=NULL;
104     GWEN_DB_NODE *dbAll;
105     AB_ACCOUNT_LIST *accountList;
106 
107     /* parse XML document */
108     rv=EB_Xml_DocFromBuffer(GWEN_Buffer_GetStart(buf), GWEN_Buffer_GetUsedBytes(buf), &orderDoc);
109     GWEN_Buffer_free(buf);
110     if (rv<0) {
111       DBG_INFO(AQEBICS_LOGDOMAIN, "here (%d)", rv);
112       return rv;
113     }
114 
115     root_node=xmlDocGetRootElement(orderDoc);
116 
117     node=EB_Xml_GetNode(root_node, "PartnerInfo", GWEN_PATH_FLAGS_NAMEMUSTEXIST);
118     if (node==NULL) {
119       DBG_ERROR(AQEBICS_LOGDOMAIN, "No PartnerInfo found");
120       xmlFreeDoc(orderDoc);
121       return GWEN_ERROR_BAD_DATA;
122     }
123 
124     dbAll=GWEN_DB_Group_new("Response");
125 
126     _sampleAccounts(node, dbAll);
127     accountList=_readAccounts(pro, dbAll);
128     if (accountList) {
129       _removeEmptyAccountsFromList(accountList);
130       _assignIdsOfStoredAccounts(pro, accountList);
131       _addOrModifyAccounts(pro, u, accountList);
132 
133       AB_Account_List_free(accountList);
134     }
135 
136     GWEN_DB_Group_free(dbAll);
137     xmlFreeDoc(orderDoc);
138     return 0;
139   }
140 }
141 
142 
143 
_sampleAccounts(xmlNodePtr node,GWEN_DB_NODE * dbAll)144 void _sampleAccounts(xmlNodePtr node, GWEN_DB_NODE *dbAll)
145 {
146   xmlNodePtr nodeX;
147 
148   /* sample accounts */
149   nodeX=node->children;
150   while (nodeX) {
151     if (nodeX->type==XML_ELEMENT_NODE) {
152       if (nodeX->name && strcmp((const char *)nodeX->name, "AccountInfo")==0) {
153         GWEN_DB_NODE *db;
154         xmlChar *xs;
155         xmlNodePtr nodeXX;
156 
157         DBG_DEBUG(AQEBICS_LOGDOMAIN, "Reading AccountInfo node");
158 
159         db=GWEN_DB_GetGroup(dbAll, GWEN_PATH_FLAGS_CREATE_GROUP, "Account");
160 
161         xs=xmlGetProp(nodeX, BAD_CAST "ID");
162         if (xs) {
163           GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "EbicsId", (const char *)xs);
164           xmlFree(xs);
165         }
166 
167         xs=xmlGetProp(nodeX, BAD_CAST "Currency");
168         if (xs) {
169           GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "Currency", (const char *)xs);
170           xmlFree(xs);
171         }
172 
173         xs=xmlGetProp(nodeX, BAD_CAST "Description");
174         if (xs) {
175           GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "AccountName", (const char *)xs);
176           xmlFree(xs);
177         }
178 
179         nodeXX=nodeX->children;
180         while (nodeXX) {
181           if (nodeXX->type==XML_ELEMENT_NODE &&
182               nodeXX->name) {
183             if (strcmp((const char *)nodeXX->name, "AccountNumber")==0) {
184               xs=xmlGetProp(nodeXX, BAD_CAST "international");
185               if (xs) {
186                 xmlNodePtr nodeXXX=NULL;
187 
188                 if (strcasecmp((const char *)xs, "false")==0) {
189                   nodeXXX=nodeXX->children;
190                   if (nodeXXX->type==XML_TEXT_NODE && nodeXXX->content) {
191                     GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "AccountNumber", (const char *)nodeXXX->content);
192                   }
193                 }
194                 else {
195                   nodeXXX=nodeXX->children;
196                   if (nodeXXX->type==XML_TEXT_NODE && nodeXXX->content) {
197                     GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "IBAN", (const char *)nodeXXX->content);
198                   }
199                 }
200                 xmlFree(xs);
201               }
202             }
203             else if (strcmp((const char *)nodeXX->name, "NationalAccountNumber")==0) {
204               xmlNodePtr nodeXXX=NULL;
205 
206               nodeXXX=nodeXX->children;
207               if (nodeXXX->type==XML_TEXT_NODE && nodeXXX->content) {
208                 GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "AccountNumber", (const char *)nodeXXX->content);
209               }
210             }
211             else if (strcmp((const char *)nodeXX->name, "BankCode")==0) {
212               xs=xmlGetProp(nodeXX, BAD_CAST "international");
213               if (xs) {
214                 xmlNodePtr nodeXXX=NULL;
215 
216                 if (strcasecmp((const char *)xs, "false")==0) {
217                   nodeXXX=nodeXX->children;
218                   if (nodeXXX->type==XML_TEXT_NODE && nodeXXX->content) {
219                     GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "BankCode", (const char *)nodeXXX->content);
220                   }
221                 }
222                 else {
223                   nodeXXX=nodeXX->children;
224                   if (nodeXXX->type==XML_TEXT_NODE && nodeXXX->content) {
225                     GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "BIC", (const char *)nodeXXX->content);
226                   }
227                 }
228                 xmlFree(xs);
229               }
230             }
231             else if (strcmp((const char *)nodeXX->name, "NationalBankCode")==0) {
232               xmlNodePtr nodeXXX=NULL;
233 
234               nodeXXX=nodeXX->children;
235               if (nodeXXX->type==XML_TEXT_NODE && nodeXXX->content) {
236                 GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "BankCode", (const char *)nodeXXX->content);
237               }
238             }
239             else if (strcmp((const char *)nodeXX->name, "AccountHolder")==0) {
240               xmlNodePtr nodeXXX=NULL;
241 
242               nodeXXX=nodeXX->children;
243               if (nodeXXX->type==XML_TEXT_NODE && nodeXXX->content) {
244                 GWEN_DB_SetCharValue(db, GWEN_DB_FLAGS_OVERWRITE_VARS, "owner", (const char *)nodeXXX->content);
245               }
246             }
247           }
248           nodeXX=nodeXX->next;
249         }
250       }
251     }
252     nodeX=nodeX->next;
253   }
254 }
255 
256 
257 
_readAccounts(AB_PROVIDER * pro,GWEN_DB_NODE * dbAll)258 AB_ACCOUNT_LIST *_readAccounts(AB_PROVIDER *pro, GWEN_DB_NODE *dbAll)
259 {
260   AB_ACCOUNT_LIST *accountList;
261   GWEN_DB_NODE *db;
262 
263   accountList=AB_Account_List_new();
264 
265   db=GWEN_DB_FindFirstGroup(dbAll, "Account");
266   while (db) {
267     AB_ACCOUNT *account;
268 
269     account=_readAccount(pro, db);
270     if (account)
271       AB_Account_List_Add(account, accountList);
272 
273     db=GWEN_DB_FindNextGroup(db, "Account");
274   }
275 
276   if (AB_Account_List_GetCount(accountList)==0) {
277     AB_Account_List_free(accountList);
278     return NULL;
279   }
280 
281   return accountList;
282 }
283 
284 
285 
_readAccount(AB_PROVIDER * pro,GWEN_DB_NODE * db)286 AB_ACCOUNT *_readAccount(AB_PROVIDER *pro, GWEN_DB_NODE *db)
287 {
288   AB_ACCOUNT *a;
289   const char *s;
290 
291   a=AB_Provider_CreateAccountObject(pro);
292   assert(a);
293 
294   AB_Account_SetAccountType(a, AB_AccountType_Bank);
295 
296   AB_Account_SetCountry(a, "de");
297 
298   s=GWEN_DB_GetCharValue(db, "ebicsId", 0, NULL);
299   if (s && *s)
300     EBC_Account_SetEbicsId(a, s);
301 
302   s=GWEN_DB_GetCharValue(db, "bankCode", 0, NULL);
303   if (s && *s)
304     AB_Account_SetBankCode(a, s);
305 
306   s=GWEN_DB_GetCharValue(db, "accountNumber", 0, NULL);
307   if (s && *s)
308     AB_Account_SetAccountNumber(a, s);
309 
310   s=GWEN_DB_GetCharValue(db, "owner", 0, NULL);
311   if (s && *s)
312     AB_Account_SetOwnerName(a, s);
313 
314 #if 0
315   s=GWEN_DB_GetCharValue(db, "accountName", 0, NULL);
316   if (s && *s)
317     AB_Account_SetAccountName(a, s);
318 #endif
319 
320   s=GWEN_DB_GetCharValue(db, "currency", 0, NULL);
321   if (s && *s)
322     AB_Account_SetCurrency(a, s);
323   else
324     AB_Account_SetCurrency(a, "EUR");
325 
326   s=GWEN_DB_GetCharValue(db, "IBAN", 0, NULL);
327   if (s && *s)
328     AB_Account_SetIban(a, s);
329 
330   s=GWEN_DB_GetCharValue(db, "BIC", 0, NULL);
331   if (s && *s)
332     AB_Account_SetBic(a, s);
333 
334   return a;
335 }
336 
337 
338 
_removeEmptyAccountsFromList(AB_ACCOUNT_LIST * accList)339 void _removeEmptyAccountsFromList(AB_ACCOUNT_LIST *accList)
340 {
341   /* only keep accounts which have at least IBAN or bankcode and account number */
342   DBG_INFO(AQEBICS_LOGDOMAIN, "Checking for empty accounts");
343   if (AB_Account_List_GetCount(accList)) {
344     AB_ACCOUNT *acc;
345 
346     acc=AB_Account_List_First(accList);
347     while (acc) {
348       AB_ACCOUNT *accNext;
349       const char *accountNum;
350       const char *bankCode;
351       const char *iban;
352 
353       accNext=AB_Account_List_Next(acc);
354       accountNum=AB_Account_GetAccountNumber(acc);
355       bankCode=AB_Account_GetBankCode(acc);
356       iban=AB_Account_GetIban(acc);
357 
358       if (!((iban && *iban) || (accountNum && *accountNum && bankCode && *bankCode))) {
359         DBG_INFO(AQEBICS_LOGDOMAIN, "Removing empty account from import list");
360         AB_Account_List_Del(acc);
361         AB_Account_free(acc);
362       }
363       acc=accNext;
364     } /* while(acc) */
365   } /* if (AB_Account_List_GetCount(accList)) */
366 }
367 
368 
369 
_assignIdsOfStoredAccounts(AB_PROVIDER * pro,AB_ACCOUNT_LIST * accountList)370 void _assignIdsOfStoredAccounts(AB_PROVIDER *pro, AB_ACCOUNT_LIST *accountList)
371 {
372   AB_ACCOUNT_SPEC_LIST *accountSpecList=NULL;
373   int rv;
374 
375   accountSpecList=AB_AccountSpec_List_new();
376   rv=AB_Banking_GetAccountSpecList(AB_Provider_GetBanking(pro), &accountSpecList);
377   if (rv<0) {
378     DBG_INFO(AQEBICS_LOGDOMAIN, "No account spec list");
379   }
380   else {
381     AB_ACCOUNT *account;
382 
383     account=AB_Account_List_First(accountList);
384     while (account) {
385       AB_ACCOUNT_SPEC *accountSpec;
386 
387       accountSpec=AB_Provider_FindMatchingAccountSpec(pro, account, accountSpecList);
388       if (accountSpec) {
389         uint32_t uniqueId;
390 
391         uniqueId=AB_AccountSpec_GetUniqueId(accountSpec);
392         DBG_INFO(AQEBICS_LOGDOMAIN, "Found a matching account (%x)", uniqueId);
393         AB_Account_SetUniqueId(account, uniqueId);
394       }
395 
396       account=AB_Account_List_Next(account);
397     }
398   }
399   AB_AccountSpec_List_free(accountSpecList);
400 }
401 
402 
403 
_addOrModifyAccounts(AB_PROVIDER * pro,AB_USER * user,AB_ACCOUNT_LIST * accountList)404 void _addOrModifyAccounts(AB_PROVIDER *pro, AB_USER *user, AB_ACCOUNT_LIST *accountList)
405 {
406   AB_ACCOUNT *account;
407 
408   account=AB_Account_List_First(accountList);
409   while (account) {
410     uint32_t uniqueId;
411 
412     uniqueId=AB_Account_GetUniqueId(account);
413     if (uniqueId) {
414       int rv;
415 
416       rv=_modifyExistingAccount(pro, user, account);
417       if (rv<0) {
418         DBG_INFO(AQEBICS_LOGDOMAIN, "here (%d)", rv);
419       }
420     }
421     else {
422       int rv;
423 
424       rv=_addAccount(pro, user, account);
425       if (rv<0) {
426         DBG_INFO(AQEBICS_LOGDOMAIN, "here (%d)", rv);
427       }
428     }
429     account=AB_Account_List_Next(account);
430   }
431 }
432 
433 
434 
_modifyExistingAccount(AB_PROVIDER * pro,AB_USER * user,AB_ACCOUNT * account)435 int _modifyExistingAccount(AB_PROVIDER *pro, AB_USER *user, AB_ACCOUNT *account)
436 {
437   int rv;
438   AB_ACCOUNT *storedAccount=NULL;
439   uint32_t uniqueId;
440 
441   uniqueId=AB_Account_GetUniqueId(account);
442 
443   /* account already exists, needs update */
444   DBG_ERROR(AQEBICS_LOGDOMAIN, "Account exists, modifying");
445   rv=AB_Provider_GetAccount(pro, uniqueId, 1, 0, &storedAccount); /* lock, don't unlock */
446   if (rv<0) {
447     DBG_ERROR(AQEBICS_LOGDOMAIN, "Error getting referenced account (%d)", rv);
448     return rv;
449   }
450   else {
451     const char *s;
452 
453     /* account is locked now, apply changes */
454     assert(storedAccount);
455 
456     s=EBC_Account_GetEbicsId(account);
457     if (s && *s)
458       EBC_Account_SetEbicsId(storedAccount, s);
459 
460     s=AB_Account_GetCountry(account);
461     if (s && *s)
462       AB_Account_SetCountry(storedAccount, s);
463 
464     s=AB_Account_GetBankCode(account);
465     if (s && *s)
466       AB_Account_SetBankCode(storedAccount, s);
467 
468     s=AB_Account_GetBankName(account);
469     if (s && *s)
470       AB_Account_SetBankName(storedAccount, s);
471 
472     s=AB_Account_GetAccountNumber(account);
473     if (s && *s)
474       AB_Account_SetAccountNumber(storedAccount, s);
475 
476     s=AB_Account_GetSubAccountId(account);
477     if (s && *s)
478       AB_Account_SetSubAccountId(storedAccount, s);
479 
480     s=AB_Account_GetIban(account);
481     if (s && *s)
482       AB_Account_SetIban(storedAccount, s);
483 
484     s=AB_Account_GetBic(account);
485     if (s && *s)
486       AB_Account_SetBic(storedAccount, s);
487 
488     s=AB_Account_GetOwnerName(account);
489     if (s && *s)
490       AB_Account_SetOwnerName(storedAccount, s);
491 
492     s=AB_Account_GetCurrency(account);
493     if (s && *s)
494       AB_Account_SetCurrency(storedAccount, s);
495 
496     AB_Account_SetAccountType(storedAccount, AB_Account_GetAccountType(account));
497 
498     /* add flags from new account */
499     EBC_Account_AddFlags(storedAccount, EBC_Account_GetFlags(account));
500 
501     /* handle users */
502     AB_Account_SetUserId(storedAccount, AB_User_GetUniqueId(user));
503 
504     /* unlock account */
505     rv=AB_Provider_EndExclUseAccount(pro, storedAccount, 0);
506     if (rv<0) {
507       DBG_INFO(AQEBICS_LOGDOMAIN, "here (%d)", rv);
508       AB_Provider_EndExclUseAccount(pro, storedAccount, 1); /* abort */
509       return rv;
510     }
511 
512     return 0;
513   }
514 }
515 
516 
517 
_addAccount(AB_PROVIDER * pro,AB_USER * user,AB_ACCOUNT * account)518 int _addAccount(AB_PROVIDER *pro, AB_USER *user, AB_ACCOUNT *account)
519 {
520   int rv;
521 
522   /* account is new, add it */
523   DBG_ERROR(AQEBICS_LOGDOMAIN, "Account is new, adding");
524   AB_Account_SetUserId(account, AB_User_GetUniqueId(user));
525   rv=AB_Provider_AddAccount(pro, account, 0); /* do not lock corresponding user, it might already be locked */
526   if (rv<0) {
527     DBG_ERROR(AQEBICS_LOGDOMAIN, "Coud not add new account (%d)", rv);
528     return rv;
529   }
530 
531   return 0;
532 }
533 
534 
535 
536 
537