Project

General

Profile

Download (13.8 KB) Statistics
| Branch: | Tag: | Revision:

aqbanking / src / libs / plugins / backends / aqhbci / applayer / outbox.c @ fe0aee9d

1
/***************************************************************************
2
    begin       : Mon Mar 01 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

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

    
15

    
16
#include "outbox_p.h"
17

    
18
#include "aqhbci/ajobs/accountjob_l.h"
19

    
20
#include "aqhbci/applayer/cbox_prepare.h"
21
#include "aqhbci/applayer/cbox_queue.h"
22

    
23
#include "aqbanking/i18n_l.h"
24

    
25
#include <gwenhywfar/debug.h>
26
#include <gwenhywfar/gui.h>
27

    
28
#include <assert.h>
29

    
30

    
31
/*#define EXTREME_DEBUGGING */
32

    
33

    
34

    
35
/* ------------------------------------------------------------------------------------------------
36
 * forward declarations
37
 * ------------------------------------------------------------------------------------------------
38
 */
39

    
40
static unsigned int _countTodoJobs(AH_OUTBOX *ob);
41
static int _sendOutboxWithProbablyLockedUsers(AH_OUTBOX *ob);
42
static AH_JOB *_findTransferJobInCheckJobList(const AH_JOB_LIST *jl, AB_USER *u, AB_ACCOUNT *a, const char *jobName);
43
static int _prepare(AH_OUTBOX *ob);
44
static void _finishCBox(AH_OUTBOX *ob, AH_OUTBOX_CBOX *cbox);
45
static int _sendAndRecvCustomerBoxes(AH_OUTBOX *ob);
46
static int _lockUsers(AH_OUTBOX *ob, AB_USER_LIST2 *lockedUsers);
47
static int _unlockUsers(AH_OUTBOX *ob, AB_USER_LIST2 *lockedUsers, int abandon);
48
static void _finishRemainingCustomerBoxes(AH_OUTBOX *ob);
49
static AH_OUTBOX_CBOX *_findCBox(const AH_OUTBOX *ob, const AB_USER *u);
50

    
51

    
52
/* ------------------------------------------------------------------------------------------------
53
 * implementations
54
 * ------------------------------------------------------------------------------------------------
55
 */
56

    
57

    
58

    
59
AH_OUTBOX *AH_Outbox_new(AB_PROVIDER *pro)
60
{
61
  AH_OUTBOX *ob;
62

    
63
  assert(pro);
64
  GWEN_NEW_OBJECT(AH_OUTBOX, ob);
65
  GWEN_INHERIT_INIT(AH_OUTBOX, ob);
66

    
67
  ob->provider=pro;
68
  ob->userBoxes=AH_OutboxCBox_List_new();
69
  ob->finishedJobs=AH_Job_List_new();
70
  ob->usage=1;
71
  return ob;
72
}
73

    
74

    
75

    
76
void AH_Outbox_free(AH_OUTBOX *ob)
77
{
78
  if (ob) {
79
    assert(ob->usage);
80
    if (--(ob->usage)==0) {
81
      AH_OutboxCBox_List_free(ob->userBoxes);
82
      AH_Job_List_free(ob->finishedJobs);
83
      GWEN_INHERIT_FINI(AH_OUTBOX, ob);
84
      GWEN_FREE_OBJECT(ob);
85
    }
86
  }
87
}
88

    
89

    
90

    
91
void AH_Outbox_Attach(AH_OUTBOX *ob)
92
{
93
  assert(ob);
94
  ob->usage++;
95
}
96

    
97

    
98

    
99
AB_IMEXPORTER_CONTEXT *AH_Outbox_GetImExContext(const AH_OUTBOX *ob)
100
{
101
  assert(ob);
102
  return ob->context;
103
}
104

    
105

    
106

    
107
AH_JOB_LIST *AH_Outbox_GetFinishedJobs(AH_OUTBOX *ob)
108
{
109
  assert(ob);
110
  assert(ob->usage);
111
  return ob->finishedJobs;
112
}
113

    
114

    
115

    
116
int AH_Outbox_Execute(AH_OUTBOX *ob,
117
                      AB_IMEXPORTER_CONTEXT *ctx,
118
                      int withProgress, int nounmount, int doLock)
119
{
120
  int rv;
121
  uint32_t pid=0;
122
  AB_USER_LIST2 *lockedUsers=NULL;
123

    
124
  assert(ob);
125

    
126
  if (withProgress) {
127
    pid=GWEN_Gui_ProgressStart(GWEN_GUI_PROGRESS_DELAY |
128
                               GWEN_GUI_PROGRESS_ALLOW_EMBED |
129
                               GWEN_GUI_PROGRESS_SHOW_PROGRESS |
130
                               GWEN_GUI_PROGRESS_SHOW_ABORT,
131
                               I18N("Executing Jobs"),
132
                               I18N("Now the jobs are sent via their "
133
                                    "backends to the credit institutes."),
134
                               _countTodoJobs(ob),
135
                               0);
136
  }
137

    
138
  ob->context=ctx;
139

    
140
  if (doLock) {
141
    lockedUsers=AB_User_List2_new();
142
    rv=_lockUsers(ob, lockedUsers);
143
    if (rv<0) {
144
      DBG_INFO(AQHBCI_LOGDOMAIN, "here (%d)", rv);
145
      AB_User_List2_free(lockedUsers);
146
    }
147
  }
148
  else
149
    rv=0;
150

    
151
  if (rv==0) {
152
    rv=_sendOutboxWithProbablyLockedUsers(ob);
153
    if (rv<0) {
154
      DBG_INFO(AQHBCI_LOGDOMAIN, "here (%d)", rv);
155
    }
156
    if (doLock) {
157
      int rv2;
158

    
159
      rv2=_unlockUsers(ob, lockedUsers, 0);
160
      if (rv2<0) {
161
        DBG_INFO(AQHBCI_LOGDOMAIN, "here (%d)", rv2);
162
      }
163
      AB_User_List2_free(lockedUsers);
164
      if (rv==0 && rv2!=0)
165
        rv=rv2;
166
    }
167
  }
168

    
169
  if (!nounmount)
170
    AB_Banking_ClearCryptTokenList(AB_Provider_GetBanking(ob->provider));
171

    
172
  if (withProgress) {
173
    GWEN_Gui_ProgressEnd(pid);
174
  }
175

    
176
  ob->context=NULL;
177
  return rv;
178
}
179

    
180

    
181

    
182
AH_JOB *AH_Outbox_FindTransferJob(AH_OUTBOX *ob, AB_USER *u, AB_ACCOUNT *a, const char *jobName)
183
{
184
  AH_OUTBOX_CBOX *cbox;
185
  AH_JOB *j;
186

    
187
  assert(ob);
188
  assert(u);
189
  assert(a);
190
  assert(jobName);
191

    
192
  DBG_INFO(AQHBCI_LOGDOMAIN, "Searching for %s job", jobName);
193
  cbox=AH_OutboxCBox_List_First(ob->userBoxes);
194
  while (cbox) {
195
    if (AH_OutboxCBox_GetUser(cbox)==u) {
196
      AH_JOBQUEUE *jq;
197

    
198
      /* check jobs in lists */
199
      j=_findTransferJobInCheckJobList(AH_OutboxCBox_GetTodoJobs(cbox), u, a, jobName);
200
      if (j)
201
        return j;
202

    
203
      /* check jobs in queues */
204
      jq=AH_JobQueue_List_First(AH_OutboxCBox_GetTodoQueues(cbox));
205
      while (jq) {
206
        const AH_JOB_LIST *jl;
207

    
208
        jl=AH_JobQueue_GetJobList(jq);
209
        if (jl) {
210
          j=_findTransferJobInCheckJobList(jl, u, a, jobName);
211
          if (j)
212
            return j;
213
        }
214
        jq=AH_JobQueue_List_Next(jq);
215
      } /* while */
216
    }
217
    else {
218
      DBG_WARN(AQHBCI_LOGDOMAIN, "Customer doesn't match");
219
    }
220

    
221
    cbox=AH_OutboxCBox_List_Next(cbox);
222
  } /* while */
223

    
224
  DBG_INFO(AQHBCI_LOGDOMAIN, "No matching multi job found");
225
  return 0;
226
}
227

    
228

    
229

    
230
int _sendOutboxWithProbablyLockedUsers(AH_OUTBOX *ob)
231
{
232
  unsigned int jobCount;
233
  int rv;
234

    
235
  assert(ob);
236
  jobCount=_countTodoJobs(ob);
237
  if (jobCount==0) {
238
    DBG_WARN(AQHBCI_LOGDOMAIN, "Empty outbox");
239
    return 0;
240
  }
241

    
242
  GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Notice, I18N("AqHBCI started"));
243

    
244
  rv=_prepare(ob);
245
  if (rv) {
246
    DBG_ERROR(AQHBCI_LOGDOMAIN, "Error preparing jobs for sending.");
247
    return rv;
248
  }
249

    
250
  rv=_sendAndRecvCustomerBoxes(ob);
251
  if (rv) {
252
    DBG_ERROR(AQHBCI_LOGDOMAIN, "Error while sending outbox.");
253
    return rv;
254
  }
255

    
256
  GWEN_Gui_ProgressLog(0, GWEN_LoggerLevel_Notice, I18N("AqHBCI finished."));
257
  return 0;
258
}
259

    
260

    
261

    
262
int _lockUsers(AH_OUTBOX *ob, AB_USER_LIST2 *lockedUsers)
263
{
264
  AH_OUTBOX_CBOX *cbox;
265

    
266
  assert(ob);
267

    
268
  cbox=AH_OutboxCBox_List_First(ob->userBoxes);
269
  while (cbox) {
270
    int rv;
271
    AB_USER *user;
272

    
273
    user=AH_OutboxCBox_GetUser(cbox);
274

    
275
    DBG_INFO(AQHBCI_LOGDOMAIN, "Locking customer \"%lu\"",
276
             (unsigned long int) AB_User_GetUniqueId(user));
277
    GWEN_Gui_ProgressLog2(0,
278
                          GWEN_LoggerLevel_Info,
279
                          I18N("Locking customer \"%lu\""),
280
                          (unsigned long int) AB_User_GetUniqueId(user));
281
    rv=AB_Provider_BeginExclUseUser(ob->provider, user);
282
    if (rv<0) {
283
      DBG_ERROR(AQHBCI_LOGDOMAIN, "Could not lock customer [%lu] (%d)", (unsigned long int) AB_User_GetUniqueId(user), rv);
284
      GWEN_Gui_ProgressLog2(0,
285
                            GWEN_LoggerLevel_Error,
286
                            I18N("Could not lock user %lu (%d)"),
287
                            (unsigned long int) AB_User_GetUniqueId(user),
288
                            rv);
289
      _unlockUsers(ob, lockedUsers, 1); /* abandon */
290
      return rv;
291
    }
292
    AB_User_List2_PushBack(lockedUsers, user);
293

    
294
    cbox=AH_OutboxCBox_List_Next(cbox);
295
  } /* while */
296

    
297
  return 0;
298
}
299

    
300

    
301

    
302
int _unlockUsers(AH_OUTBOX *ob, AB_USER_LIST2 *lockedUsers, int abandon)
303
{
304
  int errors=0;
305
  AB_USER_LIST2_ITERATOR *it;
306

    
307
  assert(ob);
308

    
309
  it=AB_User_List2_First(lockedUsers);
310
  if (it) {
311
    AB_USER *u;
312

    
313
    u=AB_User_List2Iterator_Data(it);
314
    while (u) {
315
      int rv;
316

    
317
      DBG_INFO(AQHBCI_LOGDOMAIN, "Unlocking customer \"%lu\"",
318
               (unsigned long int) AB_User_GetUniqueId(u));
319
      GWEN_Gui_ProgressLog2(0,
320
                            GWEN_LoggerLevel_Info,
321
                            I18N("Unlocking customer \"%lu\""),
322
                            (unsigned long int) AB_User_GetUniqueId(u));
323
      rv=AB_Provider_EndExclUseUser(ob->provider, u, abandon);
324
      if (rv<0) {
325
        DBG_ERROR(AQHBCI_LOGDOMAIN,
326
                  "Could not unlock user %lu (%d)",
327
                  (unsigned long int) AB_User_GetUniqueId(u),
328
                  rv);
329
        GWEN_Gui_ProgressLog2(0,
330
                              GWEN_LoggerLevel_Error,
331
                              I18N("Could not unlock user %lu (%d)"),
332
                              (unsigned long int) AB_User_GetUniqueId(u),
333
                              rv);
334
        errors++;
335
      }
336
      u=AB_User_List2Iterator_Next(it);
337
    }
338
    AB_User_List2Iterator_free(it);
339
  }
340

    
341
  if (errors)
342
    return GWEN_ERROR_GENERIC;
343

    
344
  return 0;
345
}
346

    
347

    
348

    
349
AH_OUTBOX_CBOX *_findCBox(const AH_OUTBOX *ob, const AB_USER *u)
350
{
351
  AH_OUTBOX_CBOX *cbox;
352

    
353
  assert(ob);
354
  assert(u);
355
  cbox=AH_OutboxCBox_List_First(ob->userBoxes);
356
  while (cbox) {
357
    if (AH_OutboxCBox_GetUser(cbox)==u) {
358
      DBG_DEBUG(AQHBCI_LOGDOMAIN, "CBox for customer \"%s\" found", AB_User_GetCustomerId(u));
359
      return cbox;
360
    }
361
    cbox=AH_OutboxCBox_List_Next(cbox);
362
  } /* while */
363
  DBG_INFO(AQHBCI_LOGDOMAIN, "CBox for customer \"%s\" not found", AB_User_GetCustomerId(u));
364
  return 0;
365
}
366

    
367

    
368

    
369

    
370

    
371
void AH_Outbox_AddJob(AH_OUTBOX *ob, AH_JOB *j)
372
{
373
  AB_USER *u;
374
  AH_OUTBOX_CBOX *cbox;
375

    
376
  assert(ob);
377
  assert(j);
378

    
379
  u=AH_Job_GetUser(j);
380
  assert(u);
381

    
382
  cbox=_findCBox(ob, u);
383
  if (!cbox) {
384
    DBG_NOTICE(AQHBCI_LOGDOMAIN, "Creating CBox for customer \"%s\"", AB_User_GetCustomerId(u));
385
    cbox=AH_OutboxCBox_new(ob->provider, u, ob);
386
    AH_OutboxCBox_List_Add(cbox, ob->userBoxes);
387
  }
388
  /* attach to job so that it will never be destroyed from me */
389
  AH_Job_Attach(j);
390
  AH_OutboxCBox_AddTodoJob(cbox, j);
391
}
392

    
393

    
394

    
395
int _prepare(AH_OUTBOX *ob)
396
{
397
  AH_OUTBOX_CBOX *cbox;
398
  unsigned int errors;
399

    
400
  assert(ob);
401

    
402
  errors=0;
403
  cbox=AH_OutboxCBox_List_First(ob->userBoxes);
404
  while (cbox) {
405
    AB_USER *u;
406

    
407
    u=AH_OutboxCBox_GetUser(cbox);
408
    DBG_INFO(AQHBCI_LOGDOMAIN, "Preparing queues for customer \"%s\"", AB_User_GetCustomerId(u));
409
    if (AH_OutboxCBox_Prepare(cbox)) {
410
      DBG_INFO(AQHBCI_LOGDOMAIN, "Error preparing cbox");
411
      errors++;
412
    }
413
    else {
414
      DBG_INFO(AQHBCI_LOGDOMAIN, "Preparing queues for customer \"%s\": done", AB_User_GetCustomerId(u));
415
    }
416
    cbox=AH_OutboxCBox_List_Next(cbox);
417
  } /* while */
418

    
419
  if (errors) {
420
    DBG_INFO(AQHBCI_LOGDOMAIN, "%d errors occurred", errors);
421
    return GWEN_ERROR_GENERIC;
422
  }
423

    
424
  return 0;
425
}
426

    
427

    
428

    
429
void _finishCBox(AH_OUTBOX *ob, AH_OUTBOX_CBOX *cbox)
430
{
431
  AH_JOB_LIST *jl;
432
  AH_JOB *j;
433

    
434
  assert(ob);
435
  assert(cbox);
436

    
437
  AH_OutboxCBox_Finish(cbox);
438
  jl=AH_OutboxCBox_TakeFinishedJobs(cbox);
439
  assert(jl);
440
  DBG_INFO(AQHBCI_LOGDOMAIN, "Finishing customer outbox");
441
  while ((j=AH_Job_List_First(jl))) {
442
    int rv;
443
    AH_JOB_STATUS st;
444

    
445
    AH_Job_List_Del(j);
446
    st=AH_Job_GetStatus(j);
447
    if (st==AH_JobStatusAnswered) {
448
      DBG_INFO(AQHBCI_LOGDOMAIN, "Letting job \"%s\" process", AH_Job_GetName(j));
449
      rv=AH_Job_Process(j, ob->context);
450
      if (rv) {
451
        DBG_ERROR(AQHBCI_LOGDOMAIN, "Error in job \"%s\": %d", AH_Job_GetName(j), rv);
452
        AH_Job_SetStatus(j, AH_JobStatusError);
453

    
454
        GWEN_Gui_ProgressLog2(0,
455
                              GWEN_LoggerLevel_Error,
456
                              I18N("Error processing job %s"),
457
                              AH_Job_GetName(j));
458
      }
459
    }
460
    else {
461
      DBG_INFO(AQHBCI_LOGDOMAIN,
462
               "Skipping job \"%s\" because of status \"%s\" (%d)",
463
               AH_Job_GetName(j), AH_Job_StatusName(st), st);
464
    }
465
    AH_Job_List_Add(j, ob->finishedJobs);
466
  } /* while */
467
  AH_Job_List_free(jl);
468
}
469

    
470

    
471

    
472
void _finishRemainingCustomerBoxes(AH_OUTBOX *ob)
473
{
474
  AH_OUTBOX_CBOX *cbox;
475

    
476
  assert(ob);
477
  while ((cbox=AH_OutboxCBox_List_First(ob->userBoxes))) {
478
    _finishCBox(ob, cbox);
479
    AH_OutboxCBox_List_Del(cbox);
480
    AH_OutboxCBox_free(cbox);
481
  } /* while */
482
}
483

    
484

    
485

    
486
int _sendAndRecvCustomerBoxes(AH_OUTBOX *ob)
487
{
488
  AH_OUTBOX_CBOX *cbox;
489
  int rv;
490
  int errors;
491

    
492
  errors=0;
493
  while ((cbox=AH_OutboxCBox_List_First(ob->userBoxes))) {
494
    AB_USER *u;
495

    
496
    u=AH_OutboxCBox_GetUser(cbox);
497
    DBG_INFO(AQHBCI_LOGDOMAIN,
498
             "Sending messages for customer \"%s\"",
499
             AB_User_GetCustomerId(u));
500

    
501
    rv=AH_OutboxCBox_SendAndRecvBox(cbox);
502
    _finishCBox(ob, cbox);
503
    AH_OutboxCBox_List_Del(cbox);
504
    AH_OutboxCBox_free(cbox);
505
    if (rv)
506
      errors++;
507
    if (rv==GWEN_ERROR_USER_ABORTED) {
508
      _finishRemainingCustomerBoxes(ob);
509
      return rv;
510
    }
511
  } /* while */
512

    
513
  return 0;
514
}
515

    
516

    
517

    
518
unsigned int _countTodoJobs(AH_OUTBOX *ob)
519
{
520
  unsigned int cnt;
521
  AH_OUTBOX_CBOX *cbox;
522

    
523
  assert(ob);
524
  cnt=0;
525
  cbox=AH_OutboxCBox_List_First(ob->userBoxes);
526
  while (cbox) {
527
    AH_JOBQUEUE_LIST *todoQueues;
528
    AH_JOB_LIST *todoJobs;
529
    AH_JOBQUEUE *jq;
530

    
531
    todoQueues=AH_OutboxCBox_GetTodoQueues(cbox);
532
    todoJobs=AH_OutboxCBox_GetTodoJobs(cbox);
533
    cnt+=AH_Job_List_GetCount(todoJobs);
534
    jq=AH_JobQueue_List_First(todoQueues);
535
    while (jq) {
536
      if (!(AH_JobQueue_GetFlags(jq) & AH_JOBQUEUE_FLAGS_OUTBOX)) {
537
        const AH_JOB_LIST *jl;
538

    
539
        jl=AH_JobQueue_GetJobList(jq);
540
        if (jl) {
541
          AH_JOB *j;
542

    
543
          j=AH_Job_List_First(jl);
544
          while (j) {
545
            if (!(AH_Job_GetFlags(j) & AH_JOB_FLAGS_OUTBOX))
546
              cnt++;
547

    
548
            j=AH_Job_List_Next(j);
549
          } /* while */
550
        }
551
      }
552
      jq=AH_JobQueue_List_Next(jq);
553
    } /* while */
554
    cbox=AH_OutboxCBox_List_Next(cbox);
555
  } /* while */
556

    
557
  return cnt;
558
}
559

    
560

    
561

    
562
AH_JOB *_findTransferJobInCheckJobList(const AH_JOB_LIST *jl, AB_USER *u, AB_ACCOUNT *a, const char *jobName)
563
{
564
  AH_JOB *j;
565

    
566
  assert(jl);
567
  j=AH_Job_List_First(jl);
568
  while (j) {
569
    DBG_INFO(AQHBCI_LOGDOMAIN, "Checking job \"%s\"", AH_Job_GetName(j));
570
    if (strcasecmp(AH_Job_GetName(j), jobName)==0 &&
571
        AH_AccountJob_GetAccount(j)==a) {
572
      if (AH_Job_GetTransferCount(j)<AH_Job_GetMaxTransfers(j))
573
        break;
574
      else {
575
        DBG_INFO(AQHBCI_LOGDOMAIN, "Job's already full");
576
      }
577
    }
578
    else {
579
      DBG_INFO(AQHBCI_LOGDOMAIN, "Job doesn't match");
580
    }
581

    
582
    j=AH_Job_List_Next(j);
583
  } /* while */
584

    
585
  return j;
586
}
587

    
588

    
589