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