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