1 /***************************************************************************
2 begin : Mon Mar 01 2004
3 copyright : (C) 2020 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 "job_commit_bpd.h"
16 #include "aqhbci/banking/user_l.h"
17
18 #include "aqbanking/i18n_l.h"
19
20 #include <gwenhywfar/db.h>
21 #include <gwenhywfar/debug.h>
22
23
24
25
26 /* ------------------------------------------------------------------------------------------------
27 * forward declarations
28 * ------------------------------------------------------------------------------------------------
29 */
30
31 static int _getJobGroup(GWEN_DB_NODE *dbJob, const char *groupName, GWEN_DB_NODE **pResult);
32 static void _readLanguages(GWEN_DB_NODE *dbRd, AH_BPD *bpd);
33 static void _readVersions(GWEN_DB_NODE *dbRd, AH_BPD *bpd);
34 static void _readCommParams(GWEN_DB_NODE *dbJob, AH_BPD *bpd);
35 static void _readPinTanBpd(GWEN_DB_NODE *dbJob, AH_BPD *bpd, int protocolVersion);
36 static void _readBpdJobs(GWEN_DB_NODE *dbJob, AH_BPD *bpd, GWEN_MSGENGINE *msgEngine);
37 static int _isBpdJobSegment(GWEN_MSGENGINE *msgEngine, const char *segmentName, int segmentVersion);
38 static void _dumpBpdAddr(const AH_BPD_ADDR *ba);
39
40
41
42 /* ------------------------------------------------------------------------------------------------
43 * implementations
44 * ------------------------------------------------------------------------------------------------
45 */
46
47
48
AH_Job_Commit_Bpd(AH_JOB * j)49 int AH_Job_Commit_Bpd(AH_JOB *j)
50 {
51 GWEN_DB_NODE *dbJob ;
52 GWEN_DB_NODE *dbRd=NULL;
53 AH_BPD *bpd;
54 const char *p;
55 int rv;
56 AB_USER *user;
57 GWEN_MSGENGINE *msgEngine;
58
59 user=AH_Job_GetUser(j);
60 msgEngine=AH_User_GetMsgEngine(user);
61 assert(msgEngine);
62
63 //dbJob=GWEN_DB_GetFirstGroup(j->jobResponses);
64 dbJob=AH_Job_GetResponses(j);
65
66 rv=_getJobGroup(dbJob, "bpd", &dbRd);
67 if (rv<0) {
68 if (rv!=GWEN_ERROR_NOT_FOUND) {
69 DBG_INFO(AQHBCI_LOGDOMAIN, "here (%d)", rv);
70 return rv;
71 }
72 DBG_INFO(AQHBCI_LOGDOMAIN, "No BPD in response for job %s", AH_Job_GetName(j));
73 /*GWEN_DB_Dump(j->jobResponses, 2);*/
74 return 0;
75 }
76
77 DBG_NOTICE(AQHBCI_LOGDOMAIN, "Found BPD, replacing existing");
78
79 /* create new BPD */
80 bpd=AH_Bpd_new();
81
82 /* read version */
83 AH_Bpd_SetBpdVersion(bpd, GWEN_DB_GetIntValue(dbRd, "version", 0, 0));
84
85 /* read bank name */
86 p=GWEN_DB_GetCharValue(dbRd, "name", 0, 0);
87 if (p)
88 AH_Bpd_SetBankName(bpd, p);
89
90 /* read message and job limits */
91 AH_Bpd_SetJobTypesPerMsg(bpd, GWEN_DB_GetIntValue(dbRd, "jobtypespermsg", 0, 0));
92 AH_Bpd_SetMaxMsgSize(bpd, GWEN_DB_GetIntValue(dbRd, "maxmsgsize", 0, 0));
93
94 _readLanguages(dbRd, bpd);
95 _readVersions(dbRd, bpd);
96 _readCommParams(dbJob, bpd);
97 _readPinTanBpd(dbJob, bpd, GWEN_MsgEngine_GetProtocolVersion(msgEngine));
98 _readBpdJobs(dbJob, bpd, msgEngine);
99
100 /* set BPD */
101 AH_User_SetBpd(user, bpd);
102 return 0;
103 }
104
105
106
_getJobGroup(GWEN_DB_NODE * dbJob,const char * groupName,GWEN_DB_NODE ** pResult)107 int _getJobGroup(GWEN_DB_NODE *dbJob, const char *groupName, GWEN_DB_NODE **pResult)
108 {
109 GWEN_DB_NODE *dbRd;
110
111 dbRd=GWEN_DB_GetGroup(dbJob, GWEN_PATH_FLAGS_NAMEMUSTEXIST, groupName);
112 if (dbRd==NULL) {
113 DBG_DEBUG(AQHBCI_LOGDOMAIN, "Group \"%s\" not found in response", groupName);
114 return GWEN_ERROR_NOT_FOUND;
115 }
116
117 dbRd=GWEN_DB_GetGroup(dbRd, GWEN_PATH_FLAGS_NAMEMUSTEXIST, "data");
118 if (dbRd==NULL) {
119 DBG_ERROR(AQHBCI_LOGDOMAIN, "Missing \"data\" group inside group \"%s\"", groupName);
120 return GWEN_ERROR_INVALID;
121 }
122
123 dbRd=GWEN_DB_GetGroup(dbRd, GWEN_PATH_FLAGS_NAMEMUSTEXIST, groupName);
124 if (dbRd==NULL) {
125 DBG_ERROR(AQHBCI_LOGDOMAIN, "Missing effective group \"%s\" inside response", groupName);
126 return GWEN_ERROR_INVALID;
127 }
128
129 *pResult=dbRd;
130 return 0;
131 }
132
133
134
_readLanguages(GWEN_DB_NODE * dbRd,AH_BPD * bpd)135 void _readLanguages(GWEN_DB_NODE *dbRd, AH_BPD *bpd)
136 {
137 GWEN_DB_NODE *n;
138
139 /* read languages */
140 n=GWEN_DB_GetGroup(dbRd, GWEN_PATH_FLAGS_NAMEMUSTEXIST, "languages");
141 if (n) {
142 int i;
143
144 for (i=0;; i++) {
145 int k;
146
147 k=GWEN_DB_GetIntValue(n, "language", i, 0);
148 if (k) {
149 if (AH_Bpd_AddLanguage(bpd, k)) {
150 DBG_ERROR(AQHBCI_LOGDOMAIN, "Too many languages (%d)", i);
151 break;
152 }
153 }
154 else
155 break;
156 } /* for */
157 } /* if languages */
158
159 }
160
161
162
_readVersions(GWEN_DB_NODE * dbRd,AH_BPD * bpd)163 void _readVersions(GWEN_DB_NODE *dbRd, AH_BPD *bpd)
164 {
165 GWEN_DB_NODE *n;
166
167 /* read supported version */
168 n=GWEN_DB_GetGroup(dbRd, GWEN_PATH_FLAGS_NAMEMUSTEXIST, "versions");
169 if (n) {
170 int i;
171
172 for (i=0;; i++) {
173 int k;
174
175 k=GWEN_DB_GetIntValue(n, "version", i, 0);
176 if (k) {
177 if (AH_Bpd_AddHbciVersion(bpd, k)) {
178 DBG_ERROR(AQHBCI_LOGDOMAIN, "Too many versions (%d)", i);
179 break;
180 }
181 }
182 else
183 break;
184 } /* for */
185 } /* if versions */
186 }
187
188
189
_readCommParams(GWEN_DB_NODE * dbJob,AH_BPD * bpd)190 void _readCommParams(GWEN_DB_NODE *dbJob, AH_BPD *bpd)
191 {
192 int rv;
193 GWEN_DB_NODE *dbRd=NULL;
194
195 /* communication parameters */
196 rv=_getJobGroup(dbJob, "ComData", &dbRd);
197 if (rv==0) {
198 GWEN_DB_NODE *currService;
199
200 DBG_DEBUG(AQHBCI_LOGDOMAIN, "Found communication infos");
201
202 currService=GWEN_DB_FindFirstGroup(dbRd, "service");
203 while (currService) {
204 AH_BPD_ADDR *ba;
205
206 ba=AH_BpdAddr_FromDb(currService);
207 if (ba) {
208 _dumpBpdAddr(ba); /* debug */
209 AH_Bpd_AddAddr(bpd, ba);
210 }
211 currService=GWEN_DB_FindNextGroup(currService, "service");
212 }
213 } /* if ComData found */
214 }
215
216
217
_readPinTanBpd(GWEN_DB_NODE * dbJob,AH_BPD * bpd,int protocolVersion)218 void _readPinTanBpd(GWEN_DB_NODE *dbJob, AH_BPD *bpd, int protocolVersion)
219 {
220 int rv;
221 GWEN_DB_NODE *dbRd=NULL;
222
223 /* special extension of BPD for PIN/TAN mode */
224 rv=_getJobGroup(dbJob, "PinTanBPD", &dbRd);
225 if (rv==0) {
226 GWEN_DB_NODE *bn;
227 GWEN_DB_NODE *currJob;
228
229 bn=AH_Bpd_GetBpdJobs(bpd, protocolVersion);
230 assert(bn);
231
232 currJob=GWEN_DB_FindFirstGroup(dbRd, "job");
233 while (currJob) {
234 const char *jobName;
235 int needTAN;
236 GWEN_DB_NODE *dbJob;
237
238 jobName=GWEN_DB_GetCharValue(currJob, "job", 0, 0);
239 assert(jobName);
240 dbJob=GWEN_DB_GetGroup(bn, GWEN_DB_FLAGS_DEFAULT, jobName);
241 assert(dbJob);
242 needTAN=strcasecmp(GWEN_DB_GetCharValue(currJob, "needTan", 0, "N"), "J")==0;
243 GWEN_DB_SetIntValue(dbJob, GWEN_DB_FLAGS_OVERWRITE_VARS, "needTan", needTAN);
244 currJob=GWEN_DB_FindNextGroup(currJob, "job");
245 } /* while */
246 } /* if PIN/TAN extension found */
247 }
248
249
250
_readBpdJobs(GWEN_DB_NODE * dbJob,AH_BPD * bpd,GWEN_MSGENGINE * msgEngine)251 void _readBpdJobs(GWEN_DB_NODE *dbJob, AH_BPD *bpd, GWEN_MSGENGINE *msgEngine)
252 {
253 GWEN_DB_NODE *n;
254
255 /* check for BPD jobs */
256 n=GWEN_DB_GetFirstGroup(dbJob);
257 while (n) {
258 GWEN_DB_NODE *dbRd;
259
260 dbRd=GWEN_DB_GetGroup(n, GWEN_PATH_FLAGS_NAMEMUSTEXIST, "data");
261 if (dbRd)
262 dbRd=GWEN_DB_GetFirstGroup(dbRd);
263 if (dbRd) {
264 const char *segmentName;
265 int segmentVersion;
266
267 /* check for BPD job */
268 segmentName=GWEN_DB_GroupName(dbRd);
269 segmentVersion=GWEN_DB_GetIntValue(dbRd, "head/version", 0, 0);
270 if (_isBpdJobSegment(msgEngine, segmentName, segmentVersion)) {
271 GWEN_DB_NODE *dbBpdJobs;
272 GWEN_DB_NODE *dbNewBpdJob;
273 char numbuffer[32];
274
275 DBG_NOTICE(AQHBCI_LOGDOMAIN, "Found BPD job \"%s\"", segmentName);
276 dbBpdJobs=AH_Bpd_GetBpdJobs(bpd, GWEN_MsgEngine_GetProtocolVersion(msgEngine));
277 assert(dbBpdJobs);
278 dbNewBpdJob=GWEN_DB_GetGroup(dbBpdJobs, GWEN_DB_FLAGS_DEFAULT, segmentName);
279 assert(dbNewBpdJob);
280
281 if (GWEN_Text_NumToString(segmentVersion, numbuffer, sizeof(numbuffer)-1, 0)<1) {
282 DBG_NOTICE(AQHBCI_LOGDOMAIN, "Buffer too small");
283 abort();
284 }
285 dbNewBpdJob=GWEN_DB_GetGroup(dbNewBpdJob, GWEN_DB_FLAGS_OVERWRITE_GROUPS, numbuffer);
286 assert(dbNewBpdJob);
287
288 GWEN_DB_AddGroupChildren(dbNewBpdJob, dbRd);
289 /* remove "head" and "segment" group */
290 GWEN_DB_DeleteGroup(dbNewBpdJob, "head");
291 GWEN_DB_DeleteGroup(dbNewBpdJob, "segment");
292 DBG_DEBUG(AQHBCI_LOGDOMAIN, "Added BPD Job %s:%d", segmentName, segmentVersion);
293 }
294 }
295 n=GWEN_DB_GetNextGroup(n);
296 } /* while */
297 }
298
299
300
_isBpdJobSegment(GWEN_MSGENGINE * msgEngine,const char * segmentName,int segmentVersion)301 int _isBpdJobSegment(GWEN_MSGENGINE *msgEngine, const char *segmentName, int segmentVersion)
302 {
303 GWEN_XMLNODE *xmlDescrForSegNameAndVer;
304
305 DBG_DEBUG(AQHBCI_LOGDOMAIN, "Checking whether \"%s\" version %d is a BPD job", segmentName, segmentVersion);
306 /* get segment description (first try id, then code) */
307 xmlDescrForSegNameAndVer=GWEN_MsgEngine_FindNodeByProperty(msgEngine, "SEG", "id", segmentVersion, segmentName);
308 if (xmlDescrForSegNameAndVer==NULL)
309 xmlDescrForSegNameAndVer=GWEN_MsgEngine_FindNodeByProperty(msgEngine, "SEG", "code", segmentVersion, segmentName);
310 if (xmlDescrForSegNameAndVer) {
311 DBG_DEBUG(AQHBCI_LOGDOMAIN, "Found a candidate");
312 if (atoi(GWEN_XMLNode_GetProperty(xmlDescrForSegNameAndVer, "isbpdjob", "0"))) {
313 DBG_DEBUG(AQHBCI_LOGDOMAIN, "Segment \"%s\" is a BPD job", segmentName);
314 return 1;
315 }
316 else {
317 DBG_DEBUG(AQHBCI_LOGDOMAIN, "Segment \"%s\" is known but not as a BPD job", segmentName);
318 }
319 }
320 else {
321 DBG_WARN(AQHBCI_LOGDOMAIN, "Did not find segment \"%s\" (%d)", segmentName, segmentVersion);
322 }
323 return 0;
324 }
325
326
327
_dumpBpdAddr(const AH_BPD_ADDR * ba)328 void _dumpBpdAddr(const AH_BPD_ADDR *ba)
329 {
330 GWEN_BUFFER *tbuf;
331 const char *s;
332
333 tbuf=GWEN_Buffer_new(0, 256, 0, 1);
334
335 switch (AH_BpdAddr_GetType(ba)) {
336 case AH_BPD_AddrTypeTCP:
337 GWEN_Buffer_AppendString(tbuf, "TCP: ");
338 break;
339 case AH_BPD_AddrTypeBTX:
340 GWEN_Buffer_AppendString(tbuf, "BTX: ");
341 break;
342 case AH_BPD_AddrTypeSSL:
343 GWEN_Buffer_AppendString(tbuf, "SSL: ");
344 break;
345 default:
346 GWEN_Buffer_AppendString(tbuf, "<UNK>: ");
347 break;
348 }
349
350 s=AH_BpdAddr_GetAddr(ba);
351 if (s && *s)
352 GWEN_Buffer_AppendString(tbuf, s);
353 else
354 GWEN_Buffer_AppendString(tbuf, "<empty>");
355
356 s=AH_BpdAddr_GetSuffix(ba);
357 if (s && *s) {
358 GWEN_Buffer_AppendString(tbuf, ", ");
359 GWEN_Buffer_AppendString(tbuf, s);
360 }
361
362 GWEN_Buffer_AppendString(tbuf, ", ");
363 switch (AH_BpdAddr_GetFType(ba)) {
364 case AH_BPD_FilterTypeNone:
365 GWEN_Buffer_AppendString(tbuf, "none");
366 break;
367 case AH_BPD_FilterTypeBase64:
368 GWEN_Buffer_AppendString(tbuf, "base64");
369 break;
370 case AH_BPD_FilterTypeUUE:
371 GWEN_Buffer_AppendString(tbuf, "uue");
372 break;
373 default:
374 GWEN_Buffer_AppendString(tbuf, "<unk>");
375 break;
376 }
377
378 DBG_DEBUG(AQHBCI_LOGDOMAIN, "Server address found: %s", GWEN_Buffer_GetStart(tbuf));
379 GWEN_Gui_ProgressLog2(0,
380 GWEN_LoggerLevel_Info,
381 I18N("Server address found: %s"),
382 GWEN_Buffer_GetStart(tbuf));
383 GWEN_Buffer_free(tbuf);
384 }
385
386
387