Project

General

Profile

Statistics
| Branch: | Tag: | Revision:

aqbanking / src / libs / plugins / backends / aqhbci / joblayer / jobqueue.c @ 560f92f8

History | View | Annotate | Download (34.3 KB)

1
/***************************************************************************
2
    begin       : Mon Mar 01 2004
3
    copyright   : (C) 2019 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 "jobqueue_p.h"
17
#include "aqhbci_l.h"
18
#include "job_l.h"
19
#include "aqhbci/banking/user_l.h"
20
#include "message_l.h"
21
#include "hbci_l.h"
22
#include "dialog_l.h"
23

    
24
#include <gwenhywfar/debug.h>
25
#include <gwenhywfar/misc.h>
26
#include <gwenhywfar/logger.h>
27
#include <gwenhywfar/gui.h>
28
#include <gwenhywfar/text.h>
29

    
30
#include <assert.h>
31

    
32

    
33

    
34
GWEN_LIST_FUNCTIONS(AH_JOBQUEUE, AH_JobQueue);
35

    
36

    
37

    
38
AH_JOBQUEUE *AH_JobQueue_new(AB_USER *u)
39
{
40
  AH_JOBQUEUE *jq;
41

    
42
  assert(u);
43

    
44
  GWEN_NEW_OBJECT(AH_JOBQUEUE, jq);
45
  GWEN_LIST_INIT(AH_JOBQUEUE, jq);
46

    
47
  jq->user=u;
48
  jq->signers=GWEN_StringList_new();
49
  jq->jobs=AH_Job_List_new();
50
  jq->usage=1;
51
  return jq;
52
}
53

    
54

    
55

    
56
void AH_JobQueue_free(AH_JOBQUEUE *jq)
57
{
58
  if (jq) {
59
    assert(jq->usage);
60
    if (--(jq->usage)==0) {
61
      GWEN_StringList_free(jq->signers);
62
      AH_Job_List_free(jq->jobs);
63
      free(jq->usedTan);
64
      free(jq->usedPin);
65

    
66
      GWEN_LIST_FINI(AH_JOBQUEUE, jq);
67
      GWEN_FREE_OBJECT(jq);
68
    }
69
  }
70
}
71

    
72

    
73

    
74
void AH_JobQueue_Attach(AH_JOBQUEUE *jq)
75
{
76
  assert(jq);
77
  jq->usage++;
78
}
79

    
80

    
81

    
82
AH_JOBQUEUE *AH_JobQueue_fromQueue(AH_JOBQUEUE *oldq)
83
{
84
  AH_JOBQUEUE *jq;
85

    
86
  assert(oldq);
87

    
88
  jq=AH_JobQueue_new(oldq->user);
89
  jq->signers=GWEN_StringList_dup(oldq->signers);
90
  jq->secProfile=oldq->secProfile;
91
  jq->secClass=oldq->secClass;
92
  if (oldq->usedTan)
93
    jq->usedTan=strdup(oldq->usedTan);
94
  if (oldq->usedPin)
95
    jq->usedPin=strdup(oldq->usedPin);
96

    
97
  return jq;
98
}
99

    
100

    
101

    
102
void AH_JobQueue_SetUsedTan(AH_JOBQUEUE *jq, const char *s)
103
{
104
  assert(jq);
105
  assert(jq->usage);
106
  free(jq->usedTan);
107
  if (s)
108
    jq->usedTan=strdup(s);
109
  else
110
    jq->usedTan=0;
111
}
112

    
113

    
114

    
115
void AH_JobQueue_SetUsedPin(AH_JOBQUEUE *jq, const char *s)
116
{
117
  assert(jq);
118
  assert(jq->usage);
119
  free(jq->usedPin);
120
  if (s)
121
    jq->usedPin=strdup(s);
122
  else
123
    jq->usedPin=0;
124
}
125

    
126

    
127

    
128
AH_JOBQUEUE_ADDRESULT AH_JobQueue_AddJob(AH_JOBQUEUE *jq, AH_JOB *j)
129
{
130
  int jobsPerMsg;
131
  int maxJobTypes;
132
  int jobCount;
133
  int jobTypeCount;
134
  int thisJobTypeCount;
135
  int hasSingle;
136
  int crypt;
137
  int needTAN;
138
  int noSysId;
139
  int signSeqOne;
140
  int noItan;
141
  GWEN_STRINGLIST *jobTypes;
142
  AH_JOB *cj;
143
  AH_BPD *bpd;
144

    
145
  assert(jq);
146
  assert(jq->usage);
147

    
148
  /* job owner must equal queue owner */
149
  if (AH_Job_GetUser(j)!=jq->user) {
150
    DBG_INFO(AQHBCI_LOGDOMAIN, "Owner of the job doesn't match");
151
    return AH_JobQueueAddResultJobLimit;
152
  }
153

    
154
  /* sample some variables */
155
  bpd=AH_User_GetBpd(jq->user);
156
  jobsPerMsg=AH_Job_GetJobsPerMsg(j);
157
  maxJobTypes=AH_Bpd_GetJobTypesPerMsg(bpd);
158

    
159
  jobCount=0;
160
  jobTypeCount=0;
161
  thisJobTypeCount=0;
162
  hasSingle=0;
163
  crypt=0;
164
  needTAN=0;
165
  noSysId=0;
166
  signSeqOne=0;
167
  noItan=0;
168
  jobTypes=GWEN_StringList_new();
169
  cj=AH_Job_List_First(jq->jobs);
170
  while (cj) {
171
    jobCount++;
172
    GWEN_StringList_AppendString(jobTypes, AH_Job_GetName(cj), 0, 1);
173
    if (strcasecmp(AH_Job_GetName(cj), AH_Job_GetName(j))==0)
174
      thisJobTypeCount++;
175
    hasSingle|=((AH_Job_GetFlags(cj) & AH_JOB_FLAGS_SINGLE) ||
176
                (AH_Job_GetFlags(cj) & AH_JOB_FLAGS_DLGJOB));
177
    crypt|=(AH_Job_GetFlags(cj) & AH_JOB_FLAGS_CRYPT);
178
    needTAN|=(AH_Job_GetFlags(cj) & AH_JOB_FLAGS_NEEDTAN);
179
    noSysId|=(AH_Job_GetFlags(cj) & AH_JOB_FLAGS_NOSYSID);
180
    signSeqOne|=(AH_Job_GetFlags(cj) & AH_JOB_FLAGS_SIGNSEQONE);
181
    noItan|=(AH_Job_GetFlags(cj) & AH_JOB_FLAGS_NOITAN);
182
    cj=AH_Job_List_Next(cj);
183
  } /* while */
184
  /* Account for new job when checking limits for thisJobTypeCount and
185
   * jobTypeCount */
186
  thisJobTypeCount++;
187
  GWEN_StringList_AppendString(jobTypes, AH_Job_GetName(j), 0, 1);
188
  jobTypeCount=GWEN_StringList_Count(jobTypes);
189
  GWEN_StringList_free(jobTypes);
190

    
191
  if (strcasecmp(AH_Job_GetName(j), "JobTan")!=0) {
192
    if (jobCount &&
193
        (
194
          (crypt!=(AH_Job_GetFlags(j) & AH_JOB_FLAGS_CRYPT)) ||
195
          (needTAN!=(AH_Job_GetFlags(j) & AH_JOB_FLAGS_NEEDTAN)) ||
196
          (noSysId!=(AH_Job_GetFlags(j) & AH_JOB_FLAGS_NOSYSID)) ||
197
          (noItan!=(AH_Job_GetFlags(j) & AH_JOB_FLAGS_NOITAN))
198
        )
199
       ) {
200

    
201
      DBG_INFO(AQHBCI_LOGDOMAIN,
202
               "Encryption/TAN/SysId flags for queue and this job differ");
203
      return AH_JobQueueAddResultJobLimit;
204
    }
205

    
206
    /* check for single jobs */
207
    if (hasSingle) {
208
      DBG_INFO(AQHBCI_LOGDOMAIN,
209
               "Queue already contains a job which wants to be left alone");
210
      return AH_JobQueueAddResultQueueFull;
211
    }
212

    
213
    /* check if this job is single and there already are jobs in the queue */
214
    if (((AH_Job_GetFlags(j) & AH_JOB_FLAGS_SINGLE) ||
215
         (AH_Job_GetFlags(j) & AH_JOB_FLAGS_DLGJOB)) && jobCount) {
216
      DBG_INFO(AQHBCI_LOGDOMAIN,
217
               "Queue already contains jobs and this one has the SINGLE flag");
218
      return AH_JobQueueAddResultJobLimit;
219
    }
220

    
221
    /* check if adding this job would exceed the limit of jobs of this kind */
222
    if (jobsPerMsg && thisJobTypeCount>jobsPerMsg) {
223
      DBG_INFO(AQHBCI_LOGDOMAIN,
224
               "Too many jobs of this kind (limit is %d)", jobsPerMsg);
225
      return AH_JobQueueAddResultJobLimit;
226
    }
227

    
228
    /* check for maximum of different job types per message */
229
    if (maxJobTypes && jobTypeCount>maxJobTypes) {
230
      DBG_INFO(AQHBCI_LOGDOMAIN,
231
               "Too many different job types (limit is %d)", maxJobTypes);
232
      return AH_JobQueueAddResultJobLimit;
233
    }
234

    
235
    /* check security class */
236
    if (jq->secClass==0)
237
      jq->secClass=AH_Job_GetSecurityClass(j);
238
    else {
239
      if (jq->secClass!=AH_Job_GetSecurityClass(j)) {
240
        DBG_INFO(AQHBCI_LOGDOMAIN, "Job's security class doesn't match that of the queue (%d != %d)",
241
                 jq->secClass, AH_Job_GetSecurityClass(j));
242
        return AH_JobQueueAddResultJobLimit;
243
      }
244
    }
245

    
246
    /* check for signers */
247
    if (!jobCount && !GWEN_StringList_Count(jq->signers)) {
248
      const GWEN_STRINGLIST *sl;
249

    
250
      /* no jobs in queue and no signers,
251
       * so simply copy the signers of this job */
252
      sl=AH_Job_GetSigners(j);
253
      if (sl) {
254
        DBG_INFO(AQHBCI_LOGDOMAIN, "Copying %d signers from job to queue", GWEN_StringList_Count(sl));
255
        GWEN_StringList_free(jq->signers);
256
        jq->signers=GWEN_StringList_dup(sl);
257
      }
258
    }
259
    else {
260
      const GWEN_STRINGLIST *sl;
261
      GWEN_STRINGLISTENTRY *se;
262

    
263
      sl=AH_Job_GetSigners(j);
264
      if (GWEN_StringList_Count(sl)!=GWEN_StringList_Count(jq->signers)) {
265
        DBG_INFO(AQHBCI_LOGDOMAIN,
266
                 "Number of signers of the job differs from that of the queue");
267
        return AH_JobQueueAddResultJobLimit;
268
      }
269
      se=GWEN_StringList_FirstEntry(sl);
270
      while (se) {
271
        if (!GWEN_StringList_HasString(jq->signers,
272
                                       GWEN_StringListEntry_Data(se))) {
273
          DBG_INFO(AQHBCI_LOGDOMAIN, "Signers of the job differ from those of the queue");
274
          return AH_JobQueueAddResultJobLimit;
275
        }
276
        se=GWEN_StringListEntry_Next(se);
277
      } /* while se */
278
    }
279

    
280
    /* adjust queue flags according to current job */
281
    if (AH_Job_GetFlags(j) & AH_JOB_FLAGS_CRYPT)
282
      jq->flags|=AH_JOBQUEUE_FLAGS_CRYPT;
283
    if (AH_Job_GetFlags(j) & AH_JOB_FLAGS_SIGN)
284
      jq->flags|=AH_JOBQUEUE_FLAGS_SIGN;
285
    if (AH_Job_GetFlags(j) & AH_JOB_FLAGS_NEEDTAN)
286
      jq->flags|=AH_JOBQUEUE_FLAGS_NEEDTAN;
287
    if (AH_Job_GetFlags(j) & AH_JOB_FLAGS_NOSYSID)
288
      jq->flags|=AH_JOBQUEUE_FLAGS_NOSYSID;
289
    if (AH_Job_GetFlags(j) & AH_JOB_FLAGS_SIGNSEQONE)
290
      jq->flags|=AH_JOBQUEUE_FLAGS_SIGNSEQONE;
291
    if (AH_Job_GetFlags(j) & AH_JOB_FLAGS_NOITAN)
292
      jq->flags|=AH_JOBQUEUE_FLAGS_NOITAN;
293
  }
294

    
295
  /* update maximum security profile */
296
  if (AH_Job_GetSecurityProfile(j)>jq->secProfile)
297
    jq->secProfile=AH_Job_GetSecurityProfile(j);
298

    
299
  /* actually add job to queue */
300
  AH_Job_List_Add(j, jq->jobs);
301
  AH_Job_SetStatus(j, AH_JobStatusEnqueued);
302

    
303
  DBG_INFO(AQHBCI_LOGDOMAIN, "Job added to the queue");
304
  return AH_JobQueueAddResultOk;
305
}
306

    
307

    
308

    
309
const AH_JOB_LIST *AH_JobQueue_GetJobList(const AH_JOBQUEUE *jq)
310
{
311
  assert(jq);
312
  assert(jq->usage);
313
  return jq->jobs;
314
}
315

    
316

    
317

    
318
AH_JOB_LIST *AH_JobQueue_TakeJobList(AH_JOBQUEUE *jq)
319
{
320
  AH_JOB_LIST *jl;
321

    
322
  assert(jq);
323
  assert(jq->usage);
324
  jl=jq->jobs;
325
  jq->jobs=AH_Job_List_new();
326
  return jl;
327
}
328

    
329

    
330

    
331
AH_JOB *AH_JobQueue_GetFirstJob(const AH_JOBQUEUE *jq)
332
{
333
  assert(jq);
334
  assert(jq->usage);
335
  if (jq->jobs)
336
    return AH_Job_List_First(jq->jobs);
337

    
338
  return NULL;
339
}
340

    
341

    
342

    
343
AH_MSG *AH_JobQueue_ToMessage(AH_JOBQUEUE *jq, AH_DIALOG *dlg)
344
{
345
  AH_MSG *msg;
346
  AH_JOB *j;
347
  unsigned int encodedJobs;
348
  GWEN_STRINGLISTENTRY *se;
349
  int rv;
350

    
351
  assert(jq);
352
  assert(jq->usage);
353
  assert(dlg);
354

    
355
  if (!AH_Job_List_GetCount(jq->jobs)) {
356
    DBG_ERROR(AQHBCI_LOGDOMAIN, "Empty queue");
357
    return 0;
358
  }
359
  msg=AH_Msg_new(dlg);
360
  AH_Msg_SetHbciVersion(msg, AH_User_GetHbciVersion(jq->user));
361
  AH_Msg_SetSecurityProfile(msg, jq->secProfile);
362
  AH_Msg_SetSecurityClass(msg, jq->secClass);
363

    
364
  if (AH_JobQueue_GetFlags(jq) & AH_JOBQUEUE_FLAGS_NEEDTAN) {
365
    DBG_NOTICE(AQHBCI_LOGDOMAIN, "Queue needs a TAN");
366
  }
367
  else {
368
    DBG_NOTICE(AQHBCI_LOGDOMAIN, "Queue doesn't need a TAN");
369
  }
370
  AH_Msg_SetNeedTan(msg,
371
                    (AH_JobQueue_GetFlags(jq) & AH_JOBQUEUE_FLAGS_NEEDTAN));
372

    
373
  AH_Msg_SetNoSysId(msg,
374
                    (AH_JobQueue_GetFlags(jq) & AH_JOBQUEUE_FLAGS_NOSYSID));
375

    
376
  AH_Msg_SetSignSeqOne(msg,
377
                       (AH_JobQueue_GetFlags(jq) & AH_JOBQUEUE_FLAGS_SIGNSEQONE));
378

    
379
  /* copy signers */
380
  if (AH_JobQueue_GetFlags(jq) & AH_JOBQUEUE_FLAGS_SIGN) {
381
    se=GWEN_StringList_FirstEntry(jq->signers);
382
    if (!se) {
383
      DBG_ERROR(AQHBCI_LOGDOMAIN, "Signatures needed but no signer given");
384
      AH_Msg_free(msg);
385
      return 0;
386
    }
387
    while (se) {
388
      AH_Msg_AddSignerId(msg, GWEN_StringListEntry_Data(se));
389
      se=GWEN_StringListEntry_Next(se);
390
    } /* while */
391
  }
392

    
393
  /* copy crypter */
394
  if (jq->flags & AH_JOBQUEUE_FLAGS_CRYPT) {
395
    const char *s;
396

    
397
    s=AH_User_GetPeerId(jq->user);
398
    if (!s)
399
      s=AB_User_GetUserId(jq->user);
400
    AH_Msg_SetCrypterId(msg, s);
401
  }
402

    
403
  encodedJobs=0;
404
  j=AH_Job_List_First(jq->jobs);
405
  while (j) {
406
    AH_JOB_STATUS st;
407

    
408
    st=AH_Job_GetStatus(j);
409
    /* only encode jobs which have not already been sent or which have no errors */
410
    if (st==AH_JobStatusEnqueued) {
411
      unsigned int firstSeg;
412
      unsigned int lastSeg;
413
      GWEN_DB_NODE *jargs;
414
      GWEN_XMLNODE *jnode;
415
      GWEN_BUFFER *msgBuf;
416

    
417
      DBG_INFO(AQHBCI_LOGDOMAIN, "Encoding job \"%s\"", AH_Job_GetName(j));
418
      jargs=AH_Job_GetArguments(j);
419
      jnode=AH_Job_GetXmlNode(j);
420
      if (strcasecmp(GWEN_XMLNode_GetData(jnode), "message")==0) {
421
        const char *s;
422

    
423
        s=GWEN_XMLNode_GetProperty(jnode, "name", 0);
424
        if (s) {
425
          DBG_NOTICE(AQHBCI_LOGDOMAIN,
426
                     "Getting for message specific data (%s)", s);
427
          jargs=GWEN_DB_GetGroup(jargs, GWEN_PATH_FLAGS_NAMEMUSTEXIST, s);
428
          if (!jargs) {
429
            DBG_NOTICE(AQHBCI_LOGDOMAIN, "No message specific data");
430
            jargs=AH_Job_GetArguments(j);
431
          }
432
        }
433
      }
434

    
435
      firstSeg=AH_Msg_GetCurrentSegmentNumber(msg);
436
      msgBuf=AH_Msg_GetBuffer(msg);
437
      assert(msgBuf);
438
      lastSeg=AH_Msg_AddNode(msg, jnode, jargs);
439
      if (!lastSeg) {
440
        DBG_INFO(AQHBCI_LOGDOMAIN, "Could not encode job \"%s\"",
441
                 AH_Job_GetName(j));
442
        AH_Job_SetStatus(j, AH_JobStatusError);
443
      }
444
      else {
445
        AH_Job_SetFirstSegment(j, firstSeg);
446
        AH_Job_SetLastSegment(j, lastSeg);
447

    
448
        if (AH_Job_GetStatus(j)!=AH_JobStatusError) {
449
          DBG_INFO(AQHBCI_LOGDOMAIN, "Job \"%s\" encoded",
450
                   AH_Job_GetName(j));
451
          AH_Job_SetStatus(j, AH_JobStatusEncoded);
452
          encodedJobs++;
453
        }
454
      }
455
    } /* if status matches */
456
    j=AH_Job_List_Next(j);
457
  } /* while */
458

    
459
  if (!encodedJobs) {
460
    DBG_INFO(AQHBCI_LOGDOMAIN, "No job encoded");
461
    AH_Msg_free(msg);
462
    return 0;
463
  }
464
  rv=AH_Msg_EncodeMsg(msg);
465
  if (rv) {
466
    DBG_ERROR(AQHBCI_LOGDOMAIN, "Could not encode message (%d)", rv);
467

    
468
    j=AH_Job_List_First(jq->jobs);
469
    while (j) {
470
      if (AH_Job_GetStatus(j)==AH_JobStatusEncoded)
471
        AH_Job_SetStatus(j, AH_JobStatusError);
472
      j=AH_Job_List_Next(j);
473
    } /* while */
474
    AH_Msg_free(msg);
475
    return 0;
476
  }
477

    
478
  /*
479
   * inform all jobs that they have been encoded
480
   * this is needed for multi-message jobs so that they can prepare
481
   * themselves for the next message
482
   */
483
  j=AH_Job_List_First(jq->jobs);
484
  AH_JobQueue_SetUsedTan(jq, AH_Msg_GetTan(msg));
485
  AH_JobQueue_SetUsedPin(jq, AH_Msg_GetPin(msg));
486
  while (j) {
487
    const char *s;
488

    
489
    if (AH_Job_GetStatus(j)==AH_JobStatusEncoded) {
490
      /* store some information about the message in the job */
491
      AH_Job_SetMsgNum(j, AH_Msg_GetMsgNum(msg));
492
      AH_Job_SetDialogId(j, AH_Dialog_GetDialogId(dlg));
493
      /* store expected signer and crypter (if any) */
494
      s=AH_Msg_GetExpectedSigner(msg);
495
      if (s)
496
        AH_Job_SetExpectedSigner(j, s);
497
      s=AH_Msg_GetExpectedCrypter(msg);
498
      if (s)
499
        AH_Job_SetExpectedCrypter(j, s);
500

    
501
      /* store used TAN (if any) */
502
      s=AH_Msg_GetTan(msg);
503
      if (s)
504
        AH_Job_SetUsedTan(j, s);
505
    }
506
    j=AH_Job_List_Next(j);
507
  } /* while */
508

    
509

    
510
  DBG_INFO(AQHBCI_LOGDOMAIN, "Job queue encoded and ready to be sent");
511
  return msg;
512
}
513

    
514

    
515

    
516
int AH_JobQueue__CheckTans(AH_JOBQUEUE *jq, uint32_t guiid)
517
{
518
  AH_JOB *j;
519

    
520
  assert(jq);
521
  j=AH_Job_List_First(jq->jobs);
522
  while (j) {
523
    const char *tan;
524
    AB_USER *u;
525

    
526
    u=AH_Job_GetUser(j);
527
    assert(u);
528

    
529
    tan=AH_Job_GetUsedTan(j);
530
    if (tan) {
531
      int rv;
532

    
533
      if (AH_Job_GetFlags(j) & AH_JOB_FLAGS_TANUSED) {
534
        char tbuf[256];
535

    
536
        DBG_INFO(AQHBCI_LOGDOMAIN,
537
                 "TAN \"%s\" used", tan);
538
        snprintf(tbuf, sizeof(tbuf)-1,
539
                 I18N("TAN \"%s\" has been used, please strike it out."),
540
                 tan);
541
        tbuf[sizeof(tbuf)-1]=0;
542
        GWEN_Gui_ProgressLog(guiid,
543
                             GWEN_LoggerLevel_Notice,
544
                             tbuf);
545
        rv=AH_User_SetTanStatus(jq->user,
546
                                NULL, /* no challenge here */
547
                                tan,
548
                                GWEN_Gui_PasswordStatus_Used);
549
      }
550
      else {
551
        DBG_INFO(AQHBCI_LOGDOMAIN, "TAN not used");
552
        rv=AH_User_SetTanStatus(jq->user,
553
                                NULL, /* no challenge here */
554
                                tan,
555
                                GWEN_Gui_PasswordStatus_Unused);
556
      }
557
      if (rv) {
558
        DBG_ERROR(AQHBCI_LOGDOMAIN,
559
                  "Error adjusting TAN status (%d), ignoring", rv);
560
        /*return rv;*/
561
      }
562
    } /* if tan */
563
    j=AH_Job_List_Next(j);
564
  }
565

    
566
  return 0;
567
}
568

    
569

    
570

    
571
int AH_JobQueue_DispatchMessage(AH_JOBQUEUE *jq,
572
                                AH_MSG *msg,
573
                                GWEN_DB_NODE *db)
574
{
575
  GWEN_DB_NODE *dbSecurity;
576
  GWEN_DB_NODE *dbCurr;
577
  AH_JOB *j;
578
  AH_DIALOG *dlg;
579
  const char *p;
580
  int tanRecycle;
581
  int rv;
582
  int dialogAborted=0;
583
  int abortQueue=0;
584
  int badPin=0;
585
  GWEN_STRINGLISTENTRY *se;
586
  uint32_t guiid;
587

    
588
  assert(jq);
589
  assert(jq->usage);
590
  assert(msg);
591
  assert(db);
592

    
593
  dlg=AH_Msg_GetDialog(msg);
594
  assert(dlg);
595
  guiid=0;
596

    
597
  /* log all results */
598
  tanRecycle=0;
599
  dbCurr=GWEN_DB_GetFirstGroup(db);
600
  while (dbCurr) {
601
    if (strcasecmp(GWEN_DB_GroupName(dbCurr), "SegResult")==0 ||
602
        strcasecmp(GWEN_DB_GroupName(dbCurr), "MsgResult")==0) {
603
      int rcode;
604
      const char *p;
605
      int isMsgResult;
606
      GWEN_BUFFER *logmsg;
607
      GWEN_LOGGER_LEVEL level;
608
      GWEN_DB_NODE *dbResult;
609

    
610
      DBG_NOTICE(AQHBCI_LOGDOMAIN, "Found a result");
611

    
612
      level=GWEN_LoggerLevel_Notice;
613
      isMsgResult=(strcasecmp(GWEN_DB_GroupName(dbCurr),
614
                              "MsgResult")==0);
615

    
616
      dbResult=GWEN_DB_FindFirstGroup(dbCurr, "result");
617
      while (dbResult) {
618
        rcode=GWEN_DB_GetIntValue(dbResult, "resultcode", 0, 0);
619
        p=GWEN_DB_GetCharValue(dbResult, "text", 0, "");
620

    
621
        if (rcode>=9000 && rcode<10000) {
622
          DBG_INFO(AQHBCI_LOGDOMAIN,
623
                   "Result: Error (%d: %s)", rcode, p);
624
          level=GWEN_LoggerLevel_Error;
625
          if (isMsgResult) {
626
            if (rcode==9800)
627
              dialogAborted=1;
628
            else if (rcode>9300 && rcode<9400)
629
              abortQueue=1;
630
          }
631
        }
632
        else if (rcode>=3000 && rcode<4000) {
633
          DBG_INFO(AQHBCI_LOGDOMAIN,
634
                   "Result: Warning (%d: %s)", rcode, p);
635
          if (rcode==3910)
636
            tanRecycle=1;
637
          else if (rcode==3920) {
638
            int i;
639

    
640
            AH_User_ClearTanMethodList(jq->user);
641
            for (i=0; ; i++) {
642
              int j;
643

    
644
              j=GWEN_DB_GetIntValue(dbResult, "param", i, 0);
645
              if (j==0)
646
                break;
647
              AH_User_AddTanMethod(jq->user, j);
648
            } /* for */
649
            if (i==0)
650
              /* add single step if empty list */
651
              AH_User_AddTanMethod(jq->user, 999);
652
          }
653
          level=GWEN_LoggerLevel_Warning;
654
        }
655
        else {
656
          DBG_INFO(AQHBCI_LOGDOMAIN, "Segment result: Ok (%d: %s)", rcode, p);
657
          level=GWEN_LoggerLevel_Notice;
658
        }
659

    
660
        logmsg=GWEN_Buffer_new(0, 256, 0, 1);
661
        if (p) {
662
          char numbuf[16];
663

    
664
          GWEN_Buffer_AppendString(logmsg, "HBCI: ");
665
          snprintf(numbuf, sizeof(numbuf), "%04d", rcode);
666
          GWEN_Buffer_AppendString(logmsg, numbuf);
667
          GWEN_Buffer_AppendString(logmsg, " - ");
668
          GWEN_Buffer_AppendString(logmsg, p);
669
          if (isMsgResult)
670
            GWEN_Buffer_AppendString(logmsg, " (M)");
671
          else
672
            GWEN_Buffer_AppendString(logmsg, " (S)");
673
        }
674
        else {
675
          char numbuf[16];
676

    
677
          GWEN_Buffer_AppendString(logmsg, "HBCI: ");
678
          snprintf(numbuf, sizeof(numbuf), "%04d", rcode);
679
          GWEN_Buffer_AppendString(logmsg, numbuf);
680
          GWEN_Buffer_AppendString(logmsg, " - (no text)");
681
          if (isMsgResult)
682
            GWEN_Buffer_AppendString(logmsg, " (M)");
683
          else
684
            GWEN_Buffer_AppendString(logmsg, " (S)");
685
        }
686
        GWEN_Gui_ProgressLog(0,
687
                             level,
688
                             GWEN_Buffer_GetStart(logmsg));
689
        GWEN_Buffer_free(logmsg);
690

    
691
        /* check for bad pins here */
692
        if (rcode==9340 || rcode==9942) {
693
          DBG_ERROR(AQHBCI_LOGDOMAIN,
694
                    "Bad PIN flagged: %d", rcode);
695
          badPin=1;
696
          if (jq->usedPin) {
697
            GWEN_Gui_ProgressLog(0,
698
                                 GWEN_LoggerLevel_Error,
699
                                 I18N("PIN seems to be invalid"));
700
            AH_User_SetPinStatus(jq->user, jq->usedPin,
701
                                 GWEN_Gui_PasswordStatus_Bad);
702
          }
703
        }
704

    
705
        dbResult=GWEN_DB_FindNextGroup(dbResult, "result");
706
      } /* while results */
707
    }
708

    
709
    dbCurr=GWEN_DB_GetNextGroup(dbCurr);
710
  }
711

    
712

    
713
  /* prepare security group */
714
  dbSecurity=GWEN_DB_Group_new("security");
715
  p=AH_Dialog_GetDialogId(dlg);
716
  assert(p);
717
  GWEN_DB_SetIntValue(dbSecurity,
718
                      GWEN_DB_FLAGS_DEFAULT,
719
                      "msgnum",
720
                      AH_Msg_GetMsgNum(msg));
721
  GWEN_DB_SetCharValue(dbSecurity, GWEN_DB_FLAGS_DEFAULT, "dialogId", p);
722

    
723
  /* get all signers */
724
  se=GWEN_StringList_FirstEntry(AH_Msg_GetSignerIdList(msg));
725
  while (se) {
726
    const char *p;
727

    
728
    p=GWEN_StringListEntry_Data(se);
729
    DBG_INFO(AQHBCI_LOGDOMAIN, "Adding signer \"%s\"", p);
730
    GWEN_DB_SetCharValue(dbSecurity, GWEN_DB_FLAGS_DEFAULT, "signer", p);
731
    se=GWEN_StringListEntry_Next(se);
732
  } /* while */
733

    
734
  /* set crypter */
735
  p=AH_Msg_GetCrypterId(msg);
736
  if (p) {
737
    DBG_INFO(AQHBCI_LOGDOMAIN, "Storing crypter \"%s\"", p);
738
    GWEN_DB_SetCharValue(dbSecurity, GWEN_DB_FLAGS_DEFAULT, "crypter", p);
739
  }
740

    
741
  /* remove attach points of all jobs */
742
  j=AH_Job_List_First(jq->jobs);
743
  while (j) {
744
    AH_JOB_STATUS st;
745

    
746
    st=AH_Job_GetStatus(j);
747
    if (st==AH_JobStatusSent) {
748
      if (AH_Job_GetFlags(j) & AH_JOB_FLAGS_ATTACHABLE) {
749
        GWEN_DB_NODE *args;
750

    
751
        AH_Job_SubFlags(j, AH_JOB_FLAGS_HASATTACHPOINT);
752

    
753
        /* remove the attach point */
754
        args=AH_Job_GetArguments(j);
755
        if (GWEN_DB_DeleteVar(args, "attach")) {
756
          DBG_INFO(AQHBCI_LOGDOMAIN, "Attach point removed");
757
        }
758
      } /* if job is attachable */
759
    } /* if status matches */
760

    
761
    j=AH_Job_List_Next(j);
762
  } /* while */
763

    
764
  dbCurr=GWEN_DB_GetFirstGroup(db);
765
  while (dbCurr) {
766
    GWEN_DB_NODE *dbResponse;
767
    GWEN_DB_NODE *dbData;
768
    int segNum;
769

    
770
    DBG_INFO(AQHBCI_LOGDOMAIN, "Handling response \"%s\"",
771
             GWEN_DB_GroupName(dbCurr));
772

    
773
    /* use same name for main response group */
774
    dbResponse=GWEN_DB_Group_new(GWEN_DB_GroupName(dbCurr));
775
    /* add security group */
776
    GWEN_DB_AddGroup(dbResponse, GWEN_DB_Group_dup(dbSecurity));
777
    /* create data group */
778
    dbData=GWEN_DB_GetGroup(dbResponse, GWEN_DB_FLAGS_DEFAULT, "data");
779
    assert(dbData);
780
    /* store copy of original response there */
781
    GWEN_DB_AddGroup(dbData, GWEN_DB_Group_dup(dbCurr));
782

    
783
    segNum=GWEN_DB_GetIntValue(dbCurr, "head/ref", 0, 0);
784
    if (segNum) {
785

    
786
      /* search for job to which this response belongs */
787
      j=AH_Job_List_First(jq->jobs);
788
      while (j) {
789
        AH_JOB_STATUS st;
790

    
791
        st=AH_Job_GetStatus(j);
792
        if (st==AH_JobStatusSent ||
793
            st==AH_JobStatusAnswered) {
794
          DBG_INFO(AQHBCI_LOGDOMAIN,
795
                   "Checking whether job \"%s\" has segment %d",
796
                   AH_Job_GetName(j), segNum);
797
          if ((AH_Msg_GetMsgNum(msg)==AH_Job_GetMsgNum(j)) &&
798
              AH_Job_HasSegment(j, segNum)) {
799
            DBG_INFO(AQHBCI_LOGDOMAIN,
800
                     "Job \"%s\" claims to have the segment %d",
801
                     AH_Job_GetName(j), segNum);
802
            break;
803
          }
804
        }
805
        else {
806
          DBG_INFO(AQHBCI_LOGDOMAIN,
807
                   "Skipping job \"%s\" because of status \"%s\" (%d)",
808
                   AH_Job_GetName(j), AH_Job_StatusName(st), st);
809
        }
810
        j=AH_Job_List_Next(j);
811
      } /* while j */
812
      if (j) {
813
        /* check for attachability */
814
        if (AH_Job_GetFlags(j) & AH_JOB_FLAGS_ATTACHABLE) {
815
          /* job is attachable, check whether this is segment result */
816
          if (strcasecmp(GWEN_DB_GroupName(dbCurr), "SegResult")==0) {
817
            GWEN_DB_NODE *dbResult;
818

    
819
            dbResult=GWEN_DB_FindFirstGroup(dbCurr, "result");
820
            while (dbResult) {
821
              int rcode;
822

    
823
              rcode=GWEN_DB_GetIntValue(dbResult, "resultcode", 0, 0);
824
              /* it is a segment result, does it contain an attach point ? */
825
              if (rcode==3040) {
826
                const char *p;
827

    
828
                /* it should... */
829
                p=GWEN_DB_GetCharValue(dbResult, "param", 0, 0);
830
                if (!p) {
831
                  DBG_ERROR(AQHBCI_LOGDOMAIN,
832
                            "Segment result 3040 without attachpoint");
833
                }
834
                else {
835
                  GWEN_DB_NODE *args;
836

    
837
                  /* store the attach point */
838
                  DBG_INFO(AQHBCI_LOGDOMAIN, "Storing attach point");
839
                  args=AH_Job_GetArguments(j);
840
                  GWEN_DB_SetCharValue(args, GWEN_DB_FLAGS_OVERWRITE_VARS,
841
                                       "attach", p);
842
                  AH_Job_AddFlags(j, AH_JOB_FLAGS_HASATTACHPOINT);
843
                }
844
              } /* if code 3040 (means "more data available") */
845
              dbResult=GWEN_DB_FindNextGroup(dbResult, "result");
846
            } /* while */
847
          } /* if segresult */
848
        } /* if attachable */
849

    
850
        /* check for segment results */
851
        if (strcasecmp(GWEN_DB_GroupName(dbCurr), "SegResult")==0) {
852
          GWEN_DB_NODE *dbResult;
853

    
854
          dbResult=GWEN_DB_FindFirstGroup(dbCurr, "result");
855
          while (dbResult) {
856
            int rcode;
857
            const char *p;
858

    
859
            rcode=GWEN_DB_GetIntValue(dbResult, "resultcode", 0, 0);
860
            p=GWEN_DB_GetCharValue(dbResult, "text", 0, "");
861
            if (rcode>=9000 && rcode<10000) {
862
              DBG_INFO(AQHBCI_LOGDOMAIN,
863
                       "Segment result: Error (%d: %s)", rcode, p);
864
              if (!(AH_Job_GetFlags(j) & AH_JOB_FLAGS_IGNORE_ERROR)) {
865
                AH_Job_AddFlags(j, AH_JOB_FLAGS_HASERRORS);
866
                AH_JobQueue_AddFlags(jq, AH_JOBQUEUE_FLAGS_HASERRORS);
867
              }
868
            }
869
            else if (rcode>=3000 && rcode<4000) {
870
              DBG_INFO(AQHBCI_LOGDOMAIN,
871
                       "Segment result: Warning (%d: %s)", rcode, p);
872
              if (!(AH_Job_GetFlags(j) & AH_JOB_FLAGS_IGNORE_ERROR)) {
873
                AH_Job_AddFlags(j, AH_JOB_FLAGS_HASWARNINGS);
874
                AH_JobQueue_AddFlags(jq, AH_JOBQUEUE_FLAGS_HASWARNINGS);
875
              }
876
            }
877
            else {
878
              DBG_INFO(AQHBCI_LOGDOMAIN,
879
                       "Segment result: Ok (%d: %s)", rcode, p);
880
            }
881
            dbResult=GWEN_DB_FindNextGroup(dbResult, "result");
882
          } /* while */
883
        } /* if SegResult */
884

    
885
        DBG_INFO(AQHBCI_LOGDOMAIN, "Adding response \"%s\" to job \"%s\"",
886
                 GWEN_DB_GroupName(dbCurr),
887
                 AH_Job_GetName(j));
888
        AH_Job_AddResponse(j, dbResponse);
889
        AH_Job_SetStatus(j, AH_JobStatusAnswered);
890
      } /* if matching job found */
891
      else {
892
        uint32_t plusFlags;
893

    
894
        DBG_WARN(AQHBCI_LOGDOMAIN,
895
                 "No job found, adding response \"%s\" to all jobs",
896
                 GWEN_DB_GroupName(dbCurr));
897

    
898
        /* add response to all jobs (as queue response) and to queue */
899
        plusFlags=0;
900
        if (strcasecmp(GWEN_DB_GroupName(dbCurr), "MsgResult")==0) {
901
          GWEN_DB_NODE *dbResult;
902

    
903
          dbResult=GWEN_DB_FindFirstGroup(dbCurr, "result");
904
          while (dbResult) {
905
            int rcode;
906
            const char *p;
907

    
908
            /* FIXME: This code will never be used, I guess, since
909
             * a MsgResult wil most likely not have a reference segment... */
910
            rcode=GWEN_DB_GetIntValue(dbResult, "resultcode", 0, 0);
911
            p=GWEN_DB_GetCharValue(dbResult, "text", 0, "");
912
            if (rcode>=9000 && rcode<10000) {
913
              DBG_INFO(AQHBCI_LOGDOMAIN, "Msg result: Error (%d: %s)", rcode, p);
914
              plusFlags|=AH_JOB_FLAGS_HASERRORS;
915
              AH_JobQueue_AddFlags(jq, AH_JOBQUEUE_FLAGS_HASERRORS);
916
            }
917
            else if (rcode>=3000 && rcode<4000) {
918
              DBG_INFO(AQHBCI_LOGDOMAIN, "Msg result: Warning (%d: %s)", rcode, p);
919
              plusFlags|=AH_JOB_FLAGS_HASWARNINGS;
920
              AH_JobQueue_AddFlags(jq, AH_JOBQUEUE_FLAGS_HASWARNINGS);
921
            }
922
            else {
923
              DBG_INFO(AQHBCI_LOGDOMAIN, "Msg result: Ok (%d: %s)", rcode, p);
924
            }
925
            dbResult=GWEN_DB_FindNextGroup(dbResult, "result");
926
          }
927
        }
928
        else if (strcasecmp(GWEN_DB_GroupName(dbCurr), "SegResult")==0) {
929
          GWEN_DB_NODE *dbResult;
930

    
931
          dbResult=GWEN_DB_FindFirstGroup(dbCurr, "result");
932
          while (dbResult) {
933
//            int rcode;
934

    
935
//      rcode=GWEN_DB_GetIntValue(dbResult, "resultcode", 0, 0);
936
            /* nothing to do right now */
937
            dbResult=GWEN_DB_FindNextGroup(dbResult, "result");
938
          } /* while */
939
        } /* if segresult */
940

    
941
        j=AH_Job_List_First(jq->jobs);
942
        while (j) {
943
          AH_JOB_STATUS st;
944

    
945
          st=AH_Job_GetStatus(j);
946
          if (st==AH_JobStatusSent ||
947
              st==AH_JobStatusAnswered) {
948
            if (!(AH_Job_GetFlags(j) & AH_JOB_FLAGS_IGNORE_ERROR)) {
949
              AH_Job_AddFlags(j, plusFlags);
950
              AH_Job_AddResponse(j, GWEN_DB_Group_dup(dbResponse));
951
            }
952
            AH_Job_SetStatus(j, AH_JobStatusAnswered);
953
          }
954
          else {
955
            DBG_ERROR(AQHBCI_LOGDOMAIN,
956
                      "Status %d of job doesn't match", st);
957
          }
958
          j=AH_Job_List_Next(j);
959
        } /* while */
960
        GWEN_DB_Group_free(dbResponse);
961
      }
962
    }
963
    else {
964
      uint32_t plusFlags;
965

    
966
      /* no reference segment number, add response to all jobs and
967
       * to the queue */
968
      DBG_DEBUG(AQHBCI_LOGDOMAIN,
969
                "No segment reference number, "
970
                "adding response \"%s\" to all jobs",
971
                GWEN_DB_GroupName(dbCurr));
972

    
973
      /* add response to all jobs (as queue response) and to queue */
974
      plusFlags=0;
975
      if (strcasecmp(GWEN_DB_GroupName(dbCurr), "MsgResult")==0) {
976
        GWEN_DB_NODE *dbResult;
977

    
978
        dbResult=GWEN_DB_FindFirstGroup(dbCurr, "result");
979
        while (dbResult) {
980
          int rcode;
981
          const char *p;
982

    
983
          rcode=GWEN_DB_GetIntValue(dbResult, "resultcode", 0, 0);
984
          p=GWEN_DB_GetCharValue(dbResult, "text", 0, "");
985
          if (rcode>=9000 && rcode<10000) {
986
            DBG_INFO(AQHBCI_LOGDOMAIN, "Msg result: Error (%d: %s)", rcode, p);
987
            plusFlags|=AH_JOB_FLAGS_HASERRORS;
988
            AH_JobQueue_AddFlags(jq, AH_JOBQUEUE_FLAGS_HASERRORS);
989
          }
990
          else if (rcode>=3000 && rcode<4000) {
991
            DBG_INFO(AQHBCI_LOGDOMAIN, "Msg result: Warning (%d: %s)", rcode, p);
992
            plusFlags|=AH_JOB_FLAGS_HASWARNINGS;
993
            AH_JobQueue_AddFlags(jq, AH_JOBQUEUE_FLAGS_HASWARNINGS);
994
          }
995
          else {
996
            DBG_INFO(AQHBCI_LOGDOMAIN, "Msg result: Ok (%d: %s)", rcode, p);
997
          }
998
          dbResult=GWEN_DB_FindNextGroup(dbResult, "Result");
999
        }
1000
      }
1001

    
1002
      j=AH_Job_List_First(jq->jobs);
1003
      while (j) {
1004
        AH_JOB_STATUS st;
1005

    
1006
        st=AH_Job_GetStatus(j);
1007
        if (st==AH_JobStatusSent ||
1008
            st==AH_JobStatusAnswered) {
1009
          if (!(AH_Job_GetFlags(j) & AH_JOB_FLAGS_IGNORE_ERROR)) {
1010
            AH_Job_AddFlags(j, plusFlags);
1011
            AH_Job_AddResponse(j, GWEN_DB_Group_dup(dbResponse));
1012
          }
1013
          AH_Job_SetStatus(j, AH_JobStatusAnswered);
1014
        }
1015
        j=AH_Job_List_Next(j);
1016
      } /* while */
1017
      GWEN_DB_Group_free(dbResponse);
1018
    }
1019

    
1020
    dbCurr=GWEN_DB_GetNextGroup(dbCurr);
1021
  } /* while */
1022
  GWEN_DB_Group_free(dbSecurity);
1023

    
1024
  /* set usedTan status accordingly */
1025
  j=AH_Job_List_First(jq->jobs);
1026
  while (j) {
1027
    const char *utan;
1028

    
1029
    utan=AH_Job_GetUsedTan(j);
1030
    if (utan) {
1031
      AH_JOB_STATUS st;
1032

    
1033
      AH_Job_AddFlags(j, AH_JOB_FLAGS_TANUSED);
1034
      st=AH_Job_GetStatus(j);
1035
      if (st==AH_JobStatusSent ||
1036
          st==AH_JobStatusAnswered) {
1037
        if (tanRecycle)
1038
          AH_Job_SubFlags(j, AH_JOB_FLAGS_TANUSED);
1039
      }
1040
      else {
1041
        DBG_WARN(AQHBCI_LOGDOMAIN, "Bad status %d", st);
1042
      }
1043
    }
1044
    else {
1045
      DBG_NOTICE(AQHBCI_LOGDOMAIN, "No TAN in job [%s]",
1046
                 AH_Job_GetName(j));
1047
    }
1048
    j=AH_Job_List_Next(j);
1049
  } /* while */
1050

    
1051
  /* tell the application/medium about used and unused TANs */
1052
  rv=AH_JobQueue__CheckTans(jq, guiid);
1053
  if (rv) {
1054
    DBG_INFO(AQHBCI_LOGDOMAIN, "Error checking TANs (%d)", rv);
1055
  }
1056
  if (dialogAborted) {
1057
    DBG_NOTICE(AQHBCI_LOGDOMAIN, "Dialog logically aborted by peer");
1058
    if (jq->usedPin) {
1059
      GWEN_Gui_ProgressLog(0,
1060
                           GWEN_LoggerLevel_Info,
1061
                           I18N("Dialog aborted by bank, assuming bad PIN"));
1062
      AH_User_SetPinStatus(jq->user, jq->usedPin,
1063
                           GWEN_Gui_PasswordStatus_Bad);
1064
    }
1065

    
1066
    return GWEN_ERROR_ABORTED;
1067
  }
1068

    
1069
  if (abortQueue) {
1070
    DBG_NOTICE(AQHBCI_LOGDOMAIN,
1071
               "Aborting queue");
1072
    return GWEN_ERROR_ABORTED;
1073
  }
1074

    
1075
  if (!badPin) {
1076
    DBG_INFO(AQHBCI_LOGDOMAIN,
1077
             "Dialog not aborted, assuming correct PIN");
1078
    if (jq->usedPin) {
1079
      GWEN_Gui_ProgressLog(0,
1080
                           GWEN_LoggerLevel_Info,
1081
                           I18N("Dialog not aborted, assuming PIN is ok"));
1082
      AH_User_SetPinStatus(jq->user, jq->usedPin,
1083
                           GWEN_Gui_PasswordStatus_Ok);
1084
    }
1085
  }
1086

    
1087
  return rv;
1088
}
1089

    
1090

    
1091

    
1092
uint32_t AH_JobQueue_GetFlags(AH_JOBQUEUE *jq)
1093
{
1094
  assert(jq);
1095
  assert(jq->usage);
1096
  return jq->flags;
1097
}
1098

    
1099

    
1100

    
1101
void AH_JobQueue_SetFlags(AH_JOBQUEUE *jq, uint32_t f)
1102
{
1103
  assert(jq);
1104
  assert(jq->usage);
1105
  jq->flags=f;
1106
}
1107

    
1108

    
1109

    
1110
void AH_JobQueue_AddFlags(AH_JOBQUEUE *jq, uint32_t f)
1111
{
1112
  assert(jq);
1113
  assert(jq->usage);
1114
  jq->flags|=f;
1115
}
1116

    
1117

    
1118

    
1119
void AH_JobQueue_SubFlags(AH_JOBQUEUE *jq, uint32_t f)
1120
{
1121
  assert(jq);
1122
  assert(jq->usage);
1123
  jq->flags&=~f;
1124
}
1125

    
1126

    
1127

    
1128
AB_USER *AH_JobQueue_GetUser(const AH_JOBQUEUE *jq)
1129
{
1130
  assert(jq);
1131
  assert(jq->usage);
1132
  return jq->user;
1133
}
1134

    
1135

    
1136

    
1137
void AH_JobQueue_SetJobStatusOnMatch(AH_JOBQUEUE *jq,
1138
                                     AH_JOB_STATUS matchSt,
1139
                                     AH_JOB_STATUS newSt)
1140
{
1141
  AH_JOB *j;
1142

    
1143
  assert(jq);
1144
  assert(jq->usage);
1145

    
1146
  j=AH_Job_List_First(jq->jobs);
1147
  while (j) {
1148
    if (matchSt==AH_JobStatusAll ||
1149
        AH_Job_GetStatus(j)==matchSt)
1150
      AH_Job_SetStatus(j, newSt);
1151
    j=AH_Job_List_Next(j);
1152
  } /* while */
1153
}
1154

    
1155

    
1156

    
1157
void AH_JobQueue_Dump(AH_JOBQUEUE *jq, FILE *f, unsigned int insert)
1158
{
1159
  uint32_t k;
1160
  AH_JOB *j;
1161
  GWEN_STRINGLISTENTRY *se;
1162

    
1163

    
1164
  for (k=0; k<insert; k++)
1165
    fprintf(f, " ");
1166
  fprintf(f, "JobQueue:\n");
1167

    
1168
  for (k=0; k<insert; k++)
1169
    fprintf(f, " ");
1170
  fprintf(f, "Usage   : %d\n", jq->usage);
1171

    
1172
  for (k=0; k<insert; k++)
1173
    fprintf(f, " ");
1174
  fprintf(f, "Owner   : %s\n", AB_User_GetCustomerId(jq->user));
1175

    
1176
  for (k=0; k<insert; k++)
1177
    fprintf(f, " ");
1178
  fprintf(f, "Flags: %08x ( ", jq->flags);
1179
  if (jq->flags & AH_JOBQUEUE_FLAGS_CRYPT)
1180
    fprintf(f, "CRYPT ");
1181
  if (jq->flags & AH_JOBQUEUE_FLAGS_SIGN)
1182
    fprintf(f, "SIGN ");
1183
  if (jq->flags & AH_JOBQUEUE_FLAGS_ISDIALOG)
1184
    fprintf(f, "ISDIALOG ");
1185
  if (jq->flags & AH_JOBQUEUE_FLAGS_OUTBOX)
1186
    fprintf(f, "OUTBOX ");
1187
  if (jq->flags & AH_JOBQUEUE_FLAGS_HASWARNINGS)
1188
    fprintf(f, "HASWARNINGS ");
1189
  if (jq->flags & AH_JOBQUEUE_FLAGS_HASERRORS)
1190
    fprintf(f, "HASERRORS ");
1191
  fprintf(f, ")\n");
1192

    
1193
  for (k=0; k<insert; k++)
1194
    fprintf(f, " ");
1195
  fprintf(f, "Signers:\n");
1196

    
1197
  se=GWEN_StringList_FirstEntry(jq->signers);
1198
  while (se) {
1199
    for (k=0; k<insert; k++)
1200
      fprintf(f, " ");
1201
    fprintf(f, "  \"%s\"\n", GWEN_StringListEntry_Data(se));
1202
    se=GWEN_StringListEntry_Next(se);
1203
  } /* while se */
1204

    
1205
  for (k=0; k<insert; k++)
1206
    fprintf(f, " ");
1207
  fprintf(f, "Jobs:\n");
1208
  j=AH_Job_List_First(jq->jobs);
1209
  while (j) {
1210
    AH_Job_Dump(j, f, insert+2);
1211
    j=AH_Job_List_Next(j);
1212
  } /* while j */
1213
}
1214

    
1215

    
1216
unsigned int AH_JobQueue_GetCount(const AH_JOBQUEUE *jq)
1217
{
1218
  assert(jq);
1219
  assert(jq->usage);
1220
  if (jq->jobs)
1221
    return AH_Job_List_GetCount(jq->jobs);
1222
  return 0;
1223
}
1224

    
1225

    
1226

    
1227