Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

aqbanking / src / tools / aqbanking-cli / util.c @ 5bc3f3e7

History | View | Annotate | Download (27.5 KB)

1
/***************************************************************************
2
 begin       : Tue May 03 2005
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 "globals.h"
15
#include <gwenhywfar/text.h>
16
#include <gwenhywfar/syncio_file.h>
17

    
18
#include <sys/types.h>
19
#include <sys/stat.h>
20
#include <fcntl.h>
21
#include <string.h>
22
#include <errno.h>
23
#include <unistd.h>
24
#include <ctype.h>
25

    
26

    
27

    
28
/* ========================================================================================================================
29
 *                                                readContext
30
 * ========================================================================================================================
31
 */
32

    
33
int readContext(const char *ctxFile,
34
                AB_IMEXPORTER_CONTEXT **pCtx,
35
                int mustExist) {
36
  AB_IMEXPORTER_CONTEXT *ctx;
37
  GWEN_SYNCIO *sio;
38
  GWEN_DB_NODE *dbCtx;
39
  int rv;
40

    
41
  if (ctxFile==NULL) {
42
    sio=GWEN_SyncIo_File_fromStdin();
43
    GWEN_SyncIo_AddFlags(sio,
44
                         GWEN_SYNCIO_FLAGS_DONTCLOSE |
45
                         GWEN_SYNCIO_FILE_FLAGS_READ);
46
  }
47
  else {
48
    sio=GWEN_SyncIo_File_new(ctxFile, GWEN_SyncIo_File_CreationMode_OpenExisting);
49
    GWEN_SyncIo_AddFlags(sio, GWEN_SYNCIO_FILE_FLAGS_READ);
50
    rv=GWEN_SyncIo_Connect(sio);
51
    if (rv<0) {
52
      if (!mustExist) {
53
        ctx=AB_ImExporterContext_new();
54
        *pCtx=ctx;
55
        GWEN_SyncIo_free(sio);
56
        return 0;
57
      }
58
      GWEN_SyncIo_free(sio);
59
      return 4;
60
    }
61
  }
62

    
63
  /* actually read */
64
  dbCtx=GWEN_DB_Group_new("context");
65
  rv=GWEN_DB_ReadFromIo(dbCtx, sio,
66
                        GWEN_DB_FLAGS_DEFAULT |
67
                        GWEN_PATH_FLAGS_CREATE_GROUP);
68
  if (rv<0) {
69
    DBG_ERROR(0, "Error reading context file (%d)", rv);
70
    GWEN_DB_Group_free(dbCtx);
71
    GWEN_SyncIo_Disconnect(sio);
72
    GWEN_SyncIo_free(sio);
73
    return rv;
74
  }
75
  GWEN_SyncIo_Disconnect(sio);
76
  GWEN_SyncIo_free(sio);
77

    
78
  ctx=AB_ImExporterContext_fromDb(dbCtx);
79
  if (!ctx) {
80
    DBG_ERROR(0, "No context in input data");
81
    GWEN_DB_Group_free(dbCtx);
82
    return GWEN_ERROR_BAD_DATA;
83
  }
84
  GWEN_DB_Group_free(dbCtx);
85
  *pCtx=ctx;
86

    
87
  return 0;
88
}
89

    
90

    
91

    
92
/* ========================================================================================================================
93
 *                                                writeContext
94
 * ========================================================================================================================
95
 */
96

    
97
int writeContext(const char *ctxFile, const AB_IMEXPORTER_CONTEXT *ctx) {
98
  GWEN_DB_NODE *dbCtx;
99
  GWEN_SYNCIO *sio;
100
  int rv;
101

    
102
  if (ctxFile==NULL) {
103
    sio=GWEN_SyncIo_File_fromStdout();
104
    GWEN_SyncIo_AddFlags(sio,
105
                         GWEN_SYNCIO_FLAGS_DONTCLOSE |
106
                         GWEN_SYNCIO_FILE_FLAGS_WRITE);
107
  }
108
  else {
109
    sio=GWEN_SyncIo_File_new(ctxFile, GWEN_SyncIo_File_CreationMode_CreateAlways);
110
    GWEN_SyncIo_AddFlags(sio,
111
                         GWEN_SYNCIO_FILE_FLAGS_READ |
112
                         GWEN_SYNCIO_FILE_FLAGS_WRITE |
113
                         GWEN_SYNCIO_FILE_FLAGS_UREAD |
114
                         GWEN_SYNCIO_FILE_FLAGS_UWRITE |
115
                         GWEN_SYNCIO_FILE_FLAGS_GREAD |
116
                         GWEN_SYNCIO_FILE_FLAGS_GWRITE);
117
    rv=GWEN_SyncIo_Connect(sio);
118
    if (rv<0) {
119
      DBG_ERROR(0, "Error selecting output file: %s",
120
                strerror(errno));
121
      GWEN_SyncIo_free(sio);
122
      return 4;
123
    }
124
  }
125

    
126

    
127
  dbCtx=GWEN_DB_Group_new("context");
128
  rv=AB_ImExporterContext_toDb(ctx, dbCtx);
129
  if (rv<0) {
130
    DBG_ERROR(0, "Error writing context to db (%d)", rv);
131
    GWEN_DB_Group_free(dbCtx);
132
    GWEN_SyncIo_Disconnect(sio);
133
    GWEN_SyncIo_free(sio);
134
    return rv;
135
  }
136

    
137
  rv=GWEN_DB_WriteToIo(dbCtx, sio, GWEN_DB_FLAGS_DEFAULT);
138
  if (rv<0) {
139
    DBG_ERROR(0, "Error writing context (%d)", rv);
140
  }
141
  else
142
    rv=0;
143

    
144
  GWEN_DB_Group_free(dbCtx);
145
  GWEN_SyncIo_Disconnect(sio);
146
  GWEN_SyncIo_free(sio);
147

    
148
  return rv;
149
}
150

    
151

    
152

    
153
/* ========================================================================================================================
154
 *                                                mkSepaTransfer
155
 * ========================================================================================================================
156
 */
157
AB_TRANSACTION *mkSepaTransfer(GWEN_DB_NODE *db, int cmd) {
158
  AB_TRANSACTION *t;
159
  const char *s;
160
  int i;
161
  GWEN_DATE *d;
162

    
163
  assert(db);
164

    
165
  t=AB_Transaction_new();
166

    
167
  AB_Transaction_SetType(t, AB_Transaction_TypeTransfer);
168

    
169
  s=GWEN_DB_GetCharValue(db, "name", 0, 0);
170
  if (s && *s)
171
    AB_Transaction_SetLocalName(t, s);
172

    
173
  /* remote account */
174
  s=GWEN_DB_GetCharValue(db, "remoteBankId", 0, 0);
175
  if (s && *s)
176
    AB_Transaction_SetRemoteBankCode(t, s);
177
  s=GWEN_DB_GetCharValue(db, "remoteAccountId", 0, 0);
178
  if (s && *s)
179
    AB_Transaction_SetRemoteAccountNumber(t, s);
180

    
181
  s=GWEN_DB_GetCharValue(db, "remoteIban", 0, 0);
182
  if (s && *s)
183
    AB_Transaction_SetRemoteIban(t, s);
184
  else {
185
    DBG_ERROR(0, "No remote IBAN given");
186
    AB_Transaction_free(t);
187
    return NULL;
188
  }
189

    
190
  s=GWEN_DB_GetCharValue(db, "remoteBic", 0, 0);
191
  if (s && *s)
192
    AB_Transaction_SetRemoteBic(t, s);
193
  else if (strncmp(AB_Transaction_GetLocalIban(t),
194
                   AB_Transaction_GetRemoteIban(t), 2)) {
195
    DBG_ERROR(0, "Remote BIC id required for international transaction");
196
    AB_Transaction_free(t);
197
    return NULL;
198
  }
199

    
200
  s=GWEN_DB_GetCharValue(db, "remoteName", 0, 0);
201
  if (*s && *s)
202
    AB_Transaction_SetRemoteName(t, s);
203
  else {
204
    DBG_ERROR(0, "No remote name given");
205
    AB_Transaction_free(t);
206
    return NULL;
207
  }
208

    
209
  /* transfer data */
210
  for (i=0; i<20; i++) {
211
    s=GWEN_DB_GetCharValue(db, "purpose", i, 0);
212
    if (!s)
213
      break;
214
    if (*s)
215
      AB_Transaction_AddPurposeLine(t, s);
216
  }
217
  if (i<1) {
218
    DBG_ERROR(0, "No purpose given");
219
    AB_Transaction_free(t);
220
    return NULL;
221
  }
222

    
223
  s=GWEN_DB_GetCharValue(db, "value", 0, 0);
224
  if (s && *s) {
225
    AB_VALUE *v;
226

    
227
    v=AB_Value_fromString(s);
228
    assert(v);
229
    if (AB_Value_IsNegative(v) || AB_Value_IsZero(v)) {
230
      DBG_ERROR(0, "Only positive non-zero amount allowed");
231
      AB_Transaction_free(t);
232
      return NULL;
233
    }
234
    AB_Transaction_SetValue(t, v);
235
    AB_Value_free(v);
236
  }
237
  else {
238
    DBG_ERROR(0, "No value given");
239
    AB_Transaction_free(t);
240
    return NULL;
241
  }
242

    
243
  s=GWEN_DB_GetCharValue(db, "endToEndReference", 0, 0);
244
  if (s && *s)
245
    AB_Transaction_SetEndToEndReference(t, s);
246

    
247
  /* dated transfer, SEPA debit notes */
248
  s=GWEN_DB_GetCharValue(db, "executionDate", 0, 0);
249
  if (s && *s) {
250
    GWEN_BUFFER *dbuf;
251

    
252
    dbuf=GWEN_Buffer_new(0, 32, 0, 1);
253
    GWEN_Buffer_AppendString(dbuf, s);
254
    GWEN_Buffer_AppendString(dbuf, "-00:00");
255
    d=GWEN_Date_fromStringWithTemplate(GWEN_Buffer_GetStart(dbuf), "YYYYMMDD");
256
    GWEN_Buffer_free(dbuf);
257
    if (d==0) {
258
      DBG_ERROR(0, "Invalid execution date value \"%s\"", s);
259
      AB_Transaction_free(t);
260
      return NULL;
261
    }
262
    AB_Transaction_SetDate(t, d);
263
    GWEN_Date_free(d);
264
  }
265

    
266
  /* standing orders */
267
  if (cmd==AB_Transaction_CommandCreateStandingOrder) {
268
     s=GWEN_DB_GetCharValue(db, "firstExecutionDate", 0, 0);
269
     if (!(s && *s)) {
270
       DBG_ERROR(0, "Missing first execution date");
271
       return NULL;
272
     }
273
  }
274

    
275
  if (cmd==AB_Transaction_CommandModifyStandingOrder ||
276
      cmd==AB_Transaction_CommandDeleteStandingOrder) {
277
     /*  not in the Specs, but the banks ask for it)    */
278
     s=GWEN_DB_GetCharValue(db, "nextExecutionDate", 0, 0);
279
     if (!(s && *s)) {
280
       DBG_ERROR(0, "Missing next execution date");
281
       return NULL;
282
     }
283
  }
284

    
285
  if (s && *s) {
286
    GWEN_BUFFER *dbuf;
287

    
288
    dbuf=GWEN_Buffer_new(0, 32, 0, 1);
289
    GWEN_Buffer_AppendString(dbuf, s);
290
    GWEN_Buffer_AppendString(dbuf, "-00:00");
291
    d=GWEN_Date_fromStringWithTemplate(GWEN_Buffer_GetStart(dbuf), "YYYYMMDD");
292
    GWEN_Buffer_free(dbuf);
293
    if (d==0) {
294
      DBG_ERROR(0, "Invalid first or next execution date value \"%s\"", s);
295
      AB_Transaction_free(t);
296
      return NULL;
297
    }
298
    AB_Transaction_SetFirstDate(t, d); /*next execution date, too */
299
    GWEN_Date_free(d);
300
  }
301

    
302
  s=GWEN_DB_GetCharValue(db, "lastExecutionDate", 0, 0);
303
  if (s && *s) {
304
    GWEN_BUFFER *dbuf;
305

    
306
    dbuf=GWEN_Buffer_new(0, 32, 0, 1);
307
    GWEN_Buffer_AppendString(dbuf, s);
308
    GWEN_Buffer_AppendString(dbuf, "-00:00");
309
    d=GWEN_Date_fromStringWithTemplate(GWEN_Buffer_GetStart(dbuf), "YYYYMMDD");
310
    GWEN_Buffer_free(dbuf);
311
    if (d==0) {
312
      DBG_ERROR(0, "Invalid last execution date value \"%s\"", s);
313
      AB_Transaction_free(t);
314
      return NULL;
315
    }
316
    AB_Transaction_SetLastDate(t, d);
317
    GWEN_Date_free(d);
318
  }
319

    
320
  if (cmd==AB_Transaction_CommandCreateStandingOrder ||
321
      cmd==AB_Transaction_CommandModifyStandingOrder ||
322
      cmd==AB_Transaction_CommandDeleteStandingOrder) {
323
    const char *s;
324
    AB_TRANSACTION_PERIOD period=AB_Transaction_PeriodUnknown;
325

    
326
    /* only needed for standing orders */
327
    s=GWEN_DB_GetCharValue(db, "executionPeriod", 0, 0);
328
    if (s && *s) {
329
      period=AB_Transaction_Period_fromString(s);
330
      if (period==AB_Transaction_PeriodUnknown) {
331
        DBG_ERROR(0, "Invalid execution period value \"%s\"", s);
332
        AB_Transaction_free(t);
333
        return NULL;
334
      }
335
    }
336
    else {
337
      DBG_ERROR(0, "Missing execution period value");
338
      return NULL;
339
    }
340
    AB_Transaction_SetPeriod(t, period);
341

    
342
    i=GWEN_DB_GetIntValue(db, "executionCycle", 0, -1);
343
    if (i <= 0) {
344
      DBG_ERROR(0, "Invalid execution cycle value \"%d\"", i);
345
      AB_Transaction_free(t);
346
      return NULL;
347
    }
348
    AB_Transaction_SetCycle(t, i);
349

    
350
    i=GWEN_DB_GetIntValue(db, "executionDay", 0, -1);
351
    if (i <= 0 || (period == AB_Transaction_PeriodWeekly && i > 7) ||
352
        (period == AB_Transaction_PeriodMonthly && i > 30 &&
353
         (i < 97 || i > 99))) {
354
      DBG_ERROR(0, "Invalid execution day value \"%d\"", i);
355
      AB_Transaction_free(t);
356
      return NULL;
357
    }
358
    AB_Transaction_SetExecutionDay(t, i);
359

    
360
    /* SetFiId */
361
    s=GWEN_DB_GetCharValue(db, "fiId", 0, 0);
362
    if (s && *s)
363
      AB_Transaction_SetFiId(t, s);
364
  }
365
  return t;
366
}
367

    
368

    
369

    
370
/* ========================================================================================================================
371
 *                                                mkSepaDebitNote
372
 * ========================================================================================================================
373
 */
374

    
375
AB_TRANSACTION *mkSepaDebitNote(GWEN_DB_NODE *db, int cmd) {
376
  AB_TRANSACTION *t;
377
  const char *s;
378

    
379
  t=mkSepaTransfer(db, cmd);
380
  if (t==NULL) {
381
    DBG_INFO(0, "here");
382
    return NULL;
383
  }
384

    
385
  AB_Transaction_SetType(t, cmd);
386
  
387
  /* read some additional fields */
388
  s=GWEN_DB_GetCharValue(db, "creditorSchemeId", 0, 0);
389
  if (!(s && *s)) {
390
    DBG_ERROR(0, "Missing creditor scheme id");
391
    AB_Transaction_free(t);
392
    return NULL;
393
  }
394
  AB_Transaction_SetCreditorSchemeId(t, s);
395

    
396
  s=GWEN_DB_GetCharValue(db, "mandateId", 0, 0);
397
  if (!(s && *s)) {
398
    DBG_ERROR(0, "Missing mandate id");
399
    AB_Transaction_free(t);
400
    return NULL;
401
  }
402
  AB_Transaction_SetMandateId(t, s);
403

    
404
  s=GWEN_DB_GetCharValue(db, "mandateDate", 0, 0);
405
  if (!(s && *s)) {
406
    DBG_ERROR(0, "Missing mandate date");
407
    AB_Transaction_free(t);
408
    return NULL;
409
  }
410
  else {
411
    GWEN_DATE *dt;
412

    
413
    dt=GWEN_Date_fromString(s);
414
    if (dt==NULL) {
415
      DBG_ERROR(0, "Bad date format for mandate date");
416
      AB_Transaction_free(t);
417
      return NULL;
418
    }
419
    AB_Transaction_SetMandateDate(t, dt);
420
    GWEN_Date_free(dt);
421
  }
422

    
423
  s=GWEN_DB_GetCharValue(db, "sequenceType", 0, "once");
424
  if (s && *s) {
425
    AB_TRANSACTION_SEQUENCE st;
426

    
427
    st=AB_Transaction_Sequence_fromString(s);
428
    if (st!=AB_Transaction_SequenceUnknown)
429
      AB_Transaction_SetSequence(t, st);
430
    else {
431
      DBG_ERROR(0, "Unknown sequence type [%s]", s);
432
      AB_Transaction_free(t);
433
      return NULL;
434
    }
435
  }
436
  else
437
    AB_Transaction_SetSequence(t, AB_Transaction_SequenceOnce);
438

    
439
  return t;
440
}
441

    
442

    
443

    
444
/* ========================================================================================================================
445
 *                                                getSelectedAccounts
446
 * ========================================================================================================================
447
 */
448

    
449
int getSelectedAccounts(AB_BANKING *ab, GWEN_DB_NODE *db, AB_ACCOUNT_SPEC_LIST **pAccountSpecList) {
450
  AB_ACCOUNT_SPEC_LIST *asl=NULL;
451
  uint32_t uniqueAccountId;
452
  int rv;
453

    
454
  asl=AB_AccountSpec_List_new();
455

    
456
  uniqueAccountId=(uint32_t) GWEN_DB_GetIntValue(db, "uniqueAccountId", 0, 0);
457
  if (uniqueAccountId) {
458
    AB_ACCOUNT_SPEC *as=NULL;
459

    
460
    /* specific unique id given, use that exclusively */
461
    rv=AB_Banking_GetAccountSpecByUniqueId(ab, uniqueAccountId, &as);
462
    if (rv<0) {
463
      DBG_ERROR(0, "Could not load account spec %lu (%d)", (unsigned long int) uniqueAccountId, rv);
464
      AB_AccountSpec_List_free(asl);
465
      return rv;
466
    }
467
    AB_AccountSpec_List_Add(as, asl);
468
  }
469
  else {
470
    /* no unique account id given, try match parameters */
471
    rv=AB_Banking_GetAccountSpecList(ab, &asl);
472
    if (rv<0) {
473
      DBG_ERROR(0, "Could not load account specs (%d)", rv);
474
      AB_AccountSpec_List_free(asl);
475
      return rv;
476
    }
477
    else {
478
      const char *backendName;
479
      const char *country;
480
      const char *bankId;
481
      const char *accountId;
482
      const char *subAccountId;
483
      const char *iban;
484
      const char *s;
485
      AB_ACCOUNT_TYPE aType=AB_AccountType_Unknown;
486
      AB_ACCOUNT_SPEC *as;
487

    
488
      backendName=GWEN_DB_GetCharValue(db, "backendName", 0, "*");
489
      country=GWEN_DB_GetCharValue(db, "country", 0, "*");
490
      bankId=GWEN_DB_GetCharValue(db, "bankId", 0, "*");
491
      accountId=GWEN_DB_GetCharValue(db, "accountId", 0, "*");
492
      subAccountId=GWEN_DB_GetCharValue(db, "subAccountId", 0, "*");
493
      iban=GWEN_DB_GetCharValue(db, "iban", 0, "*");
494
      s=GWEN_DB_GetCharValue(db, "accountType", 0, NULL);
495
      if (s && *s)
496
        aType=AB_AccountType_fromChar(s);
497
      if (aType==AB_AccountType_Invalid) {
498
        DBG_ERROR(0, "Invalid Could not load account specs (%d)", rv);
499
        AB_AccountSpec_List_free(asl);
500
        return GWEN_ERROR_INVALID;
501
      }
502

    
503
      as=AB_AccountSpec_List_First(asl);
504
      while(as) {
505
        AB_ACCOUNT_SPEC *asNext;
506

    
507
        asNext=AB_AccountSpec_List_Next(as);
508
        if (AB_AccountSpec_Matches(as, backendName,
509
                                   country, bankId, accountId, subAccountId,
510
                                   iban,
511
                                   "*", /* currency */
512
                                   aType)<1) {
513
          /* doesn't match, remove from list */
514
          AB_AccountSpec_List_Del(as);
515
          AB_AccountSpec_free(as);
516
        }
517
        as=asNext;
518
      }
519
    }
520
  }
521

    
522
  if (AB_AccountSpec_List_GetCount(asl))
523
    *pAccountSpecList=asl;
524
  else {
525
    AB_AccountSpec_List_free(asl);
526
    *pAccountSpecList=NULL;
527
    return GWEN_ERROR_NOT_FOUND;
528
  }
529
  return 0;
530
}
531

    
532

    
533

    
534
/* ========================================================================================================================
535
 *                                                getSingleSelectedAccount
536
 * ========================================================================================================================
537
 */
538

    
539

    
540
AB_ACCOUNT_SPEC *getSingleSelectedAccount(AB_BANKING *ab, GWEN_DB_NODE *db) {
541
  int rv;
542
  AB_ACCOUNT_SPEC_LIST *al=NULL;
543
  AB_ACCOUNT_SPEC *as;
544

    
545
  rv=getSelectedAccounts(ab, db, &al);
546
  if (rv<0) {
547
    if (rv==GWEN_ERROR_NOT_FOUND)
548
      fprintf(stderr, "No matching accounts\n");
549
    else
550
      fprintf(stderr, "Error getting selected accounts (%d)\n", rv);
551
    return NULL;
552
  }
553

    
554
  if (AB_AccountSpec_List_GetCount(al)>1) {
555
    fprintf(stderr, "Ambiguous account specification (%d accounts matching)\n", AB_AccountSpec_List_GetCount(al));
556
    AB_AccountSpec_List_free(al);
557
    return NULL;
558
  }
559

    
560
  as=AB_AccountSpec_List_First(al);
561
  assert(as);
562
  AB_AccountSpec_List_Del(as);
563
  AB_AccountSpec_List_free(al);
564
  return as;
565
}
566

    
567

    
568

    
569
/* ========================================================================================================================
570
 *                                                replaceVars
571
 * ========================================================================================================================
572
 */
573

    
574
int replaceVars(const char *s, GWEN_DB_NODE *db, GWEN_BUFFER *dbuf) {
575
    const char *p;
576

    
577
  p=s;
578
  while(*p) {
579
    if (*p=='$') {
580
      p++;
581
      if (*p=='$')
582
        GWEN_Buffer_AppendByte(dbuf, '$');
583
      else if (*p=='(') {
584
        const char *pStart;
585

    
586
        p++;
587
        pStart=p;
588
        while(*p && *p!=')')
589
          p++;
590
        if (*p!=')') {
591
          DBG_ERROR(GWEN_LOGDOMAIN, "Unterminated variable name in code");
592
          return GWEN_ERROR_BAD_DATA;
593
        }
594
        else {
595
          int len;
596
          char *name;
597
          const char *valueString;
598
          int valueInt;
599
          char numbuf[32];
600
          int rv;
601

    
602
          len=p-pStart;
603
          if (len<1) {
604
            DBG_ERROR(GWEN_LOGDOMAIN, "Empty variable name in code");
605
            return GWEN_ERROR_BAD_DATA;
606
          }
607
          name=(char*) malloc(len+1);
608
          assert(name);
609
          memmove(name, pStart, len);
610
          name[len]=0;
611

    
612
          switch(GWEN_DB_GetVariableType(db, name)) {
613
          case GWEN_DB_NodeType_ValueInt:
614
            valueInt=GWEN_DB_GetIntValue(db, name, 0, 0);
615
            rv=GWEN_Text_NumToString(valueInt, numbuf, sizeof(numbuf)-1, 0);
616
            if (rv>=0)
617
              GWEN_Buffer_AppendString(dbuf, numbuf);
618
            break;
619
          case GWEN_DB_NodeType_ValueChar:
620
            valueString=GWEN_DB_GetCharValue(db, name, 0, NULL);
621
            if (valueString)
622
              GWEN_Buffer_AppendString(dbuf, valueString);
623
#if 0 /* just replace with empty value */
624
            else {
625
              GWEN_Buffer_AppendString(dbuf, " [__VALUE OF ");
626
              GWEN_Buffer_AppendString(dbuf, name);
627
              GWEN_Buffer_AppendString(dbuf, " WAS NOT SET__] ");
628
            }
629
#endif
630
            break;
631

    
632
          default:
633
            break;
634
          }
635
          free(name);
636
        }
637
      }
638
      else {
639
        DBG_ERROR(GWEN_LOGDOMAIN, "Bad variable string in code");
640
        return GWEN_ERROR_BAD_DATA;
641
      }
642
      p++;
643
    }
644
    else {
645
      if (*p=='#') {
646
        /* let # lines begin on a new line */
647
        GWEN_Buffer_AppendByte(dbuf, '\n');
648
        GWEN_Buffer_AppendByte(dbuf, *p);
649

    
650
        /* skip introducing cross and copy all stuff until the next cross
651
         * upon which wa inject a newline (to make the preprocessor happy)
652
         */
653
        p++;
654
        while(*p && *p!='#') {
655
          GWEN_Buffer_AppendByte(dbuf, *p);
656
          p++;
657
        }
658
        if (*p=='#') {
659
          GWEN_Buffer_AppendByte(dbuf, '\n');
660
          p++;
661
        }
662
      }
663
      else if (*p=='\\') {
664
        /* check for recognized control escapes */
665
        if (tolower(p[1])=='n') {
666
          GWEN_Buffer_AppendByte(dbuf, '\n');
667
          p+=2; /* skip introducing backslash and control character */
668
        }
669
        else if (tolower(p[1])=='t') {
670
          GWEN_Buffer_AppendByte(dbuf, '\t');
671
          p+=2; /* skip introducing backslash and control character */
672
        }
673
        else if (tolower(p[1])=='\\') {
674
          GWEN_Buffer_AppendByte(dbuf, '\\');
675
          p+=2; /* skip introducing backslash and control character */
676
        }
677
        else {
678
          /* no known escape character, just add literally */
679
          GWEN_Buffer_AppendByte(dbuf, *p);
680
          p++;
681
        }
682
      }
683
      else {
684
        GWEN_Buffer_AppendByte(dbuf, *p);
685
        p++;
686
      }
687
    }
688
  }
689

    
690
  return 0;
691
}
692

    
693

    
694

    
695
/* ========================================================================================================================
696
 *                                                checkTransactionIbans
697
 * ========================================================================================================================
698
 */
699

    
700
int checkTransactionIbans(const AB_TRANSACTION *t) {
701
  const char *rIBAN;
702
  const char *lIBAN;
703
  const char *lBIC;
704
  int rv;
705

    
706
  assert(t);
707

    
708
  /* some checks */
709
  rIBAN=AB_Transaction_GetRemoteIban(t);
710
  lIBAN=AB_Transaction_GetLocalIban(t);
711
  lBIC=AB_Transaction_GetLocalBic(t);
712

    
713
  if (!rIBAN || !(*rIBAN)) {
714
    fprintf(stderr, "Missing remote IBAN\n");
715
    return 1;
716
  }
717
  rv=AB_Banking_CheckIban(rIBAN);
718
  if (rv != 0) {
719
    fprintf(stderr, "Invalid remote IBAN (%s)\n", rIBAN);
720
    return 3;
721
  }
722

    
723
  if (!lBIC || !(*lBIC)) {
724
    fprintf(stderr, "Missing local BIC\n");
725
    return 1;
726
  }
727
  if (!lIBAN || !(*lIBAN)) {
728
    fprintf(stderr, "Missing local IBAN\n");
729
    return 1;
730
  }
731
  rv=AB_Banking_CheckIban(lIBAN);
732
  if (rv != 0) {
733
    fprintf(stderr, "Invalid local IBAN (%s)\n", rIBAN);
734
    return 3;
735
  }
736

    
737
  return 0;
738
}
739

    
740

    
741

    
742
/* ========================================================================================================================
743
 *                                                checkTransactionLimits
744
 * ========================================================================================================================
745
 */
746

    
747
int checkTransactionLimits(const AB_TRANSACTION *t, const AB_TRANSACTION_LIMITS *lim, uint32_t flags) {
748
  if (lim==NULL) {
749
    fprintf(stderr, "ERROR: Job not supported with this account.\n");
750
    return 3;
751
  }
752

    
753
  if (flags & AQBANKING_TOOL_LIMITFLAGS_PURPOSE)
754
    if (AB_Banking_CheckTransactionAgainstLimits_Purpose(t, lim)) {
755
      fprintf(stderr, "ERROR: Purpose violates job limits.\n");
756
      return 3;
757
    }
758

    
759
  if (flags & AQBANKING_TOOL_LIMITFLAGS_NAMES)
760
    if (AB_Banking_CheckTransactionAgainstLimits_Names(t, lim)) {
761
      fprintf(stderr, "ERROR: Names violate job limits.\n");
762
      return 3;
763
    }
764

    
765
  if (flags & AQBANKING_TOOL_LIMITFLAGS_SEQUENCE)
766
    if (AB_Banking_CheckTransactionAgainstLimits_Sequence(t, lim)) {
767
      fprintf(stderr, "ERROR: Sequence violate job limits.\n");
768
      return 3;
769
    }
770

    
771
  if (flags & AQBANKING_TOOL_LIMITFLAGS_DATE)
772
    if (AB_Banking_CheckTransactionAgainstLimits_Date(t, lim)) {
773
      fprintf(stderr, "ERROR: Date violate job limits.\n");
774
      return 3;
775
    }
776

    
777
  if (flags & AQBANKING_TOOL_LIMITFLAGS_SEPA)
778
    if (AB_Banking_CheckTransactionForSepaConformity(t, 0)) {
779
      fprintf(stderr, "ERROR: Transaction fails SEPA conformity check.\n");
780
      return 3;
781
    }
782

    
783
  return 0;
784
}
785

    
786

    
787

    
788
/* ========================================================================================================================
789
 *                                                addTransactionToContextFile
790
 * ========================================================================================================================
791
 */
792

    
793
int addTransactionToContextFile(const AB_TRANSACTION *t, const char *ctxFile) {
794
  int rv;
795
  AB_IMEXPORTER_CONTEXT *ctx=NULL;
796

    
797
  /* load ctx file */
798
  rv=readContext(ctxFile, &ctx, 0);
799
  if (rv<0) {
800
    DBG_ERROR(0, "Error reading context (%d)", rv);
801
    return 4;
802
  }
803

    
804
  /* add transaction to */
805
  AB_ImExporterContext_AddTransaction(ctx, AB_Transaction_dup(t));
806

    
807
  /* write result back */
808
  rv=writeContext(ctxFile, ctx);
809
  AB_ImExporterContext_free(ctx);
810
  if (rv<0) {
811
    DBG_ERROR(0, "Error writing context file (%d)", rv);
812
    return 4;
813
  }
814

    
815
  /* write result */
816
  rv=writeContext(ctxFile, ctx);
817
  AB_ImExporterContext_free(ctx);
818
  if (rv<0) {
819
    DBG_ERROR(0, "Error writing context file (%d)", rv);
820
    AB_ImExporterContext_free(ctx);
821
    return 4;
822
  }
823
  AB_ImExporterContext_free(ctx);
824

    
825
  return 0;
826
}
827

    
828

    
829

    
830
/* ========================================================================================================================
831
 *                                                execBankingJobs
832
 * ========================================================================================================================
833
 */
834

    
835
int execBankingJobs(AB_BANKING *ab, AB_TRANSACTION_LIST2 *tList, const char *ctxFile) {
836
  int rv;
837
  int rvExec=0;
838
  AB_IMEXPORTER_CONTEXT *ctx=NULL;
839

    
840
  /* execute job */
841
  ctx=AB_ImExporterContext_new();
842
  rv=AB_Banking_SendCommands(ab, tList, ctx);
843
  if (rv) {
844
    fprintf(stderr, "Error on executeQueue (%d)\n", rv);
845
    rvExec=3;
846
  }
847

    
848
  /* write result */
849
  rv=writeContext(ctxFile, ctx);
850
  AB_ImExporterContext_free(ctx);
851
  if (rv<0) {
852
    DBG_ERROR(0, "Error writing context file (%d)", rv);
853
    if (rvExec==0)
854
      return 4;
855
  }
856

    
857
  return rvExec;
858
}
859

    
860

    
861

    
862
/* ========================================================================================================================
863
 *                                                execSingleBankingJob
864
 * ========================================================================================================================
865
 */
866

    
867
int execSingleBankingJob(AB_BANKING *ab, AB_TRANSACTION *t, const char *ctxFile) {
868
  AB_TRANSACTION_LIST2 *jobList;
869
  int rv;
870

    
871
  jobList=AB_Transaction_List2_new();
872
  AB_Transaction_List2_PushBack(jobList, t);
873
  rv=execBankingJobs(ab, jobList, ctxFile);
874
  AB_Transaction_List2_free(jobList);
875

    
876
  return rv;
877
}
878

    
879

    
880

    
881
/* ========================================================================================================================
882
 *                                                createAndCheckRequest
883
 * ========================================================================================================================
884
 */
885

    
886
AB_TRANSACTION *createAndCheckRequest(AB_BANKING *ab, AB_ACCOUNT_SPEC *as, AB_TRANSACTION_COMMAND cmd) {
887
  if (AB_AccountSpec_GetTransactionLimitsForCommand(as, cmd)) {
888
    AB_TRANSACTION *j;
889

    
890
    j=AB_Transaction_new();
891
    AB_Transaction_SetUniqueAccountId(j, AB_AccountSpec_GetUniqueId(as));
892
    AB_Transaction_SetCommand(j, cmd);
893
    return j;
894
  }
895
  else {
896
    return NULL;
897
  }
898
}
899

    
900

    
901

    
902
/* ========================================================================================================================
903
 *                                                createAndAddRequest
904
 * ========================================================================================================================
905
 */
906

    
907
int createAndAddRequest(AB_BANKING *ab,
908
                        AB_TRANSACTION_LIST2 *tList,
909
                        AB_ACCOUNT_SPEC *as,
910
                        AB_TRANSACTION_COMMAND cmd,
911
                        const GWEN_DATE *fromDate,
912
                        const GWEN_DATE *toDate,
913
                        int ignoreUnsupported) {
914
  uint32_t aid;
915
  AB_TRANSACTION *j;
916

    
917
  assert(as);
918
  aid=AB_AccountSpec_GetUniqueId(as);
919

    
920
  j=createAndCheckRequest(ab, as, cmd);
921
  if (j) {
922
    if (cmd==AB_Transaction_CommandGetTransactions) {
923
      if (fromDate)
924
        AB_Transaction_SetFirstDate(j, fromDate);
925
      if (toDate)
926
        AB_Transaction_SetLastDate(j, toDate);
927
    }
928
    AB_Transaction_List2_PushBack(tList, j);
929
    return 0;
930
  }
931
  else {
932
    if (ignoreUnsupported) {
933
      fprintf(stderr, "Warning: Ignoring request \"%s\" for %lu, not supported.\n",
934
              AB_Transaction_Command_toString(cmd),
935
              (unsigned long int) aid);
936
      return 0;
937
    }
938
    else {
939
      fprintf(stderr, "Error: Request \"%s\" for %lu not supported.\n",
940
              AB_Transaction_Command_toString(cmd),
941
              (unsigned long int) aid);
942
      return GWEN_ERROR_GENERIC;
943
    }
944
  }
945
}
946

    
947

    
948

    
949
/* ========================================================================================================================
950
 *                                                createAndAddRequests
951
 * ========================================================================================================================
952
 */
953

    
954
int createAndAddRequests(AB_BANKING *ab,
955
                         AB_TRANSACTION_LIST2 *tList,
956
                         AB_ACCOUNT_SPEC *as,
957
                         const GWEN_DATE *fromDate,
958
                         const GWEN_DATE *toDate,
959
                         uint32_t requestFlags) {
960
  int ignoreUnsupported=requestFlags & AQBANKING_TOOL_REQUEST_IGNORE_UNSUP;
961
  int rv;
962

    
963
  assert(ab);
964
  assert(tList);
965
  assert(as);
966

    
967
  /* create and add requests */
968
  if (requestFlags & AQBANKING_TOOL_REQUEST_BALANCE) {
969
    rv=createAndAddRequest(ab, tList, as, AB_Transaction_CommandGetBalance, fromDate, toDate, ignoreUnsupported);
970
    if (rv)
971
      return rv;
972
  }
973

    
974
  if (requestFlags & AQBANKING_TOOL_REQUEST_STATEMENTS) {
975
    rv=createAndAddRequest(ab, tList, as, AB_Transaction_CommandGetTransactions, fromDate, toDate, ignoreUnsupported);
976
    if (rv)
977
      return rv;
978
  }
979

    
980
  if (requestFlags & AQBANKING_TOOL_REQUEST_SEPASTO) {
981
    rv=createAndAddRequest(ab, tList, as, AB_Transaction_CommandSepaGetStandingOrders, fromDate, toDate, ignoreUnsupported);
982
    if (rv)
983
      return rv;
984
  }
985

    
986
  if (requestFlags & AQBANKING_TOOL_REQUEST_ESTATEMENTS) {
987
    rv=createAndAddRequest(ab, tList, as, AB_Transaction_CommandGetEStatements, fromDate, toDate, ignoreUnsupported);
988
    if (rv)
989
      return rv;
990
  }
991

    
992
  return 0;
993
}
994

    
995

    
996

    
997