Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

aqbanking / src / libs / plugins / parsers / swift / swift.c @ 5bc3f3e7

History | View | Annotate | Download (24.6 KB)

1
/***************************************************************************
2
 begin       : Fri Apr 02 2004
3
 copyright   : (C) 2004-2010 by Martin Preuss
4
 email       : martin@libchipcard.de
5

6
 ***************************************************************************
7
 *          Please see toplevel file COPYING for license details           *
8
 ***************************************************************************/
9

    
10

    
11
#ifdef HAVE_CONFIG_H
12
# include <config.h>
13
#endif
14

    
15
#include "swift_p.h"
16
#include "swift940_l.h"
17
#include "swift535_l.h"
18
#include "i18n_l.h"
19
#include <aqbanking/banking.h>
20
#include <gwenhywfar/text.h>
21
#include <gwenhywfar/debug.h>
22
#include <gwenhywfar/gui.h>
23
#include <gwenhywfar/fastbuffer.h>
24
#include <gwenhywfar/dbio_be.h>
25
#include <gwenhywfar/syncio_file.h>
26
#include <gwenhywfar/syncio_buffered.h>
27

    
28
#include <stdlib.h>
29
#include <string.h>
30
#include <assert.h>
31
#include <ctype.h>
32
#include <sys/types.h>
33
#include <sys/stat.h>
34
#include <fcntl.h>
35
#include <errno.h>
36

    
37

    
38
GWEN_LIST_FUNCTIONS(AHB_SWIFT_TAG, AHB_SWIFT_Tag);
39
GWEN_LIST_FUNCTIONS(AHB_SWIFT_SUBTAG, AHB_SWIFT_SubTag);
40

    
41

    
42

    
43
int AHB_SWIFT_Condense(char *buffer, int keepMultipleBlanks) {
44
  char *src;
45
  char *dst;
46

    
47
  if (keepMultipleBlanks) {
48
    src=buffer;
49
    dst=buffer;
50

    
51
    /* only remove line feed */
52
    while(*src) {
53
      if (*src!=10) {
54
        *dst=*src;
55
        dst++;
56
      }
57
      src++;
58
    } /* while */
59
  }
60
  else {
61
    int lastWasBlank;
62

    
63
    src=buffer;
64
    while(*src && isspace(*src)) src++;
65
    dst=buffer;
66
    lastWasBlank=0;
67
    while(*src) {
68
      if (isspace(*src) && (*src!=10)) {
69
        if (!lastWasBlank) {
70
          *(dst++)=' ';
71
          lastWasBlank=1;
72
        }
73
      }
74
      else {
75
        lastWasBlank=0;
76
        if (*src!=10) {
77
          *(dst++)=*src;
78
        }
79
      }
80
      src++;
81
    } /* while */
82
  }
83
  *dst=0;
84
  return 0;
85
}
86

    
87

    
88

    
89
/* Create a tag object from a tag ID and the content of the tag. Example:
90
   Given the following line inside a SWIFT data block:
91

92
     :28C:7/1
93

94
   You'd call AHB_SWIFT_Tag_new like this:
95

96
     AHB_SWIFT_Tag_new("28C", "7/1")
97

98
   @return a new AHB_SWIFT_TAG
99
 */
100
AHB_SWIFT_TAG *AHB_SWIFT_Tag_new(const char *id,
101
                                 const char *content){
102
  AHB_SWIFT_TAG *tg;
103

    
104
  assert(id);
105
  assert(content);
106
  GWEN_NEW_OBJECT(AHB_SWIFT_TAG, tg);
107
  GWEN_LIST_INIT(AHB_SWIFT_TAG, tg);
108
  tg->id=strdup(id);
109
  tg->content=strdup(content);
110

    
111
  return tg;
112
}
113

    
114

    
115

    
116
void AHB_SWIFT_Tag_free(AHB_SWIFT_TAG *tg){
117
  if (tg) {
118
    GWEN_LIST_FINI(AHB_SWIFT_TAG, tg);
119
    free(tg->id);
120
    free(tg->content);
121
    GWEN_FREE_OBJECT(tg);
122
  }
123
}
124

    
125

    
126

    
127
const char *AHB_SWIFT_Tag_GetId(const AHB_SWIFT_TAG *tg){
128
  assert(tg);
129
  return tg->id;
130
}
131

    
132

    
133

    
134
const char *AHB_SWIFT_Tag_GetData(const AHB_SWIFT_TAG *tg){
135
  assert(tg);
136
  return tg->content;
137
}
138

    
139

    
140

    
141

    
142

    
143
AHB_SWIFT_SUBTAG *AHB_SWIFT_SubTag_new(int id, const char *content, int clen) {
144
  AHB_SWIFT_SUBTAG *stg;
145

    
146
  assert(content);
147
  GWEN_NEW_OBJECT(AHB_SWIFT_SUBTAG, stg);
148
  GWEN_LIST_INIT(AHB_SWIFT_SUBTAG, stg);
149
  stg->id=id;
150
  if (clen==-1)
151
    clen=strlen(content);
152
  stg->content=(char*)malloc(clen+1);
153
  memmove(stg->content, content, clen);
154
  stg->content[clen]=0;
155
  return stg;
156
}
157

    
158

    
159

    
160
void AHB_SWIFT_SubTag_free(AHB_SWIFT_SUBTAG *stg) {
161
  if (stg) {
162
    GWEN_LIST_FINI(AHB_SWIFT_SUBTAG, stg);
163
    free(stg->content);
164
    GWEN_FREE_OBJECT(stg);
165
  }
166
}
167

    
168

    
169

    
170
int AHB_SWIFT_SubTag_GetId(const AHB_SWIFT_SUBTAG *stg){
171
  assert(stg);
172
  return stg->id;
173
}
174

    
175

    
176

    
177
const char *AHB_SWIFT_SubTag_GetData(const AHB_SWIFT_SUBTAG *stg){
178
  assert(stg);
179
  return stg->content;
180
}
181

    
182

    
183

    
184
AHB_SWIFT_SUBTAG *AHB_SWIFT_FindSubTagById(const AHB_SWIFT_SUBTAG_LIST *stlist, int id) {
185
  AHB_SWIFT_SUBTAG *stg;
186

    
187
  stg=AHB_SWIFT_SubTag_List_First(stlist);
188
  while(stg) {
189
    if (stg->id==id)
190
      break;
191
    stg=AHB_SWIFT_SubTag_List_Next(stg);
192
  }
193

    
194
  return stg;
195
}
196

    
197

    
198

    
199
void AHB_SWIFT_SubTag_Condense(AHB_SWIFT_SUBTAG *stg, int keepMultipleBlanks) {
200
  assert(stg);
201
  AHB_SWIFT_Condense(stg->content, keepMultipleBlanks);
202
}
203

    
204

    
205

    
206
int AHB_SWIFT_GetNextSubTag(const char **sptr, AHB_SWIFT_SUBTAG **tptr) {
207
  const char *s;
208
  int id=0;
209
  int nextId=0;
210
  const char *content=NULL;
211
  AHB_SWIFT_SUBTAG *stg;
212

    
213
  s=*sptr;
214
  if (*s=='?') {
215
    const char *t;
216

    
217
    t=s;
218
    t++;
219
    if (*t==0x0a)
220
      t++;
221
    if (*t && isdigit(*t)) {
222
      id=(*(t++)-'0')*10;
223
      if (*t==0x0a)
224
        t++;
225
      if (*t && isdigit(*t)) {
226
        id+=*(t++)-'0';
227
        s=t;
228
      }
229
    }
230
  }
231
  content=s;
232

    
233
  /* find end of content */
234
  for (;;) {
235
    while(*s && *s!='?')
236
      s++;
237

    
238
    if (*s=='?') {
239
      const char *t;
240
  
241
      t=s;
242
      t++;
243
      if (*t==0x0a)
244
        t++;
245
      if (*t && isdigit(*t)) {
246
        nextId=(*(t++)-'0')*10;
247
        if (*t==0x0a)
248
          t++;
249
        if (*t && isdigit(*t)) {
250
          /*nextId+=*(t++)-'0';*/
251
          /* TODO: check nextId */
252
          /* s is the beginning of a new subtag, so the end has been found */
253
          break;
254
        }
255
        else {
256
          /* next is not a digit, so this is not the begin of a new tag */
257
          if (*s)
258
            s++;
259
          else
260
            /* end of string, also end of content */
261
            break;
262
        }
263
      }
264
      else {
265
        /* next is not a digit, so this is not the begin of a new tag */
266
        if (*s)
267
          s++;
268
        else
269
          /* end of string, also end of content */
270
          break;
271
      }
272
    }
273
    else if (*s)
274
      /* not the beginning of a new tag, continue */
275
      s++;
276
    else
277
      /* end of string, also end of content */
278
      break;
279
  }
280

    
281
  /* create subtag */
282
  stg=AHB_SWIFT_SubTag_new(id, content, s-content);
283

    
284
  /* update return pointers */
285
  *tptr=stg;
286
  *sptr=s;
287
  return 0;
288
}
289

    
290

    
291

    
292
int AHB_SWIFT_ParseSubTags(const char *s, AHB_SWIFT_SUBTAG_LIST *stlist, int keepMultipleBlanks) {
293
  while(*s) {
294
    int rv;
295
    AHB_SWIFT_SUBTAG *stg=NULL;
296

    
297
    rv=AHB_SWIFT_GetNextSubTag(&s, &stg);
298
    if (rv) {
299
      DBG_INFO(AQBANKING_LOGDOMAIN, "here (%d)", rv);
300
      return rv;
301
    }
302
    AHB_SWIFT_SubTag_Condense(stg, keepMultipleBlanks);
303
    AHB_SWIFT_SubTag_List_Add(stg, stlist);
304
  }
305

    
306
  return 0;
307
}
308

    
309

    
310

    
311

    
312
/* This reads a line within a SWIFT data block (block 4)
313
   @param *fb     pointer to a GWEN_FAST_BUFFER input buffer
314
   @param *buffer pointer to a char* output buffer 
315
   @param s       size of the output buffer
316
   */
317
int AHB_SWIFT_ReadLine(GWEN_FAST_BUFFER *fb,
318
                       char *buffer,
319
                       unsigned int s){
320
  int lastWasAt;
321
  char *obuffer;
322

    
323
  assert(fb);
324
  assert(buffer);
325
  assert(s);
326

    
327
  obuffer=buffer;
328

    
329
  *buffer=0;
330
  lastWasAt=0;
331

    
332
  for(;;) {
333
    int c;
334

    
335
    GWEN_FASTBUFFER_PEEKBYTE(fb, c);
336
    if (c<0) {
337
      if (c==GWEN_ERROR_EOF) {
338
        if (*obuffer==0) {
339
          return GWEN_ERROR_EOF;
340
        }
341
        break;
342
      }
343
      else  {
344
        DBG_ERROR(AQBANKING_LOGDOMAIN, "Error reading from stream");
345
        *buffer=0;
346
        return c;
347
      }
348
    }
349
    if (c=='}') {
350
      /* stop on curly bracket without reading it */
351
      break;
352
    }
353
    GWEN_FASTBUFFER_READBYTE(fb, c);
354

    
355
    if (c==10)
356
      break;
357
    else if (c=='@') {
358
      if (lastWasAt)
359
        break;
360
      else
361
        lastWasAt=1;
362
    }
363
    else {
364
      lastWasAt=0;
365
      if (c!=13) {
366
        if (s<2) {
367
          DBG_ERROR(AQBANKING_LOGDOMAIN, "Buffer full (line too long)");
368
          *buffer=0;
369
          return -1;
370
        }
371
        *buffer=c;
372
        buffer++;
373
        s--;
374
      }
375
    }
376
  } /* for */
377
  *buffer=0;
378

    
379
  /*GWEN_Text_DumpString(obuffer, buffer-obuffer+1, stderr, 2);*/
380

    
381
  return 0;
382
}
383

    
384

    
385

    
386
/* This will read the contents of a SWIFT data block ({4: ... })
387
   inside of a SWIFT document
388
 */
389
int AHB_SWIFT_ReadTextBlock(GWEN_FAST_BUFFER *fb,
390
                            AHB_SWIFT_TAG_LIST *tl,
391
                            unsigned int maxTags) {
392
  GWEN_BUFFER *lbuf;
393
  char buffer[AHB_SWIFT_MAXLINELEN];
394
  char *p;
395
  char *p2;
396
  AHB_SWIFT_TAG *tag;
397
  int tagCount;
398
  int rv;
399

    
400
  lbuf=GWEN_Buffer_new(0, AHB_SWIFT_MAXLINELEN, 0, 1);
401
  tagCount=0;
402

    
403
  /* read first line, should be empty */
404
  for (;;) {
405
    rv=AHB_SWIFT_ReadLine(fb, buffer, sizeof(buffer)-1);
406
    if (rv<0) {
407
      if (rv==GWEN_ERROR_EOF) {
408
        GWEN_Buffer_free(lbuf);
409
        return 1;
410
      }
411
      DBG_ERROR(AQBANKING_LOGDOMAIN, "Error reading from stream (%d)", rv);
412
      GWEN_Buffer_free(lbuf);
413
      return rv;
414
    }
415
    if (buffer[0])
416
      /* line is not empty, let's dance */
417
      break;
418
  } /* for */
419

    
420
  if (buffer[0]=='-') {
421
    DBG_WARN(AQBANKING_LOGDOMAIN, "Empty report");
422
    GWEN_Buffer_free(lbuf);
423
    return 1;
424
  }
425

    
426
  for (;;) {
427
    /* get a tag */
428
    GWEN_Buffer_Reset(lbuf);
429

    
430
    if (buffer[0]) {
431
      if (buffer[0]=='-' && buffer[1]==0) {
432
        DBG_INFO(AQBANKING_LOGDOMAIN, "End of SWIFT document reached");
433
        GWEN_Buffer_free(lbuf);
434
        return 0;
435
      }
436
      GWEN_Buffer_AppendString(lbuf, buffer);
437
    }
438

    
439
    /* get a complete tag, don't be fooled by CR/LF inside a tag.
440
     * well, normally a CR/LF sequence ends a tag. However, in :86: tags
441
     * we may have fields which might include CR/LF sequences...
442
     */
443
    for (;;) {
444
      buffer[0]=0;
445
      GWEN_FASTBUFFER_PEEKBYTE(fb, rv);
446
      if (rv<0) {
447
        if (rv==GWEN_ERROR_EOF) {
448
          /* eof met */
449
          if (GWEN_Buffer_GetUsedBytes(lbuf)==0) {
450
            /* eof met and buffer empty, finished */
451
            DBG_INFO(AQBANKING_LOGDOMAIN,
452
                     "SWIFT document not terminated by \'-\'");
453
            GWEN_Buffer_free(lbuf);
454
            return 0;
455
          }
456
          else {
457
            buffer[0]='-';
458
            buffer[1]=0;
459
            break;
460
          }
461
        }
462
        else {
463
          DBG_INFO(AQBANKING_LOGDOMAIN, "here (%d)", rv);
464
          GWEN_Buffer_free(lbuf);
465
          return rv;
466
        }
467
      }
468
      else {
469
        /* read next line */
470
        rv=AHB_SWIFT_ReadLine(fb, buffer, sizeof(buffer)-1);
471
        if (rv<0) {
472
          DBG_ERROR(AQBANKING_LOGDOMAIN,
473
                    "Error reading from stream (%d)", rv);
474
          GWEN_Buffer_free(lbuf);
475
          return rv;
476
        }
477
      }
478

    
479
      /* check whether the line starts with a new tag (:123x:) */
480
      if (buffer[0]==':') {
481
        const char *s;
482

    
483
        if (strncasecmp(buffer, ":NS:", 4)==0) {
484
          break;
485
        }
486
        else {
487
          s=buffer+1;
488
          while(*s && isdigit(*s))
489
            s++;
490
          if (isalpha(*s))
491
            s++;
492
          if (*s==':') {
493
            DBG_DEBUG(AQBANKING_LOGDOMAIN, "End of tag reached");
494
            break;
495
          }
496
        }
497
      }
498

    
499
      /* check whether the line starts with a ":" or "-" */
500
      if (buffer[0]=='-' && buffer[1]==0) {
501
        /* it does, so the buffer contains the next line, go handle the
502
         * previous line */
503
        DBG_DEBUG(AQBANKING_LOGDOMAIN, "End of doc reached");
504
        break;
505
      }
506

    
507
      /* it doesn't, so there is a CR/LF inside the tag */
508
      if (GWEN_Buffer_GetUsedBytes(lbuf)>AHB_SWIFT_MAXLINELEN*4) {
509
        DBG_ERROR(AQBANKING_LOGDOMAIN,
510
                  "Too many bytes in line, maybe not SWIFT");
511
        GWEN_Buffer_free(lbuf);
512
        return -1;
513
      }
514

    
515
      GWEN_Buffer_AppendByte(lbuf, 10);
516
      GWEN_Buffer_AppendString(lbuf, buffer);
517
    } /* for */
518

    
519
    /* tag complete, parse it */
520
    p=GWEN_Buffer_GetStart(lbuf);
521

    
522
    if (*p!=':') {
523
      DBG_ERROR(AQBANKING_LOGDOMAIN,
524
                "Error in SWIFT data: no tag name");
525
      GWEN_Text_DumpString(GWEN_Buffer_GetStart(lbuf),
526
                           GWEN_Buffer_GetUsedBytes(lbuf), 2);
527
      GWEN_Buffer_free(lbuf);
528
      return -1;
529
    }
530
    p++;
531
    p2=p;
532
    while(*p2 && *p2!=':') p2++;
533
    if (*p2!=':') {
534
      DBG_ERROR(AQBANKING_LOGDOMAIN,
535
                "Error in SWIFT data: incomplete tag name");
536
      GWEN_Text_DumpString(GWEN_Buffer_GetStart(lbuf),
537
                           GWEN_Buffer_GetUsedBytes(lbuf), 2);
538
      GWEN_Buffer_free(lbuf);
539
      return -1;
540
    }
541
    *p2=0;
542
    p2++;
543

    
544
    /* create tag */
545
    DBG_DEBUG(AQBANKING_LOGDOMAIN,
546
              "Creating tag \"%s\" (%s)", p, p2);
547
    tag=AHB_SWIFT_Tag_new(p, p2);
548
    AHB_SWIFT_Tag_List_Add(tag, tl);
549
    tagCount++;
550
    if (maxTags && tagCount>=maxTags) {
551
      DBG_INFO(AQBANKING_LOGDOMAIN,
552
               "Read maximum number of tags (%d)", tagCount);
553
      GWEN_Buffer_free(lbuf);
554
      return 0;
555
    }
556

    
557
  } /* for */
558

    
559
  /* we should never reach this point... */
560
  return 0;
561
}
562

    
563

    
564
#if 0
565
int AHB_SWIFT_ReadDocument(GWEN_FAST_BUFFER *fb,
566
                           AHB_SWIFT_TAG_LIST *tl,
567
                           unsigned int maxTags) {
568
  int rv;
569
  int c;
570
  int isFullSwift=0;
571

572
  /* check for first character being a curly bracket */
573
  for (;;) {
574
    GWEN_FASTBUFFER_PEEKBYTE(fb, c);
575
    if (c<0) {
576
      if (c==GWEN_ERROR_EOF) {
577
        DBG_INFO(AQBANKING_LOGDOMAIN,
578
                 "EOF met, empty document");
579
        return 1;
580
      }
581
      DBG_ERROR(AQBANKING_LOGDOMAIN,
582
                "Error reading from BIO (%d)", c);
583
      return c;
584
    }
585
    if (c=='{') {
586
      isFullSwift=1;
587
      break;
588
    }
589
    else if (c>3)
590
      /* some SWIFT documents contain 01 at the beginning and 03 at the end,
591
       * we simply skip those characters here */
592
      break;
593
    GWEN_FASTBUFFER_READBYTE(fb, c);
594
  } /* for */
595

596
  if (isFullSwift) {
597
    /* read header, seek block 4 */
598
    for (;;) {
599
      int err;
600
      char swhead[4];
601
      unsigned int bsize;
602
      int curls=0;
603

604
      /* read block start ("{n:...") */
605
      bsize=3;
606

607
      GWEN_FASTBUFFER_READFORCED(fb, err, swhead, bsize);
608
      if (err<0) {
609
        DBG_ERROR_ERR(AQBANKING_LOGDOMAIN, err);
610
        return err;
611
      }
612
      if (swhead[2]!=':') {
613
        DBG_ERROR(AQBANKING_LOGDOMAIN, "Not a SWIFT block");
614
        GWEN_Text_DumpString(swhead, 4, 2);
615
        return GWEN_ERROR_BAD_DATA;
616
      }
617
      DBG_DEBUG(0, "Reading block %d", swhead[1]-'0');
618
      if (swhead[1]=='4')
619
        break;
620

621
      /* skip block */
622
      for (;;) {
623
        GWEN_FASTBUFFER_READBYTE(fb, c);
624
        if (c<0) {
625
          if (c==GWEN_ERROR_EOF) {
626
            DBG_ERROR(AQBANKING_LOGDOMAIN,
627
                      "EOF met (%d)", c);
628
            return GWEN_ERROR_EOF;
629
          }
630
          DBG_ERROR(AQBANKING_LOGDOMAIN,
631
                    "Error reading from BIO (%d)", c);
632
          return GWEN_ERROR_READ;
633
        }
634
        if (c=='{')
635
          curls++;
636
        else if (c=='}') {
637
          if (curls==0)
638
            break;
639
          else
640
            curls--;
641
        }
642
      }
643
    } /* for */
644
  }
645

646
  rv=AHB_SWIFT_ReadTextBlock(fb, tl, maxTags);
647
  if (rv)
648
    return rv;
649

650
  if (isFullSwift) {
651
    int curls=0;
652

653
    /* read trailer */
654

655
    /* skip rest of block 4 */
656
    for (;;) {
657
      GWEN_FASTBUFFER_READBYTE(fb, c);
658
      if (c<0) {
659
        if (c==GWEN_ERROR_EOF) {
660
          DBG_ERROR(AQBANKING_LOGDOMAIN,
661
                    "EOF met (%d)", c);
662
          return c;
663
        }
664
        DBG_ERROR(AQBANKING_LOGDOMAIN,
665
                  "Error reading from BIO (%d)", c);
666
        return c;
667
      }
668
      if (c=='{')
669
        curls++;
670
      else if (c=='}') {
671
        if (curls==0)
672
          break;
673
        else
674
          curls--;
675
      }
676
    }
677

678
    GWEN_FASTBUFFER_PEEKBYTE(fb, c);
679
    if (c>=0) {
680
      for (;;) {
681
        int err;
682
        char swhead[4];
683
        unsigned int bsize;
684
        int curls=0;
685
  
686
        /* read block start ("{n:...") */
687
        bsize=3;
688
        GWEN_FASTBUFFER_READFORCED(fb, err, swhead, bsize);
689
        if (err<0) {
690
          if (err==GWEN_ERROR_EOF) {
691
            DBG_ERROR(AQBANKING_LOGDOMAIN,
692
                      "EOF met (%d)", c);
693
            return 0;
694
          }
695
          DBG_ERROR_ERR(AQBANKING_LOGDOMAIN, err);
696
          return err;
697
        }
698
#if 0
699
        if (swhead[2]!=':') {
700
          DBG_ERROR(AQBANKING_LOGDOMAIN, "Not a SWIFT block");
701
          return GWEN_ERROR_BAD_DATA;
702
        }
703
#endif
704
        /* skip block */
705
        for (;;) {
706
          GWEN_FASTBUFFER_READBYTE(fb, c);
707
          if (c<0) {
708
            if (c==GWEN_ERROR_EOF) {
709
              DBG_ERROR(AQBANKING_LOGDOMAIN,
710
                        "EOF met (%d)", c);
711
              return 0;
712
            }
713
            DBG_ERROR(AQBANKING_LOGDOMAIN,
714
                      "Error reading from BIO (%d)", c);
715
            return GWEN_ERROR_READ;
716
          }
717
          if (c=='{')
718
            curls++;
719
          else if (c=='}') {
720
            if (curls==0)
721
              break;
722
            else
723
              curls--;
724
          }
725
        }
726
  
727
        if (swhead[1]=='5')
728
          break;
729
      } /* for */
730
    } /* if something follows block 4 */
731
  } /* if full SWIFT with blocks */
732

    
733
  return 0;
734
}
735
#endif
736

    
737

    
738

    
739
int AHB_SWIFT_ReadDocument(GWEN_FAST_BUFFER *fb,
740
                           AHB_SWIFT_TAG_LIST *tl,
741
                           unsigned int maxTags) {
742
  int rv;
743
  int c;
744
  int isFullSwift=0;
745
  int subDocs=0;
746

    
747
  /* check for first character being a curly bracket */
748
  for (;;) {
749
    GWEN_FASTBUFFER_PEEKBYTE(fb, c);
750
    if (c<0) {
751
      if (c==GWEN_ERROR_EOF) {
752
        DBG_INFO(AQBANKING_LOGDOMAIN,
753
                 "EOF met, empty document");
754
        return 1;
755
      }
756
      DBG_ERROR(AQBANKING_LOGDOMAIN,
757
                "Error reading from BIO (%d)", c);
758
      return c;
759
    }
760
    if (c=='{') {
761
      isFullSwift=1;
762
      break;
763
    }
764
    else if (c>3)
765
      /* some SWIFT documents contain 01 at the beginning and 03 at the end,
766
       * we simply skip those characters here */
767
      break;
768
    GWEN_FASTBUFFER_READBYTE(fb, c);
769
  } /* for */
770

    
771
  if (isFullSwift) {
772
    /* read header, seek block 4 */
773
    for (;;) {
774
      int err;
775
      char swhead[4];
776
      unsigned int bsize;
777
      int curls=0;
778

    
779
      /* skip everything before curly bracket */
780
      for (;;) {
781
        GWEN_FASTBUFFER_PEEKBYTE(fb, c);
782
        if (c<0) {
783
          if (c==GWEN_ERROR_EOF) {
784
            DBG_INFO(AQBANKING_LOGDOMAIN, "EOF met, empty block");
785
            if (subDocs>0) {
786
              DBG_INFO(AQBANKING_LOGDOMAIN, "We got %d text blocks, returning", subDocs);
787
              return 0;
788
            }
789
            return 1;
790
          }
791
          DBG_ERROR(AQBANKING_LOGDOMAIN,
792
                    "Error reading from BIO (%d)", c);
793
          return c;
794
        }
795
        if (c=='{') {
796
          break;
797
        }
798
        GWEN_FASTBUFFER_READBYTE(fb, c);
799
      } /* for */
800

    
801
      /* read block start ("{n:...") */
802
      bsize=3;
803

    
804
      GWEN_FASTBUFFER_READFORCED(fb, err, swhead, bsize);
805
      if (err<0) {
806
        DBG_ERROR_ERR(AQBANKING_LOGDOMAIN, err);
807
        return err;
808
      }
809
      if (swhead[2]!=':') {
810
        DBG_ERROR(AQBANKING_LOGDOMAIN, "Not a SWIFT block");
811
        GWEN_Text_DumpString(swhead, 4, 2);
812
        return GWEN_ERROR_BAD_DATA;
813
      }
814

    
815
      /* handle block */
816
      DBG_DEBUG(0, "Reading block %d", swhead[1]-'0');
817
      if (swhead[1]=='4') {
818
        /* read document from block 4 */
819
        rv=AHB_SWIFT_ReadTextBlock(fb, tl, maxTags);
820
        if (rv) {
821
          DBG_INFO(AQBANKING_LOGDOMAIN, "here (%d)", rv);
822
          return rv;
823
        }
824
        subDocs++;
825
      }
826

    
827
      /* skip block */
828
      for (;;) {
829
        GWEN_FASTBUFFER_READBYTE(fb, c);
830
        if (c<0) {
831
          if (c==GWEN_ERROR_EOF) {
832
            DBG_ERROR(AQBANKING_LOGDOMAIN,
833
                      "EOF met (%d)", c);
834
            return GWEN_ERROR_EOF;
835
          }
836
          DBG_ERROR(AQBANKING_LOGDOMAIN,
837
                    "Error reading from BIO (%d)", c);
838
          return GWEN_ERROR_READ;
839
        }
840
        if (c=='{')
841
          curls++;
842
        else if (c=='}') {
843
          if (curls==0)
844
            break;
845
          else
846
            curls--;
847
        }
848
      } /* for */
849
    } /* for */
850
  }
851
  else {
852
    /* not a full swift document, just read the SWIFT document directly */
853
    rv=AHB_SWIFT_ReadTextBlock(fb, tl, maxTags);
854
    if (rv)
855
      return rv;
856
  }
857

    
858
  return 0;
859
}
860

    
861

    
862

    
863
int AHB_SWIFT_Import(GWEN_DBIO *dbio,
864
                     GWEN_SYNCIO *sio,
865
                     GWEN_DB_NODE *data,
866
                     GWEN_DB_NODE *cfg,
867
                     uint32_t flags) {
868
  int rv;
869
  const char *p;
870
  int skipFileLines;
871
  int skipDocLines;
872
  GWEN_FAST_BUFFER *fb;
873
  int docsImported=0;
874

    
875
  p=GWEN_DB_GetCharValue(cfg, "type", 0, "mt940");
876
  if (strcasecmp(p, "mt940")!=0 &&
877
      strcasecmp(p, "mt942")!=0 &&
878
      strcasecmp(p, "mt535")!=0) {
879
    DBG_ERROR(AQBANKING_LOGDOMAIN,
880
              "Type \"%s\" not supported by plugin \"%s\"",
881
              p,
882
              GWEN_DBIO_GetName(dbio));
883
    return GWEN_ERROR_INVALID;
884
  }
885

    
886
  skipFileLines=GWEN_DB_GetIntValue(cfg, "skipFileLines", 0, 0);
887
  skipDocLines=GWEN_DB_GetIntValue(cfg, "skipDocLines", 0, 0);
888

    
889
  fb=GWEN_FastBuffer_new(256, sio);
890

    
891
  /* skip lines at the beginning if requested */
892
  if (skipFileLines>0) {
893
    int i;
894
    GWEN_BUFFER *lbuf;
895

    
896
    lbuf=GWEN_Buffer_new(0, 256, 0, 1);
897
    for (i=0; i<skipFileLines; i++) {
898
      int err;
899

    
900
      err=GWEN_FastBuffer_ReadLineToBuffer(fb, lbuf);
901
      if (err<0) {
902
        if (err==GWEN_ERROR_EOF && i==0)
903
          break;
904
        DBG_INFO(AQBANKING_LOGDOMAIN,
905
                 "Error in report, aborting (%d)", err);
906
        GWEN_Buffer_free(lbuf);
907
        GWEN_FastBuffer_free(fb);
908
        return err;
909
      }
910
      GWEN_Buffer_Reset(lbuf);
911
    }
912
    GWEN_Buffer_free(lbuf);
913

    
914
    if (i<skipFileLines) {
915
      /* not enough lines to skip, assume end of document */
916

    
917
      GWEN_FastBuffer_free(fb);
918
      DBG_INFO(AQBANKING_LOGDOMAIN, "To few lines in file");
919
      GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error,
920
                           I18N("Empty SWIFT file, aborting"));
921
      return GWEN_ERROR_EOF;
922
    }
923
  }
924

    
925
  for (;;) {
926
    AHB_SWIFT_TAG_LIST *tl;
927

    
928
    /* check for user abort */
929
    rv=GWEN_Gui_ProgressAdvance(0, GWEN_GUI_PROGRESS_NONE);
930
    if (rv==GWEN_ERROR_USER_ABORTED) {
931
      DBG_INFO(AQBANKING_LOGDOMAIN, "User aborted");
932
      GWEN_FastBuffer_free(fb);
933
      return rv;
934
    }
935

    
936
    GWEN_Gui_ProgressLog2(0, GWEN_LoggerLevel_Debug,
937
                          I18N("Reading SWIFT document %d"), docsImported+1);
938

    
939
    /* skip lines at the beginning if requested */
940
    if (skipDocLines>0) {
941
      int i;
942
      GWEN_BUFFER *lbuf;
943
  
944
      lbuf=GWEN_Buffer_new(0, 256, 0, 1);
945
      for (i=0; i<skipDocLines; i++) {
946
        int err;
947

    
948
        err=GWEN_FastBuffer_ReadLineToBuffer(fb, lbuf);
949
        if (err<0) {
950
          if (err==GWEN_ERROR_EOF && i==0)
951
            break;
952
          DBG_INFO(AQBANKING_LOGDOMAIN,
953
                   "Error in report, aborting (%d)", err);
954
          GWEN_Buffer_free(lbuf);
955
          GWEN_FastBuffer_free(fb);
956
          return err;
957
        }
958
        GWEN_Buffer_Reset(lbuf);
959
      }
960
      GWEN_Buffer_free(lbuf);
961

    
962
      if (i<skipDocLines)
963
        /* not enough lines to skip, assume end of document */
964
        break;
965
    }
966

    
967
    GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Debug,
968
                         I18N("Parsing SWIFT data"));
969
    tl=AHB_SWIFT_Tag_List_new();
970
    assert(tl);
971
    rv=AHB_SWIFT_ReadDocument(fb, tl, 0);
972
    if (rv<0) {
973
      DBG_INFO(AQBANKING_LOGDOMAIN, "Error in report, aborting");
974
      GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error,
975
                           I18N("Error parsing SWIFT data"));
976
      GWEN_FastBuffer_free(fb);
977
      AHB_SWIFT_Tag_List_free(tl);
978
      return rv;
979
    }
980

    
981
    if (rv==1) {
982
      DBG_INFO(AQBANKING_LOGDOMAIN, "End of document reached");
983
      AHB_SWIFT_Tag_List_free(tl);
984
      if (docsImported==0) {
985
        DBG_INFO(AQBANKING_LOGDOMAIN, "Empty document, aborting");
986
        GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error,
987
                             I18N("Empty SWIFT document, aborting"));
988
        GWEN_FastBuffer_free(fb);
989
        return GWEN_ERROR_EOF;
990
      }
991
      break;
992
    }
993

    
994
    /* now all tags have been read, transform them */
995
    GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Debug,
996
                         I18N("Importing SWIFT data"));
997

    
998
    DBG_INFO(AQBANKING_LOGDOMAIN, "*** before branching ***");
999
    if(strcasecmp(p, "mt940")==0 || strcasecmp(p, "mt942")==0)
1000
      rv=AHB_SWIFT940_Import(tl, data, cfg, flags);
1001
    if(strcasecmp(p, "mt535")==0)
1002
      rv=AHB_SWIFT535_Import(tl, data, cfg, flags);
1003

    
1004
    
1005
    if (rv) {
1006
      DBG_INFO(AQBANKING_LOGDOMAIN, "Error importing SWIFT MT940/942/535");
1007
      GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Error,
1008
                           I18N("Error importing SWIFT data"));
1009
      GWEN_FastBuffer_free(fb);
1010
      AHB_SWIFT_Tag_List_free(tl);
1011
      return rv;
1012
    }
1013
    AHB_SWIFT_Tag_List_free(tl);
1014
    GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Debug,
1015
                         I18N("Swift document successfully imported"));
1016
    docsImported++;
1017
  } /* for */
1018

    
1019
  GWEN_FastBuffer_free(fb);
1020
  DBG_INFO(AQBANKING_LOGDOMAIN, "SWIFT MT940/942/535 successfully imported");
1021

    
1022
  return 0;
1023
}
1024

    
1025

    
1026

    
1027
int AHB_SWIFT_Export(GWEN_DBIO *dbio,
1028
                     GWEN_SYNCIO *sio,
1029
                     GWEN_DB_NODE *data,
1030
                     GWEN_DB_NODE *cfg,
1031
                     uint32_t flags) {
1032
  DBG_ERROR(AQBANKING_LOGDOMAIN, "AHB_SWIFT_Export: Not yet implemented");
1033
  return -1;
1034
}
1035

    
1036

    
1037

    
1038
GWEN_DBIO_CHECKFILE_RESULT AHB_SWIFT_CheckFile(GWEN_DBIO *dbio,
1039
                                               const char *fname) {
1040
  int i;
1041
  GWEN_DBIO_CHECKFILE_RESULT res;
1042
  GWEN_BUFFER *lbuf;
1043
  GWEN_SYNCIO *sio;
1044
  GWEN_SYNCIO *baseIo;
1045
  int rv;
1046

    
1047
  assert(dbio);
1048
  assert(fname);
1049

    
1050
  sio=GWEN_SyncIo_File_new(fname, GWEN_SyncIo_File_CreationMode_OpenExisting);
1051
  GWEN_SyncIo_AddFlags(sio, GWEN_SYNCIO_FILE_FLAGS_READ);
1052
  baseIo=sio;
1053

    
1054
  sio=GWEN_SyncIo_Buffered_new(baseIo);
1055
  rv=GWEN_SyncIo_Connect(sio);
1056
  if (rv<0) {
1057
    /* error */
1058
    DBG_ERROR(AQBANKING_LOGDOMAIN,
1059
              "open(%s): %s", fname, strerror(errno));
1060
    GWEN_SyncIo_free(sio);
1061
    return GWEN_DBIO_CheckFileResultNotOk;
1062
  }
1063

    
1064
  /* search for ":20:" tag */
1065
  lbuf=GWEN_Buffer_new(0, 256, 0, 1);
1066
  res=GWEN_DBIO_CheckFileResultNotOk;
1067
  for (i=0; i<20; i++) {
1068
    int err;
1069
    const char *p;
1070

    
1071
    err=GWEN_SyncIo_Buffered_ReadLineToBuffer(sio, lbuf);
1072
    if (err<0) {
1073
      DBG_INFO(AQBANKING_LOGDOMAIN, "Error in report, aborting");
1074
      res=GWEN_DBIO_CheckFileResultNotOk;
1075
      break;
1076
    }
1077
    else if (err==0)
1078
      break;
1079
    p=GWEN_Buffer_GetStart(lbuf);
1080
    if (strstr(p, ":20:")) {
1081
      /* don't be too sure about the file being importable... */
1082
      res=GWEN_DBIO_CheckFileResultUnknown;
1083
      break;
1084
    }
1085
    GWEN_Buffer_Reset(lbuf);
1086
  } /* for */
1087
  GWEN_Buffer_free(lbuf);
1088

    
1089
  GWEN_SyncIo_Disconnect(sio);
1090
  GWEN_SyncIo_free(sio);
1091

    
1092
  return res;
1093
}
1094

    
1095

    
1096

    
1097
GWEN_DBIO *GWEN_DBIO_SWIFT_Factory(GWEN_PLUGIN *pl) {
1098
  GWEN_DBIO *dbio;
1099

    
1100
  dbio=GWEN_DBIO_new("swift", "Imports and exports SWIFT data");
1101
  GWEN_DBIO_SetImportFn(dbio, AHB_SWIFT_Import);
1102
  GWEN_DBIO_SetExportFn(dbio, AHB_SWIFT_Export);
1103
  GWEN_DBIO_SetCheckFileFn(dbio, AHB_SWIFT_CheckFile);
1104
  return dbio;
1105
}
1106

    
1107

    
1108

    
1109
GWEN_PLUGIN *dbio_swift_factory(GWEN_PLUGIN_MANAGER *pm,
1110
                                const char *modName,
1111
                                const char *fileName) {
1112
  GWEN_PLUGIN *pl;
1113

    
1114
  pl=GWEN_DBIO_Plugin_new(pm, modName, fileName);
1115
  assert(pl);
1116

    
1117
  GWEN_DBIO_Plugin_SetFactoryFn(pl, GWEN_DBIO_SWIFT_Factory);
1118

    
1119
  return pl;
1120

    
1121
}
1122

    
1123

    
1124

    
1125

    
1126