merchant

Merchant backend to process payments, run by merchants
Log | Files | Refs | Submodules | README | LICENSE

taler-merchant-kyccheck.c (40525B)


      1 /*
      2   This file is part of TALER
      3   Copyright (C) 2024 Taler Systems SA
      4 
      5   TALER is free software; you can redistribute it and/or modify it under the
      6   terms of the GNU Affero General Public License as published by the Free Software
      7   Foundation; either version 3, or (at your option) any later version.
      8 
      9   TALER is distributed in the hope that it will be useful, but WITHOUT ANY
     10   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
     11   A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more details.
     12 
     13   You should have received a copy of the GNU Affero General Public License along with
     14   TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file taler-merchant-kyccheck.c
     18  * @brief Process that check the KYC status of our bank accounts at all exchanges
     19  * @author Christian Grothoff
     20  */
     21 #include "platform.h"
     22 #include "microhttpd.h"
     23 #include <gnunet/gnunet_util_lib.h>
     24 #include <jansson.h>
     25 #include <pthread.h>
     26 #include <regex.h>
     27 #include <taler/taler_dbevents.h>
     28 #include <taler/taler_json_lib.h>
     29 #include <taler/taler_exchange_service.h>
     30 #include "taler_merchant_util.h"
     31 #include "taler_merchant_bank_lib.h"
     32 #include "taler_merchantdb_lib.h"
     33 #include "taler_merchantdb_plugin.h"
     34 
     35 /**
     36  * Timeout for the exchange interaction.  Rather long as we should do
     37  * long-polling and do not want to wake up too often.
     38  */
     39 #define EXCHANGE_TIMEOUT GNUNET_TIME_relative_multiply ( \
     40           GNUNET_TIME_UNIT_MINUTES, \
     41           30)
     42 
     43 /**
     44  * How long do we wait between requests if all we wait
     45  * for is a change in the AML investigation status?
     46  * Default value.
     47  */
     48 #define AML_FREQ GNUNET_TIME_relative_multiply ( \
     49           GNUNET_TIME_UNIT_HOURS, \
     50           6)
     51 
     52 /**
     53  * How long do we wait between requests if all we wait
     54  * for is a change in the AML investigation status?
     55  */
     56 static struct GNUNET_TIME_Relative aml_freq;
     57 
     58 /**
     59  * How frequently do we check for updates to our KYC status
     60  * if there is no actual reason to check? Set to a very low
     61  * frequency, just to ensure we eventually notice.
     62  * Default value.
     63  */
     64 #define AML_LOW_FREQ GNUNET_TIME_relative_multiply ( \
     65           GNUNET_TIME_UNIT_DAYS, \
     66           7)
     67 
     68 /**
     69  * How frequently do we check for updates to our KYC status
     70  * if there is no actual reason to check? Set to a very low
     71  * frequency, just to ensure we eventually notice.
     72  */
     73 static struct GNUNET_TIME_Relative aml_low_freq;
     74 
     75 
     76 /**
     77  * How many inquiries do we process concurrently at most.
     78  */
     79 #define OPEN_INQUIRY_LIMIT 1024
     80 
     81 
     82 /**
     83  * Information about an exchange.
     84  */
     85 struct Exchange
     86 {
     87   /**
     88    * Kept in a DLL.
     89    */
     90   struct Exchange *next;
     91 
     92   /**
     93    * Kept in a DLL.
     94    */
     95   struct Exchange *prev;
     96 
     97   /**
     98    * The keys of this exchange
     99    */
    100   struct TALER_EXCHANGE_Keys *keys;
    101 
    102 };
    103 
    104 
    105 /**
    106  * Information about an Account.
    107  */
    108 struct Account
    109 {
    110   /**
    111    * Kept in a DLL.
    112    */
    113   struct Account *next;
    114 
    115   /**
    116    * Kept in a DLL.
    117    */
    118   struct Account *prev;
    119 
    120   /**
    121    * Head of inquiries for this account.
    122    */
    123   struct Inquiry *i_head;
    124 
    125   /**
    126    * Tail of inquiries for this account.
    127    */
    128   struct Inquiry *i_tail;
    129 
    130   /**
    131    * Merchant instance this account belongs to.
    132    */
    133   char *instance_id;
    134 
    135   /**
    136    * The payto-URI of this account.
    137    */
    138   struct TALER_FullPayto merchant_account_uri;
    139 
    140   /**
    141    * Wire hash of the merchant bank account (with the
    142    * respective salt).
    143    */
    144   struct TALER_MerchantWireHashP h_wire;
    145 
    146   /**
    147    * Private key of the instance.
    148    */
    149   union TALER_AccountPrivateKeyP ap;
    150 
    151   /**
    152    * Hash of the @e merchant_account_uri.
    153    */
    154   struct TALER_NormalizedPaytoHashP h_payto;
    155 
    156   /**
    157    * Database generation when this account
    158    * was last active.
    159    */
    160   uint64_t account_gen;
    161 
    162 };
    163 
    164 
    165 /**
    166  * Information about an inquiry job.
    167  */
    168 struct Inquiry
    169 {
    170   /**
    171    * Kept in a DLL.
    172    */
    173   struct Inquiry *next;
    174 
    175   /**
    176    * Kept in a DLL.
    177    */
    178   struct Inquiry *prev;
    179 
    180   /**
    181    * Main task for this inquiry.
    182    */
    183   struct GNUNET_SCHEDULER_Task *task;
    184 
    185   /**
    186    * Which exchange is this inquiry about.
    187    */
    188   struct Exchange *e;
    189 
    190   /**
    191    * Which account is this inquiry about.
    192    */
    193   struct Account *a;
    194 
    195   /**
    196    * AccountLimits that apply to the account, NULL
    197    * if unknown.
    198    */
    199   json_t *jlimits;
    200 
    201   /**
    202    * Handle for the actual HTTP request to the exchange.
    203    */
    204   struct TALER_EXCHANGE_KycCheckHandle *kyc;
    205 
    206   /**
    207    * Access token for the /kyc-info API.
    208    */
    209   struct TALER_AccountAccessTokenP access_token;
    210 
    211   /**
    212    * Last time we called the /kyc-check endpoint.
    213    */
    214   struct GNUNET_TIME_Timestamp last_kyc_check;
    215 
    216   /**
    217    * When is the next KYC check due?
    218    */
    219   struct GNUNET_TIME_Absolute due;
    220 
    221   /**
    222    * When should the current KYC time out?
    223    */
    224   struct GNUNET_TIME_Absolute timeout;
    225 
    226   /**
    227    * Current exponential backoff.
    228    */
    229   struct GNUNET_TIME_Relative backoff;
    230 
    231   /**
    232    * Rule generation known to the client, 0 for none.
    233    * Corresponds to the decision row in the exchange.
    234    */
    235   uint64_t rule_gen;
    236 
    237   /**
    238    * Last HTTP status returned by the exchange from
    239    * the /kyc-check endpoint.
    240    */
    241   unsigned int last_http_status;
    242 
    243   /**
    244    * Last Taler error code returned by the exchange from
    245    * the /kyc-check endpoint.
    246    */
    247   enum TALER_ErrorCode last_ec;
    248 
    249   /**
    250    * True if this is not our first time we make this request.
    251    */
    252   bool not_first_time;
    253 
    254   /**
    255    * Do soft limits on transactions apply to this merchant for operations
    256    * merchants care about? If so, we should increase our request frequency
    257    * and ask more often to see if they were lifted.
    258    */
    259   bool zero_limited;
    260 
    261   /**
    262    * Did we not run this inquiry due to limits?
    263    */
    264   bool limited;
    265 
    266   /**
    267    * Do we believe this account's KYC is in good shape?
    268    */
    269   bool kyc_ok;
    270 
    271   /**
    272    * True if merchant did perform this account's KYC AUTH transfer and @e access_token is set.
    273    */
    274   bool auth_ok;
    275 
    276   /**
    277    * True if the account is known to be currently under
    278    * investigation by AML staff.
    279    */
    280   bool aml_review;
    281 
    282 };
    283 
    284 
    285 /**
    286  * Head of known exchanges.
    287  */
    288 static struct Exchange *e_head;
    289 
    290 /**
    291  * Tail of known exchanges.
    292  */
    293 static struct Exchange *e_tail;
    294 
    295 /**
    296  * Head of accounts.
    297  */
    298 static struct Account *a_head;
    299 
    300 /**
    301  * Tail of accounts.
    302  */
    303 static struct Account *a_tail;
    304 
    305 /**
    306  * The merchant's configuration.
    307  */
    308 static const struct GNUNET_CONFIGURATION_Handle *cfg;
    309 
    310 /**
    311  * Our database plugin.
    312  */
    313 static struct TALER_MERCHANTDB_Plugin *db_plugin;
    314 
    315 /**
    316  * Handle to the context for interacting with the bank.
    317  */
    318 static struct GNUNET_CURL_Context *ctx;
    319 
    320 /**
    321  * Scheduler context for running the @e ctx.
    322  */
    323 static struct GNUNET_CURL_RescheduleContext *rc;
    324 
    325 /**
    326  * Event handler to learn that there may be new bank
    327  * accounts to check.
    328  */
    329 static struct GNUNET_DB_EventHandler *eh_accounts;
    330 
    331 /**
    332  * Event handler to learn that there may be new exchange
    333  * keys to check.
    334  */
    335 static struct GNUNET_DB_EventHandler *eh_keys;
    336 
    337 /**
    338  * Event handler to learn that there was a KYC
    339  * rule triggered and we need to check the KYC
    340  * status for an account.
    341  */
    342 static struct GNUNET_DB_EventHandler *eh_rule;
    343 
    344 /**
    345  * Main task to discover (new) accounts.
    346  */
    347 static struct GNUNET_SCHEDULER_Task *account_task;
    348 
    349 /**
    350  * Counter determining how often we have called
    351  * "select_accounts" on the database.
    352  */
    353 static uint64_t database_gen;
    354 
    355 /**
    356  * How many active inquiries do we have right now.
    357  */
    358 static unsigned int active_inquiries;
    359 
    360 /**
    361  * Value to return from main(). 0 on success, non-zero on errors.
    362  */
    363 static int global_ret;
    364 
    365 /**
    366  * #GNUNET_YES if we are in test mode and should exit when idle.
    367  */
    368 static int test_mode;
    369 
    370 /**
    371  * True if the last DB query was limited by the
    372  * #OPEN_INQUIRY_LIMIT and we thus should check again
    373  * as soon as we are substantially below that limit,
    374  * and not only when we get a DB notification.
    375  */
    376 static bool at_limit;
    377 
    378 
    379 /**
    380  * Check about performing a /kyc-check request with the
    381  * exchange for the given inquiry.
    382  *
    383  * @param cls a `struct Inquiry` to process
    384  */
    385 static void
    386 inquiry_work (void *cls);
    387 
    388 
    389 /**
    390  * An inquiry finished, check if we should resume others.
    391  */
    392 static void
    393 end_inquiry (void)
    394 {
    395   GNUNET_assert (active_inquiries > 0);
    396   active_inquiries--;
    397   if ( (active_inquiries < OPEN_INQUIRY_LIMIT / 2) &&
    398        (at_limit) )
    399   {
    400     at_limit = false;
    401     for (struct Account *a = a_head;
    402          NULL != a;
    403          a = a->next)
    404     {
    405       for (struct Inquiry *i = a->i_head;
    406            NULL != i;
    407            i = i->next)
    408       {
    409         if (! i->limited)
    410           continue;
    411         GNUNET_assert (NULL == i->task);
    412         /* done synchronously so that the active_inquiries
    413            is updated immediately */
    414         inquiry_work (i);
    415         if (at_limit)
    416           break;
    417       }
    418       if (at_limit)
    419         break;
    420     }
    421   }
    422   if ( (! at_limit) &&
    423        (0 == active_inquiries) &&
    424        (test_mode) )
    425   {
    426     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    427                 "No more open inquiries and in test mode. Existing.\n");
    428     GNUNET_SCHEDULER_shutdown ();
    429     return;
    430   }
    431 }
    432 
    433 
    434 /**
    435  * Pack the given @a limit into the JSON @a limits array.
    436  *
    437  * @param limit account limit to pack
    438  * @param[in,out] limits JSON array to extend
    439  */
    440 static void
    441 pack_limit (const struct TALER_EXCHANGE_AccountLimit *limit,
    442             json_t *limits)
    443 {
    444   json_t *jl;
    445 
    446   jl = GNUNET_JSON_PACK (
    447     TALER_JSON_pack_kycte ("operation_type",
    448                            limit->operation_type),
    449     GNUNET_JSON_pack_time_rel ("timeframe",
    450                                limit->timeframe),
    451     TALER_JSON_pack_amount ("threshold",
    452                             &limit->threshold),
    453     GNUNET_JSON_pack_bool ("soft_limit",
    454                            limit->soft_limit)
    455     );
    456   GNUNET_assert (0 ==
    457                  json_array_append_new (limits,
    458                                         jl));
    459 }
    460 
    461 
    462 /**
    463  * Update KYC status for @a i based on
    464  * @a account_kyc_status
    465  *
    466  * @param[in,out] i inquiry context, jlimits is updated
    467  * @param account_kyc_status account KYC status details
    468  */
    469 static void
    470 store_kyc_status (
    471   struct Inquiry *i,
    472   const struct TALER_EXCHANGE_AccountKycStatus *account_kyc_status)
    473 {
    474   json_t *jlimits;
    475 
    476   json_decref (i->jlimits);
    477   jlimits = json_array ();
    478   GNUNET_assert (NULL != jlimits);
    479   i->zero_limited = false;
    480   for (unsigned int j = 0; j<account_kyc_status->limits_length; j++)
    481   {
    482     const struct TALER_EXCHANGE_AccountLimit *limit
    483       = &account_kyc_status->limits[j];
    484 
    485     pack_limit (limit,
    486                 jlimits);
    487     if (TALER_amount_is_zero (&limit->threshold) &&
    488         limit->soft_limit &&
    489         ( (TALER_KYCLOGIC_KYC_TRIGGER_DEPOSIT == limit->operation_type) ||
    490           (TALER_KYCLOGIC_KYC_TRIGGER_AGGREGATE == limit->operation_type) ||
    491           (TALER_KYCLOGIC_KYC_TRIGGER_TRANSACTION == limit->operation_type) ) )
    492     {
    493       i->zero_limited = true;
    494     }
    495   }
    496   i->jlimits = jlimits;
    497   GNUNET_break (! GNUNET_is_zero (&account_kyc_status->access_token));
    498   i->access_token = account_kyc_status->access_token;
    499   i->auth_ok = true;
    500   i->aml_review = account_kyc_status->aml_review;
    501   i->kyc_ok = (MHD_HTTP_OK == i->last_http_status);
    502 }
    503 
    504 
    505 /**
    506  * Function called with the result of a KYC check.
    507  *
    508  * @param cls a `struct Inquiry *`
    509  * @param ks the account's KYC status details
    510  */
    511 static void
    512 exchange_check_cb (
    513   void *cls,
    514   const struct TALER_EXCHANGE_KycStatus *ks)
    515 {
    516   struct Inquiry *i = cls;
    517   bool progress = false;
    518 
    519   if (! i->not_first_time)
    520     progress = true;
    521   i->kyc = NULL;
    522   i->last_http_status = ks->hr.http_status;
    523   i->last_ec = ks->hr.ec;
    524   i->rule_gen = 0;
    525   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    526               "Checking KYC status of `%s' at `%s' is %u\n",
    527               i->a->merchant_account_uri.full_payto,
    528               i->e->keys->exchange_url,
    529               ks->hr.http_status);
    530   switch (ks->hr.http_status)
    531   {
    532   case MHD_HTTP_OK:
    533     if (! i->kyc_ok)
    534       progress = true;
    535     i->rule_gen = ks->details.ok.rule_gen;
    536     i->last_kyc_check = GNUNET_TIME_timestamp_get ();
    537     /* exchange says KYC is OK, gives status information */
    538     store_kyc_status (i,
    539                       &ks->details.ok);
    540     i->backoff = GNUNET_TIME_UNIT_MINUTES;
    541     if (i->aml_review || i->zero_limited)
    542     {
    543       if (! progress)
    544         i->due = GNUNET_TIME_relative_to_absolute (
    545           GNUNET_TIME_randomize (GNUNET_TIME_relative_max (aml_freq,
    546                                                            i->backoff)));
    547     }
    548     else
    549     {
    550       /* KYC is OK, only check again if triggered */
    551       i->due = GNUNET_TIME_relative_to_absolute (
    552         GNUNET_TIME_randomize (GNUNET_TIME_relative_max (aml_low_freq,
    553                                                          i->backoff)));
    554     }
    555     break;
    556   case MHD_HTTP_ACCEPTED:
    557     progress = ! i->auth_ok;
    558     i->rule_gen = ks->details.ok.rule_gen;
    559     i->last_kyc_check = GNUNET_TIME_timestamp_get ();
    560 
    561     /* exchange says KYC is required */
    562     store_kyc_status (i,
    563                       &ks->details.accepted);
    564     i->backoff = GNUNET_TIME_UNIT_MINUTES;
    565     /* Start immediately with long-polling */
    566     if (! progress)
    567       i->due = GNUNET_TIME_absolute_max (i->last_kyc_check.abs_time,
    568                                          i->timeout);
    569     break;
    570   case MHD_HTTP_NO_CONTENT:
    571     i->last_kyc_check = GNUNET_TIME_timestamp_get ();
    572     i->backoff = GNUNET_TIME_UNIT_MINUTES;
    573     /* exchange claims KYC is off! */
    574     i->kyc_ok = true;
    575     i->aml_review = false;
    576     /* Clear limits, in case exchange had KYC on previously */
    577     json_decref (i->jlimits);
    578     i->jlimits = NULL;
    579     /* KYC is OK, only check again if triggered */
    580     i->due = GNUNET_TIME_relative_to_absolute (
    581       GNUNET_TIME_randomize (GNUNET_TIME_relative_max (aml_low_freq,
    582                                                        i->backoff)));
    583     break;
    584   case MHD_HTTP_FORBIDDEN: /* bad signature */
    585     i->last_kyc_check = GNUNET_TIME_timestamp_get ();
    586     /* Forbidden => KYC auth must be wrong */
    587     i->auth_ok = false;
    588     /* Start with long-polling */
    589     if (! progress)
    590       i->due = GNUNET_TIME_absolute_max (i->last_kyc_check.abs_time,
    591                                          i->timeout);
    592     i->backoff = GNUNET_TIME_UNIT_MINUTES;
    593     break;
    594   case MHD_HTTP_NOT_FOUND: /* account unknown */
    595     i->last_kyc_check = GNUNET_TIME_timestamp_get ();
    596     /* Account unknown => no KYC auth yet */
    597     i->auth_ok = false;
    598     /* unknown account => wire transfer required! */
    599     i->kyc_ok = false;
    600     /* There should not be any limits yet, but clear them
    601        just in case the exchange has amnesia */
    602     json_decref (i->jlimits);
    603     i->jlimits = NULL;
    604     /* Start immediately with Long-polling */
    605     if (! progress)
    606       i->due = GNUNET_TIME_absolute_max (i->last_kyc_check.abs_time,
    607                                          i->timeout);
    608     i->backoff = GNUNET_TIME_UNIT_MINUTES;
    609     break;
    610   case MHD_HTTP_CONFLICT: /* no account_pub known */
    611     i->last_kyc_check = GNUNET_TIME_timestamp_get ();
    612     /* Conflict => KYC auth wire transfer missing! */
    613     i->auth_ok = false;
    614     /* Start immediately with Long-polling */
    615     if (! progress)
    616       i->due = GNUNET_TIME_absolute_max (i->last_kyc_check.abs_time,
    617                                          i->timeout);
    618     i->backoff = GNUNET_TIME_UNIT_MINUTES;
    619     break;
    620   default:
    621     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    622                 "Exchange responded with HTTP status %u (%d) to /kyc-check request!\n",
    623                 ks->hr.http_status,
    624                 ks->hr.ec);
    625     i->backoff
    626       = GNUNET_TIME_randomized_backoff (i->backoff,
    627                                         EXCHANGE_TIMEOUT);
    628     i->last_kyc_check = GNUNET_TIME_timestamp_get ();
    629     i->due = GNUNET_TIME_relative_to_absolute (i->backoff);
    630     i->auth_ok = false;
    631     break;
    632   }
    633 
    634   {
    635     enum GNUNET_DB_QueryStatus qs;
    636 
    637     qs = db_plugin->account_kyc_set_status (
    638       db_plugin->cls,
    639       i->a->instance_id,
    640       &i->a->h_wire,
    641       i->e->keys->exchange_url,
    642       i->last_kyc_check,
    643       i->last_http_status,
    644       i->last_ec,
    645       i->rule_gen,
    646       (i->auth_ok)
    647       ? &i->access_token
    648       : NULL,
    649       i->jlimits,
    650       i->aml_review,
    651       i->kyc_ok);
    652     if (qs < 0)
    653     {
    654       GNUNET_break (0);
    655       global_ret = EXIT_FAILURE;
    656       GNUNET_SCHEDULER_shutdown ();
    657       return;
    658     }
    659     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    660                 "account_set_kyc_status (%s, %u, %s, %s) returned %d\n",
    661                 i->e->keys->exchange_url,
    662                 i->last_http_status,
    663                 i->auth_ok ? "auth OK" : "auth needed",
    664                 NULL == i->jlimits ? "default limits" : "custom limits",
    665                 (int) qs);
    666     i->not_first_time = true;
    667   }
    668   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    669               "Will repeat inquiry in %s\n",
    670               GNUNET_TIME_relative2s (
    671                 GNUNET_TIME_absolute_get_remaining (i->due),
    672                 true));
    673   if (! GNUNET_TIME_absolute_is_never (i->due))
    674     i->task = GNUNET_SCHEDULER_add_at (i->due,
    675                                        &inquiry_work,
    676                                        i);
    677   end_inquiry ();
    678 }
    679 
    680 
    681 static void
    682 inquiry_work (void *cls)
    683 {
    684   struct Inquiry *i = cls;
    685   enum TALER_EXCHANGE_KycLongPollTarget lpt;
    686 
    687   i->task = NULL;
    688   if (! GNUNET_TIME_absolute_is_past (i->due))
    689   {
    690     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    691                 "Will start inquiry on %s for %s in %s\n",
    692                 i->a->merchant_account_uri.full_payto,
    693                 i->e->keys->exchange_url,
    694                 GNUNET_TIME_relative2s (
    695                   GNUNET_TIME_absolute_get_remaining (i->due),
    696                   true));
    697     i->task
    698       = GNUNET_SCHEDULER_add_at (i->due,
    699                                  &inquiry_work,
    700                                  i);
    701     goto finish;
    702   }
    703 
    704   GNUNET_assert (OPEN_INQUIRY_LIMIT >= active_inquiries);
    705   if (OPEN_INQUIRY_LIMIT <= active_inquiries)
    706   {
    707     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    708                 "Not looking for work: at limit\n");
    709     i->limited = true;
    710     at_limit = true;
    711     return;
    712   }
    713   at_limit = false;
    714   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    715               "Checking KYC status of `%s' at `%s'\n",
    716               i->a->merchant_account_uri.full_payto,
    717               i->e->keys->exchange_url);
    718   i->timeout
    719     = GNUNET_TIME_relative_to_absolute (EXCHANGE_TIMEOUT);
    720   lpt = TALER_EXCHANGE_KLPT_NONE;
    721   if (! i->auth_ok)
    722     lpt = TALER_EXCHANGE_KLPT_KYC_AUTH_TRANSFER;
    723   else if (! i->kyc_ok)
    724     lpt = TALER_EXCHANGE_KLPT_KYC_OK;
    725   else if (i->aml_review)
    726     lpt = TALER_EXCHANGE_KLPT_INVESTIGATION_DONE;
    727   if (! i->not_first_time)
    728     lpt = TALER_EXCHANGE_KLPT_NONE;
    729   i->kyc = TALER_EXCHANGE_kyc_check (
    730     ctx,
    731     i->e->keys->exchange_url,
    732     &i->a->h_payto,
    733     &i->a->ap,
    734     i->rule_gen,
    735     lpt,
    736     i->not_first_time && (! test_mode)
    737     ? EXCHANGE_TIMEOUT
    738     : GNUNET_TIME_UNIT_ZERO,
    739     &exchange_check_cb,
    740     i);
    741   if (NULL == i->kyc)
    742   {
    743     GNUNET_break (0);
    744     i->due = i->timeout;
    745     i->task
    746       = GNUNET_SCHEDULER_add_at (i->due,
    747                                  &inquiry_work,
    748                                  i);
    749     goto finish;
    750   }
    751   active_inquiries++;
    752 finish:
    753   if ( (0 == active_inquiries) &&
    754        (test_mode) )
    755   {
    756     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    757                 "No more open inquiries and in test mode. Existing.\n");
    758     GNUNET_SCHEDULER_shutdown ();
    759     return;
    760   }
    761 }
    762 
    763 
    764 /**
    765  * Check if the account @a could work with exchange that
    766  * has keys @a keys.
    767  *
    768  * @param keys the keys of an exchange
    769  * @param a an account
    770  */
    771 static bool
    772 is_eligible (const struct TALER_EXCHANGE_Keys *keys,
    773              const struct Account *a)
    774 {
    775   struct TALER_NormalizedPayto np;
    776   bool ret;
    777 
    778   np = TALER_payto_normalize (a->merchant_account_uri);
    779   ret = TALER_EXCHANGE_keys_test_account_allowed (keys,
    780                                                   true,
    781                                                   np);
    782   GNUNET_free (np.normalized_payto);
    783   return ret;
    784 }
    785 
    786 
    787 /**
    788  * Start the KYC checking for account @a at exchange @a e.
    789  *
    790  * @param e an exchange
    791  * @param a an account
    792  */
    793 static void
    794 start_inquiry (struct Exchange *e,
    795                struct Account *a)
    796 {
    797   struct Inquiry *i;
    798   enum GNUNET_DB_QueryStatus qs;
    799 
    800   i = GNUNET_new (struct Inquiry);
    801   i->e = e;
    802   i->a = a;
    803   GNUNET_CONTAINER_DLL_insert (a->i_head,
    804                                a->i_tail,
    805                                i);
    806   qs = db_plugin->get_kyc_status (db_plugin->cls,
    807                                   a->merchant_account_uri,
    808                                   a->instance_id,
    809                                   e->keys->exchange_url,
    810                                   &i->auth_ok,
    811                                   &i->access_token,
    812                                   &i->kyc_ok,
    813                                   &i->last_http_status,
    814                                   &i->last_ec,
    815                                   &i->rule_gen,
    816                                   &i->last_kyc_check,
    817                                   &i->aml_review,
    818                                   &i->jlimits);
    819   if (qs < 0)
    820   {
    821     GNUNET_break (0);
    822     global_ret = EXIT_FAILURE;
    823     GNUNET_SCHEDULER_shutdown ();
    824     return;
    825   }
    826   if (qs > 0)
    827     i->not_first_time = true;
    828   switch (i->last_http_status)
    829   {
    830   case MHD_HTTP_OK:
    831     /* KYC is OK, but we could have missed some triggers,
    832        so let's check, but slowly within the next minute
    833        so that we do not overdo it if this process happens
    834        to be restarted a lot. */
    835     if (GNUNET_YES != test_mode)
    836     {
    837       i->due = GNUNET_TIME_relative_to_absolute (
    838         GNUNET_TIME_randomize (GNUNET_TIME_UNIT_MINUTES));
    839       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    840                   "Previous KYC status is OK, randomizing inquiry to start at %s\n",
    841                   GNUNET_TIME_absolute2s (i->due));
    842     }
    843     break;
    844   case MHD_HTTP_ACCEPTED:
    845     /* KYC required, due immediately */
    846     break;
    847   case MHD_HTTP_NO_CONTENT:
    848     /* KYC is OFF, only check again if triggered */
    849     if (GNUNET_YES != test_mode)
    850     {
    851       i->due = GNUNET_TIME_relative_to_absolute (
    852         GNUNET_TIME_randomize (aml_low_freq));
    853       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    854                   "KYC was disabled, randomizing inquiry to start at %s\n",
    855                   GNUNET_TIME_absolute2s (i->due));
    856     }
    857     break;
    858   case MHD_HTTP_FORBIDDEN: /* bad signature */
    859   case MHD_HTTP_NOT_FOUND: /* account unknown */
    860   case MHD_HTTP_CONFLICT: /* no account_pub known */
    861     /* go immediately into long-polling */
    862     break;
    863   default:
    864     /* start with decent back-off after hard failure */
    865     if (GNUNET_YES != test_mode)
    866     {
    867       i->backoff
    868         = GNUNET_TIME_randomize (GNUNET_TIME_UNIT_MINUTES);
    869       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    870                   "Last KYC check failed, starting with backoff %s\n",
    871                   GNUNET_TIME_relative2s (i->backoff,
    872                                           true));
    873     }
    874     break;
    875   }
    876   inquiry_work (i);
    877 }
    878 
    879 
    880 /**
    881  * Stop KYC inquiry @a i.
    882  *
    883  * @param[in] i the inquiry to stop
    884  */
    885 static void
    886 stop_inquiry (struct Inquiry *i)
    887 {
    888   struct Account *a = i->a;
    889 
    890   GNUNET_CONTAINER_DLL_remove (a->i_head,
    891                                a->i_tail,
    892                                i);
    893   if (NULL != i->task)
    894   {
    895     GNUNET_SCHEDULER_cancel (i->task);
    896     i->task = NULL;
    897   }
    898   if (NULL != i->kyc)
    899   {
    900     TALER_EXCHANGE_kyc_check_cancel (i->kyc);
    901     i->kyc = NULL;
    902   }
    903   if (NULL != i->jlimits)
    904   {
    905     json_decref (i->jlimits);
    906     i->jlimits = NULL;
    907   }
    908   GNUNET_free (i);
    909 }
    910 
    911 
    912 /**
    913  * Stop KYC inquiry for account @a at exchange @a e.
    914  *
    915  * @param e an exchange
    916  * @param a an account
    917  */
    918 static void
    919 stop_inquiry_at (struct Exchange *e,
    920                  struct Account *a)
    921 {
    922   for (struct Inquiry *i = a->i_head;
    923        NULL != i;
    924        i = i->next)
    925   {
    926     if (e == i->e)
    927     {
    928       stop_inquiry (i);
    929       return;
    930     }
    931   }
    932   /* strange, there should have been a match! */
    933   GNUNET_break (0);
    934 }
    935 
    936 
    937 /**
    938  * Start inquries for all exchanges on account @a a.
    939  *
    940  * @param a an account
    941  */
    942 static void
    943 start_inquiries (struct Account *a)
    944 {
    945   for (struct Exchange *e = e_head;
    946        NULL != e;
    947        e = e->next)
    948   {
    949     if (is_eligible (e->keys,
    950                      a))
    951       start_inquiry (e,
    952                      a);
    953     else
    954       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    955                   "Account %s not eligible at exchange %s\n",
    956                   a->merchant_account_uri.full_payto,
    957                   e->keys->exchange_url);
    958   }
    959 }
    960 
    961 
    962 /**
    963  * Stop all inquries involving account @a a.
    964  *
    965  * @param a an account
    966  */
    967 static void
    968 stop_inquiries (struct Account *a)
    969 {
    970   struct Inquiry *i;
    971 
    972   while (NULL != (i = a->i_head))
    973     stop_inquiry (i);
    974 }
    975 
    976 
    977 /**
    978  * Callback invoked with information about a bank account.
    979  *
    980  * @param cls closure
    981  * @param merchant_priv private key of the merchant instance
    982  * @param ad details about the account
    983  */
    984 static void
    985 account_cb (
    986   void *cls,
    987   const struct TALER_MerchantPrivateKeyP *merchant_priv,
    988   const struct TALER_MERCHANTDB_AccountDetails *ad)
    989 {
    990   struct TALER_FullPayto payto_uri = ad->payto_uri;
    991 
    992   if (! ad->active)
    993     return;
    994   if (NULL == merchant_priv)
    995     return; /* instance was deleted */
    996   for (struct Account *a = a_head;
    997        NULL != a;
    998        a = a->next)
    999   {
   1000     if (0 ==
   1001         TALER_full_payto_cmp (payto_uri,
   1002                               a->merchant_account_uri))
   1003     {
   1004       a->account_gen = database_gen;
   1005       return;
   1006     }
   1007   }
   1008   {
   1009     struct Account *a = GNUNET_new (struct Account);
   1010 
   1011     a->account_gen = database_gen;
   1012     a->merchant_account_uri.full_payto
   1013       = GNUNET_strdup (ad->payto_uri.full_payto);
   1014     a->instance_id
   1015       = GNUNET_strdup (ad->instance_id);
   1016     a->h_wire
   1017       = ad->h_wire;
   1018     a->ap.merchant_priv
   1019       = *merchant_priv;
   1020     TALER_full_payto_normalize_and_hash (a->merchant_account_uri,
   1021                                          &a->h_payto);
   1022     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1023                 "Found account %s of instance %s with H_PAYTO %s\n",
   1024                 ad->payto_uri.full_payto,
   1025                 ad->instance_id,
   1026                 GNUNET_sh2s (&a->h_payto.hash));
   1027     GNUNET_CONTAINER_DLL_insert (a_head,
   1028                                  a_tail,
   1029                                  a);
   1030     start_inquiries (a);
   1031   }
   1032 }
   1033 
   1034 
   1035 /**
   1036  * The set of bank accounts has changed, update our
   1037  * list of active inquiries.
   1038  *
   1039  * @param cls unused
   1040  */
   1041 static void
   1042 find_accounts (void *cls)
   1043 {
   1044   enum GNUNET_DB_QueryStatus qs;
   1045 
   1046   (void) cls;
   1047   account_task = NULL;
   1048   database_gen++;
   1049   qs = db_plugin->select_accounts (db_plugin->cls,
   1050                                    NULL, /* all instances */
   1051                                    &account_cb,
   1052                                    NULL);
   1053   if (qs < 0)
   1054   {
   1055     GNUNET_break (0);
   1056     return;
   1057   }
   1058   for (struct Account *a = a_head;
   1059        NULL != a;
   1060        a = a->next)
   1061   {
   1062     if (a->account_gen < database_gen)
   1063       stop_inquiries (a);
   1064   }
   1065 }
   1066 
   1067 
   1068 /**
   1069  * Function called when transfers are added to the merchant database.  We look
   1070  * for more work.
   1071  *
   1072  * @param cls closure (NULL)
   1073  * @param extra additional event data provided
   1074  * @param extra_size number of bytes in @a extra
   1075  */
   1076 static void
   1077 account_changed (void *cls,
   1078                  const void *extra,
   1079                  size_t extra_size)
   1080 {
   1081   (void) cls;
   1082   (void) extra;
   1083   (void) extra_size;
   1084   if (NULL != account_task)
   1085     return;
   1086   account_task
   1087     = GNUNET_SCHEDULER_add_now (&find_accounts,
   1088                                 NULL);
   1089 }
   1090 
   1091 
   1092 /**
   1093  * Interact with the database to get the current set
   1094  * of exchange keys known to us.
   1095  *
   1096  * @param exchange_url the exchange URL to check
   1097  */
   1098 static void
   1099 find_keys (const char *exchange_url)
   1100 {
   1101   enum GNUNET_DB_QueryStatus qs;
   1102   struct TALER_EXCHANGE_Keys *keys;
   1103   struct Exchange *e;
   1104   struct GNUNET_TIME_Absolute first_retry;
   1105 
   1106   qs = db_plugin->select_exchange_keys (db_plugin->cls,
   1107                                         exchange_url,
   1108                                         &first_retry,
   1109                                         &keys);
   1110   if (qs < 0)
   1111   {
   1112     GNUNET_break (0);
   1113     return;
   1114   }
   1115   if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
   1116   {
   1117     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1118                 "No %s/keys yet!\n",
   1119                 exchange_url);
   1120     return;
   1121   }
   1122   for (e = e_head; NULL != e; e = e->next)
   1123   {
   1124     if (0 == strcmp (e->keys->exchange_url,
   1125                      keys->exchange_url))
   1126     {
   1127       struct TALER_EXCHANGE_Keys *old_keys = e->keys;
   1128 
   1129       e->keys = keys;
   1130       for (struct Account *a = a_head;
   1131            NULL != a;
   1132            a = a->next)
   1133       {
   1134         bool was_eligible = is_eligible (old_keys,
   1135                                          a);
   1136         bool now_eligible = is_eligible (keys,
   1137                                          a);
   1138 
   1139         if (was_eligible == now_eligible)
   1140           continue; /* no change, do nothing */
   1141         if (was_eligible)
   1142           stop_inquiry_at (e,
   1143                            a);
   1144         else /* is_eligible */
   1145           start_inquiry (e,
   1146                          a);
   1147       }
   1148       TALER_EXCHANGE_keys_decref (old_keys);
   1149       return;
   1150     }
   1151   }
   1152   e = GNUNET_new (struct Exchange);
   1153   e->keys = keys;
   1154   GNUNET_CONTAINER_DLL_insert (e_head,
   1155                                e_tail,
   1156                                e);
   1157   for (struct Account *a = a_head;
   1158        NULL != a;
   1159        a = a->next)
   1160   {
   1161     if ( (a->account_gen == database_gen) &&
   1162          (is_eligible (e->keys,
   1163                        a)) )
   1164       start_inquiry (e,
   1165                      a);
   1166   }
   1167 }
   1168 
   1169 
   1170 /**
   1171  * Function called when keys were changed in the
   1172  * merchant database. Updates ours.
   1173  *
   1174  * @param cls closure (NULL)
   1175  * @param extra additional event data provided
   1176  * @param extra_size number of bytes in @a extra
   1177  */
   1178 static void
   1179 keys_changed (void *cls,
   1180               const void *extra,
   1181               size_t extra_size)
   1182 {
   1183   const char *url = extra;
   1184 
   1185   (void) cls;
   1186   if ( (NULL == extra) ||
   1187        (0 == extra_size) )
   1188   {
   1189     GNUNET_break (0);
   1190     return;
   1191   }
   1192   if ('\0' != url[extra_size - 1])
   1193   {
   1194     GNUNET_break (0);
   1195     return;
   1196   }
   1197   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1198               "Received keys change notification: reload `%s'\n",
   1199               url);
   1200   find_keys (url);
   1201 }
   1202 
   1203 
   1204 /**
   1205  * Function called when a KYC rule was triggered by
   1206  * a transaction and we need to get the latest KYC
   1207  * status immediately.
   1208  *
   1209  * @param cls closure (NULL)
   1210  * @param extra additional event data provided
   1211  * @param extra_size number of bytes in @a extra
   1212  */
   1213 static void
   1214 rule_triggered (void *cls,
   1215                 const void *extra,
   1216                 size_t extra_size)
   1217 {
   1218   const char *text = extra;
   1219   const char *space;
   1220   struct TALER_MerchantWireHashP h_wire;
   1221   const char *exchange_url;
   1222 
   1223   (void) cls;
   1224   if ( (NULL == extra) ||
   1225        (0 == extra_size) )
   1226   {
   1227     GNUNET_break (0);
   1228     return;
   1229   }
   1230   if ('\0' != text[extra_size - 1])
   1231   {
   1232     GNUNET_break (0);
   1233     return;
   1234   }
   1235   space = memchr (extra,
   1236                   ' ',
   1237                   extra_size);
   1238   if (NULL == space)
   1239   {
   1240     GNUNET_break (0);
   1241     return;
   1242   }
   1243   if (GNUNET_OK !=
   1244       GNUNET_STRINGS_string_to_data (extra,
   1245                                      space - text,
   1246                                      &h_wire,
   1247                                      sizeof (h_wire)))
   1248   {
   1249     GNUNET_break (0);
   1250     return;
   1251   }
   1252   exchange_url = &space[1];
   1253   if (! TALER_is_web_url (exchange_url))
   1254   {
   1255     GNUNET_break (0);
   1256     return;
   1257   }
   1258 
   1259   for (struct Account *a = a_head;
   1260        NULL != a;
   1261        a = a->next)
   1262   {
   1263     if (0 !=
   1264         GNUNET_memcmp (&h_wire,
   1265                        &a->h_wire))
   1266       continue;
   1267     for (struct Inquiry *i = a->i_head;
   1268          NULL != i;
   1269          i = i->next)
   1270     {
   1271       if (0 != strcmp (exchange_url,
   1272                        i->e->keys->exchange_url))
   1273         continue;
   1274       i->kyc_ok = false;
   1275       i->due = GNUNET_TIME_UNIT_ZERO_ABS;
   1276       if (NULL != i->task)
   1277       {
   1278         GNUNET_SCHEDULER_cancel (i->task);
   1279         i->task = NULL;
   1280       }
   1281       if (NULL != i->kyc)
   1282       {
   1283         GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1284                     "/kyc-check already running for %s\n",
   1285                     text);
   1286         return;
   1287       }
   1288       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1289                   "Starting %skyc-check for `%s' due to KYC rule trigger\n",
   1290                   exchange_url,
   1291                   i->a->merchant_account_uri.full_payto);
   1292       i->task = GNUNET_SCHEDULER_add_at (i->due,
   1293                                          &inquiry_work,
   1294                                          i);
   1295       return;
   1296     }
   1297   }
   1298   GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1299               "KYC rule trigger notification `%s' matches none of our accounts\n",
   1300               text);
   1301 }
   1302 
   1303 
   1304 /**
   1305  * Function called on each configuration section. Finds sections
   1306  * about exchanges, parses the entries.
   1307  *
   1308  * @param cls NULL
   1309  * @param section name of the section
   1310  */
   1311 static void
   1312 accept_exchanges (void *cls,
   1313                   const char *section)
   1314 {
   1315   char *url;
   1316 
   1317   (void) cls;
   1318   if (0 !=
   1319       strncasecmp (section,
   1320                    "merchant-exchange-",
   1321                    strlen ("merchant-exchange-")))
   1322     return;
   1323   if (GNUNET_YES ==
   1324       GNUNET_CONFIGURATION_get_value_yesno (cfg,
   1325                                             section,
   1326                                             "DISABLED"))
   1327     return;
   1328   if (GNUNET_OK !=
   1329       GNUNET_CONFIGURATION_get_value_string (cfg,
   1330                                              section,
   1331                                              "EXCHANGE_BASE_URL",
   1332                                              &url))
   1333   {
   1334     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
   1335                                section,
   1336                                "EXCHANGE_BASE_URL");
   1337     global_ret = EXIT_NOTCONFIGURED;
   1338     GNUNET_SCHEDULER_shutdown ();
   1339     return;
   1340   }
   1341   find_keys (url);
   1342   GNUNET_free (url);
   1343 }
   1344 
   1345 
   1346 /**
   1347  * We're being aborted with CTRL-C (or SIGTERM). Shut down.
   1348  *
   1349  * @param cls closure (NULL)
   1350  */
   1351 static void
   1352 shutdown_task (void *cls)
   1353 {
   1354   (void) cls;
   1355   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
   1356               "Running shutdown\n");
   1357   while (NULL != e_head)
   1358   {
   1359     struct Exchange *e = e_head;
   1360 
   1361     if (NULL != e->keys)
   1362     {
   1363       TALER_EXCHANGE_keys_decref (e->keys);
   1364       e->keys = NULL;
   1365     }
   1366     GNUNET_CONTAINER_DLL_remove (e_head,
   1367                                  e_tail,
   1368                                  e);
   1369     GNUNET_free (e);
   1370   }
   1371   while (NULL != a_head)
   1372   {
   1373     struct Account *a = a_head;
   1374 
   1375     stop_inquiries (a);
   1376     GNUNET_CONTAINER_DLL_remove (a_head,
   1377                                  a_tail,
   1378                                  a);
   1379     GNUNET_free (a->merchant_account_uri.full_payto);
   1380     GNUNET_free (a->instance_id);
   1381     GNUNET_free (a);
   1382   }
   1383   if (NULL != eh_accounts)
   1384   {
   1385     db_plugin->event_listen_cancel (eh_accounts);
   1386     eh_accounts = NULL;
   1387   }
   1388   if (NULL != account_task)
   1389   {
   1390     GNUNET_SCHEDULER_cancel (account_task);
   1391     account_task = NULL;
   1392   }
   1393   if (NULL != eh_keys)
   1394   {
   1395     db_plugin->event_listen_cancel (eh_keys);
   1396     eh_keys = NULL;
   1397   }
   1398   if (NULL != eh_rule)
   1399   {
   1400     db_plugin->event_listen_cancel (eh_rule);
   1401     eh_rule = NULL;
   1402   }
   1403   TALER_MERCHANTDB_plugin_unload (db_plugin);
   1404   db_plugin = NULL;
   1405   cfg = NULL;
   1406   if (NULL != ctx)
   1407   {
   1408     GNUNET_CURL_fini (ctx);
   1409     ctx = NULL;
   1410   }
   1411   if (NULL != rc)
   1412   {
   1413     GNUNET_CURL_gnunet_rc_destroy (rc);
   1414     rc = NULL;
   1415   }
   1416 }
   1417 
   1418 
   1419 /**
   1420  * First task.
   1421  *
   1422  * @param cls closure, NULL
   1423  * @param args remaining command-line arguments
   1424  * @param cfgfile name of the configuration file used (for saving, can be NULL!)
   1425  * @param c configuration
   1426  */
   1427 static void
   1428 run (void *cls,
   1429      char *const *args,
   1430      const char *cfgfile,
   1431      const struct GNUNET_CONFIGURATION_Handle *c)
   1432 {
   1433   (void) args;
   1434   (void) cfgfile;
   1435 
   1436   cfg = c;
   1437   if (GNUNET_OK !=
   1438       GNUNET_CONFIGURATION_get_value_time (cfg,
   1439                                            "merchant-kyccheck",
   1440                                            "AML_FREQ",
   1441                                            &aml_freq))
   1442   {
   1443     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
   1444                                "merchant-kyccheck",
   1445                                "AML_FREQ");
   1446     /* use default */
   1447     aml_freq = AML_FREQ;
   1448   }
   1449   if (GNUNET_OK !=
   1450       GNUNET_CONFIGURATION_get_value_time (cfg,
   1451                                            "merchant-kyccheck",
   1452                                            "AML_LOW_FREQ",
   1453                                            &aml_low_freq))
   1454   {
   1455     GNUNET_log_config_missing (GNUNET_ERROR_TYPE_WARNING,
   1456                                "merchant-kyccheck",
   1457                                "AML_LOW_FREQ");
   1458     /* use default */
   1459     aml_low_freq = AML_LOW_FREQ;
   1460   }
   1461   if (GNUNET_TIME_relative_cmp (aml_low_freq,
   1462                                 <,
   1463                                 aml_freq))
   1464   {
   1465     aml_low_freq = GNUNET_TIME_relative_multiply (aml_freq,
   1466                                                   10);
   1467     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
   1468                 "AML_LOW_FREQ was set to less than AML_FREQ. Using %s instead\n",
   1469                 GNUNET_TIME_relative2s (aml_low_freq,
   1470                                         true));
   1471   }
   1472   GNUNET_SCHEDULER_add_shutdown (&shutdown_task,
   1473                                  NULL);
   1474   ctx = GNUNET_CURL_init (&GNUNET_CURL_gnunet_scheduler_reschedule,
   1475                           &rc);
   1476   rc = GNUNET_CURL_gnunet_rc_create (ctx);
   1477   if (NULL == ctx)
   1478   {
   1479     GNUNET_break (0);
   1480     GNUNET_SCHEDULER_shutdown ();
   1481     global_ret = EXIT_FAILURE;
   1482     return;
   1483   }
   1484   if (NULL ==
   1485       (db_plugin = TALER_MERCHANTDB_plugin_load (cfg)))
   1486   {
   1487     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1488                 "Failed to initialize DB subsystem\n");
   1489     GNUNET_SCHEDULER_shutdown ();
   1490     global_ret = EXIT_NOTCONFIGURED;
   1491     return;
   1492   }
   1493   if (GNUNET_OK !=
   1494       db_plugin->connect (db_plugin->cls))
   1495   {
   1496     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
   1497                 "Failed to connect to database. Consider running taler-merchant-dbinit.\n");
   1498     GNUNET_SCHEDULER_shutdown ();
   1499     global_ret = EXIT_FAILURE;
   1500     return;
   1501   }
   1502   {
   1503     struct GNUNET_DB_EventHeaderP es = {
   1504       .size = htons (sizeof (es)),
   1505       .type = htons (TALER_DBEVENT_MERCHANT_EXCHANGE_KEYS)
   1506     };
   1507 
   1508     eh_keys
   1509       = db_plugin->event_listen (db_plugin->cls,
   1510                                  &es,
   1511                                  GNUNET_TIME_UNIT_FOREVER_REL,
   1512                                  &keys_changed,
   1513                                  NULL);
   1514   }
   1515   {
   1516     struct GNUNET_DB_EventHeaderP es = {
   1517       .size = htons (sizeof (es)),
   1518       .type = htons (TALER_DBEVENT_MERCHANT_EXCHANGE_KYC_RULE_TRIGGERED)
   1519     };
   1520 
   1521     eh_rule
   1522       = db_plugin->event_listen (db_plugin->cls,
   1523                                  &es,
   1524                                  GNUNET_TIME_UNIT_FOREVER_REL,
   1525                                  &rule_triggered,
   1526                                  NULL);
   1527   }
   1528   GNUNET_CONFIGURATION_iterate_sections (cfg,
   1529                                          &accept_exchanges,
   1530                                          NULL);
   1531   {
   1532     struct GNUNET_DB_EventHeaderP es = {
   1533       .size = htons (sizeof (es)),
   1534       .type = htons (TALER_DBEVENT_MERCHANT_ACCOUNTS_CHANGED)
   1535     };
   1536 
   1537     eh_accounts
   1538       = db_plugin->event_listen (db_plugin->cls,
   1539                                  &es,
   1540                                  GNUNET_TIME_UNIT_FOREVER_REL,
   1541                                  &account_changed,
   1542                                  NULL);
   1543   }
   1544   GNUNET_assert (NULL == account_task);
   1545   account_task
   1546     = GNUNET_SCHEDULER_add_now (&find_accounts,
   1547                                 NULL);
   1548 }
   1549 
   1550 
   1551 /**
   1552  * The main function of taler-merchant-kyccheck
   1553  *
   1554  * @param argc number of arguments from the command line
   1555  * @param argv command line arguments
   1556  * @return 0 ok, 1 on error
   1557  */
   1558 int
   1559 main (int argc,
   1560       char *const *argv)
   1561 {
   1562   struct GNUNET_GETOPT_CommandLineOption options[] = {
   1563     GNUNET_GETOPT_option_timetravel ('T',
   1564                                      "timetravel"),
   1565     GNUNET_GETOPT_option_flag ('t',
   1566                                "test",
   1567                                "run in test mode and exit when idle",
   1568                                &test_mode),
   1569     GNUNET_GETOPT_option_version (VERSION "-" VCS_VERSION),
   1570     GNUNET_GETOPT_OPTION_END
   1571   };
   1572   enum GNUNET_GenericReturnValue ret;
   1573 
   1574   ret = GNUNET_PROGRAM_run (
   1575     TALER_MERCHANT_project_data (),
   1576     argc, argv,
   1577     "taler-merchant-kyccheck",
   1578     gettext_noop (
   1579       "background process that checks the KYC state of our bank accounts at various exchanges"),
   1580     options,
   1581     &run, NULL);
   1582   if (GNUNET_SYSERR == ret)
   1583     return EXIT_INVALIDARGUMENT;
   1584   if (GNUNET_NO == ret)
   1585     return EXIT_SUCCESS;
   1586   return global_ret;
   1587 }
   1588 
   1589 
   1590 /* end of taler-merchant-kyccheck.c */