Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

aqbanking / src / libs / plugins / parsers / swift / swift940.c @ f4a16f5b

History | View | Annotate | Download (35.6 KB)

1
/***************************************************************************
2
 begin       : Fri Apr 02 2004
3
 copyright   : (C) 2018 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
#include "swift940_p.h"
15
#include "i18n_l.h"
16

    
17
/* #include <aqhbci/aqhbci.h> */
18
#include <aqbanking/error.h>
19
#include <aqbanking/imexporter_be.h>
20

    
21
#include <gwenhywfar/text.h>
22
#include <gwenhywfar/debug.h>
23
#include <gwenhywfar/gwentime.h>
24
#include <gwenhywfar/gui.h>
25
#include <stdlib.h>
26
#include <string.h>
27
#include <ctype.h>
28
#include <assert.h>
29

    
30

    
31

    
32
/*#define ENABLE_FULL_SEPA_LOG*/
33

    
34

    
35
#define CENTURY_CUTOFF_YEAR 79
36

    
37

    
38

    
39
static char *my_strndup(const char *src, size_t n) {
40
  int len;
41

    
42
  len=strlen(src);
43
  if (len<n)
44
    return strdup(src);
45
  else {
46
    char *cpy;
47

    
48
    cpy=(char*) malloc(n+1);
49
    assert(cpy);
50
    memmove(cpy, src, n);
51
    cpy[n]=0;
52
    return cpy;
53
  }
54
}
55

    
56

    
57

    
58
static void _iso8859_1ToUtf8(const char *p, int size, GWEN_BUFFER *buf) {
59
  while(*p) {
60
    unsigned int c;
61

    
62
    if (!size)
63
      break;
64

    
65
    c=(unsigned char)(*(p++));
66
    if (c<32 || c==127)
67
      c=32;
68
    if (c & 0x80) {
69
      GWEN_Buffer_AppendByte(buf, 0xc0 | c>>6);
70
      c &= ~0x40;
71
    }
72
    GWEN_Buffer_AppendByte(buf, c);
73
    if (size!=-1)
74
      size--;
75
  } /* while */
76
}
77

    
78

    
79

    
80

    
81
int AHB_SWIFT__SetCharValue(GWEN_DB_NODE *db,
82
                            uint32_t flags,
83
                            const char *name,
84
                            const char *s) {
85
  GWEN_BUFFER *vbuf;
86
  int rv;
87

    
88
  vbuf=GWEN_Buffer_new(0, strlen(s)+32, 0, 1);
89
  _iso8859_1ToUtf8(s, -1, vbuf);
90
  rv=GWEN_DB_SetCharValue(db, flags, name, GWEN_Buffer_GetStart(vbuf));
91
  GWEN_Buffer_free(vbuf);
92
  return rv;
93
}
94

    
95

    
96

    
97
int AHB_SWIFT940_Parse_25(const AHB_SWIFT_TAG *tg,
98
                          uint32_t flags,
99
                          GWEN_DB_NODE *data,
100
                          GWEN_DB_NODE *cfg){
101
  const char *p;
102
  const char *p2;
103

    
104
  p=AHB_SWIFT_Tag_GetData(tg);
105
  assert(p);
106

    
107
  while(*p && *p==32)
108
    p++;
109
  if (*p==0) {
110
    DBG_WARN(AQBANKING_LOGDOMAIN, "Tag 25 is empty");
111
    return 0;
112
  }
113

    
114
  p2=strchr(p, '/');
115
  if (p2) {
116
    char *s;
117

    
118
    /* "BLZ/Konto" */
119
    s=(char*)GWEN_Memory_malloc(p2-p+1);
120
    memmove(s, p, p2-p+1);
121
    s[p2-p]=0;
122
    AHB_SWIFT__SetCharValue(data,
123
                            GWEN_DB_FLAGS_OVERWRITE_VARS,
124
                            "localBankCode", s);
125
    GWEN_Memory_dealloc(s);
126
    p=p2+1;
127
  }
128

    
129
  /* Skip leading whitespaces */
130
  while(*p && *p==32)
131
    p++;
132

    
133
  if (*p) {
134
    char *s;
135
    int ll;
136

    
137
    /* Reaching this point, the remainder is at least 1 byte long. */
138
    p2 = p + strlen(p) - 1;
139

    
140
    /* Remove trailing whitespaces. */
141
    while( (*p2 == 32) && (p2>p) )
142
      p2--;
143

    
144
    /* p2 now points to the last non-space character (or the beginning of the string),
145
     * so the total size without the trailing zero is (p2-p)+1
146
     */
147
    ll=(p2-p)+1;
148
    s=(char*)GWEN_Memory_malloc(ll+1); /* account for trailing zero */
149
    memmove(s, p, ll);                 /* copy string without trailing zero */
150
    s[ll]=0;                           /* ensure terminating zero */
151
    AHB_SWIFT__SetCharValue(data,
152
                            GWEN_DB_FLAGS_OVERWRITE_VARS,
153
                            "localAccountNumber", s);
154
    GWEN_Memory_dealloc(s);
155
  }
156
  else {
157
      DBG_INFO(AQBANKING_LOGDOMAIN,
158
               "LocalAccountNumber is empty (%s)", p);
159
      AHB_SWIFT__SetCharValue(data,
160
                              GWEN_DB_FLAGS_OVERWRITE_VARS,
161
                              "localAccountNumber", p);
162
  }
163

    
164
  return 0;
165
}
166

    
167

    
168

    
169
int AHB_SWIFT940_Parse_86(const AHB_SWIFT_TAG *tg,
170
                          uint32_t flags,
171
                          GWEN_DB_NODE *data,
172
                          GWEN_DB_NODE *cfg){
173
  const char *p;
174
  int isStructured;
175
  int code;
176
  int keepMultipleBlanks;
177

    
178
  keepMultipleBlanks=GWEN_DB_GetIntValue(cfg, "keepMultipleBlanks", 0, 1);
179
  p=AHB_SWIFT_Tag_GetData(tg);
180
  assert(p);
181
  isStructured=0;
182
  code=999;
183
  if (strlen(p)>3) {
184
    if (isdigit(p[0]) && isdigit(p[1]) && isdigit(p[2])) {
185
      /* starts with a three digit number */
186
      code=(((p[0]-'0')*100) + ((p[1]-'0')*10) + (p[2]-'0'));
187
      if (p[3]=='?')
188
        /* it is structured, get the code */
189
        isStructured=1;
190
      p+=3;
191
    }
192
  }
193

    
194
  if (isStructured) {
195
    AHB_SWIFT_SUBTAG_LIST *stlist;
196
    int rv;
197

    
198
    /* store code */
199
    GWEN_DB_SetIntValue(data, flags, "transactioncode", code);
200

    
201
    stlist=AHB_SWIFT_SubTag_List_new();
202
    rv=AHB_SWIFT_ParseSubTags(p, stlist, keepMultipleBlanks);
203
    if (rv<0) {
204
      DBG_WARN(AQBANKING_LOGDOMAIN, "Handling tag :86: as unstructured (%d)", rv);
205
      isStructured=0;
206
    }
207
    else {
208
      if (code<900) {
209
        AHB_SWIFT_SUBTAG *stg;
210
        GWEN_DB_NODE *dbSepaTags=NULL;
211
        GWEN_BUFFER *bufFullPurpose;
212
        int realSepaTagCount=0;
213

    
214
        bufFullPurpose=GWEN_Buffer_new(0, 256, 0, 1);
215

    
216
        /* SEPA transaction, needs special handling */
217
        dbSepaTags=GWEN_DB_Group_new("sepa-tags");
218

    
219
        stg=AHB_SWIFT_SubTag_List_First(stlist);
220
        while(stg) {
221
          const char *s;
222
          int id;
223
          int intVal;
224

    
225
          id=AHB_SWIFT_SubTag_GetId(stg);
226
          s=AHB_SWIFT_SubTag_GetData(stg);
227
          switch(id) {
228
          case 0: /* Buchungstext */
229
            AHB_SWIFT__SetCharValue(data, flags, "transactionText", s);
230
            break;
231
          case 10: /* Primanota */
232
            AHB_SWIFT__SetCharValue(data, flags, "primanota", s);
233
            break;
234
      
235
          case 20:
236
          case 21:
237
          case 22:
238
          case 23:
239
          case 24:
240
          case 25:
241
          case 26:
242
          case 27:
243
          case 28:
244
          case 29:
245
          case 60:
246
          case 61:
247
          case 62:
248
          case 63: /* Verwendungszweck */
249
            /* store purpose in any case, if the transaction doesn't have SEPA tags
250
             * we can just use what we produced here. */
251
            GWEN_DB_SetCharValue(data, GWEN_DB_FLAGS_DEFAULT, "purpose", s);
252
            /* possibly handle full purpose later */
253
            GWEN_Buffer_AppendString(bufFullPurpose, s);
254
            break;
255

    
256
          case 30: /* BLZ Gegenseite */
257
            AHB_SWIFT__SetCharValue(data, flags, "remoteBankCode", s);
258
            break;
259
      
260
          case 31: /* Kontonummer Gegenseite */
261
            AHB_SWIFT__SetCharValue(data, flags, "remoteAccountNumber", s);
262
            break;
263
      
264
          case 32: 
265
          case 33: /* Name Auftraggeber */
266
            //DBG_ERROR(AQBANKING_LOGDOMAIN, "Setting remote name: [%s]", s);
267
            AHB_SWIFT__SetCharValue(data, flags, "remoteName", s);
268
            break;
269
      
270
          case 34: /* Textschluesselergaenzung */
271
            if (1==sscanf(s, "%d", &intVal)) {
272
              GWEN_DB_SetIntValue(data, flags, "textkeyExt", intVal);
273
            }
274
            else {
275
              DBG_WARN(AQBANKING_LOGDOMAIN,
276
                       "Value [%s] is not a number (textkeyext)", s);
277
            }
278
            break;
279
  
280
          case 38: /* IBAN */
281
            AHB_SWIFT__SetCharValue(data, flags, "remoteIban", s);
282
            break;
283
  
284
          default: /* ignore all other fields (if any) */
285
            DBG_WARN(AQBANKING_LOGDOMAIN, "Unknown :86: field \"%02d\" (%s) (%s)", id, s,
286
                     AHB_SWIFT_Tag_GetData(tg));
287
            break;
288
          } /* switch */
289
          stg=AHB_SWIFT_SubTag_List_Next(stg);
290
        } /* while */
291

    
292
        /* create real purpose string from data */
293
        if (GWEN_Buffer_GetUsedBytes(bufFullPurpose)) {
294
          GWEN_BUFFER *tbuf;
295
          int i;
296

    
297
          tbuf=GWEN_Buffer_new(0, 256, 0, 1);
298
          for (i=0; i<99; i++) {
299
            const char *s;
300

    
301
            s=GWEN_DB_GetCharValue(data, "purpose", i, 0);
302
            if (s && *s) {
303
              if (GWEN_Buffer_GetUsedBytes(tbuf))
304
                GWEN_Buffer_AppendString(tbuf, "\n");
305
              GWEN_Buffer_AppendString(tbuf, s);
306
            }
307
          }
308

    
309
          GWEN_DB_DeleteVar(data, "purpose");
310
          GWEN_DB_SetCharValue(data, GWEN_DB_FLAGS_DEFAULT, "purpose", GWEN_Buffer_GetStart(tbuf));
311
          GWEN_Buffer_free(tbuf);
312
        }
313

    
314
        /* check for SEPA tags */
315
        if (GWEN_Buffer_GetUsedBytes(bufFullPurpose)) {
316
          const char *s;
317
          const char *sLastTagStart;
318

    
319
#ifdef ENABLE_FULL_SEPA_LOG
320
          DBG_ERROR(0, "FullPurposeBuffer:");
321
          GWEN_Buffer_Dump(bufFullPurpose, 2);
322
#endif
323

    
324
          s=GWEN_Buffer_GetStart(bufFullPurpose);
325
          sLastTagStart=s;
326

    
327
          /* sample all SEPA fields from concatenated string of purpose lines */
328
          while(*s) {
329
            /* look for begin of next tag */
330
            while(*s) {
331
              if ((*s && isalpha(*s)) &&
332
                  (s[1] && isalpha(s[1])) &&
333
                  (s[2] && isalpha(s[2])) &&
334
                  (s[3] && isalpha(s[3])) &&
335
                  s[4]=='+')
336
                break;
337
              /* not the beginning of a SEPA field, just skip */
338
              s++;
339
            }
340

    
341
            /* found begin of the next SEPA field or end of buffer */
342
            if (s > sLastTagStart) {
343
              int tagLen;
344

    
345
              /* we currently have a field, close that first */
346
              tagLen=s-sLastTagStart;
347

    
348
#ifdef ENABLE_FULL_SEPA_LOG
349
              DBG_ERROR(0, "Current tag:");
350
              GWEN_Text_LogString(sLastTagStart, tagLen, 0, GWEN_LoggerLevel_Error);
351
#endif
352

    
353
              /* check tag length (must be long enough for 'XXX+', i.e. at least 5 bytes) */
354
              if (tagLen>5 && sLastTagStart[4]=='+') {
355
                char sIdentifier[6];
356
                const char *sPayload;
357

    
358
                /* ok, 5 bytes or more, 4 alphas and a plus sign, should be the begin of a SEPA tag */
359
                strncpy(sIdentifier, sLastTagStart, 5);
360
                sIdentifier[5]=0;
361

    
362
                /* remove leading blanks */
363
                sPayload=sLastTagStart+5;
364
                tagLen-=5;
365
                while(tagLen>0 && *sPayload && isblank(*sPayload)) {
366
                  sPayload++;
367
                  tagLen--;
368
                }
369

    
370
                /* remove trailing blanks */
371
                if (tagLen>0) {
372
                  while(tagLen>0) {
373
                    if (!isblank(sPayload[tagLen-1]))
374
                      break;
375
                    tagLen--;
376
                  }
377
                }
378

    
379
                /* store tag, if still data left */
380
                if (tagLen>0) {
381
                  char *sCopyPayload;
382

    
383
                  sCopyPayload=my_strndup(sPayload, tagLen);
384
                  GWEN_DB_SetCharValue(dbSepaTags, GWEN_DB_FLAGS_DEFAULT, sIdentifier, sCopyPayload);
385
                  free(sCopyPayload);
386
                  realSepaTagCount++;
387
                }
388
                else {
389
                  DBG_WARN(GWEN_LOGDOMAIN, "Ignoring empty SEPA field \"%s\"", sIdentifier);
390
                }
391
              }
392
              else {
393
                /* tag is shorter than 5 bytes or pos 4 doesn't contain a plus, treat as normal purpose */
394
                if (tagLen>0) {
395
                  char *sCopyPayload;
396

    
397
                  sCopyPayload=my_strndup(sLastTagStart, tagLen);
398
                  GWEN_DB_SetCharValue(dbSepaTags, GWEN_DB_FLAGS_DEFAULT, "_purpose", sCopyPayload);
399
                  free(sCopyPayload);
400
                }
401
              }
402
            }
403

    
404
            if (*s) {
405
              /* save start of next tag */
406
              sLastTagStart=s;
407
              /* skip XXX+ at the beginning, otherwise we would immediately stop in next loop
408
               * we know that the next 5 bytes are valid, so it is safe to skip them */
409
              s+=5;
410
            }
411
          } /* while */
412

    
413
        } /* if GWEN_Buffer_GetUsedBytes(bufFullPurpose) */
414
        /* buffer no longer needed */
415
        GWEN_Buffer_free(bufFullPurpose);
416

    
417
        /* handle SEPA tags, iterate through them and parse according to variable name */
418
        if (realSepaTagCount>0 && GWEN_DB_Variables_Count(dbSepaTags)) {
419
          GWEN_DB_NODE *dbVar;
420

    
421
#ifdef ENABLE_FULL_SEPA_LOG
422
          DBG_ERROR(0, "Got these SEPA tags:");
423
          GWEN_DB_Dump(dbSepaTags, 2);
424
#endif
425

    
426
          /* clear purpose variable, since we are about to add it back from SEPA tags */
427
          GWEN_DB_DeleteVar(data, "purpose");
428

    
429
          dbVar=GWEN_DB_GetFirstVar(dbSepaTags);
430
          while(dbVar) {
431
            const char *sVarName;
432

    
433
            sVarName=GWEN_DB_VariableName(dbVar);
434
            if (sVarName && *sVarName) {
435
              GWEN_BUFFER *tbuf;
436
              GWEN_DB_NODE *dbValue;
437

    
438
              /* sample all values into a buffer and concatenate */
439
              tbuf=GWEN_Buffer_new(0, 128, 0, 1);
440
              dbValue=GWEN_DB_GetFirstValue(dbVar);
441
              while(dbValue) {
442
                const char *s;
443

    
444
                s=GWEN_DB_GetCharValueFromNode(dbValue);
445
                if (s && *s)
446
                  GWEN_Buffer_AppendString(tbuf, s);
447

    
448
                dbValue=GWEN_DB_GetNextValue(dbValue);
449
              }
450

    
451
              if (strcasecmp(sVarName, "EREF+")==0) {
452
                AHB_SWIFT__SetCharValue(data, flags, "endToEndReference", GWEN_Buffer_GetStart(tbuf));
453
              }
454
              else if (strcasecmp(sVarName, "KREF+")==0) {
455
                AHB_SWIFT__SetCharValue(data, flags, "customerReference", GWEN_Buffer_GetStart(tbuf));
456
              }
457
              else if (strcasecmp(sVarName, "MREF+")==0) {
458
                AHB_SWIFT__SetCharValue(data, flags, "mandateId", GWEN_Buffer_GetStart(tbuf));
459
              }
460
              else if (strcasecmp(sVarName, "CRED+")==0) {
461
                AHB_SWIFT__SetCharValue(data, flags, "creditorSchemeId", GWEN_Buffer_GetStart(tbuf));
462
              }
463
              else if (strcasecmp(sVarName, "DEBT+")==0) {
464
                AHB_SWIFT__SetCharValue(data, flags, "originatorId", GWEN_Buffer_GetStart(tbuf));
465
              }
466
              else if (strcasecmp(sVarName, "SVWZ+")==0) {
467
                AHB_SWIFT__SetCharValue(data, flags, "purpose", GWEN_Buffer_GetStart(tbuf));
468
              }
469
              else if (strcasecmp(sVarName, "ABWA+")==0) {
470
                /* "abweichender Auftraggeber" */
471
                AHB_SWIFT__SetCharValue(data, flags, "sepa/ABWA", GWEN_Buffer_GetStart(tbuf));
472
              }
473
              else if (strcasecmp(sVarName, "ABWE+")==0) {
474
                /* "abweichender Empfaenger" */
475
                AHB_SWIFT__SetCharValue(data, flags, "sepa/ABWE", GWEN_Buffer_GetStart(tbuf));
476
              }
477
              else if (strcasecmp(sVarName, "_purpose")==0) {
478
                /* manually added tag (i.e. data outside a tag)
479
                 * TODO: only add if there was no real purpose field (i.e. no "SVWZ+") */
480
                AHB_SWIFT__SetCharValue(data, flags, "purpose", GWEN_Buffer_GetStart(tbuf));
481
              }
482

    
483
              GWEN_Buffer_free(tbuf);
484
            }
485

    
486
            dbVar=GWEN_DB_GetNextVar(dbVar);
487
          }
488
        }
489

    
490
#ifdef ENABLE_FULL_SEPA_LOG
491
        DBG_ERROR(0, "SEPA Tags:");
492
        GWEN_DB_Dump(dbSepaTags, 2);
493
#endif
494

    
495
        GWEN_DB_Group_free(dbSepaTags);
496
      } /* if sepa */
497
      else {
498
        AHB_SWIFT_SUBTAG *stg;
499

    
500
        /* non-sepa */
501
        stg=AHB_SWIFT_SubTag_List_First(stlist);
502
        while(stg) {
503
          int id;
504
          const char *s;
505
          int intVal;
506

    
507
          id=AHB_SWIFT_SubTag_GetId(stg);
508
          s=AHB_SWIFT_SubTag_GetData(stg);
509
          switch(id) {
510
          case 0: /* Buchungstext */
511
            AHB_SWIFT__SetCharValue(data, flags, "transactionText", s);
512
            break;
513
          case 10: /* Primanota */
514
            AHB_SWIFT__SetCharValue(data, flags, "primanota", s);
515
            break;
516
      
517
          case 20:
518
          case 21:
519
          case 22:
520
          case 23:
521
          case 24:
522
          case 25:
523
          case 26:
524
          case 27:
525
          case 28:
526
          case 29:
527
          case 60:
528
          case 61:
529
          case 62:
530
          case 63: /* Verwendungszweck */
531
            AHB_SWIFT__SetCharValue(data, flags, "purpose", s);
532
            break;
533

    
534
          case 30: /* BLZ Gegenseite */
535
            AHB_SWIFT__SetCharValue(data, flags, "remoteBankCode", s);
536
            break;
537
      
538
          case 31: /* Kontonummer Gegenseite */
539
            AHB_SWIFT__SetCharValue(data, flags, "remoteAccountNumber", s);
540
            break;
541
      
542
          case 32: 
543
          case 33: /* Name Auftraggeber */
544
            AHB_SWIFT__SetCharValue(data, flags, "remoteName", s);
545
            break;
546
      
547
          case 34: /* Textschluesselergaenzung */
548
            if (1==sscanf(s, "%d", &intVal)) {
549
              GWEN_DB_SetIntValue(data, flags, "textkeyExt", intVal);
550
            }
551
            else {
552
              DBG_WARN(AQBANKING_LOGDOMAIN,
553
                       "Value [%s] is not a number (textkeyext)", s);
554
            }
555
            break;
556
  
557
          case 38: /* IBAN */
558
            AHB_SWIFT__SetCharValue(data, flags, "remoteIban", s);
559
            break;
560
  
561
          default: /* ignore all other fields (if any) */
562
            DBG_WARN(AQBANKING_LOGDOMAIN, "Unknown :86: field \"%02d\" (%s) (%s)", id, s,
563
                     AHB_SWIFT_Tag_GetData(tg));
564
            break;
565
          } /* switch */
566
          stg=AHB_SWIFT_SubTag_List_Next(stg);
567
        } /* while */
568
      }
569
    } /* if really structured */
570
    AHB_SWIFT_SubTag_List_free(stlist);
571
  } /* if isStructured */
572
  else {
573
    char *pcopy=strdup(p);
574
    char *p1;
575

    
576
    /* unstructured :86:, simply store as mutliple purpose lines */
577
    p1=pcopy;
578
    while(p1 && *p1) {
579
      char *p2;
580

    
581
      p2=strchr(p1, 10);
582
      if (p2) {
583
        *p2=0;
584
        p2++;
585
      }
586

    
587
      /* look for pattern "KTO/BLZ", if found try to extract remote account info
588
       * from unstructured purpose string */
589
      if (-1!=GWEN_Text_ComparePattern(p1, "*KTO/BLZ */*", 0)) {
590
        char *p3;
591
        char *kto;
592

    
593
        p3=p1;
594
        while(*p3) {
595
          *p3=toupper(*p3);
596
          p3++;
597
        }
598
        kto=strstr(p1, "KTO/BLZ ");
599
        if (kto) {
600
          char *blz;
601

    
602
          kto+=8;
603
          blz=strchr(kto, '/');
604
          if (blz) {
605
            *blz=0;
606
            blz++;
607

    
608
            p3=blz;
609
            while(*p3 && isdigit(*p3))
610
              p3++;
611
            *p3=0;
612

    
613
            AHB_SWIFT__SetCharValue(data, flags, "remoteBankCode", blz);
614
            AHB_SWIFT__SetCharValue(data, flags, "remoteAccountNumber", kto);
615
          }
616
        }
617
        else {
618
          AHB_SWIFT__SetCharValue(data, flags, "purpose", p1);
619
        }
620
      }
621
      else
622
        AHB_SWIFT__SetCharValue(data, flags, "purpose", p1);
623
      p1=p2;
624
    }
625
    free(pcopy);
626
  }
627

    
628
  return 0;
629
}
630

    
631

    
632

    
633
int AHB_SWIFT940_Parse_61(const AHB_SWIFT_TAG *tg,
634
                          uint32_t flags,
635
                          GWEN_DB_NODE *data,
636
                          GWEN_DB_NODE *cfg){
637
  const char *p;
638
  const char *p2;
639
  char *s;
640
  char buffer[32];
641
  unsigned int bleft;
642
  int d1a, d2a, d3a;
643
  int d1b, d2b, d3b;
644
  int neg;
645
  GWEN_DATE *dt;
646
  //char curr3=0;
647

    
648
  p=AHB_SWIFT_Tag_GetData(tg);
649
  assert(p);
650
  bleft=strlen(p);
651

    
652
  /* valuata date (M) */
653
  if (bleft<6) {
654
    DBG_ERROR(AQBANKING_LOGDOMAIN, "Missing valuta date (%s)", p);
655
    GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error,
656
                          "SWIFT: Missing valuta date");
657
    return -1;
658
  }
659
  d1a=((p[0]-'0')*10) + (p[1]-'0');
660
  if (d1a>CENTURY_CUTOFF_YEAR)
661
    d1a+=1900;
662
  else
663
    d1a+=2000;
664
  d2a=((p[2]-'0')*10) + (p[3]-'0');
665
  d3a=((p[4]-'0')*10) + (p[5]-'0');
666

    
667
  if (d3a==30 && d2a==2) {
668
    int ju;
669

    
670
    /* date is Feb 30, this date is invalid. However, some banks use this
671
     * to indicate the last day of February, so we move along */
672
    d3a=1;
673
    d2a=3;
674
    dt=GWEN_Date_fromGregorian(d1a, d2a, d3a);
675
    assert(dt);
676
    ju=GWEN_Date_GetJulian(dt);
677
    /* subtract a day to get the last day in FEB */
678
    ju--;
679
    GWEN_Date_free(dt);
680
    dt=GWEN_Date_fromJulian(ju);
681
  }
682
  else {
683
    dt=GWEN_Date_fromGregorian(d1a, d2a, d3a);
684
    assert(dt);
685
  }
686
  GWEN_DB_SetCharValue(data, GWEN_DB_FLAGS_DEFAULT, "valutaDate", GWEN_Date_GetString(dt));
687
  GWEN_Date_free(dt);
688
  p+=6;
689
  bleft-=6;
690

    
691
  /* booking date (K) */
692
  if (*p && isdigit(*p)) {
693
    if (bleft<4) {
694
      DBG_ERROR(AQBANKING_LOGDOMAIN, "Bad booking date (%s)", p);
695
      GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Info,
696
                            "SWIFT: Bad booking date");
697
      return -1;
698
    }
699
    d2b=((p[0]-'0')*10) + (p[1]-'0');
700
    d3b=((p[2]-'0')*10) + (p[3]-'0');
701
    /* use year from valutaDate.
702
     * However: if valuta date and booking date are in different years
703
     * the booking year might be too high.
704
     * We detect this case by comparing the months: If the booking month
705
     * is and the valuta month differ by more than 10 months then the year
706
     * of the booking date will be adjusted.
707
     */
708
    if (d2b-d2a>7) {
709
      /* booked before actually withdrawn */
710
      d1b=d1a-1;
711
    }
712
    else if (d2a-d2b>7) {
713
      /* withdrawn and booked later */
714
      d1b=d1a+1;
715
    }
716
    else
717
      d1b=d1a;
718

    
719
    dt=GWEN_Date_fromGregorian(d1b, d2b, d3b);
720
    assert(dt);
721
    GWEN_DB_SetCharValue(data, GWEN_DB_FLAGS_DEFAULT, "date", GWEN_Date_GetString(dt));
722
    GWEN_Date_free(dt);
723
    p+=4;
724
    bleft-=4;
725
  }
726

    
727
  /* credit/debit mark (M) */
728
  if (bleft<2) {
729
    DBG_ERROR(AQBANKING_LOGDOMAIN, "Bad value string (%s)", p);
730
    GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error,
731
                          "SWIFT: Bad value string");
732
    return -1;
733
  }
734
  neg=0;
735
  if (*p=='R') {
736
    if (p[1]=='C' || p[1]=='c')
737
      neg=1;
738
    p+=2;
739
    bleft-=2;
740
  }
741
  else {
742
    if (*p=='D' || *p=='d')
743
      neg=1;
744
    p++;
745
    bleft--;
746
  }
747

    
748
  /* third character of currency (K) */
749
  if (bleft<1) {
750
    DBG_ERROR(AQBANKING_LOGDOMAIN, "Bad data (%s)", p);
751
    GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error,
752
                          "SWIFT: Bad currency");
753
    return -1;
754
  }
755
  if (!isdigit(*p)) {
756
    /* found third character, skip it */
757
    //curr3=*p;
758
    p++;
759
    bleft--;
760
  }
761

    
762
  /* value (M) */
763
  p2=p;
764
  while(*p2 && (isdigit(*p2) || *p2==','))
765
    p2++;
766
  if (p2==p) {
767
    DBG_ERROR(AQBANKING_LOGDOMAIN, "No value (%s)", p);
768
    GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error,
769
                          "SWIFT: Bad value");
770
    return -1;
771
  }
772
  s=(char*)GWEN_Memory_malloc(p2-p+1+(neg?1:0));
773
  if (neg) {
774
    s[0]='-';
775
    memmove(s+1, p, p2-p+1);
776
    s[p2-p+1]=0;
777
  }
778
  else {
779
    memmove(s, p, p2-p+1);
780
    s[p2-p]=0;
781
  }
782
  if (1) {
783
    GWEN_BUFFER *tbuf;
784
    const char *cu;
785

    
786
    tbuf=GWEN_Buffer_new(0, 64, 0, 1);
787
    GWEN_Buffer_AppendString(tbuf, s);
788
    cu=GWEN_DB_GetCharValue(cfg, "currency", 0, 0);
789
    if (cu) {
790
      GWEN_Buffer_AppendString(tbuf, ":");
791
      GWEN_Buffer_AppendString(tbuf, cu);
792
    }
793
    AHB_SWIFT__SetCharValue(data, flags, "value", GWEN_Buffer_GetStart(tbuf));
794
    GWEN_Buffer_free(tbuf);
795
  }
796
  GWEN_Memory_dealloc(s);
797
  bleft-=p2-p;
798
  p=p2;
799

    
800
  /* skip 'N' */
801
  p++;
802
  bleft--;
803

    
804
  /* key (M) */
805
  if (bleft<3) {
806
    DBG_ERROR(AQBANKING_LOGDOMAIN, "Missing booking key (%s)", p);
807
    GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error,
808
                          "SWIFT: Missing booking key");
809
    return -1;
810
  }
811
  memmove(buffer, p, 3);
812
  buffer[3]=0;
813
  AHB_SWIFT__SetCharValue(data, flags, "transactionKey", buffer);
814
  p+=3;
815
  bleft-=3;
816

    
817
  /* customer reference (M) */
818
  if (bleft>0) {
819
    if (bleft>1) {
820
      if (*p=='/' && p[1]!='/') {
821
        p++;
822
        bleft--;
823
      }
824
    }
825

    
826
    p2=p;
827
    while(*p2 && *p2!='/' && *p2!=10)
828
      p2++;
829

    
830
    if (p2==p) {
831
      DBG_WARN(AQBANKING_LOGDOMAIN, "Missing customer reference (%s)", p);
832
      GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error,
833
                            "SWIFT: Missing customer reference");
834
    }
835
    else {
836
      s=(char*)GWEN_Memory_malloc(p2-p+1);
837
      memmove(s, p, p2-p);
838
      s[p2-p]=0;
839
      if (strcasecmp(s, "NONREF")!=0)
840
        AHB_SWIFT__SetCharValue(data, flags, "customerReference", s);
841
      GWEN_Memory_dealloc(s);
842
    }
843
    bleft-=p2-p;
844
    p=p2;
845
    assert(bleft>=0);
846
  }
847

    
848
  /* bank reference (K) */
849
  if (bleft>1) {
850
    if (*p=='/' && p[1]=='/') {
851
      /* found bank reference */
852
      p+=2;
853
      bleft-=2;
854

    
855
      p2=p;
856
      while(*p2 && *p2!='/' && *p2!=10) p2++;
857
      if (p2==p) {
858
        DBG_WARN(AQBANKING_LOGDOMAIN, "Missing bank reference (%s) - ignored", p);
859
        GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Warning,
860
                              "SWIFT: Non-Standard MT940 file: Missing bank reference field in :61: line - ignored.");
861
        return 0;
862
      }
863
      s=(char*)GWEN_Memory_malloc(p2-p+1);
864
      memmove(s, p, p2-p+1);
865
      s[p2-p]=0;
866
      AHB_SWIFT__SetCharValue(data, flags, "bankReference", s);
867
      GWEN_Memory_dealloc(s);
868
      bleft-=p2-p;
869
      p=p2;
870
      assert(bleft>=0);
871
    }
872
  }
873

    
874
  /* more information ? */
875
  if (*p==10) {
876
    /* yes... */
877
    p++;
878
    bleft--;
879

    
880
    while(*p) {
881
      /* read extra information */
882
      if (*p=='/') {
883
        if (p[1]==0)
884
          return 0;
885

    
886
        if (bleft<6) {
887
          DBG_WARN(AQBANKING_LOGDOMAIN,
888
                   "Unknown extra data, ignoring (%s)", p);
889
          return 0;
890
        }
891
        if (strncasecmp(p, "/OCMT/", 6)==0) {
892
          /* original value */
893
          p+=6;
894
          bleft-=6;
895
          /* get currency */
896
          memmove(buffer, p, 3);
897
          buffer[3]=0;
898
          AHB_SWIFT__SetCharValue(data, flags, "origvalue/currency", buffer);
899
          p+=3;
900
          bleft-=3;
901
          if (*p=='/') { /* Deutsche Bank seems to be sending */
902
            p++;         /* a "/" between currency and amount */
903
            bleft--;
904
          }
905
          /* get value */
906
          p2=p;
907
          while(*p2 && *p2!='/') p2++;
908
          if (p2==p) {
909
            DBG_ERROR(AQBANKING_LOGDOMAIN, "Bad original value (%s)", p);
910
            GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error,
911
                                  "SWIFT: Bad original value");
912
            return -1;
913
          }
914
          s=(char*)GWEN_Memory_malloc(p2-p+1);
915
          memmove(s, p, p2-p+1);
916
          s[p2-p]=0;
917
          AHB_SWIFT__SetCharValue(data, flags, "origvalue", s);
918
          GWEN_Memory_dealloc(s);
919
          bleft-=p2-p;
920
          p=p2;
921
        }
922
        else if (strncasecmp(p, "/CHGS/", 6)==0) {
923
          /* charges */
924
          p+=6;
925
          bleft-=6;
926
          /* get currency */
927
          memmove(buffer, p, 3);
928
          buffer[3]=0;
929
          AHB_SWIFT__SetCharValue(data, flags, "charges/currency", buffer);
930
          p+=3;
931
          bleft-=3;
932
          if (*p=='/') { /* Deutsche Bank seems to be sending */
933
            p++;         /* a "/" between currency and amount */
934
            bleft--;
935
          }
936
          /* get value */
937
          p2=p;
938
          while(*p2 && *p2!='/') p2++;
939
          if (p2==p) {
940
            DBG_ERROR(AQBANKING_LOGDOMAIN, "Bad charges value (%s)", p);
941
            GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error,
942
                                  "SWIFT: Bad charges value");
943
            return -1;
944
          }
945
          s=(char*)GWEN_Memory_malloc(p2-p+1);
946
          memmove(s, p, p2-p+1);
947
          s[p2-p]=0;
948
          AHB_SWIFT__SetCharValue(data, flags, "charges", s);
949
          GWEN_Memory_dealloc(s);
950
          bleft-=p2-p;
951
          p=p2;
952
        }
953
        else {
954
          DBG_WARN(AQBANKING_LOGDOMAIN,
955
                   "Unknown extra data, ignoring (%s)", p);
956
          return 0;
957
        }
958
      }
959
      else {
960
        DBG_WARN(AQBANKING_LOGDOMAIN, "Bad extra data, ignoring (%s)", p);
961
        return 0;
962
      }
963
    } /* while */
964
  } /* if there is extra data */
965

    
966
  return 0;
967
}
968

    
969

    
970

    
971
int AHB_SWIFT940_Parse_6_0_2(const AHB_SWIFT_TAG *tg,
972
                             uint32_t flags,
973
                             GWEN_DB_NODE *data,
974
                             GWEN_DB_NODE *cfg){
975
  const char *p;
976
  const char *p2;
977
  char *s;
978
  char buffer[32];
979
  unsigned int bleft;
980
  int d1, d2, d3;
981
  int neg;
982
  GWEN_DATE *dt;
983

    
984
  p=AHB_SWIFT_Tag_GetData(tg);
985
  assert(p);
986
  bleft=strlen(p);
987

    
988
  /* credit/debit mark (M) */
989
  if (bleft<2) {
990
    DBG_ERROR(AQBANKING_LOGDOMAIN, "Bad value string (%s)", p);
991
    GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error,
992
                          "SWIFT: Bad value string");
993
    return -1;
994
  }
995
  neg=0;
996
  if (*p=='D' || *p=='d')
997
    neg=1;
998
  p++;
999
  bleft--;
1000

    
1001
  /* date (M) */
1002
  if (bleft<6) {
1003
    DBG_ERROR(AQBANKING_LOGDOMAIN, "Missing date (%s)", p);
1004
    GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error,
1005
                          "SWIFT: Missing date");
1006
    return -1;
1007
  }
1008
  d1=((p[0]-'0')*10) + (p[1]-'0');
1009
  if (d1>CENTURY_CUTOFF_YEAR)
1010
    d1+=1900;
1011
  else
1012
    d1+=2000;
1013
  d2=((p[2]-'0')*10) + (p[3]-'0');
1014
  d3=((p[4]-'0')*10) + (p[5]-'0');
1015

    
1016
  dt=GWEN_Date_fromGregorian(d1, d2, d3);
1017
  assert(dt);
1018
  GWEN_DB_SetCharValue(data, GWEN_DB_FLAGS_OVERWRITE_VARS, "date", GWEN_Date_GetString(dt));
1019
  GWEN_Date_free(dt);
1020

    
1021
  p+=6;
1022
  bleft-=6;
1023

    
1024
  /* currency (M) */
1025
  if (!isdigit(*p)) {
1026
    /* only read currency if this is not part of the value (like in some
1027
     * swiss MT940) */
1028
    if (bleft<3) {
1029
      DBG_ERROR(AQBANKING_LOGDOMAIN, "Missing currency (%s)", p);
1030
      GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error,
1031
                            "SWIFT: Missing currency");
1032
      return -1;
1033
    }
1034
    memmove(buffer, p, 3);
1035
    buffer[3]=0;
1036
    AHB_SWIFT__SetCharValue(data, flags, "value/currency", buffer);
1037
    p+=3;
1038
    bleft-=3;
1039
  }
1040

    
1041
  /* value (M) */
1042
  if (bleft<1) {
1043
    DBG_ERROR(AQBANKING_LOGDOMAIN, "Missing value (%s)", p);
1044
    GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error,
1045
                          "SWIFT: Missing value");
1046
    return -1;
1047
  }
1048

    
1049
  p2=p;
1050
  while(*p2 && (isdigit(*p2) || *p2==',')) p2++;
1051
  if (p2==p) {
1052
    DBG_ERROR(AQBANKING_LOGDOMAIN, "Bad value (%s)", p);
1053
    GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error,
1054
                          "SWIFT: Bad value");
1055
    return -1;
1056
  }
1057
  s=(char*)GWEN_Memory_malloc(p2-p+1+(neg?1:0));
1058
  if (neg) {
1059
    s[0]='-';
1060
    memmove(s+1, p, p2-p+1);
1061
    s[p2-p+1]=0;
1062
  }
1063
  else {
1064
    memmove(s, p, p2-p+1);
1065
    s[p2-p]=0;
1066
  }
1067
  AHB_SWIFT__SetCharValue(data, flags, "value", s);
1068
  GWEN_Memory_dealloc(s);
1069
  /*bleft-=p2-p;*/
1070
  /*p=p2;*/
1071

    
1072
  return 0;
1073
}
1074

    
1075

    
1076

    
1077
int AHB_SWIFT940_Parse_NS(const AHB_SWIFT_TAG *tg,
1078
                          uint32_t flags,
1079
                          GWEN_DB_NODE *data,
1080
                          GWEN_DB_NODE *cfg){
1081
  const char *p;
1082
  const char *p2;
1083

    
1084
  /* TODO: Use AHB_SWIFT_ParseSubTags */
1085
  p=AHB_SWIFT_Tag_GetData(tg);
1086
  assert(p);
1087

    
1088
  while(*p) {
1089
    int code;
1090

    
1091
    code=0;
1092
    /* read code */
1093
    if (strlen(p)>2) {
1094
      if (isdigit(p[0]) && isdigit(p[1])) {
1095
        /* starts with a two digit number */
1096
        code=(((p[0]-'0')*10) + (p[1]-'0'));
1097
        p+=2;
1098
      }
1099
    }
1100

    
1101
    /* search for end of line */
1102
    p2=p;
1103
    while(*p2 && *p2!=10 && *p2!=13)
1104
      p2++;
1105

    
1106
    if (code==0) {
1107
      DBG_WARN(AQBANKING_LOGDOMAIN, "No code in line");
1108
      p=p2;
1109
    }
1110
    else {
1111
      int len;
1112

    
1113
      len=p2-p;
1114
      if (len<1 || (len==1 && *p=='/')) {
1115
        DBG_DEBUG(AQBANKING_LOGDOMAIN, "Empty field %02d", code);
1116
      }
1117
      else {
1118
        char *s;
1119

    
1120
        s=(char*)GWEN_Memory_malloc(len+1);
1121
        memmove(s, p, len);
1122
        s[len]=0;
1123
        DBG_DEBUG(AQBANKING_LOGDOMAIN, "Got his field: %02d: %s", code, s);
1124

    
1125
        switch(code) {
1126
        case 1:
1127
        case 2:
1128
        case 3:
1129
        case 4:
1130
        case 5:
1131
        case 6:
1132
        case 7:
1133
        case 8:
1134
        case 9:
1135
        case 10:
1136
        case 11:
1137
        case 12:
1138
        case 13:
1139
        case 14:
1140
          AHB_SWIFT__SetCharValue(data, flags, "purpose", s);
1141
          break;
1142

    
1143
        case 15: /* Auftraggeber1 */
1144
        case 16: /* Auftraggeber2 */
1145
          AHB_SWIFT__SetCharValue(data, flags, "localName", s);
1146
          break;
1147

    
1148
        case 17: /* Buchungstext */
1149
          AHB_SWIFT__SetCharValue(data, flags, "transactionText", s);
1150
          break;
1151

    
1152
        case 18: /* Primanota */
1153
          AHB_SWIFT__SetCharValue(data, flags, "primanota", s);
1154
          break;
1155

    
1156
        case 19: /* Uhrzeit der Buchung */
1157
        case 20: /* Anzahl der Sammlerposten */
1158
        case 33: /* BLZ Auftraggeber */
1159
        case 34: /* Konto Auftraggeber */
1160
          break;
1161

    
1162
        default: /* ignore all other fields (if any) */
1163
          DBG_WARN(AQBANKING_LOGDOMAIN,
1164
                   "Unknown :NS: field \"%02d\" (%s) (%s)",
1165
                   code, s,
1166
                   AHB_SWIFT_Tag_GetData(tg));
1167
          break;
1168
        }
1169
        GWEN_Memory_dealloc(s);
1170
      }
1171
      p=p2;
1172
    }
1173

    
1174
    if (*p==10)
1175
      p++;
1176
    if (*p==13)
1177
      p++;
1178
    if (*p==10)
1179
      p++;
1180
  } /* while */
1181

    
1182
  return 0;
1183
}
1184

    
1185

    
1186
/* Import SWIFT MT940 data.
1187
   @param tl input: list of tags. Tags are lines in a SWIFT data block (block 4). A tag has an
1188
          id and content. See the AHB_SWIFT_Tag_new function for more information.
1189
 */
1190
int AHB_SWIFT940_Import(AHB_SWIFT_TAG_LIST *tl,
1191
                        GWEN_DB_NODE *data,
1192
                        GWEN_DB_NODE *cfg,
1193
                        uint32_t flags) {
1194
  AHB_SWIFT_TAG *tg;
1195
  GWEN_DB_NODE *dbDay=NULL;
1196
  GWEN_DB_NODE *dbTemplate=NULL;
1197
  GWEN_DB_NODE *dbTransaction=NULL;
1198
  GWEN_DB_NODE *dbDate=NULL;
1199
  uint32_t progressId;
1200
  const char *acceptTag20="*";
1201
  const char *rejectTag20=NULL;
1202
  int ignoreCurrentReport=0;
1203

    
1204
  acceptTag20=GWEN_DB_GetCharValue(cfg, "acceptTag20", 0, NULL);
1205
  if (acceptTag20 && *acceptTag20==0)
1206
    acceptTag20=NULL;
1207
  rejectTag20=GWEN_DB_GetCharValue(cfg, "rejectTag20", 0, NULL);
1208
  if (rejectTag20 && *rejectTag20==0)
1209
    rejectTag20=NULL;
1210

    
1211
  dbTemplate=GWEN_DB_Group_new("template");
1212

    
1213
  progressId=GWEN_Gui_ProgressStart(GWEN_GUI_PROGRESS_DELAY |
1214
                                    GWEN_GUI_PROGRESS_ALLOW_EMBED |
1215
                                    GWEN_GUI_PROGRESS_SHOW_PROGRESS |
1216
                                    GWEN_GUI_PROGRESS_SHOW_ABORT,
1217
                                    I18N("Importing SWIFT tags..."),
1218
                                    NULL,
1219
                                    AHB_SWIFT_Tag_List_GetCount(tl),
1220
                                    0);
1221

    
1222
  tg=AHB_SWIFT_Tag_List_First(tl);
1223
  while(tg) {
1224
    const char *id;
1225

    
1226
    id=AHB_SWIFT_Tag_GetId(tg);
1227
    assert(id);
1228

    
1229
    if (strcasecmp(id, "20")==0) {
1230
      if (acceptTag20 || rejectTag20) {
1231
        const char *p;
1232

    
1233
        p=AHB_SWIFT_Tag_GetData(tg);
1234
        assert(p);
1235
        if (rejectTag20) {
1236
          if (-1!=GWEN_Text_ComparePattern(p, rejectTag20, 0)) {
1237
            DBG_INFO(AQBANKING_LOGDOMAIN, "Ignoring report [%s]", p);
1238
            ignoreCurrentReport=1;
1239
          }
1240
          else {
1241
            ignoreCurrentReport=0;
1242
          }
1243
        }
1244
        else if (acceptTag20) {
1245
          if (-1==GWEN_Text_ComparePattern(p, acceptTag20, 0)) {
1246
            DBG_INFO(AQBANKING_LOGDOMAIN,
1247
                     "Ignoring report [%s] (not matching [%s])",
1248
                     p, acceptTag20);
1249
            ignoreCurrentReport=1;
1250
          }
1251
          else {
1252
            ignoreCurrentReport=0;
1253
          }
1254
        }
1255

    
1256
      }
1257
    }
1258
    else {
1259
      if (!ignoreCurrentReport) {
1260
        if (strcasecmp(id, "25")==0) { /* LocalAccount */
1261
          if (AHB_SWIFT940_Parse_25(tg, flags, dbTemplate, cfg)) {
1262
            DBG_INFO(AQBANKING_LOGDOMAIN, "Error in tag");
1263
            GWEN_DB_Group_free(dbTemplate);
1264
            GWEN_Gui_ProgressEnd(progressId);
1265
            return -1;
1266
          }
1267
        }
1268
        else if (strcasecmp(id, "28C")==0) {
1269
          /* Sequence/Statement Number - currently ignored */
1270
          /* PostFinance statements don't have a correctly incrementing count... */
1271
        }
1272
        else if (strcasecmp(id, "60M")==0 || /* Interim StartSaldo */
1273
                 strcasecmp(id, "60F")==0) { /* StartSaldo */
1274
          GWEN_DB_NODE *dbSaldo;
1275
          const char *curr;
1276
    
1277
          /* start a new day */
1278
          dbDay=GWEN_DB_GetGroup(data, GWEN_PATH_FLAGS_CREATE_GROUP, "day");
1279
    
1280
          dbTransaction=0;
1281
          DBG_INFO(AQBANKING_LOGDOMAIN, "Starting new day");
1282
          dbSaldo=GWEN_DB_GetGroup(dbDay, GWEN_PATH_FLAGS_CREATE_GROUP,
1283
                                   "StartSaldo");
1284
          GWEN_DB_AddGroupChildren(dbSaldo, dbTemplate);
1285
          if (AHB_SWIFT940_Parse_6_0_2(tg, flags, dbSaldo, cfg)) {
1286
            DBG_INFO(AQBANKING_LOGDOMAIN, "Error in tag");
1287
            GWEN_DB_Group_free(dbTemplate);
1288
            GWEN_Gui_ProgressEnd(progressId);
1289
            return -1;
1290
          }
1291
          else {
1292
            dbDate=GWEN_DB_GetGroup(dbSaldo, GWEN_PATH_FLAGS_NAMEMUSTEXIST,
1293
                                    "date");
1294
          }
1295
    
1296
          curr=GWEN_DB_GetCharValue(dbSaldo, "value/currency", 0, 0);
1297
          if (curr) {
1298
            AHB_SWIFT__SetCharValue(dbTemplate, flags,
1299
                                    "value/currency", curr);
1300
          }
1301
        }
1302
        else if (strcasecmp(id, "62M")==0 || /* Interim EndSaldo */
1303
                 strcasecmp(id, "62F")==0) { /* EndSaldo */
1304
          GWEN_DB_NODE *dbSaldo;
1305
    
1306
          /* end current day */
1307
          dbTransaction=0;
1308
          if (!dbDay) {
1309
            DBG_WARN(AQBANKING_LOGDOMAIN, "Your bank does not send an opening saldo");
1310
            dbDay=GWEN_DB_GetGroup(data, GWEN_PATH_FLAGS_CREATE_GROUP, "day");
1311
          }
1312
          dbSaldo=GWEN_DB_GetGroup(dbDay, GWEN_PATH_FLAGS_CREATE_GROUP,
1313
                                   "EndSaldo");
1314
          GWEN_DB_AddGroupChildren(dbSaldo, dbTemplate);
1315
          if (AHB_SWIFT940_Parse_6_0_2(tg, flags, dbSaldo, cfg)) {
1316
            DBG_INFO(AQBANKING_LOGDOMAIN, "Error in tag");
1317
            GWEN_DB_Group_free(dbTemplate);
1318
            GWEN_Gui_ProgressEnd(progressId);
1319
            return -1;
1320
          }
1321
          dbDay=0;
1322
        }
1323
        else if (strcasecmp(id, "61")==0) {
1324
          if (!dbDay) {
1325
            DBG_WARN(AQBANKING_LOGDOMAIN,
1326
                     "Your bank does not send an opening saldo");
1327
            dbDay=GWEN_DB_GetGroup(data, GWEN_PATH_FLAGS_CREATE_GROUP, "day");
1328
          }
1329
    
1330
          DBG_INFO(AQBANKING_LOGDOMAIN, "Creating new transaction");
1331
          dbTransaction=GWEN_DB_GetGroup(dbDay, GWEN_PATH_FLAGS_CREATE_GROUP,
1332
                                         "transaction");
1333
          GWEN_DB_AddGroupChildren(dbTransaction, dbTemplate);
1334
          if (dbDate) {
1335
            GWEN_DB_NODE *dbT;
1336
    
1337
            /* dbDate is set upon parsing of tag 60F, use it as a default
1338
             * if possible */
1339
            dbT=GWEN_DB_GetGroup(dbTransaction, GWEN_DB_FLAGS_OVERWRITE_GROUPS,
1340
                                 "date");
1341
            assert(dbT);
1342
            GWEN_DB_AddGroupChildren(dbT, dbDate);
1343
          }
1344
          if (AHB_SWIFT940_Parse_61(tg, flags, dbTransaction, cfg)) {
1345
            DBG_INFO(AQBANKING_LOGDOMAIN, "Error in tag");
1346
            GWEN_DB_Group_free(dbTemplate);
1347
            GWEN_Gui_ProgressEnd(progressId);
1348
            return -1;
1349
          }
1350
        }
1351
        else if (strcasecmp(id, "86")==0) {
1352
          if (!dbTransaction) {
1353
            DBG_WARN(AQBANKING_LOGDOMAIN,
1354
                     "Bad sequence of tags (86 before 61), ignoring");
1355
          }
1356
          else {
1357
            if (AHB_SWIFT940_Parse_86(tg, flags, dbTransaction, cfg)) {
1358
              DBG_INFO(AQBANKING_LOGDOMAIN, "Error in tag");
1359
              GWEN_DB_Group_free(dbTemplate);
1360
              GWEN_Gui_ProgressEnd(progressId);
1361
              return -1;
1362
            }
1363
          }
1364
        }
1365
        else if (strcasecmp(id, "NS")==0) {
1366
          if (!dbTransaction) {
1367
            DBG_DEBUG(AQBANKING_LOGDOMAIN,
1368
                      "Ignoring NS tags outside transactions");
1369
          }
1370
          else {
1371
            if (AHB_SWIFT940_Parse_NS(tg, flags, dbTransaction, cfg)) {
1372
              DBG_INFO(AQBANKING_LOGDOMAIN, "Error in tag");
1373
              GWEN_DB_Group_free(dbTemplate);
1374
              GWEN_Gui_ProgressEnd(progressId);
1375
              return -1;
1376
            }
1377
          }
1378
        }
1379
        else if (strcmp(id, "21")==0) {
1380
          const char *p;
1381

    
1382
          p=AHB_SWIFT_Tag_GetData(tg);
1383
          assert (p);
1384
          if (0==strcmp(p, "NONREF")) {
1385
            DBG_INFO(AQBANKING_LOGDOMAIN, "Ignoring related reference '%s' in document tag 21.", p);
1386
          }
1387
          else {
1388
            DBG_WARN(AQBANKING_LOGDOMAIN, "Unexpected related reference '%s' in document tag 21 encountered.", p);
1389
          }
1390
        }
1391
        else {
1392
          DBG_WARN(AQBANKING_LOGDOMAIN, "Unexpected tag '%s' found.", id)
1393
          DBG_WARN(AQBANKING_LOGDOMAIN, "To debug set environment variable AQBANKING_LOGLEVEL=info and rerun");
1394
        }
1395

    
1396
      }
1397
    }
1398

    
1399
    if (GWEN_Gui_ProgressAdvance(progressId, GWEN_GUI_PROGRESS_ONE)==
1400
        GWEN_ERROR_USER_ABORTED) {
1401
      GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error,
1402
                           I18N("Aborted by user"));
1403
      GWEN_Gui_ProgressEnd(progressId);
1404
      GWEN_DB_Group_free(dbTemplate);
1405
      return GWEN_ERROR_USER_ABORTED;
1406
    }
1407

    
1408
    tg=AHB_SWIFT_Tag_List_Next(tg);
1409
  } /* while */
1410

    
1411
  GWEN_DB_Group_free(dbTemplate);
1412
  GWEN_Gui_ProgressEnd(progressId);
1413

    
1414
  return 0;
1415
}
1416