1 /***************************************************************************
2 begin : Mon Mar 01 2004
3 copyright : (C) 2018 by Martin Preuss
4 email : martin@libchipcard.de
5
6 ***************************************************************************
7 * This file is part of the project "AqBanking". *
8 * Please see toplevel file COPYING of that project for license details. *
9 ***************************************************************************/
10
11 #ifdef HAVE_CONFIG_H
12 # include <config.h>
13 #endif
14
15 #include "imexporter_p.h"
16
17 #include <gwenhywfar/debug.h>
18 #include <gwenhywfar/misc.h>
19 #include <gwenhywfar/inherit.h>
20 #include <gwenhywfar/syncio_file.h>
21 #include <gwenhywfar/syncio_memory.h>
22
23 #include <assert.h>
24 #include <ctype.h>
25
26
27 GWEN_INHERIT_FUNCTIONS(AB_IMEXPORTER)
GWEN_LIST_FUNCTIONS(AB_IMEXPORTER,AB_ImExporter)28 GWEN_LIST_FUNCTIONS(AB_IMEXPORTER, AB_ImExporter)
29
30 GWEN_INHERIT(GWEN_PLUGIN, AB_PLUGIN_IMEXPORTER)
31
32
33
34
35 AB_IMEXPORTER *AB_ImExporter_new(AB_BANKING *ab, const char *name)
36 {
37 AB_IMEXPORTER *ie;
38
39 assert(ab);
40 assert(name);
41 GWEN_NEW_OBJECT(AB_IMEXPORTER, ie);
42 GWEN_LIST_INIT(AB_IMEXPORTER, ie);
43 GWEN_INHERIT_INIT(AB_IMEXPORTER, ie);
44
45 ie->banking=ab;
46 ie->name=strdup(name);
47
48 return ie;
49 }
50
51
AB_ImExporter_free(AB_IMEXPORTER * ie)52 void AB_ImExporter_free(AB_IMEXPORTER *ie)
53 {
54 if (ie) {
55 DBG_INFO(AQBANKING_LOGDOMAIN, "Destroying AB_IMEXPORTER");
56 GWEN_INHERIT_FINI(AB_IMEXPORTER, ie);
57 if (ie->libLoader) {
58 GWEN_LibLoader_CloseLibrary(ie->libLoader);
59 GWEN_LibLoader_free(ie->libLoader);
60 }
61 free(ie->name);
62 GWEN_LIST_FINI(AB_IMEXPORTER, ie);
63 GWEN_FREE_OBJECT(ie);
64 }
65 }
66
67
68
AB_ImExporter_GetFlags(const AB_IMEXPORTER * ie)69 uint32_t AB_ImExporter_GetFlags(const AB_IMEXPORTER *ie)
70 {
71 assert(ie);
72 return ie->flags;
73 }
74
75
76
AB_ImExporter_SetFlags(AB_IMEXPORTER * ie,uint32_t flags)77 void AB_ImExporter_SetFlags(AB_IMEXPORTER *ie, uint32_t flags)
78 {
79 assert(ie);
80 ie->flags=flags;
81 }
82
83
84
AB_ImExporter_AddFlags(AB_IMEXPORTER * ie,uint32_t flags)85 void AB_ImExporter_AddFlags(AB_IMEXPORTER *ie, uint32_t flags)
86 {
87 assert(ie);
88 ie->flags|=flags;
89 }
90
91
92
AB_ImExporter_SubFlags(AB_IMEXPORTER * ie,uint32_t flags)93 void AB_ImExporter_SubFlags(AB_IMEXPORTER *ie, uint32_t flags)
94 {
95 assert(ie);
96 ie->flags&=~flags;
97 }
98
99
100
AB_ImExporter_Import(AB_IMEXPORTER * ie,AB_IMEXPORTER_CONTEXT * ctx,GWEN_SYNCIO * sio,GWEN_DB_NODE * params)101 int AB_ImExporter_Import(AB_IMEXPORTER *ie,
102 AB_IMEXPORTER_CONTEXT *ctx,
103 GWEN_SYNCIO *sio,
104 GWEN_DB_NODE *params)
105 {
106 assert(ie);
107 assert(ctx);
108 assert(sio);
109 assert(params);
110
111 if (ie->importFn) {
112 if (GWEN_SyncIo_GetStatus(sio)!=GWEN_SyncIo_Status_Connected) {
113 DBG_ERROR(AQBANKING_LOGDOMAIN, "GWEN_SYNCIO %s not connected (%d); did you forget to call GWEN_SyncIo_Connect()?",
114 GWEN_SyncIo_GetTypeName(sio),
115 GWEN_SyncIo_GetStatus(sio));
116 return GWEN_ERROR_NOT_OPEN;
117 }
118
119 return ie->importFn(ie, ctx, sio, params);
120 }
121 else
122 return GWEN_ERROR_NOT_SUPPORTED;
123 }
124
125
126
AB_ImExporter_Export(AB_IMEXPORTER * ie,AB_IMEXPORTER_CONTEXT * ctx,GWEN_SYNCIO * sio,GWEN_DB_NODE * params)127 int AB_ImExporter_Export(AB_IMEXPORTER *ie,
128 AB_IMEXPORTER_CONTEXT *ctx,
129 GWEN_SYNCIO *sio,
130 GWEN_DB_NODE *params)
131 {
132 assert(ie);
133 assert(ctx);
134 assert(sio);
135 assert(params);
136
137 if (ie->exportFn)
138 return ie->exportFn(ie, ctx, sio, params);
139 else
140 return GWEN_ERROR_NOT_SUPPORTED;
141 }
142
143
144
AB_ImExporter_CheckFile(AB_IMEXPORTER * ie,const char * fname)145 int AB_ImExporter_CheckFile(AB_IMEXPORTER *ie,
146 const char *fname)
147 {
148 assert(ie);
149 assert(fname);
150
151 if (ie->checkFileFn)
152 return ie->checkFileFn(ie, fname);
153 else
154 return GWEN_ERROR_NOT_SUPPORTED;
155 }
156
157
158
AB_ImExporter_GetEditProfileDialog(AB_IMEXPORTER * ie,GWEN_DB_NODE * dbProfile,const char * testFileName,GWEN_DIALOG ** pDlg)159 int AB_ImExporter_GetEditProfileDialog(AB_IMEXPORTER *ie,
160 GWEN_DB_NODE *dbProfile,
161 const char *testFileName,
162 GWEN_DIALOG **pDlg)
163 {
164 assert(ie);
165 assert(dbProfile);
166
167 if (ie->getEditProfileDialogFn)
168 return ie->getEditProfileDialogFn(ie, dbProfile, testFileName, pDlg);
169 else
170 return GWEN_ERROR_NOT_SUPPORTED;
171 }
172
173
174
AB_ImExporter_SetImportFn(AB_IMEXPORTER * ie,AB_IMEXPORTER_IMPORT_FN f)175 void AB_ImExporter_SetImportFn(AB_IMEXPORTER *ie,
176 AB_IMEXPORTER_IMPORT_FN f)
177 {
178 assert(ie);
179 ie->importFn=f;
180 }
181
182
183
AB_ImExporter_SetExportFn(AB_IMEXPORTER * ie,AB_IMEXPORTER_EXPORT_FN f)184 void AB_ImExporter_SetExportFn(AB_IMEXPORTER *ie,
185 AB_IMEXPORTER_EXPORT_FN f)
186 {
187 assert(ie);
188 ie->exportFn=f;
189 }
190
191
192
AB_ImExporter_SetCheckFileFn(AB_IMEXPORTER * ie,AB_IMEXPORTER_CHECKFILE_FN f)193 void AB_ImExporter_SetCheckFileFn(AB_IMEXPORTER *ie,
194 AB_IMEXPORTER_CHECKFILE_FN f)
195 {
196 assert(ie);
197 ie->checkFileFn=f;
198 }
199
200
201
AB_ImExporter_SetGetEditProfileDialogFn(AB_IMEXPORTER * ie,AB_IMEXPORTER_GET_EDITPROFILE_DIALOG_FN f)202 void AB_ImExporter_SetGetEditProfileDialogFn(AB_IMEXPORTER *ie,
203 AB_IMEXPORTER_GET_EDITPROFILE_DIALOG_FN f)
204 {
205 assert(ie);
206 ie->getEditProfileDialogFn=f;
207 }
208
209
210
AB_ImExporter_GetBanking(const AB_IMEXPORTER * ie)211 AB_BANKING *AB_ImExporter_GetBanking(const AB_IMEXPORTER *ie)
212 {
213 assert(ie);
214 return ie->banking;
215 }
216
217
218
AB_ImExporter_GetName(const AB_IMEXPORTER * ie)219 const char *AB_ImExporter_GetName(const AB_IMEXPORTER *ie)
220 {
221 assert(ie);
222 return ie->name;
223 }
224
225
226
AB_ImExporter_SetLibLoader(AB_IMEXPORTER * ie,GWEN_LIBLOADER * ll)227 void AB_ImExporter_SetLibLoader(AB_IMEXPORTER *ie, GWEN_LIBLOADER *ll)
228 {
229 assert(ie);
230 ie->libLoader=ll;
231 }
232
233
234
235
236
237
238
239
240
241
AB_ImExporter_Utf8ToDta(const char * p,int size,GWEN_BUFFER * buf)242 void AB_ImExporter_Utf8ToDta(const char *p,
243 int size,
244 GWEN_BUFFER *buf)
245 {
246 while (*p) {
247 unsigned int c;
248
249 if (!size)
250 break;
251
252 c=(unsigned char)(*(p++));
253 if (size!=-1)
254 size--;
255 switch (c & 0xc0) {
256 case 0xc0:
257 if (!size) {
258 DBG_ERROR(AQBANKING_LOGDOMAIN, "Incomplete UTF-8 sequence");
259 c=' ';
260 break;
261 }
262 c=(unsigned char)(*(p++));
263 if (size!=-1)
264 size--;
265 if ((c & 0xc0) != 0x80) {
266 DBG_ERROR(AQBANKING_LOGDOMAIN, "Invalid UTF-8 sequence");
267 c=' ';
268 break;
269 }
270 if (size && (*p & 0xc0) == 0x80)
271 /* a sequence of 3 bytes and more cannot be translated to DTA */
272 goto nextUtf8;
273 switch (c) {
274 case 0x84:
275 case 0xa4:
276 c=0x5b;
277 break;
278 case 0x96:
279 case 0xb6:
280 c=0x5c;
281 break;
282 case 0x9c:
283 case 0xbc:
284 c=0x5d;
285 break;
286 case 0x9f:
287 c=0x7e;
288 break;
289 default:
290 c=' ';
291 break;
292 } /* switch */
293 break;
294
295 case 0x80:
296 DBG_ERROR(AQBANKING_LOGDOMAIN, "Invalid UTF-8 sequence");
297 nextUtf8:
298 c=' ';
299 while (size && (*p & 0xc0) == 0x80) {
300 p++;
301 if (size!=-1)
302 size--;
303 }
304 break;
305
306 default:
307 c=toupper(c);
308 if (!(isdigit(c) ||
309 (c>='A' && c<='Z') ||
310 (strchr(" .,&-+*%/$", c))))
311 c=' ';
312 } /* switch */
313 GWEN_Buffer_AppendByte(buf, c);
314 } /* while */
315 }
316
317
318
AB_ImExporter_DtaToUtf8(const char * p,int size,GWEN_BUFFER * buf)319 void AB_ImExporter_DtaToUtf8(const char *p,
320 int size,
321 GWEN_BUFFER *buf)
322 {
323 while (*p) {
324 unsigned int c;
325
326 if (!size)
327 break;
328
329 c=(unsigned char)(*(p++));
330 switch (c) {
331 case 0x5b: /* AE */
332 GWEN_Buffer_AppendByte(buf, 0xc3);
333 GWEN_Buffer_AppendByte(buf, 0x84);
334 break;
335
336 case 0x5c: /* OE */
337 GWEN_Buffer_AppendByte(buf, 0xc3);
338 GWEN_Buffer_AppendByte(buf, 0x96);
339 break;
340
341 case 0x5d: /* UE */
342 GWEN_Buffer_AppendByte(buf, 0xc3);
343 GWEN_Buffer_AppendByte(buf, 0x9c);
344 break;
345
346 case 0x7e: /* sharp s */
347 GWEN_Buffer_AppendByte(buf, 0xc3);
348 GWEN_Buffer_AppendByte(buf, 0x9f);
349 break;
350
351 default:
352 if (c & 0x80) {
353 /* produce sane UTF-8 even if something went wrong */
354 DBG_ERROR(AQBANKING_LOGDOMAIN, "Invalid character in DTA string");
355 c=' ';
356 }
357 GWEN_Buffer_AppendByte(buf, c);
358 }
359 if (size!=-1)
360 size--;
361 } /* while */
362 }
363
364
365
AB_ImExporter_DateFromString(const char * p,const char * tmpl,int inUtc)366 GWEN_TIME *AB_ImExporter_DateFromString(const char *p, const char *tmpl,
367 int inUtc)
368 {
369 GWEN_TIME *ti;
370
371 if (strchr(tmpl, 'h')==0) {
372 GWEN_BUFFER *dbuf;
373 GWEN_BUFFER *tbuf;
374
375 dbuf=GWEN_Buffer_new(0, 32, 0, 1);
376 GWEN_Buffer_AppendString(dbuf, p);
377 GWEN_Buffer_AppendString(dbuf, "-12:00");
378
379 tbuf=GWEN_Buffer_new(0, 32, 0, 1);
380 GWEN_Buffer_AppendString(tbuf, tmpl);
381 GWEN_Buffer_AppendString(tbuf, "-hh:mm");
382
383 ti=GWEN_Time_fromUtcString(GWEN_Buffer_GetStart(dbuf),
384 GWEN_Buffer_GetStart(tbuf));
385 GWEN_Buffer_free(tbuf);
386 GWEN_Buffer_free(dbuf);
387 }
388 else {
389 if (inUtc)
390 ti=GWEN_Time_fromUtcString(p, tmpl);
391 else
392 ti=GWEN_Time_fromString(p, tmpl);
393 }
394 return ti;
395 }
396
397
AB_ImExporter_Iso8859_1ToUtf8(const char * p,int size,GWEN_BUFFER * buf)398 void AB_ImExporter_Iso8859_1ToUtf8(const char *p,
399 int size,
400 GWEN_BUFFER *buf)
401 {
402 while (*p) {
403 unsigned int c;
404
405 if (!size)
406 break;
407
408 c=(unsigned char)(*(p++));
409 if (c<32 || c==127)
410 c=32;
411 if (c & 0x80) {
412 GWEN_Buffer_AppendByte(buf, 0xc0 | c>>6);
413 c &= ~0x40;
414 }
415 GWEN_Buffer_AppendByte(buf, c);
416 if (size!=-1)
417 size--;
418 } /* while */
419 }
420
421
422
AB_ImExporter__Transform_Var(GWEN_DB_NODE * db,int level)423 int AB_ImExporter__Transform_Var(GWEN_DB_NODE *db, int level)
424 {
425 GWEN_DB_NODE *dbC;
426
427 dbC=GWEN_DB_GetFirstValue(db);
428 while (dbC) {
429 if (GWEN_DB_GetValueType(dbC)==GWEN_DB_NodeType_ValueChar) {
430 const char *s;
431 unsigned int l;
432
433 s=GWEN_DB_GetCharValueFromNode(dbC);
434 assert(s);
435 l=strlen(s);
436 if (l) {
437 GWEN_BUFFER *vbuf;
438
439 vbuf=GWEN_Buffer_new(0, 1+(l*15/10), 0, 1);
440 AB_ImExporter_Iso8859_1ToUtf8(s, l, vbuf);
441 GWEN_DB_SetCharValueInNode(dbC, GWEN_Buffer_GetStart(vbuf));
442 GWEN_Buffer_free(vbuf);
443 }
444 }
445 dbC=GWEN_DB_GetNextValue(dbC);
446 }
447
448 return 0;
449 }
450
451
452
AB_ImExporter__Transform_Group(GWEN_DB_NODE * db,int level)453 int AB_ImExporter__Transform_Group(GWEN_DB_NODE *db, int level)
454 {
455 GWEN_DB_NODE *dbC;
456 int rv;
457
458 if (level>AH_IMEXPORTER_TRANSFORM_MAXLEVEL) {
459 DBG_ERROR(AQBANKING_LOGDOMAIN, "DB too deep (%d)", level);
460 return -1;
461 }
462
463 dbC=GWEN_DB_GetFirstGroup(db);
464 while (dbC) {
465 rv=AB_ImExporter__Transform_Group(dbC, level+1);
466 if (rv)
467 return rv;
468 dbC=GWEN_DB_GetNextGroup(dbC);
469 }
470
471 dbC=GWEN_DB_GetFirstVar(db);
472 while (dbC) {
473 rv=AB_ImExporter__Transform_Var(dbC, level+1);
474 if (rv)
475 return rv;
476 dbC=GWEN_DB_GetNextVar(dbC);
477 }
478
479 return 0;
480 }
481
482
483
AB_ImExporter_DbFromIso8859_1ToUtf8(GWEN_DB_NODE * db)484 int AB_ImExporter_DbFromIso8859_1ToUtf8(GWEN_DB_NODE *db)
485 {
486 return AB_ImExporter__Transform_Group(db, 0);
487 }
488
489
490
491
492
493
494
495
496
AB_Plugin_ImExporter_new(GWEN_PLUGIN_MANAGER * pm,const char * name,const char * fileName)497 GWEN_PLUGIN *AB_Plugin_ImExporter_new(GWEN_PLUGIN_MANAGER *pm,
498 const char *name,
499 const char *fileName)
500 {
501 GWEN_PLUGIN *pl;
502 AB_PLUGIN_IMEXPORTER *xpl;
503
504 pl=GWEN_Plugin_new(pm, name, fileName);
505 GWEN_NEW_OBJECT(AB_PLUGIN_IMEXPORTER, xpl);
506 GWEN_INHERIT_SETDATA(GWEN_PLUGIN, AB_PLUGIN_IMEXPORTER, pl, xpl,
507 AB_Plugin_ImExporter_FreeData);
508
509 return pl;
510 }
511
512
513
AB_Plugin_ImExporter_FreeData(void * bp,void * p)514 void GWENHYWFAR_CB AB_Plugin_ImExporter_FreeData(void *bp, void *p)
515 {
516 AB_PLUGIN_IMEXPORTER *xpl;
517
518 xpl=(AB_PLUGIN_IMEXPORTER *)p;
519 GWEN_FREE_OBJECT(xpl);
520 }
521
522
523
AB_Plugin_ImExporter_Factory(GWEN_PLUGIN * pl,AB_BANKING * ab)524 AB_IMEXPORTER *AB_Plugin_ImExporter_Factory(GWEN_PLUGIN *pl,
525 AB_BANKING *ab)
526 {
527 AB_PLUGIN_IMEXPORTER *xpl;
528
529 assert(pl);
530 xpl=GWEN_INHERIT_GETDATA(GWEN_PLUGIN, AB_PLUGIN_IMEXPORTER, pl);
531 assert(xpl);
532
533 assert(xpl->pluginFactoryFn);
534 return xpl->pluginFactoryFn(pl, ab);
535 }
536
537
AB_Plugin_ImExporter_SetFactoryFn(GWEN_PLUGIN * pl,AB_PLUGIN_IMEXPORTER_FACTORY_FN fn)538 void AB_Plugin_ImExporter_SetFactoryFn(GWEN_PLUGIN *pl,
539 AB_PLUGIN_IMEXPORTER_FACTORY_FN fn)
540 {
541 AB_PLUGIN_IMEXPORTER *xpl;
542
543 assert(pl);
544 xpl=GWEN_INHERIT_GETDATA(GWEN_PLUGIN, AB_PLUGIN_IMEXPORTER, pl);
545 assert(xpl);
546
547 xpl->pluginFactoryFn=fn;
548 }
549
550
551
552
553
554
555