merchant

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

taler-merchant-httpd_post-private-accounts-H_WIRE-kycauth.c (20591B)


      1 /*
      2   This file is part of TALER
      3   (C) 2026 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 General Public License for more details.
     12 
     13   You should have received a copy of the GNU Affero General Public License
     14   along with TALER; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
     15 */
     16 /**
     17  * @file taler-merchant-httpd_post-private-accounts-H_WIRE-kycauth.c
     18  * @brief Handle POST /private/accounts/$H_WIRE/kycauth requests
     19  * @author Christian Grothoff
     20  */
     21 #include "taler/platform.h"
     22 #include <jansson.h>
     23 #include <microhttpd.h>
     24 #include <gnunet/gnunet_json_lib.h>
     25 #include <taler/taler_json_lib.h>
     26 #include <taler/taler_mhd_lib.h>
     27 #include <taler/taler_bank_service.h>
     28 #include "taler-merchant-httpd.h"
     29 #include "taler-merchant-httpd_exchanges.h"
     30 #include "taler-merchant-httpd_post-private-accounts-H_WIRE-kycauth.h"
     31 
     32 
     33 /**
     34  * Processing phases for a kycauth POST request.
     35  */
     36 enum KycAuthPhase
     37 {
     38   /**
     39    * Parse the request body and URL path.
     40    */
     41   KP_PARSE = 0,
     42 
     43   /**
     44    * Fetch exchange /keys (and optionally register with bank gateway).
     45    * The connection is suspended in this phase.
     46    */
     47   KP_CHECK_EXCHANGES,
     48 
     49   /**
     50    * Return the prepared response to the client.
     51    */
     52   KP_RETURN_RESPONSE,
     53 
     54   /**
     55    * Return MHD_YES to finish handling.
     56    */
     57   KP_END_YES,
     58 
     59   /**
     60    * Return MHD_NO to close the connection.
     61    */
     62   KP_END_NO
     63 };
     64 
     65 
     66 struct ExchangeAccount
     67 {
     68 
     69   /**
     70    * Payto URI of the exchange, saved from /keys.
     71    */
     72   struct TALER_FullPayto payto;
     73 
     74   /**
     75    * Pending bank gateway registration handle, or NULL.
     76    */
     77   struct TALER_BANK_RegistrationHandle *brh;
     78 
     79   /**
     80    * Context we are operating in.
     81    */
     82   struct KycAuthContext *kac;
     83 
     84   /**
     85    * Transfer subjects to use for the account.
     86    */
     87   struct TALER_BANK_TransferSubject *subjects;
     88 
     89   /**
     90    * Length of the @e subjects array.
     91    */
     92   unsigned int num_subjects;
     93 
     94   /**
     95    * Expiration time for the given @e ts.
     96    */
     97   struct GNUNET_TIME_Timestamp expiration;
     98 };
     99 
    100 
    101 /**
    102  * Per-request context for POST /private/accounts/$H_WIRE/kycauth.
    103  */
    104 struct KycAuthContext
    105 {
    106 
    107   /**
    108    * Kept in doubly-linked list.
    109    */
    110   struct KycAuthContext *next;
    111 
    112   /**
    113    * Kept in doubly-linked list.
    114    */
    115   struct KycAuthContext *prev;
    116 
    117   /**
    118    * MHD connection we are handling.
    119    */
    120   struct MHD_Connection *connection;
    121 
    122   /**
    123    * Handler context for this request.
    124    */
    125   struct TMH_HandlerContext *hc;
    126 
    127   /**
    128    * Prepared HTTP response to return, or NULL.
    129    */
    130   struct MHD_Response *response;
    131 
    132   /**
    133    * Exchange URL from the request body.
    134    */
    135   char *exchange_url;
    136 
    137   /**
    138    * Payto URI of our merchant bank account (from DB).
    139    */
    140   struct TALER_FullPayto payto_uri;
    141 
    142   /**
    143    * Pending /keys lookup operation with the exchange.
    144    */
    145   struct TMH_EXCHANGES_KeysOperation *fo;
    146 
    147   /**
    148    * Tiny amount from exchange /keys, used as the transfer amount.
    149    */
    150   struct TALER_Amount tiny_amount;
    151 
    152   /**
    153    * Array of exchange wire account payto URIs, saved from /keys.
    154    * Length is @e exchange_accounts_len.
    155    */
    156   struct ExchangeAccount *exchange_accounts;
    157 
    158   /**
    159    * Number of entries in @e exchange_accounts.
    160    */
    161   unsigned int exchange_accounts_len;
    162 
    163   /**
    164    * Number of active registrations in @e exchange_accounts.
    165    */
    166   unsigned int active_registrations;
    167 
    168   /**
    169    * HTTP status code to send with @e response.
    170    * UINT_MAX indicates a hard error (return MHD_NO).
    171    */
    172   unsigned int response_code;
    173 
    174   /**
    175    * Current processing phase.
    176    */
    177   enum KycAuthPhase phase;
    178 
    179   /**
    180    * #GNUNET_NO if the connection is not suspended,
    181    * #GNUNET_YES if the connection is suspended,
    182    * #GNUNET_SYSERR if suspended and being force-resumed during shutdown.
    183    */
    184   enum GNUNET_GenericReturnValue suspended;
    185 
    186 };
    187 
    188 
    189 /**
    190  * Head of the doubly-linked list of active kycauth contexts.
    191  */
    192 static struct KycAuthContext *kac_head;
    193 
    194 /**
    195  * Tail of the doubly-linked list of active kycauth contexts.
    196  */
    197 static struct KycAuthContext *kac_tail;
    198 
    199 
    200 void
    201 TMH_force_kac_resume (void)
    202 {
    203   for (struct KycAuthContext *kac = kac_head;
    204        NULL != kac;
    205        kac = kac->next)
    206   {
    207     if (NULL != kac->fo)
    208     {
    209       TMH_EXCHANGES_keys4exchange_cancel (kac->fo);
    210       kac->fo = NULL;
    211     }
    212     if (GNUNET_YES == kac->suspended)
    213     {
    214       kac->suspended = GNUNET_SYSERR;
    215       MHD_resume_connection (kac->connection);
    216     }
    217   }
    218 }
    219 
    220 
    221 /**
    222  * Resume processing of @a kac after an async operation completed.
    223  *
    224  * @param[in,out] kac context to resume
    225  */
    226 static void
    227 kac_resume (struct KycAuthContext *kac)
    228 {
    229   GNUNET_assert (GNUNET_YES == kac->suspended);
    230   kac->suspended = GNUNET_NO;
    231   MHD_resume_connection (kac->connection);
    232   TALER_MHD_daemon_trigger ();
    233 }
    234 
    235 
    236 /**
    237  * Clean up a kycauth context, freeing all resources.
    238  *
    239  * @param cls a `struct KycAuthContext` to clean up
    240  */
    241 static void
    242 kac_cleanup (void *cls)
    243 {
    244   struct KycAuthContext *kac = cls;
    245 
    246   if (NULL != kac->fo)
    247   {
    248     TMH_EXCHANGES_keys4exchange_cancel (kac->fo);
    249     kac->fo = NULL;
    250   }
    251   if (NULL != kac->response)
    252   {
    253     MHD_destroy_response (kac->response);
    254     kac->response = NULL;
    255   }
    256   GNUNET_free (kac->exchange_url);
    257   GNUNET_free (kac->payto_uri.full_payto);
    258   for (unsigned int i = 0; i < kac->exchange_accounts_len; i++)
    259   {
    260     struct ExchangeAccount *acc = &kac->exchange_accounts[i];
    261 
    262     if (NULL != acc->brh)
    263     {
    264       TALER_BANK_registration_cancel (acc->brh);
    265       acc->brh = NULL;
    266     }
    267     for (unsigned int j = 0; j<acc->num_subjects; j++)
    268       TALER_BANK_transfer_subject_free (&acc->subjects[j]);
    269     GNUNET_free (acc->subjects);
    270     GNUNET_free (acc->payto.full_payto);
    271   }
    272   GNUNET_free (kac->exchange_accounts);
    273   GNUNET_CONTAINER_DLL_remove (kac_head,
    274                                kac_tail,
    275                                kac);
    276   GNUNET_free (kac);
    277 }
    278 
    279 
    280 /**
    281  * Convert a @a ts (transfer subject) to a JSON object.
    282  * The resulting object has a "type" field discriminating the format,
    283  * matching the JSON format returned by the bank gateway's /registration.
    284  *
    285  * @param acc general account details
    286  * @param ts the specific transfer subject to convert
    287  * @return freshly allocated JSON object, or NULL on error
    288  */
    289 static json_t *
    290 transfer_subject_to_json (const struct ExchangeAccount *acc,
    291                           const struct TALER_BANK_TransferSubject *ts)
    292 {
    293   struct KycAuthContext *kac = acc->kac;
    294 
    295   switch (ts->format)
    296   {
    297   case TALER_BANK_SUBJECT_FORMAT_SIMPLE:
    298     return GNUNET_JSON_PACK (
    299       GNUNET_JSON_pack_string ("type",
    300                                "SIMPLE"),
    301       TALER_JSON_pack_amount ("credit_amount",
    302                               &kac->tiny_amount),
    303       GNUNET_JSON_pack_data_auto ("subject",
    304                                   &kac->hc->instance->merchant_pub));
    305   case TALER_BANK_SUBJECT_FORMAT_URI:
    306     return GNUNET_JSON_PACK (
    307       GNUNET_JSON_pack_string ("type",
    308                                "URI"),
    309       TALER_JSON_pack_amount ("credit_amount",
    310                               &kac->tiny_amount),
    311       GNUNET_JSON_pack_string ("uri",
    312                                ts->details.uri.uri));
    313   case TALER_BANK_SUBJECT_FORMAT_CH_QR_BILL:
    314     return GNUNET_JSON_PACK (
    315       GNUNET_JSON_pack_string ("type",
    316                                "CH_QR_BILL"),
    317       TALER_JSON_pack_amount ("credit_amount",
    318                               &ts->details.ch_qr_bill.credit_amount),
    319       GNUNET_JSON_pack_string ("qr_reference_number",
    320                                ts->details.ch_qr_bill.qr_reference_number));
    321   }
    322   GNUNET_break (0);
    323   return NULL;
    324 }
    325 
    326 
    327 /**
    328  * Generate the final "OK" response for the request in @a kac.
    329  * Builds the wire_instructions JSON array from the saved exchange accounts
    330  * and the given transfer subject.
    331  *
    332  * @param[in,out] request with all the details ready to build a response
    333  */
    334 static void
    335 generate_ok_response (struct KycAuthContext *kac)
    336 {
    337   json_t *arr;
    338 
    339   arr = json_array ();
    340   GNUNET_assert (NULL != arr);
    341   for (unsigned int i = 0; i < kac->exchange_accounts_len; i++)
    342   {
    343     const struct ExchangeAccount *acc = &kac->exchange_accounts[i];
    344     json_t *subj;
    345     json_t *entry;
    346 
    347     for (unsigned int j = 0; j < acc->num_subjects; j++)
    348     {
    349       subj = transfer_subject_to_json (acc,
    350                                        &acc->subjects[j]);
    351       GNUNET_assert (NULL != subj);
    352       entry = GNUNET_JSON_PACK (
    353         TALER_JSON_pack_amount ("amount",
    354                                 &kac->tiny_amount),
    355         TALER_JSON_pack_full_payto ("target_payto",
    356                                     acc->payto),
    357         GNUNET_JSON_pack_object_steal ("subject",
    358                                        subj),
    359         GNUNET_JSON_pack_timestamp ("expiration",
    360                                     acc->expiration));
    361       GNUNET_assert (NULL != entry);
    362       GNUNET_assert (0 ==
    363                      json_array_append_new (arr,
    364                                             entry));
    365     }
    366   }
    367   kac->response_code = MHD_HTTP_OK;
    368   kac->response = TALER_MHD_MAKE_JSON_PACK (
    369     GNUNET_JSON_pack_array_steal ("wire_instructions",
    370                                   arr));
    371   kac->phase = KP_RETURN_RESPONSE;
    372   kac_resume (kac);
    373 }
    374 
    375 
    376 /**
    377  * Callback invoked with the result of the bank gateway /registration request.
    378  *
    379  * @param cls our `struct KycAuthContext`
    380  * @param rr response details
    381  */
    382 static void
    383 registration_cb (void *cls,
    384                  const struct TALER_BANK_RegistrationResponse *rr)
    385 {
    386   struct ExchangeAccount *acc = cls;
    387   struct KycAuthContext *kac = acc->kac;
    388 
    389   acc->brh = NULL;
    390   kac->active_registrations--;
    391   if (MHD_HTTP_OK != rr->http_status)
    392   {
    393     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    394                 "Bank gateway registration failed with HTTP status %u\n",
    395                 rr->http_status);
    396     kac->response_code = MHD_HTTP_BAD_GATEWAY;
    397     kac->response = TALER_MHD_make_error (
    398       TALER_EC_MERCHANT_POST_ACCOUNTS_KYCAUTH_BANK_GATEWAY_UNREACHABLE,
    399       "bank gateway /registration failed");
    400   }
    401   GNUNET_free (acc->subjects);
    402   acc->num_subjects = rr->details.ok.num_subjects;
    403   acc->subjects = GNUNET_new_array (acc->num_subjects,
    404                                     struct TALER_BANK_TransferSubject);
    405   for (unsigned int i = 0; i<acc->num_subjects; i++)
    406   {
    407     TALER_BANK_transfer_subject_copy (&acc->subjects[i],
    408                                       &rr->details.ok.subjects[i]);
    409   }
    410   acc->expiration = rr->details.ok.expiration;
    411   if (0 != kac->active_registrations)
    412     return; /* wait for more replies */
    413   generate_ok_response (kac);
    414 }
    415 
    416 
    417 /**
    418  * Callback invoked with the /keys of the selected exchange.
    419  *
    420  * Saves tiny_amount and exchange account payto URIs from the keys, then
    421  * either calls the bank gateway /registration (if wire_transfer_gateway is
    422  * present) or directly constructs the SIMPLE-format response.
    423  *
    424  * @param cls our `struct KycAuthContext`
    425  * @param keys the exchange's key material, or NULL on failure
    426  * @param exchange internal exchange handle (unused)
    427  */
    428 static void
    429 process_keys_cb (void *cls,
    430                  struct TALER_EXCHANGE_Keys *keys,
    431                  struct TMH_Exchange *exchange)
    432 {
    433   struct KycAuthContext *kac = cls;
    434   struct TMH_MerchantInstance *mi = kac->hc->instance;
    435 
    436   (void) exchange;
    437   kac->fo = NULL;
    438   if (NULL == keys)
    439   {
    440     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    441                 "Could not get /keys from exchange `%s'\n",
    442                 kac->exchange_url);
    443     kac->response_code = MHD_HTTP_BAD_GATEWAY;
    444     kac->response = TALER_MHD_make_error (
    445       TALER_EC_MERCHANT_POST_ACCOUNTS_KYCAUTH_EXCHANGE_UNREACHABLE,
    446       kac->exchange_url);
    447     kac->phase = KP_RETURN_RESPONSE;
    448     kac_resume (kac);
    449     return;
    450   }
    451   if (! keys->tiny_amount_available)
    452   {
    453     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    454                 "Exchange `%s' did not provide tiny_amount in /keys\n",
    455                 kac->exchange_url);
    456     kac->response_code = MHD_HTTP_BAD_GATEWAY;
    457     kac->response = TALER_MHD_make_error (
    458       TALER_EC_MERCHANT_POST_ACCOUNTS_EXCHANGE_TOO_OLD,
    459       "exchange /keys missing tiny_amount");
    460     kac->phase = KP_RETURN_RESPONSE;
    461     kac_resume (kac);
    462     return;
    463   }
    464 
    465   /* Save tiny_amount and exchange wire accounts from keys */
    466   kac->tiny_amount = keys->tiny_amount;
    467   kac->exchange_accounts_len = keys->accounts_len;
    468   if (0 == keys->accounts_len)
    469   {
    470     GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
    471                 "Exchange `%s' did not provide any wire accounts in /keys\n",
    472                 kac->exchange_url);
    473     kac->response_code = MHD_HTTP_BAD_GATEWAY;
    474     kac->response = TALER_MHD_make_error (
    475       TALER_EC_MERCHANT_GENERIC_EXCHANGE_UNEXPECTED_STATUS,
    476       "exchange /keys missing wire accounts");
    477     kac->phase = KP_RETURN_RESPONSE;
    478     kac_resume (kac);
    479     return;
    480   }
    481 
    482   kac->exchange_accounts
    483     = GNUNET_new_array (keys->accounts_len,
    484                         struct ExchangeAccount);
    485   for (unsigned int i = 0; i < keys->accounts_len; i++)
    486   {
    487     struct ExchangeAccount *acc = &kac->exchange_accounts[i];
    488     struct TALER_ReserveMapAuthorizationPrivateKeyP apk;
    489 
    490     GNUNET_CRYPTO_eddsa_key_create (&apk.eddsa_priv);
    491     acc->kac = kac;
    492     acc->payto.full_payto
    493       = GNUNET_strdup (keys->accounts[i].fpayto_uri.full_payto);
    494     acc->subjects = GNUNET_new (struct TALER_BANK_TransferSubject);
    495     acc->num_subjects = 1;
    496     acc->subjects[0].format = TALER_BANK_SUBJECT_FORMAT_SIMPLE;
    497     acc->expiration = GNUNET_TIME_UNIT_FOREVER_TS;
    498     if (NULL == keys->accounts[i].wire_transfer_gateway)
    499       continue;
    500     acc->brh = TALER_BANK_registration (
    501       TMH_curl_ctx,
    502       keys->accounts[i].wire_transfer_gateway,
    503       &kac->tiny_amount,
    504       TALER_BANK_REGISTRATION_TYPE_KYC,
    505       (const union TALER_AccountPublicKeyP *) &mi->merchant_pub,
    506       // FIXME: turn this into an option when modernizing the BANK API...
    507       &apk,
    508       false, /* recurrent */
    509       &registration_cb,
    510       acc);
    511     if (NULL == acc->brh)
    512     {
    513       GNUNET_break (0);
    514       kac->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
    515       kac->response = TALER_MHD_make_error (
    516         TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE,
    517         "could not start bank gateway registration");
    518       kac->phase = KP_RETURN_RESPONSE;
    519       kac_resume (kac);
    520       return;
    521     }
    522     kac->active_registrations++;
    523   }
    524   if (0 != kac->active_registrations)
    525     return;
    526   generate_ok_response (kac);
    527 }
    528 
    529 
    530 /**
    531  * Process the PARSE phase: validate the URL path, parse the request body,
    532  * and look up the merchant account in the database.
    533  *
    534  * @param[in,out] kac context to process
    535  */
    536 static void
    537 phase_parse (struct KycAuthContext *kac)
    538 {
    539   const char *h_wire_s = kac->hc->infix;
    540   struct TALER_MerchantWireHashP h_wire;
    541   const char *exchange_url;
    542   enum GNUNET_GenericReturnValue res;
    543   struct GNUNET_JSON_Specification spec[] = {
    544     GNUNET_JSON_spec_string ("exchange_url",
    545                              &exchange_url),
    546     GNUNET_JSON_spec_end ()
    547   };
    548 
    549   GNUNET_assert (NULL != h_wire_s);
    550   if (GNUNET_OK !=
    551       GNUNET_STRINGS_string_to_data (h_wire_s,
    552                                      strlen (h_wire_s),
    553                                      &h_wire,
    554                                      sizeof (h_wire)))
    555   {
    556     GNUNET_break_op (0);
    557     kac->response_code = MHD_HTTP_BAD_REQUEST;
    558     kac->response = TALER_MHD_make_error (
    559       TALER_EC_MERCHANT_GENERIC_H_WIRE_MALFORMED,
    560       h_wire_s);
    561     kac->phase = KP_RETURN_RESPONSE;
    562     return;
    563   }
    564 
    565   res = TALER_MHD_parse_json_data (kac->connection,
    566                                    kac->hc->request_body,
    567                                    spec);
    568   if (GNUNET_OK != res)
    569   {
    570     kac->phase = (GNUNET_NO == res) ? KP_END_YES : KP_END_NO;
    571     return;
    572   }
    573 
    574   /* Look up the merchant account in the database */
    575   {
    576     struct TALER_MERCHANTDB_AccountDetails ad = { 0 };
    577     enum GNUNET_DB_QueryStatus qs;
    578 
    579     qs = TMH_db->select_account (TMH_db->cls,
    580                                  kac->hc->instance->settings.id,
    581                                  &h_wire,
    582                                  &ad);
    583     if (0 > qs)
    584     {
    585       GNUNET_break (0);
    586       GNUNET_JSON_parse_free (spec);
    587       kac->response_code = MHD_HTTP_INTERNAL_SERVER_ERROR;
    588       kac->response = TALER_MHD_make_error (
    589         TALER_EC_GENERIC_DB_FETCH_FAILED,
    590         "select_account");
    591       kac->phase = KP_RETURN_RESPONSE;
    592       return;
    593     }
    594     if (0 == qs)
    595     {
    596       GNUNET_JSON_parse_free (spec);
    597       kac->response_code = MHD_HTTP_NOT_FOUND;
    598       kac->response = TALER_MHD_make_error (
    599         TALER_EC_MERCHANT_GENERIC_ACCOUNT_UNKNOWN,
    600         h_wire_s);
    601       kac->phase = KP_RETURN_RESPONSE;
    602       return;
    603     }
    604     kac->payto_uri.full_payto = GNUNET_strdup (ad.payto_uri.full_payto);
    605     /* Free fields we do not need */
    606     GNUNET_free (ad.payto_uri.full_payto);
    607     GNUNET_free (ad.credit_facade_url);
    608     GNUNET_free (ad.extra_wire_subject_metadata);
    609     json_decref (ad.credit_facade_credentials);
    610   }
    611 
    612   kac->exchange_url = GNUNET_strdup (exchange_url);
    613   GNUNET_JSON_parse_free (spec);
    614   kac->phase = KP_CHECK_EXCHANGES;
    615 }
    616 
    617 
    618 /**
    619  * Process the CHECK_EXCHANGES phase: start an async /keys fetch from
    620  * the requested exchange and suspend the connection.
    621  *
    622  * @param[in,out] kac context to process
    623  */
    624 static void
    625 phase_check_exchanges (struct KycAuthContext *kac)
    626 {
    627   kac->fo = TMH_EXCHANGES_keys4exchange (kac->exchange_url,
    628                                          false,
    629                                          &process_keys_cb,
    630                                          kac);
    631   if (NULL == kac->fo)
    632   {
    633     GNUNET_break_op (0);
    634     kac->response_code = MHD_HTTP_BAD_REQUEST;
    635     kac->response = TALER_MHD_make_error (
    636       TALER_EC_MERCHANT_GENERIC_EXCHANGE_UNTRUSTED,
    637       kac->exchange_url);
    638     kac->phase = KP_RETURN_RESPONSE;
    639     return;
    640   }
    641   MHD_suspend_connection (kac->connection);
    642   kac->suspended = GNUNET_YES;
    643 }
    644 
    645 
    646 /**
    647  * Process the RETURN_RESPONSE phase: queue the prepared response into MHD.
    648  *
    649  * @param[in,out] kac context to process
    650  */
    651 static void
    652 phase_return_response (struct KycAuthContext *kac)
    653 {
    654   MHD_RESULT ret;
    655 
    656   if (UINT_MAX == kac->response_code)
    657   {
    658     GNUNET_break (0);
    659     kac->phase = KP_END_NO;
    660     return;
    661   }
    662   GNUNET_assert (0 != kac->response_code);
    663   ret = MHD_queue_response (kac->connection,
    664                             kac->response_code,
    665                             kac->response);
    666   kac->phase = (MHD_YES == ret) ? KP_END_YES : KP_END_NO;
    667 }
    668 
    669 
    670 MHD_RESULT
    671 TMH_private_post_accounts_H_WIRE_kycauth (
    672   const struct TMH_RequestHandler *rh,
    673   struct MHD_Connection *connection,
    674   struct TMH_HandlerContext *hc)
    675 {
    676   struct KycAuthContext *kac = hc->ctx;
    677 
    678   (void) rh;
    679   GNUNET_assert (NULL != hc->infix);
    680   if (NULL == kac)
    681   {
    682     kac = GNUNET_new (struct KycAuthContext);
    683     kac->connection = connection;
    684     kac->hc = hc;
    685     hc->ctx = kac;
    686     hc->cc = &kac_cleanup;
    687     GNUNET_CONTAINER_DLL_insert (kac_head,
    688                                  kac_tail,
    689                                  kac);
    690   }
    691 
    692   while (1)
    693   {
    694     GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    695                 "Processing POST /private/accounts/$H_WIRE/kycauth"
    696                 " in phase %d\n",
    697                 (int) kac->phase);
    698     switch (kac->phase)
    699     {
    700     case KP_PARSE:
    701       phase_parse (kac);
    702       break;
    703     case KP_CHECK_EXCHANGES:
    704       phase_check_exchanges (kac);
    705       break;
    706     case KP_RETURN_RESPONSE:
    707       phase_return_response (kac);
    708       break;
    709     case KP_END_YES:
    710       return MHD_YES;
    711     case KP_END_NO:
    712       return MHD_NO;
    713     default:
    714       GNUNET_assert (0);
    715       return MHD_NO;
    716     }
    717 
    718     switch (kac->suspended)
    719     {
    720     case GNUNET_SYSERR:
    721       /* Shutdown in progress */
    722       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    723                   "Processing POST /private/accounts/$H_WIRE/kycauth"
    724                   " ends due to shutdown in phase %d\n",
    725                   (int) kac->phase);
    726       return MHD_NO;
    727     case GNUNET_NO:
    728       /* Not suspended, continue with next phase */
    729       break;
    730     case GNUNET_YES:
    731       GNUNET_log (GNUNET_ERROR_TYPE_INFO,
    732                   "Processing POST /private/accounts/$H_WIRE/kycauth"
    733                   " suspended in phase %d\n",
    734                   (int) kac->phase);
    735       return MHD_YES;
    736     }
    737   }
    738   GNUNET_assert (0);
    739   return MHD_YES;
    740 }
    741 
    742 
    743 /* end of taler-merchant-httpd_private-post-accounts-H_WIRE-kycauth.c */