Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

aqbanking / src / libs / plugins / parsers / swift / swift940.c @ 8f5406fe

History | View | Annotate | Download (41.5 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 "aqbanking/i18n_l.h"
16

    
17
/* #include <aqhbci/aqhbci.h> */
18
#include <aqbanking/error.h>
19
#include <aqbanking/backendsupport/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

    
26
#include <ctype.h>
27

    
28

    
29

    
30
/*#define ENABLE_FULL_SEPA_LOG*/
31

    
32

    
33
#define CENTURY_CUTOFF_YEAR 79
34

    
35

    
36

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

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

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

    
55

    
56

    
57
static void _iso8859_1ToUtf8(const char *p, int size, GWEN_BUFFER *buf)
58
{
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
{
86
  GWEN_BUFFER *vbuf;
87
  int rv;
88

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

    
96

    
97

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

    
106
  p=AHB_SWIFT_Tag_GetData(tg);
107
  assert(p);
108

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

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

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

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

    
135
  if (*p) {
136
    char *s;
137
    int ll;
138

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

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

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

    
166
  return 0;
167
}
168

    
169

    
170

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

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

    
197
  if (isStructured) {
198
    AHB_SWIFT_SUBTAG_LIST *stlist;
199
    int rv;
200

    
201
    /* store code */
202
    GWEN_DB_SetIntValue(data, flags, "transactioncode", code);
203

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

    
217
        bufFullPurpose=GWEN_Buffer_new(0, 256, 0, 1);
218

    
219
        /* SEPA transaction, needs special handling */
220
        dbSepaTags=GWEN_DB_Group_new("sepa-tags");
221

    
222
        stg=AHB_SWIFT_SubTag_List_First(stlist);
223
        while (stg) {
224
          const char *s;
225
          int id;
226
          int intVal;
227

    
228
          id=AHB_SWIFT_SubTag_GetId(stg);
229
          s=AHB_SWIFT_SubTag_GetData(stg);
230
          switch (id) {
231
          case 0: /* Buchungstext */
232
            AHB_SWIFT__SetCharValue(data, flags, "transactionText", s);
233
            break;
234
          case 10: /* Primanota */
235
            AHB_SWIFT__SetCharValue(data, flags, "primanota", s);
236
            break;
237

    
238
          case 20:
239
          case 21:
240
          case 22:
241
          case 23:
242
          case 24:
243
          case 25:
244
          case 26:
245
          case 27:
246
          case 28:
247
          case 29:
248
          case 60:
249
          case 61:
250
          case 62:
251
          case 63: /* Verwendungszweck */
252
            /* store purpose in any case, if the transaction doesn't have SEPA tags
253
                   * we can just use what we produced here. */
254
            GWEN_DB_SetCharValue(data, GWEN_DB_FLAGS_DEFAULT, "purpose", s);
255
            /* possibly handle full purpose later */
256
            GWEN_Buffer_AppendString(bufFullPurpose, s);
257
            break;
258

    
259
          case 30: /* BLZ Gegenseite */
260
            AHB_SWIFT__SetCharValue(data, flags, "remoteBankCode", s);
261
            break;
262

    
263
          case 31: /* Kontonummer Gegenseite */
264
            AHB_SWIFT__SetCharValue(data, flags, "remoteAccountNumber", s);
265
            break;
266

    
267
          case 32:
268
          case 33: /* Name Auftraggeber */
269
            //DBG_ERROR(AQBANKING_LOGDOMAIN, "Setting remote name: [%s]", s);
270
            AHB_SWIFT__SetCharValue(data, flags, "remoteName", s);
271
            break;
272

    
273
          case 34: /* Textschluesselergaenzung */
274
            if (1==sscanf(s, "%d", &intVal)) {
275
              GWEN_DB_SetIntValue(data, flags, "textkeyExt", intVal);
276
            }
277
            else {
278
              DBG_WARN(AQBANKING_LOGDOMAIN,
279
                       "Value [%s] is not a number (textkeyext)", s);
280
            }
281
            break;
282

    
283
          case 38: /* IBAN */
284
            AHB_SWIFT__SetCharValue(data, flags, "remoteIban", s);
285
            break;
286

    
287
          default: /* ignore all other fields (if any) */
288
            DBG_WARN(AQBANKING_LOGDOMAIN, "Unknown :86: field \"%02d\" (%s) (%s)", id, s,
289
                     AHB_SWIFT_Tag_GetData(tg));
290
            break;
291
          } /* switch */
292
          stg=AHB_SWIFT_SubTag_List_Next(stg);
293
        } /* while */
294

    
295
        /* create real purpose string from data */
296
        if (GWEN_Buffer_GetUsedBytes(bufFullPurpose)) {
297
          GWEN_BUFFER *tbuf;
298
          int i;
299

    
300
          tbuf=GWEN_Buffer_new(0, 256, 0, 1);
301
          for (i=0; i<99; i++) {
302
            const char *s;
303

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

    
312
          GWEN_DB_DeleteVar(data, "purpose");
313
          GWEN_DB_SetCharValue(data, GWEN_DB_FLAGS_DEFAULT, "purpose", GWEN_Buffer_GetStart(tbuf));
314
          GWEN_Buffer_free(tbuf);
315
        }
316

    
317
        /* check for SEPA tags */
318
        if (GWEN_Buffer_GetUsedBytes(bufFullPurpose)) {
319
          const char *s;
320
          const char *sLastTagStart;
321

    
322
#ifdef ENABLE_FULL_SEPA_LOG
323
          DBG_ERROR(0, "FullPurposeBuffer:");
324
          GWEN_Buffer_Dump(bufFullPurpose, 2);
325
#endif
326

    
327
          s=GWEN_Buffer_GetStart(bufFullPurpose);
328
          sLastTagStart=s;
329

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

    
344
            /* found begin of the next SEPA field or end of buffer */
345
            if (s > sLastTagStart) {
346
              int tagLen;
347

    
348
              /* we currently have a field, close that first */
349
              tagLen=s-sLastTagStart;
350

    
351
#ifdef ENABLE_FULL_SEPA_LOG
352
              DBG_ERROR(0, "Current tag:");
353
              GWEN_Text_LogString(sLastTagStart, tagLen, 0, GWEN_LoggerLevel_Error);
354
#endif
355

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

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

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

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

    
382
                /* store tag, if still data left */
383
                if (tagLen>0) {
384
                  char *sCopyPayload;
385

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

    
400
                  sCopyPayload=my_strndup(sLastTagStart, tagLen);
401
                  GWEN_DB_SetCharValue(dbSepaTags, GWEN_DB_FLAGS_DEFAULT, "_purpose", sCopyPayload);
402
                  free(sCopyPayload);
403
                }
404
              }
405
            }
406

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

    
416
        } /* if GWEN_Buffer_GetUsedBytes(bufFullPurpose) */
417
        /* buffer no longer needed */
418
        GWEN_Buffer_free(bufFullPurpose);
419

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

    
424
#ifdef ENABLE_FULL_SEPA_LOG
425
          DBG_ERROR(0, "Got these SEPA tags:");
426
          GWEN_DB_Dump(dbSepaTags, 2);
427
#endif
428

    
429
          /* clear purpose variable, since we are about to add it back from SEPA tags */
430
          GWEN_DB_DeleteVar(data, "purpose");
431

    
432
          dbVar=GWEN_DB_GetFirstVar(dbSepaTags);
433
          while (dbVar) {
434
            const char *sVarName;
435

    
436
            sVarName=GWEN_DB_VariableName(dbVar);
437
            if (sVarName && *sVarName) {
438
              GWEN_BUFFER *tbuf;
439
              GWEN_DB_NODE *dbValue;
440

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

    
447
                s=GWEN_DB_GetCharValueFromNode(dbValue);
448
                if (s && *s)
449
                  GWEN_Buffer_AppendString(tbuf, s);
450

    
451
                dbValue=GWEN_DB_GetNextValue(dbValue);
452
              }
453

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

    
486
              GWEN_Buffer_free(tbuf);
487
            }
488

    
489
            dbVar=GWEN_DB_GetNextVar(dbVar);
490
          }
491
        }
492

    
493
#ifdef ENABLE_FULL_SEPA_LOG
494
        DBG_ERROR(0, "SEPA Tags:");
495
        GWEN_DB_Dump(dbSepaTags, 2);
496
#endif
497

    
498
        GWEN_DB_Group_free(dbSepaTags);
499
      } /* if sepa */
500
      else {
501
        AHB_SWIFT_SUBTAG *stg;
502

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

    
510
          id=AHB_SWIFT_SubTag_GetId(stg);
511
          s=AHB_SWIFT_SubTag_GetData(stg);
512
          switch (id) {
513
          case 0: /* Buchungstext */
514
            AHB_SWIFT__SetCharValue(data, flags, "transactionText", s);
515
            break;
516
          case 10: /* Primanota */
517
            AHB_SWIFT__SetCharValue(data, flags, "primanota", s);
518
            break;
519

    
520
          case 20:
521
          case 21:
522
          case 22:
523
          case 23:
524
          case 24:
525
          case 25:
526
          case 26:
527
          case 27:
528
          case 28:
529
          case 29:
530
          case 60:
531
          case 61:
532
          case 62:
533
          case 63: /* Verwendungszweck */
534
            AHB_SWIFT__SetCharValue(data, flags, "purpose", s);
535
            break;
536

    
537
          case 30: /* BLZ Gegenseite */
538
            AHB_SWIFT__SetCharValue(data, flags, "remoteBankCode", s);
539
            break;
540

    
541
          case 31: /* Kontonummer Gegenseite */
542
            AHB_SWIFT__SetCharValue(data, flags, "remoteAccountNumber", s);
543
            break;
544

    
545
          case 32:
546
          case 33: /* Name Auftraggeber */
547
            AHB_SWIFT__SetCharValue(data, flags, "remoteName", s);
548
            break;
549

    
550
          case 34: /* Textschluesselergaenzung */
551
            if (1==sscanf(s, "%d", &intVal)) {
552
              GWEN_DB_SetIntValue(data, flags, "textkeyExt", intVal);
553
            }
554
            else {
555
              DBG_WARN(AQBANKING_LOGDOMAIN,
556
                       "Value [%s] is not a number (textkeyext)", s);
557
            }
558
            break;
559

    
560
          case 38: /* IBAN */
561
            AHB_SWIFT__SetCharValue(data, flags, "remoteIban", s);
562
            break;
563

    
564
          default: /* ignore all other fields (if any) */
565
            DBG_WARN(AQBANKING_LOGDOMAIN, "Unknown :86: field \"%02d\" (%s) (%s)", id, s,
566
                     AHB_SWIFT_Tag_GetData(tg));
567
            break;
568
          } /* switch */
569
          stg=AHB_SWIFT_SubTag_List_Next(stg);
570
        } /* while */
571
      }
572
    } /* if really structured */
573
    AHB_SWIFT_SubTag_List_free(stlist);
574
  } /* if isStructured */
575
  else {
576
    char *pcopy=strdup(p);
577
    char *p1;
578

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

    
584
      p2=strchr(p1, 10);
585
      if (p2) {
586
        *p2=0;
587
        p2++;
588
      }
589

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

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

    
605
          kto+=8;
606
          blz=strchr(kto, '/');
607
          if (blz) {
608
            *blz=0;
609
            blz++;
610

    
611
            p3=blz;
612
            while (*p3 && isdigit(*p3))
613
              p3++;
614
            *p3=0;
615

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

    
631
  return 0;
632
}
633

    
634

    
635

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

    
652
  p=AHB_SWIFT_Tag_GetData(tg);
653
  assert(p);
654
  bleft=strlen(p);
655

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

    
671
  if (d3a==30 && d2a==2) {
672
    int ju;
673

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

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

    
723
    dt=GWEN_Date_fromGregorian(d1b, d2b, d3b);
724
    assert(dt);
725
    GWEN_DB_SetCharValue(data, GWEN_DB_FLAGS_DEFAULT, "date", GWEN_Date_GetString(dt));
726
    GWEN_Date_free(dt);
727
    p+=4;
728
    bleft-=4;
729
  }
730

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

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

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

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

    
804
  /* skip 'N' */
805
  p++;
806
  bleft--;
807

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

    
821
  /* customer reference (M) */
822
  if (bleft>0) {
823
    if (bleft>1) {
824
      if (*p=='/' && p[1]!='/') {
825
        p++;
826
        bleft--;
827
      }
828
    }
829

    
830
    p2=p;
831
    while (*p2 && *p2!='/' && *p2!=10)
832
      p2++;
833

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

    
852
  /* bank reference (K) */
853
  if (bleft>1) {
854
    if (*p=='/' && p[1]=='/') {
855
      /* found bank reference */
856
      p+=2;
857
      bleft-=2;
858

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

    
879
  /* more information ? */
880
  if (*p==10) {
881
    /* yes... */
882
    p++;
883
    bleft--;
884

    
885
    while (*p) {
886
      /* read extra information */
887
      if (*p=='/') {
888
        if (p[1]==0)
889
          return 0;
890

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

    
973
  return 0;
974
}
975

    
976

    
977

    
978
int AHB_SWIFT940_Parse_6_0_2(const AHB_SWIFT_TAG *tg,
979
                             uint32_t flags,
980
                             GWEN_DB_NODE *data,
981
                             GWEN_DB_NODE *cfg)
982
{
983
  const char *p;
984
  const char *p2;
985
  char *s;
986
  char buffer[32];
987
  unsigned int bleft;
988
  int d1, d2, d3;
989
  int neg;
990
  GWEN_DATE *dt;
991

    
992
  p=AHB_SWIFT_Tag_GetData(tg);
993
  assert(p);
994
  bleft=strlen(p);
995

    
996
  /* credit/debit mark (M) */
997
  if (bleft<2) {
998
    DBG_ERROR(AQBANKING_LOGDOMAIN, "Bad value string (%s)", p);
999
    GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error,
1000
                         "SWIFT: Bad value string");
1001
    return -1;
1002
  }
1003
  neg=0;
1004
  if (*p=='D' || *p=='d')
1005
    neg=1;
1006
  p++;
1007
  bleft--;
1008

    
1009
  /* date (M) */
1010
  if (bleft<6) {
1011
    DBG_ERROR(AQBANKING_LOGDOMAIN, "Missing date (%s)", p);
1012
    GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error,
1013
                         "SWIFT: Missing date");
1014
    return -1;
1015
  }
1016
  d1=((p[0]-'0')*10) + (p[1]-'0');
1017
  if (d1>CENTURY_CUTOFF_YEAR)
1018
    d1+=1900;
1019
  else
1020
    d1+=2000;
1021
  d2=((p[2]-'0')*10) + (p[3]-'0');
1022
  d3=((p[4]-'0')*10) + (p[5]-'0');
1023

    
1024
  dt=GWEN_Date_fromGregorian(d1, d2, d3);
1025
  assert(dt);
1026
  GWEN_DB_SetCharValue(data, GWEN_DB_FLAGS_OVERWRITE_VARS, "date", GWEN_Date_GetString(dt));
1027
  GWEN_Date_free(dt);
1028

    
1029
  p+=6;
1030
  bleft-=6;
1031

    
1032
  /* currency (M) */
1033
  if (!isdigit(*p)) {
1034
    /* only read currency if this is not part of the value (like in some
1035
     * swiss MT940) */
1036
    if (bleft<3) {
1037
      DBG_ERROR(AQBANKING_LOGDOMAIN, "Missing currency (%s)", p);
1038
      GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error,
1039
                           "SWIFT: Missing currency");
1040
      return -1;
1041
    }
1042
    memmove(buffer, p, 3);
1043
    buffer[3]=0;
1044
    AHB_SWIFT__SetCharValue(data, GWEN_DB_FLAGS_OVERWRITE_VARS, "value/currency", buffer);
1045
    p+=3;
1046
    bleft-=3;
1047
  }
1048

    
1049
  /* value (M) */
1050
  if (bleft<1) {
1051
    DBG_ERROR(AQBANKING_LOGDOMAIN, "Missing value (%s)", p);
1052
    GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error,
1053
                         "SWIFT: Missing value");
1054
    return -1;
1055
  }
1056

    
1057
  p2=p;
1058
  while (*p2 && (isdigit(*p2) || *p2==','))
1059
    p2++;
1060
  if (p2==p) {
1061
    DBG_ERROR(AQBANKING_LOGDOMAIN, "Bad value (%s)", p);
1062
    GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error,
1063
                         "SWIFT: Bad value");
1064
    return -1;
1065
  }
1066
  s=(char *)GWEN_Memory_malloc(p2-p+1+(neg?1:0));
1067
  if (neg) {
1068
    s[0]='-';
1069
    memmove(s+1, p, p2-p+1);
1070
    s[p2-p+1]=0;
1071
  }
1072
  else {
1073
    memmove(s, p, p2-p+1);
1074
    s[p2-p]=0;
1075
  }
1076
  AHB_SWIFT__SetCharValue(data, GWEN_DB_FLAGS_OVERWRITE_VARS, "value/value", s);
1077
  GWEN_Memory_dealloc(s);
1078
  /*bleft-=p2-p;*/
1079
  /*p=p2;*/
1080

    
1081
  return 0;
1082
}
1083

    
1084

    
1085

    
1086
int AHB_SWIFT940_Parse_NS(const AHB_SWIFT_TAG *tg,
1087
                          uint32_t flags,
1088
                          GWEN_DB_NODE *data,
1089
                          GWEN_DB_NODE *cfg)
1090
{
1091
  const char *p;
1092
  const char *p2;
1093

    
1094
  /* TODO: Use AHB_SWIFT_ParseSubTags */
1095
  p=AHB_SWIFT_Tag_GetData(tg);
1096
  assert(p);
1097

    
1098
  while (*p) {
1099
    int code;
1100

    
1101
    code=0;
1102
    /* read code */
1103
    if (strlen(p)>2) {
1104
      if (isdigit(p[0]) && isdigit(p[1])) {
1105
        /* starts with a two digit number */
1106
        code=(((p[0]-'0')*10) + (p[1]-'0'));
1107
        p+=2;
1108
      }
1109
    }
1110

    
1111
    /* search for end of line */
1112
    p2=p;
1113
    while (*p2 && *p2!=10 && *p2!=13)
1114
      p2++;
1115

    
1116
    if (code==0) {
1117
      DBG_WARN(AQBANKING_LOGDOMAIN, "No code in line");
1118
      p=p2;
1119
    }
1120
    else {
1121
      int len;
1122

    
1123
      len=p2-p;
1124
      if (len<1 || (len==1 && *p=='/')) {
1125
        DBG_DEBUG(AQBANKING_LOGDOMAIN, "Empty field %02d", code);
1126
      }
1127
      else {
1128
        char *s;
1129

    
1130
        s=(char *)GWEN_Memory_malloc(len+1);
1131
        memmove(s, p, len);
1132
        s[len]=0;
1133
        DBG_DEBUG(AQBANKING_LOGDOMAIN, "Got his field: %02d: %s", code, s);
1134

    
1135
        switch (code) {
1136
        case 1:
1137
        case 2:
1138
        case 3:
1139
        case 4:
1140
        case 5:
1141
        case 6:
1142
        case 7:
1143
        case 8:
1144
        case 9:
1145
        case 10:
1146
        case 11:
1147
        case 12:
1148
        case 13:
1149
        case 14:
1150
          AHB_SWIFT__SetCharValue(data, flags, "purpose", s);
1151
          break;
1152

    
1153
        case 15: /* Auftraggeber1 */
1154
        case 16: /* Auftraggeber2 */
1155
          AHB_SWIFT__SetCharValue(data, flags, "localName", s);
1156
          break;
1157

    
1158
        case 17: /* Buchungstext */
1159
          AHB_SWIFT__SetCharValue(data, flags, "transactionText", s);
1160
          break;
1161

    
1162
        case 18: /* Primanota */
1163
          AHB_SWIFT__SetCharValue(data, flags, "primanota", s);
1164
          break;
1165

    
1166
        case 19: /* Uhrzeit der Buchung */
1167
        case 20: /* Anzahl der Sammlerposten */
1168
        case 33: /* BLZ Auftraggeber */
1169
        case 34: /* Konto Auftraggeber */
1170
          break;
1171

    
1172
        default: /* ignore all other fields (if any) */
1173
          DBG_WARN(AQBANKING_LOGDOMAIN,
1174
                   "Unknown :NS: field \"%02d\" (%s) (%s)",
1175
                   code, s,
1176
                   AHB_SWIFT_Tag_GetData(tg));
1177
          break;
1178
        }
1179
        GWEN_Memory_dealloc(s);
1180
      }
1181
      p=p2;
1182
    }
1183

    
1184
    if (*p==10)
1185
      p++;
1186
    if (*p==13)
1187
      p++;
1188
    if (*p==10)
1189
      p++;
1190
  } /* while */
1191

    
1192
  return 0;
1193
}
1194

    
1195

    
1196
/* Import SWIFT MT940 data.
1197
   @param tl input: list of tags. Tags are lines in a SWIFT data block (block 4). A tag has an
1198
          id and content. See the AHB_SWIFT_Tag_new function for more information.
1199
 */
1200
int AHB_SWIFT940_Import(AHB_SWIFT_TAG_LIST *tl,
1201
                        GWEN_DB_NODE *data,
1202
                        GWEN_DB_NODE *cfg,
1203
                        uint32_t flags)
1204
{
1205
  AHB_SWIFT_TAG *tg;
1206
  GWEN_DB_NODE *dbDay=NULL;
1207
  GWEN_DB_NODE *dbTemplate=NULL;
1208
  GWEN_DB_NODE *dbTransaction=NULL;
1209
  GWEN_DB_NODE *dbDate=NULL;
1210
  uint32_t progressId;
1211
  const char *acceptTag20="*";
1212
  const char *rejectTag20=NULL;
1213
  int ignoreCurrentReport=0;
1214

    
1215
  acceptTag20=GWEN_DB_GetCharValue(cfg, "acceptTag20", 0, NULL);
1216
  if (acceptTag20 && *acceptTag20==0)
1217
    acceptTag20=NULL;
1218
  rejectTag20=GWEN_DB_GetCharValue(cfg, "rejectTag20", 0, NULL);
1219
  if (rejectTag20 && *rejectTag20==0)
1220
    rejectTag20=NULL;
1221

    
1222
  dbTemplate=GWEN_DB_Group_new("template");
1223

    
1224
  progressId=GWEN_Gui_ProgressStart(GWEN_GUI_PROGRESS_DELAY |
1225
                                    GWEN_GUI_PROGRESS_ALLOW_EMBED |
1226
                                    GWEN_GUI_PROGRESS_SHOW_PROGRESS |
1227
                                    GWEN_GUI_PROGRESS_SHOW_ABORT,
1228
                                    I18N("Importing SWIFT tags..."),
1229
                                    NULL,
1230
                                    AHB_SWIFT_Tag_List_GetCount(tl),
1231
                                    0);
1232

    
1233
  tg=AHB_SWIFT_Tag_List_First(tl);
1234
  while (tg) {
1235
    const char *id;
1236

    
1237
    id=AHB_SWIFT_Tag_GetId(tg);
1238
    assert(id);
1239

    
1240
    if (strcasecmp(id, "20")==0) {
1241
      if (acceptTag20 || rejectTag20) {
1242
        const char *p;
1243

    
1244
        p=AHB_SWIFT_Tag_GetData(tg);
1245
        assert(p);
1246
        if (rejectTag20) {
1247
          if (-1!=GWEN_Text_ComparePattern(p, rejectTag20, 0)) {
1248
            DBG_INFO(AQBANKING_LOGDOMAIN, "Ignoring report [%s]", p);
1249
            ignoreCurrentReport=1;
1250
          }
1251
          else {
1252
            ignoreCurrentReport=0;
1253
          }
1254
        }
1255
        else if (acceptTag20) {
1256
          if (-1==GWEN_Text_ComparePattern(p, acceptTag20, 0)) {
1257
            DBG_INFO(AQBANKING_LOGDOMAIN,
1258
                     "Ignoring report [%s] (not matching [%s])",
1259
                     p, acceptTag20);
1260
            ignoreCurrentReport=1;
1261
          }
1262
          else {
1263
            ignoreCurrentReport=0;
1264
          }
1265
        }
1266

    
1267
      }
1268
    }
1269
    else {
1270
      if (!ignoreCurrentReport) {
1271
        if (strcasecmp(id, "25")==0) { /* LocalAccount */
1272
          if (AHB_SWIFT940_Parse_25(tg, flags, dbTemplate, cfg)) {
1273
            DBG_INFO(AQBANKING_LOGDOMAIN, "Error in tag");
1274
            GWEN_DB_Group_free(dbTemplate);
1275
            GWEN_Gui_ProgressEnd(progressId);
1276
            return -1;
1277
          }
1278
        }
1279
        else if (strcasecmp(id, "28C")==0) {
1280
          /* Sequence/Statement Number - currently ignored */
1281
          /* PostFinance statements don't have a correctly incrementing count... */
1282
        }
1283
        else if (strcasecmp(id, "60M")==0 || /* Interim StartSaldo */
1284
                 strcasecmp(id, "60F")==0) { /* StartSaldo */
1285
          GWEN_DB_NODE *dbSaldo;
1286
          const char *curr;
1287

    
1288
          /* start a new day */
1289
          dbDay=GWEN_DB_GetGroup(data, GWEN_PATH_FLAGS_CREATE_GROUP, "day");
1290

    
1291
          dbTransaction=0;
1292
          DBG_INFO(AQBANKING_LOGDOMAIN, "Starting new day");
1293
          if (strcasecmp(id, "60F")==0)
1294
            dbSaldo=GWEN_DB_GetGroup(dbDay, GWEN_PATH_FLAGS_CREATE_GROUP, "StartSaldo");
1295
          else
1296
            dbSaldo=GWEN_DB_GetGroup(dbDay, GWEN_PATH_FLAGS_CREATE_GROUP, "InterimStartSaldo");
1297
          GWEN_DB_AddGroupChildren(dbSaldo, dbTemplate);
1298
          if (AHB_SWIFT940_Parse_6_0_2(tg, flags, dbSaldo, cfg)) {
1299
            DBG_INFO(AQBANKING_LOGDOMAIN, "Error in tag");
1300
            GWEN_DB_Group_free(dbTemplate);
1301
            GWEN_Gui_ProgressEnd(progressId);
1302
            return -1;
1303
          }
1304
          else {
1305
            dbDate=GWEN_DB_GetGroup(dbSaldo, GWEN_PATH_FLAGS_NAMEMUSTEXIST,
1306
                                    "date");
1307
          }
1308

    
1309
          curr=GWEN_DB_GetCharValue(dbSaldo, "value/currency", 0, 0);
1310
          if (curr) {
1311
            AHB_SWIFT__SetCharValue(dbTemplate, flags,
1312
                                    "value/currency", curr);
1313
          }
1314
          if (strcasecmp(id, "60F")==0)
1315
            GWEN_DB_SetCharValue(dbSaldo, GWEN_DB_FLAGS_OVERWRITE_VARS, "type", "final");
1316
          else
1317
            GWEN_DB_SetCharValue(dbSaldo, GWEN_DB_FLAGS_OVERWRITE_VARS, "type", "interim");
1318

    
1319
        }
1320
        else if (strcasecmp(id, "62M")==0 || /* Interim EndSaldo */
1321
                 strcasecmp(id, "62F")==0) { /* EndSaldo */
1322
          GWEN_DB_NODE *dbSaldo;
1323

    
1324
          /* end current day */
1325
          dbTransaction=0;
1326
          if (!dbDay) {
1327
            DBG_WARN(AQBANKING_LOGDOMAIN, "Your bank does not send an opening saldo");
1328
            dbDay=GWEN_DB_GetGroup(data, GWEN_PATH_FLAGS_CREATE_GROUP, "day");
1329
          }
1330
          dbSaldo=GWEN_DB_GetGroup(dbDay, GWEN_PATH_FLAGS_CREATE_GROUP, "EndSaldo");
1331
          GWEN_DB_AddGroupChildren(dbSaldo, dbTemplate);
1332
          if (AHB_SWIFT940_Parse_6_0_2(tg, flags, dbSaldo, cfg)) {
1333
            DBG_INFO(AQBANKING_LOGDOMAIN, "Error in tag");
1334
            GWEN_DB_Group_free(dbTemplate);
1335
            GWEN_Gui_ProgressEnd(progressId);
1336
            return -1;
1337
          }
1338
          if (strcasecmp(id, "62F")==0)
1339
            GWEN_DB_SetCharValue(dbSaldo, GWEN_DB_FLAGS_OVERWRITE_VARS, "type", "final");
1340
          else
1341
            GWEN_DB_SetCharValue(dbSaldo, GWEN_DB_FLAGS_OVERWRITE_VARS, "type", "interim");
1342
          dbDay=0;
1343

    
1344
        }
1345
        else if (strcasecmp(id, "61")==0) {
1346
          if (!dbDay) {
1347
            DBG_WARN(AQBANKING_LOGDOMAIN,
1348
                     "Your bank does not send an opening saldo");
1349
            dbDay=GWEN_DB_GetGroup(data, GWEN_PATH_FLAGS_CREATE_GROUP, "day");
1350
          }
1351

    
1352
          DBG_INFO(AQBANKING_LOGDOMAIN, "Creating new transaction");
1353
          dbTransaction=GWEN_DB_GetGroup(dbDay, GWEN_PATH_FLAGS_CREATE_GROUP,
1354
                                         "transaction");
1355
          GWEN_DB_AddGroupChildren(dbTransaction, dbTemplate);
1356
          if (dbDate) {
1357
            GWEN_DB_NODE *dbT;
1358

    
1359
            /* dbDate is set upon parsing of tag 60F, use it as a default
1360
             * if possible */
1361
            dbT=GWEN_DB_GetGroup(dbTransaction, GWEN_DB_FLAGS_OVERWRITE_GROUPS,
1362
                                 "date");
1363
            assert(dbT);
1364
            GWEN_DB_AddGroupChildren(dbT, dbDate);
1365
          }
1366
          if (AHB_SWIFT940_Parse_61(tg, flags, dbTransaction, cfg)) {
1367
            DBG_INFO(AQBANKING_LOGDOMAIN, "Error in tag");
1368
            GWEN_DB_Group_free(dbTemplate);
1369
            GWEN_Gui_ProgressEnd(progressId);
1370
            return -1;
1371
          }
1372
        }
1373
        else if (strcasecmp(id, "86")==0) {
1374
          if (!dbTransaction) {
1375
            DBG_WARN(AQBANKING_LOGDOMAIN,
1376
                     "Bad sequence of tags (86 before 61), ignoring");
1377
          }
1378
          else {
1379
            if (AHB_SWIFT940_Parse_86(tg, flags, dbTransaction, cfg)) {
1380
              DBG_INFO(AQBANKING_LOGDOMAIN, "Error in tag");
1381
              GWEN_DB_Group_free(dbTemplate);
1382
              GWEN_Gui_ProgressEnd(progressId);
1383
              return -1;
1384
            }
1385
          }
1386
        }
1387
        else if (strcasecmp(id, "NS")==0) {
1388
          if (!dbTransaction) {
1389
            DBG_DEBUG(AQBANKING_LOGDOMAIN,
1390
                      "Ignoring NS tags outside transactions");
1391
          }
1392
          else {
1393
            if (AHB_SWIFT940_Parse_NS(tg, flags, dbTransaction, cfg)) {
1394
              DBG_INFO(AQBANKING_LOGDOMAIN, "Error in tag");
1395
              GWEN_DB_Group_free(dbTemplate);
1396
              GWEN_Gui_ProgressEnd(progressId);
1397
              return -1;
1398
            }
1399
          }
1400
        }
1401
        else if (strcmp(id, "21")==0) {
1402
          const char *p;
1403

    
1404
          p=AHB_SWIFT_Tag_GetData(tg);
1405
          assert(p);
1406
          if (0==strcmp(p, "NONREF")) {
1407
            DBG_INFO(AQBANKING_LOGDOMAIN, "Ignoring related reference '%s' in document tag 21.", p);
1408
          }
1409
          else {
1410
            DBG_WARN(AQBANKING_LOGDOMAIN, "Unexpected related reference '%s' in document tag 21 encountered.", p);
1411
          }
1412
        }
1413
        else if (strcmp(id, "13")==0 ||  /* "Erstellungszeitpunkt */
1414
                 strcmp(id, "34F")==0 || /* "Mindestbetrag" (sometimes contains some strange values) */
1415
                 strcmp(id, "90D")==0 || /* "Anzahl und Summe Soll-Buchungen" (examples I've seen are invalid anyway) */
1416
                 strcmp(id, "90C")==0) { /* "Anzahl und Summe Haben-Buchungen" (examples I've seen are invalid anyway) */
1417
          /* ignore some well known tags */
1418
          DBG_INFO(AQBANKING_LOGDOMAIN, "Ignoring well known tag \"%s\"", id);
1419
        }
1420
        else {
1421
          DBG_WARN(AQBANKING_LOGDOMAIN,
1422
                   "Unhandled tag '%s' found. "
1423
                   "This only means the file contains info we currently don't read, "
1424
                   "in most cases this is unimportant data.",
1425
                   id);
1426
          DBG_WARN(AQBANKING_LOGDOMAIN,
1427
                   "To debug set environment variable AQBANKING_LOGLEVEL=info and rerun,"
1428
                   "otherwise just ignore this message.");
1429
        }
1430

    
1431
      }
1432
    }
1433

    
1434
    if (GWEN_Gui_ProgressAdvance(progressId, GWEN_GUI_PROGRESS_ONE)==
1435
        GWEN_ERROR_USER_ABORTED) {
1436
      GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error,
1437
                           I18N("Aborted by user"));
1438
      GWEN_Gui_ProgressEnd(progressId);
1439
      GWEN_DB_Group_free(dbTemplate);
1440
      return GWEN_ERROR_USER_ABORTED;
1441
    }
1442

    
1443
    tg=AHB_SWIFT_Tag_List_Next(tg);
1444
  } /* while */
1445

    
1446
  GWEN_DB_Group_free(dbTemplate);
1447
  GWEN_Gui_ProgressEnd(progressId);
1448

    
1449
  return 0;
1450
}
1451