LCOV - code coverage report
Current view: top level - lib - merchant_api_post-orders-ORDER_ID-pay.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 434 0
Test Date: 2026-04-12 12:58:13 Functions: 0.0 % 7 0

            Line data    Source code
       1              : /*
       2              :   This file is part of TALER
       3              :   Copyright (C) 2014-2026 Taler Systems SA
       4              : 
       5              :   TALER is free software; you can redistribute it and/or modify
       6              :   it under the terms of the GNU Lesser General Public License as
       7              :   published by the Free Software Foundation; either version 2.1,
       8              :   or (at your option) any later version.
       9              : 
      10              :   TALER is distributed in the hope that it will be useful,
      11              :   but WITHOUT ANY WARRANTY; without even the implied warranty of
      12              :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13              :   GNU Lesser General Public License for more details.
      14              : 
      15              :   You should have received a copy of the GNU Lesser General
      16              :   Public License along with TALER; see the file COPYING.LGPL.
      17              :   If not, see <http://www.gnu.org/licenses/>
      18              : */
      19              : /**
      20              :  * @file merchant_api_post-orders-ORDER_ID-pay-new.c
      21              :  * @brief Implementation of the POST /orders/$ORDER_ID/pay request
      22              :  * @author Christian Grothoff
      23              :  * @author Marcello Stanisci
      24              :  */
      25              : #include "taler/platform.h"
      26              : #include <curl/curl.h>
      27              : #include <jansson.h>
      28              : #include <microhttpd.h> /* just for HTTP status codes */
      29              : #include <gnunet/gnunet_util_lib.h>
      30              : #include <gnunet/gnunet_curl_lib.h>
      31              : #include <taler/merchant/post-orders-ORDER_ID-pay.h>
      32              : #include "merchant_api_curl_defaults.h"
      33              : #include "merchant_api_common.h"
      34              : #include <taler/taler_json_lib.h>
      35              : #include <taler/taler_curl_lib.h>
      36              : #include <taler/taler_signatures.h>
      37              : #include <donau/donau_service.h>
      38              : #include <donau/donau_json_lib.h>
      39              : 
      40              : /**
      41              :  * Handle for a POST /orders/$ORDER_ID/pay operation.
      42              :  */
      43              : struct TALER_MERCHANT_PostOrdersPayHandle
      44              : {
      45              :   /**
      46              :    * Base URL of the merchant backend.
      47              :    */
      48              :   char *base_url;
      49              : 
      50              :   /**
      51              :    * The full URL for this request.
      52              :    */
      53              :   char *url;
      54              : 
      55              :   /**
      56              :    * Handle for the request.
      57              :    */
      58              :   struct GNUNET_CURL_Job *job;
      59              : 
      60              :   /**
      61              :    * Function to call with the result.
      62              :    */
      63              :   TALER_MERCHANT_PostOrdersPayCallback cb;
      64              : 
      65              :   /**
      66              :    * Closure for @a cb.
      67              :    */
      68              :   TALER_MERCHANT_POST_ORDERS_PAY_RESULT_CLOSURE *cb_cls;
      69              : 
      70              :   /**
      71              :    * Reference to the execution context.
      72              :    */
      73              :   struct GNUNET_CURL_Context *ctx;
      74              : 
      75              :   /**
      76              :    * Minor context that holds body and headers.
      77              :    */
      78              :   struct TALER_CURL_PostContext post_ctx;
      79              : 
      80              :   /**
      81              :    * Order identifier.
      82              :    */
      83              :   char *order_id;
      84              : 
      85              :   /**
      86              :    * The coins we are paying with (frontend mode, already signed).
      87              :    */
      88              :   struct TALER_MERCHANT_PostOrdersPayPaidCoin *paid_coins;
      89              : 
      90              :   /**
      91              :    * Number of @e paid_coins.
      92              :    */
      93              :   unsigned int num_paid_coins;
      94              : 
      95              :   /**
      96              :    * Hash of the contract terms (wallet mode).
      97              :    */
      98              :   struct TALER_PrivateContractHashP h_contract_terms;
      99              : 
     100              :   /**
     101              :    * Public key of the merchant (wallet mode).
     102              :    */
     103              :   struct TALER_MerchantPublicKeyP merchant_pub;
     104              : 
     105              :   /**
     106              :    * Merchant signature (wallet mode).
     107              :    */
     108              :   struct TALER_MerchantSignatureP merchant_sig;
     109              : 
     110              :   /**
     111              :    * Total payment amount (wallet mode).
     112              :    */
     113              :   struct TALER_Amount amount;
     114              : 
     115              :   /**
     116              :    * Maximum fee (wallet mode).
     117              :    */
     118              :   struct TALER_Amount max_fee;
     119              : 
     120              :   /**
     121              :    * Contract timestamp (wallet mode).
     122              :    */
     123              :   struct GNUNET_TIME_Timestamp timestamp;
     124              : 
     125              :   /**
     126              :    * Refund deadline (wallet mode).
     127              :    */
     128              :   struct GNUNET_TIME_Timestamp refund_deadline;
     129              : 
     130              :   /**
     131              :    * Payment deadline (wallet mode).
     132              :    */
     133              :   struct GNUNET_TIME_Timestamp pay_deadline;
     134              : 
     135              :   /**
     136              :    * Hash of merchant wire details (wallet mode).
     137              :    */
     138              :   struct TALER_MerchantWireHashP h_wire;
     139              : 
     140              :   /**
     141              :    * Choice index (wallet mode).
     142              :    */
     143              :   int choice_index;
     144              : 
     145              :   /**
     146              :    * Coins with private keys (wallet mode).
     147              :    */
     148              :   struct TALER_MERCHANT_PostOrdersPayCoin *coins;
     149              : 
     150              :   /**
     151              :    * Number of @e coins (wallet mode).
     152              :    */
     153              :   unsigned int num_coins;
     154              : 
     155              :   /**
     156              :    * Optional session identifier.
     157              :    */
     158              :   char *session_id;
     159              : 
     160              :   /**
     161              :    * Optional wallet data (JSON).
     162              :    */
     163              :   json_t *wallet_data;
     164              : 
     165              :   /**
     166              :    * Used tokens (public form, frontend mode).
     167              :    */
     168              :   struct TALER_MERCHANT_PostOrdersPayUsedToken *used_tokens;
     169              : 
     170              :   /**
     171              :    * Number of @e used_tokens.
     172              :    */
     173              :   unsigned int num_used_tokens;
     174              : 
     175              :   /**
     176              :    * Use tokens (private form, wallet mode).
     177              :    */
     178              :   struct TALER_MERCHANT_PostOrdersPayUseToken *use_tokens;
     179              : 
     180              :   /**
     181              :    * Number of @e use_tokens.
     182              :    */
     183              :   unsigned int num_use_tokens;
     184              : 
     185              :   /**
     186              :    * Output tokens (wallet mode).
     187              :    */
     188              :   struct TALER_MERCHANT_PostOrdersPayOutputToken *output_tokens;
     189              : 
     190              :   /**
     191              :    * Number of @e output_tokens.
     192              :    */
     193              :   unsigned int num_output_tokens;
     194              : 
     195              :   /**
     196              :    * Output tokens as JSON array (frontend mode).
     197              :    */
     198              :   json_t *output_tokens_json;
     199              : 
     200              :   /**
     201              :    * Base URL of the selected donau for donation receipts.
     202              :    */
     203              :   char *donau_url;
     204              : 
     205              :   /**
     206              :    * Tax year used for the donau.
     207              :    */
     208              :   unsigned int donau_year;
     209              : 
     210              :   /**
     211              :    * Array of blinded donation receipts.
     212              :    */
     213              :   struct DONAU_BlindedUniqueDonorIdentifierKeyPair *donau_bkps;
     214              : 
     215              :   /**
     216              :    * Length of the @e donau_bkps array.
     217              :    */
     218              :   size_t num_donau_bkps;
     219              : 
     220              :   /**
     221              :    * Set to true if this is the wallet mode (private keys available).
     222              :    */
     223              :   bool am_wallet;
     224              : };
     225              : 
     226              : 
     227              : /**
     228              :  * Parse blindly signed output tokens from JSON response.
     229              :  *
     230              :  * @param token_sigs the JSON array with the token signatures, can be NULL
     231              :  * @param[out] tokens where to store the parsed tokens
     232              :  * @param[out] num_tokens where to store the length of the @a tokens array
     233              :  * @return #GNUNET_YES on success
     234              :  */
     235              : static enum GNUNET_GenericReturnValue
     236            0 : parse_tokens (const json_t *token_sigs,
     237              :               struct TALER_MERCHANT_PostOrdersPayOutputToken **tokens,
     238              :               unsigned int *num_tokens)
     239              : {
     240            0 :   GNUNET_array_grow (*tokens,
     241              :                      *num_tokens,
     242              :                      json_array_size (token_sigs));
     243              : 
     244            0 :   for (unsigned int i = 0; i < (*num_tokens); i++)
     245              :   {
     246            0 :     struct TALER_MERCHANT_PostOrdersPayOutputToken *token = &(*tokens)[i];
     247              :     struct GNUNET_JSON_Specification spec[] = {
     248            0 :       TALER_JSON_spec_blinded_token_issue_sig ("blind_sig",
     249              :                                                &token->blinded_sig),
     250            0 :       GNUNET_JSON_spec_end ()
     251              :     };
     252              :     const json_t *jtoken
     253            0 :       = json_array_get (token_sigs,
     254              :                         i);
     255              : 
     256            0 :     if (NULL == jtoken)
     257              :     {
     258            0 :       GNUNET_break (0);
     259            0 :       return GNUNET_SYSERR;
     260              :     }
     261            0 :     if (GNUNET_OK !=
     262            0 :         GNUNET_JSON_parse (jtoken,
     263              :                            spec,
     264              :                            NULL, NULL))
     265              :     {
     266            0 :       GNUNET_break (0);
     267            0 :       return GNUNET_SYSERR;
     268              :     }
     269              :   }
     270              : 
     271            0 :   return GNUNET_YES;
     272              : }
     273              : 
     274              : 
     275              : /**
     276              :  * Function called when we're done processing the
     277              :  * HTTP POST /orders/$ORDER_ID/pay request.
     278              :  *
     279              :  * @param cls the `struct TALER_MERCHANT_PostOrdersPayHandle`
     280              :  * @param response_code HTTP response code, 0 on error
     281              :  * @param response response body, NULL if not in JSON
     282              :  */
     283              : static void
     284            0 : handle_pay_finished (void *cls,
     285              :                      long response_code,
     286              :                      const void *response)
     287              : {
     288            0 :   struct TALER_MERCHANT_PostOrdersPayHandle *poph = cls;
     289            0 :   const json_t *json = response;
     290            0 :   struct TALER_MERCHANT_PostOrdersPayResponse pr = {
     291            0 :     .hr.http_status = (unsigned int) response_code,
     292              :     .hr.reply = json
     293              :   };
     294              : 
     295            0 :   poph->job = NULL;
     296            0 :   GNUNET_log (GNUNET_ERROR_TYPE_INFO,
     297              :               "POST /orders/$ID/pay completed with response code %u\n",
     298              :               (unsigned int) response_code);
     299            0 :   switch (response_code)
     300              :   {
     301            0 :   case 0:
     302            0 :     pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     303            0 :     break;
     304            0 :   case MHD_HTTP_OK:
     305            0 :     if (poph->am_wallet)
     306              :     {
     307            0 :       const json_t *token_sigs = NULL;
     308              :       struct GNUNET_JSON_Specification spec[] = {
     309            0 :         GNUNET_JSON_spec_fixed_auto ("sig",
     310              :                                      &pr.details.ok.merchant_sig),
     311            0 :         GNUNET_JSON_spec_mark_optional (
     312              :           GNUNET_JSON_spec_string ("pos_confirmation",
     313              :                                    &pr.details.ok.pos_confirmation),
     314              :           NULL),
     315            0 :         GNUNET_JSON_spec_mark_optional (
     316              :           GNUNET_JSON_spec_array_const ("token_sigs",
     317              :                                         &token_sigs),
     318              :           NULL),
     319            0 :         GNUNET_JSON_spec_end ()
     320              :       };
     321              : 
     322            0 :       if (GNUNET_OK !=
     323            0 :           GNUNET_JSON_parse (json,
     324              :                              spec,
     325              :                              NULL, NULL))
     326              :       {
     327            0 :         GNUNET_break_op (0);
     328            0 :         pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     329            0 :         pr.hr.http_status = 0;
     330            0 :         pr.hr.hint = "sig field missing in response";
     331            0 :         break;
     332              :       }
     333              : 
     334            0 :       if (GNUNET_OK !=
     335            0 :           parse_tokens (token_sigs,
     336              :                         &pr.details.ok.tokens,
     337              :                         &pr.details.ok.num_tokens))
     338              :       {
     339            0 :         GNUNET_break_op (0);
     340            0 :         pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     341            0 :         pr.hr.http_status = 0;
     342            0 :         pr.hr.hint = "failed to parse token_sigs field in response";
     343            0 :         break;
     344              :       }
     345              : 
     346            0 :       if (GNUNET_OK !=
     347            0 :           TALER_merchant_pay_verify (&poph->h_contract_terms,
     348            0 :                                      &poph->merchant_pub,
     349              :                                      &pr.details.ok.merchant_sig))
     350              :       {
     351            0 :         GNUNET_break_op (0);
     352            0 :         pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     353            0 :         pr.hr.http_status = 0;
     354            0 :         pr.hr.hint = "signature invalid";
     355              :       }
     356              :     }
     357            0 :     break;
     358            0 :   case MHD_HTTP_BAD_REQUEST:
     359            0 :     pr.hr.ec = TALER_JSON_get_error_code (json);
     360            0 :     pr.hr.hint = TALER_JSON_get_error_hint (json);
     361            0 :     break;
     362            0 :   case MHD_HTTP_PAYMENT_REQUIRED:
     363            0 :     pr.hr.ec = TALER_JSON_get_error_code (json);
     364            0 :     pr.hr.hint = TALER_JSON_get_error_hint (json);
     365            0 :     break;
     366            0 :   case MHD_HTTP_FORBIDDEN:
     367            0 :     pr.hr.ec = TALER_JSON_get_error_code (json);
     368            0 :     pr.hr.hint = TALER_JSON_get_error_hint (json);
     369            0 :     break;
     370            0 :   case MHD_HTTP_NOT_FOUND:
     371            0 :     pr.hr.ec = TALER_JSON_get_error_code (json);
     372            0 :     pr.hr.hint = TALER_JSON_get_error_hint (json);
     373            0 :     break;
     374            0 :   case MHD_HTTP_REQUEST_TIMEOUT:
     375            0 :     pr.hr.ec = TALER_JSON_get_error_code (json);
     376            0 :     pr.hr.hint = TALER_JSON_get_error_hint (json);
     377            0 :     break;
     378            0 :   case MHD_HTTP_CONFLICT:
     379            0 :     TALER_MERCHANT_parse_error_details_ (json,
     380              :                                          MHD_HTTP_CONFLICT,
     381              :                                          &pr.hr);
     382              :     {
     383            0 :       const char *eu = json_string_value (
     384            0 :         json_object_get (json, "exchange_url"));
     385              : 
     386            0 :       pr.details.conflict.exchange_url = eu;
     387            0 :       pr.details.conflict.exchange_ec = pr.hr.exchange_code;
     388              :       pr.details.conflict.exchange_http_status
     389            0 :         = pr.hr.exchange_http_status;
     390              :     }
     391            0 :     break;
     392            0 :   case MHD_HTTP_GONE:
     393            0 :     TALER_MERCHANT_parse_error_details_ (json,
     394              :                                          response_code,
     395              :                                          &pr.hr);
     396            0 :     break;
     397            0 :   case MHD_HTTP_PRECONDITION_FAILED:
     398            0 :     TALER_MERCHANT_parse_error_details_ (json,
     399              :                                          response_code,
     400              :                                          &pr.hr);
     401            0 :     break;
     402            0 :   case MHD_HTTP_UNAVAILABLE_FOR_LEGAL_REASONS:
     403              :     {
     404            0 :       json_t *ebus = json_object_get (json,
     405              :                                       "exchange_base_urls");
     406            0 :       if (NULL == ebus)
     407              :       {
     408            0 :         GNUNET_break_op (0);
     409            0 :         pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     410            0 :         pr.hr.http_status = 0;
     411              :         pr.hr.hint
     412            0 :           = "failed to parse exchange_base_urls field in response";
     413            0 :         break;
     414              :       }
     415            0 :       {
     416            0 :         size_t alen = json_array_size (ebus);
     417            0 :         const char *ebua[GNUNET_NZL (alen)];
     418              :         size_t idx;
     419              :         json_t *jebu;
     420            0 :         bool ok = true;
     421              : 
     422            0 :         GNUNET_assert (alen <= UINT_MAX);
     423            0 :         json_array_foreach (ebus, idx, jebu)
     424              :         {
     425            0 :           ebua[idx] = json_string_value (jebu);
     426            0 :           if (NULL == ebua[idx])
     427              :           {
     428            0 :             GNUNET_break_op (0);
     429            0 :             pr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
     430            0 :             pr.hr.http_status = 0;
     431              :             pr.hr.hint
     432            0 :               = "non-string value in exchange_base_urls in response";
     433            0 :             ok = false;
     434            0 :             break;
     435              :           }
     436              :         }
     437            0 :         if (! ok)
     438            0 :           break;
     439              :         pr.details.unavailable_for_legal_reasons.num_exchanges
     440            0 :           = (unsigned int) alen;
     441              :         pr.details.unavailable_for_legal_reasons.exchanges
     442            0 :           = ebua;
     443            0 :         poph->cb (poph->cb_cls,
     444              :                   &pr);
     445            0 :         TALER_MERCHANT_post_orders_pay_cancel (poph);
     446            0 :         return;
     447              :       }
     448              :     }
     449              :     break;
     450            0 :   case MHD_HTTP_INTERNAL_SERVER_ERROR:
     451            0 :     TALER_MERCHANT_parse_error_details_ (json,
     452              :                                          response_code,
     453              :                                          &pr.hr);
     454            0 :     break;
     455            0 :   case MHD_HTTP_NOT_IMPLEMENTED:
     456            0 :     TALER_MERCHANT_parse_error_details_ (json,
     457              :                                          response_code,
     458              :                                          &pr.hr);
     459            0 :     break;
     460            0 :   case MHD_HTTP_BAD_GATEWAY:
     461            0 :     TALER_MERCHANT_parse_error_details_ (json,
     462              :                                          response_code,
     463              :                                          &pr.hr);
     464              :     {
     465            0 :       const char *eu = json_string_value (
     466            0 :         json_object_get (json, "exchange_url"));
     467              : 
     468            0 :       pr.details.bad_gateway.exchange_url = eu;
     469            0 :       pr.details.bad_gateway.exchange_ec = pr.hr.exchange_code;
     470              :       pr.details.bad_gateway.exchange_http_status
     471            0 :         = pr.hr.exchange_http_status;
     472              :     }
     473            0 :     break;
     474            0 :   case MHD_HTTP_GATEWAY_TIMEOUT:
     475            0 :     TALER_MERCHANT_parse_error_details_ (json,
     476              :                                          response_code,
     477              :                                          &pr.hr);
     478            0 :     break;
     479            0 :   default:
     480            0 :     TALER_MERCHANT_parse_error_details_ (json,
     481              :                                          response_code,
     482              :                                          &pr.hr);
     483            0 :     GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     484              :                 "Unexpected response code %u/%d\n",
     485              :                 (unsigned int) response_code,
     486              :                 (int) pr.hr.ec);
     487            0 :     GNUNET_break_op (0);
     488            0 :     break;
     489              :   }
     490            0 :   poph->cb (poph->cb_cls,
     491              :             &pr);
     492            0 :   TALER_MERCHANT_post_orders_pay_cancel (poph);
     493              : }
     494              : 
     495              : 
     496              : struct TALER_MERCHANT_PostOrdersPayHandle *
     497            0 : TALER_MERCHANT_post_orders_pay_frontend_create (
     498              :   struct GNUNET_CURL_Context *ctx,
     499              :   const char *url,
     500              :   const char *order_id,
     501              :   unsigned int num_coins,
     502              :   const struct TALER_MERCHANT_PostOrdersPayPaidCoin coins[static num_coins])
     503            0 : {
     504              :   struct TALER_MERCHANT_PostOrdersPayHandle *poph;
     505              : 
     506            0 :   poph = GNUNET_new (struct TALER_MERCHANT_PostOrdersPayHandle);
     507            0 :   poph->ctx = ctx;
     508            0 :   poph->base_url = GNUNET_strdup (url);
     509            0 :   poph->order_id = GNUNET_strdup (order_id);
     510            0 :   poph->am_wallet = false;
     511            0 :   poph->num_paid_coins = num_coins;
     512            0 :   poph->paid_coins = GNUNET_new_array (
     513              :     num_coins,
     514              :     struct TALER_MERCHANT_PostOrdersPayPaidCoin);
     515            0 :   for (unsigned int i = 0; i < num_coins; i++)
     516              :   {
     517            0 :     struct TALER_MERCHANT_PostOrdersPayPaidCoin *dst = &poph->paid_coins[i];
     518            0 :     const struct TALER_MERCHANT_PostOrdersPayPaidCoin *src = &coins[i];
     519              : 
     520            0 :     *dst = *src;
     521              :     /* deep copy fields that need it */
     522            0 :     TALER_denom_pub_copy (&dst->denom_pub,
     523              :                           &src->denom_pub);
     524            0 :     TALER_denom_sig_copy (&dst->denom_sig,
     525              :                           &src->denom_sig);
     526            0 :     dst->exchange_url = GNUNET_strdup (src->exchange_url);
     527              :   }
     528            0 :   return poph;
     529              : }
     530              : 
     531              : 
     532              : struct TALER_MERCHANT_PostOrdersPayHandle *
     533            0 : TALER_MERCHANT_post_orders_pay_create (
     534              :   struct GNUNET_CURL_Context *ctx,
     535              :   const char *url,
     536              :   const char *order_id,
     537              :   const struct TALER_PrivateContractHashP *h_contract_terms,
     538              :   const struct TALER_Amount *amount,
     539              :   const struct TALER_Amount *max_fee,
     540              :   const struct TALER_MerchantPublicKeyP *merchant_pub,
     541              :   const struct TALER_MerchantSignatureP *merchant_sig,
     542              :   struct GNUNET_TIME_Timestamp timestamp,
     543              :   struct GNUNET_TIME_Timestamp refund_deadline,
     544              :   struct GNUNET_TIME_Timestamp pay_deadline,
     545              :   const struct TALER_MerchantWireHashP *h_wire,
     546              :   unsigned int num_coins,
     547              :   const struct TALER_MERCHANT_PostOrdersPayCoin coins[static num_coins])
     548            0 : {
     549              :   struct TALER_MERCHANT_PostOrdersPayHandle *poph;
     550              : 
     551            0 :   if (GNUNET_YES !=
     552            0 :       TALER_amount_cmp_currency (amount,
     553              :                                  max_fee))
     554              :   {
     555            0 :     GNUNET_break (0);
     556            0 :     return NULL;
     557              :   }
     558              : 
     559            0 :   poph = GNUNET_new (struct TALER_MERCHANT_PostOrdersPayHandle);
     560            0 :   poph->ctx = ctx;
     561            0 :   poph->base_url = GNUNET_strdup (url);
     562            0 :   poph->order_id = GNUNET_strdup (order_id);
     563            0 :   poph->am_wallet = true;
     564            0 :   poph->h_contract_terms = *h_contract_terms;
     565            0 :   poph->choice_index = -1;
     566            0 :   poph->amount = *amount;
     567            0 :   poph->max_fee = *max_fee;
     568            0 :   poph->merchant_pub = *merchant_pub;
     569            0 :   poph->merchant_sig = *merchant_sig;
     570            0 :   poph->timestamp = timestamp;
     571            0 :   poph->refund_deadline = refund_deadline;
     572            0 :   poph->pay_deadline = pay_deadline;
     573            0 :   poph->h_wire = *h_wire;
     574            0 :   poph->num_coins = num_coins;
     575            0 :   poph->coins = GNUNET_new_array (num_coins,
     576              :                                   struct TALER_MERCHANT_PostOrdersPayCoin);
     577            0 :   for (unsigned int i = 0; i < num_coins; i++)
     578              :   {
     579            0 :     struct TALER_MERCHANT_PostOrdersPayCoin *dst = &poph->coins[i];
     580            0 :     const struct TALER_MERCHANT_PostOrdersPayCoin *src = &coins[i];
     581              : 
     582            0 :     *dst = *src;
     583            0 :     TALER_denom_pub_copy (&dst->denom_pub,
     584              :                           &src->denom_pub);
     585            0 :     TALER_denom_sig_copy (&dst->denom_sig,
     586              :                           &src->denom_sig);
     587            0 :     dst->exchange_url = GNUNET_strdup (src->exchange_url);
     588              :   }
     589            0 :   return poph;
     590              : }
     591              : 
     592              : 
     593              : enum GNUNET_GenericReturnValue
     594            0 : TALER_MERCHANT_post_orders_pay_set_options_ (
     595              :   struct TALER_MERCHANT_PostOrdersPayHandle *poph,
     596              :   unsigned int num_options,
     597              :   const struct TALER_MERCHANT_PostOrdersPayOptionValue *options)
     598              : {
     599            0 :   for (unsigned int i = 0; i < num_options; i++)
     600              :   {
     601            0 :     switch (options[i].option)
     602              :     {
     603            0 :     case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_END:
     604            0 :       return GNUNET_OK;
     605            0 :     case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_SESSION_ID:
     606            0 :       GNUNET_free (poph->session_id);
     607            0 :       if (NULL != options[i].details.session_id)
     608            0 :         poph->session_id = GNUNET_strdup (options[i].details.session_id);
     609            0 :       break;
     610            0 :     case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_WALLET_DATA:
     611            0 :       json_decref (poph->wallet_data);
     612            0 :       poph->wallet_data = NULL;
     613            0 :       if (NULL != options[i].details.wallet_data)
     614            0 :         poph->wallet_data = json_incref (
     615            0 :           (json_t *) options[i].details.wallet_data);
     616            0 :       break;
     617            0 :     case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_USED_TOKENS:
     618            0 :       GNUNET_free (poph->used_tokens);
     619            0 :       poph->num_used_tokens = options[i].details.used_tokens.num;
     620            0 :       if (0 < poph->num_used_tokens)
     621              :       {
     622            0 :         poph->used_tokens = GNUNET_new_array (
     623              :           poph->num_used_tokens,
     624              :           struct TALER_MERCHANT_PostOrdersPayUsedToken);
     625            0 :         GNUNET_memcpy (poph->used_tokens,
     626              :                        options[i].details.used_tokens.tokens,
     627              :                        poph->num_used_tokens
     628              :                        * sizeof (struct TALER_MERCHANT_PostOrdersPayUsedToken));
     629              :       }
     630            0 :       break;
     631            0 :     case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_USE_TOKENS:
     632            0 :       GNUNET_free (poph->use_tokens);
     633            0 :       poph->num_use_tokens = options[i].details.use_tokens.num;
     634            0 :       if (0 < poph->num_use_tokens)
     635              :       {
     636            0 :         poph->use_tokens = GNUNET_new_array (
     637              :           poph->num_use_tokens,
     638              :           struct TALER_MERCHANT_PostOrdersPayUseToken);
     639            0 :         GNUNET_memcpy (poph->use_tokens,
     640              :                        options[i].details.use_tokens.tokens,
     641              :                        poph->num_use_tokens
     642              :                        * sizeof (struct TALER_MERCHANT_PostOrdersPayUseToken));
     643              :       }
     644            0 :       break;
     645            0 :     case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_OUTPUT_TOKENS:
     646            0 :       GNUNET_free (poph->output_tokens);
     647            0 :       poph->num_output_tokens = options[i].details.output_tokens.num;
     648            0 :       if (0 < poph->num_output_tokens)
     649              :       {
     650            0 :         poph->output_tokens = GNUNET_new_array (
     651              :           poph->num_output_tokens,
     652              :           struct TALER_MERCHANT_PostOrdersPayOutputToken);
     653            0 :         GNUNET_memcpy (
     654              :           poph->output_tokens,
     655              :           options[i].details.output_tokens.tokens,
     656              :           poph->num_output_tokens
     657              :           * sizeof (struct TALER_MERCHANT_PostOrdersPayOutputToken));
     658              :       }
     659            0 :       break;
     660            0 :     case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_OUTPUT_TOKENS_JSON:
     661            0 :       json_decref (poph->output_tokens_json);
     662            0 :       poph->output_tokens_json = NULL;
     663            0 :       if (NULL != options[i].details.output_tokens_json)
     664            0 :         poph->output_tokens_json = json_incref (
     665            0 :           options[i].details.output_tokens_json);
     666            0 :       break;
     667            0 :     case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_OUTPUT_DONAU:
     668            0 :       if (NULL != poph->donau_url)
     669              :       {
     670            0 :         GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
     671              :                     "Only one set of donation receipts is allowed to be specified\n");
     672            0 :         return GNUNET_NO;
     673              :       }
     674              :       poph->donau_url
     675            0 :         = GNUNET_strdup (options[i].details.output_donau.donau_base_url);
     676              :       poph->donau_year
     677            0 :         = options[i].details.output_donau.year;
     678            0 :       poph->num_donau_bkps = options[i].details.output_donau.num_bkps;
     679            0 :       poph->donau_bkps = GNUNET_new_array (
     680              :         poph->num_donau_bkps,
     681              :         struct DONAU_BlindedUniqueDonorIdentifierKeyPair);
     682            0 :       for (size_t j=0; j<poph->num_donau_bkps; j++)
     683              :       {
     684            0 :         const struct DONAU_BlindedUniqueDonorIdentifierKeyPair *src
     685            0 :           = &options[i].details.output_donau.bkps[j];
     686            0 :         struct DONAU_BlindedUniqueDonorIdentifierKeyPair *dst
     687            0 :           = &poph->donau_bkps[j];
     688              : 
     689            0 :         dst->h_donation_unit_pub = src->h_donation_unit_pub;
     690              :         dst->blinded_udi.blinded_message
     691            0 :           = GNUNET_CRYPTO_blinded_message_incref (
     692            0 :               src->blinded_udi.blinded_message);
     693              :       }
     694            0 :       break;
     695            0 :     case TALER_MERCHANT_POST_ORDERS_PAY_OPTION_CHOICE_INDEX:
     696            0 :       poph->choice_index = options[i].details.choice_index;
     697            0 :       break;
     698            0 :     default:
     699            0 :       GNUNET_break (0);
     700            0 :       return GNUNET_SYSERR;
     701              :     }
     702              :   }
     703            0 :   return GNUNET_OK;
     704              : }
     705              : 
     706              : 
     707              : enum TALER_ErrorCode
     708            0 : TALER_MERCHANT_post_orders_pay_start (
     709              :   struct TALER_MERCHANT_PostOrdersPayHandle *poph,
     710              :   TALER_MERCHANT_PostOrdersPayCallback cb,
     711              :   TALER_MERCHANT_POST_ORDERS_PAY_RESULT_CLOSURE *cb_cls)
     712              : {
     713              :   json_t *pay_obj;
     714              :   json_t *j_coins;
     715            0 :   json_t *j_tokens = NULL;
     716            0 :   json_t *j_output_tokens = NULL;
     717              :   CURL *eh;
     718              : 
     719            0 :   poph->cb = cb;
     720            0 :   poph->cb_cls = cb_cls;
     721              :   {
     722              :     char *path;
     723              : 
     724            0 :     GNUNET_asprintf (&path,
     725              :                      "orders/%s/pay",
     726              :                      poph->order_id);
     727            0 :     poph->url = TALER_url_join (poph->base_url,
     728              :                                 path,
     729              :                                 NULL);
     730            0 :     GNUNET_free (path);
     731              :   }
     732            0 :   if (NULL == poph->url)
     733            0 :     return TALER_EC_GENERIC_CONFIGURATION_INVALID;
     734              : 
     735            0 :   if (poph->am_wallet)
     736              :   {
     737              :     /* Wallet mode: sign coins and tokens, build wallet_data */
     738            0 :     json_t *wallet_data = poph->wallet_data;
     739            0 :     json_t *j_donau_data = NULL;
     740              :     struct GNUNET_HashCode wallet_data_hash;
     741              : 
     742            0 :     if (NULL != poph->donau_url)
     743              :     {
     744              :       json_t *budis;
     745              : 
     746            0 :       budis = json_array ();
     747            0 :       GNUNET_assert (NULL != budis);
     748            0 :       for (size_t i=0; i<poph->num_donau_bkps; i++)
     749              :       {
     750            0 :         const struct DONAU_BlindedUniqueDonorIdentifierKeyPair *bkp
     751            0 :           = &poph->donau_bkps[i];
     752            0 :         json_t *budikeypair = GNUNET_JSON_PACK (
     753              :           GNUNET_JSON_pack_data_auto ("h_donation_unit_pub",
     754              :                                       &bkp->h_donation_unit_pub),
     755              :           DONAU_JSON_pack_blinded_donation_identifier ("blinded_udi",
     756              :                                                        &bkp->blinded_udi));
     757              : 
     758            0 :         GNUNET_assert (0 ==
     759              :                        json_array_append_new (budis,
     760              :                                               budikeypair));
     761              :       }
     762              : 
     763            0 :       j_donau_data = GNUNET_JSON_PACK (
     764              :         GNUNET_JSON_pack_string ("url",
     765              :                                  poph->donau_url),
     766              :         GNUNET_JSON_pack_int64 ("year",
     767              :                                 poph->donau_year),
     768              :         GNUNET_JSON_pack_array_steal ("budikeypairs",
     769              :                                       budis));
     770              :     }
     771              : 
     772              :     /* Build output token envelopes JSON if we have output tokens */
     773            0 :     if (0 < poph->num_output_tokens)
     774              :     {
     775            0 :       j_output_tokens = json_array ();
     776            0 :       GNUNET_assert (NULL != j_output_tokens);
     777            0 :       for (unsigned int i = 0; i < poph->num_output_tokens; i++)
     778              :       {
     779              :         json_t *j_token_ev;
     780            0 :         const struct TALER_MERCHANT_PostOrdersPayOutputToken *ev
     781            0 :           = &poph->output_tokens[i];
     782              : 
     783            0 :         j_token_ev = GNUNET_JSON_PACK (
     784              :           TALER_JSON_pack_token_envelope (NULL,
     785              :                                           &ev->envelope));
     786            0 :         if (0 !=
     787            0 :             json_array_append_new (j_output_tokens,
     788              :                                    j_token_ev))
     789              :         {
     790            0 :           GNUNET_break (0);
     791            0 :           json_decref (j_output_tokens);
     792            0 :           json_decref (j_donau_data);
     793            0 :           return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
     794              :         }
     795              :       }
     796              :     }
     797            0 :     else if (NULL != poph->output_tokens_json)
     798              :     {
     799            0 :       j_output_tokens = json_incref (poph->output_tokens_json);
     800              :     }
     801              : 
     802              :     /* Build wallet_data if choice_index is valid */
     803            0 :     if (0 <= poph->choice_index)
     804              :     {
     805            0 :       if (NULL == wallet_data)
     806              :       {
     807            0 :         wallet_data = GNUNET_JSON_PACK (
     808              :           GNUNET_JSON_pack_int64 ("choice_index",
     809              :                                   poph->choice_index),
     810              :           GNUNET_JSON_pack_allow_null (
     811              :             GNUNET_JSON_pack_object_incref ("donau",
     812              :                                             j_donau_data)),
     813              :           GNUNET_JSON_pack_allow_null (
     814              :             GNUNET_JSON_pack_array_incref ("tokens_evs",
     815              :                                            j_output_tokens)));
     816              :       }
     817            0 :       TALER_json_hash (wallet_data,
     818              :                        &wallet_data_hash);
     819              :     }
     820            0 :     json_decref (j_donau_data);
     821            0 :     j_donau_data = NULL;
     822              : 
     823            0 :     if ( (0 < poph->num_use_tokens || 0 < poph->num_output_tokens
     824            0 :           || NULL != poph->output_tokens_json)
     825            0 :          && (0 > poph->choice_index) )
     826              :     {
     827            0 :       GNUNET_break (0);
     828            0 :       json_decref (j_output_tokens);
     829            0 :       if ( (NULL == poph->wallet_data) &&
     830              :            (NULL != wallet_data) )
     831            0 :         json_decref (wallet_data);
     832            0 :       return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
     833              :     }
     834              : 
     835              :     /* Sign coins */
     836            0 :     j_coins = json_array ();
     837            0 :     GNUNET_assert (NULL != j_coins);
     838            0 :     for (unsigned int i = 0; i < poph->num_coins; i++)
     839              :     {
     840            0 :       const struct TALER_MERCHANT_PostOrdersPayCoin *coin = &poph->coins[i];
     841              :       struct TALER_CoinSpendPublicKeyP coin_pub;
     842              :       struct TALER_CoinSpendSignatureP coin_sig;
     843              :       struct TALER_Amount fee;
     844              :       struct TALER_DenominationHashP h_denom_pub;
     845              :       json_t *j_coin;
     846              : 
     847            0 :       if (0 >
     848            0 :           TALER_amount_subtract (&fee,
     849              :                                  &coin->amount_with_fee,
     850              :                                  &coin->amount_without_fee))
     851              :       {
     852            0 :         GNUNET_break (0);
     853            0 :         json_decref (j_coins);
     854            0 :         json_decref (j_output_tokens);
     855            0 :         if ( (NULL == poph->wallet_data) &&
     856              :              (NULL != wallet_data) )
     857            0 :           json_decref (wallet_data);
     858            0 :         return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
     859              :       }
     860            0 :       TALER_denom_pub_hash (&coin->denom_pub,
     861              :                             &h_denom_pub);
     862            0 :       TALER_wallet_deposit_sign (&coin->amount_with_fee,
     863              :                                  &fee,
     864            0 :                                  &poph->h_wire,
     865            0 :                                  &poph->h_contract_terms,
     866            0 :                                  (0 <= poph->choice_index)
     867              :                                  ? &wallet_data_hash
     868              :                                  : NULL,
     869            0 :                                  GNUNET_is_zero (&coin->h_age_commitment)
     870              :                                  ? NULL
     871              :                                  : &coin->h_age_commitment,
     872              :                                  NULL /* h_extensions */,
     873              :                                  &h_denom_pub,
     874              :                                  poph->timestamp,
     875            0 :                                  &poph->merchant_pub,
     876              :                                  poph->refund_deadline,
     877              :                                  &coin->coin_priv,
     878              :                                  &coin_sig);
     879            0 :       GNUNET_CRYPTO_eddsa_key_get_public (&coin->coin_priv.eddsa_priv,
     880              :                                           &coin_pub.eddsa_pub);
     881            0 :       j_coin = GNUNET_JSON_PACK (
     882              :         TALER_JSON_pack_amount ("contribution",
     883              :                                 &coin->amount_with_fee),
     884              :         GNUNET_JSON_pack_data_auto ("coin_pub",
     885              :                                     &coin_pub),
     886              :         GNUNET_JSON_pack_string ("exchange_url",
     887              :                                  coin->exchange_url),
     888              :         GNUNET_JSON_pack_data_auto ("h_denom",
     889              :                                     &h_denom_pub),
     890              :         TALER_JSON_pack_denom_sig ("ub_sig",
     891              :                                    &coin->denom_sig),
     892              :         GNUNET_JSON_pack_data_auto ("coin_sig",
     893              :                                     &coin_sig));
     894            0 :       if (0 !=
     895            0 :           json_array_append_new (j_coins,
     896              :                                  j_coin))
     897              :       {
     898            0 :         GNUNET_break (0);
     899            0 :         json_decref (j_coins);
     900            0 :         json_decref (j_output_tokens);
     901            0 :         if ( (NULL == poph->wallet_data) &&
     902              :              (NULL != wallet_data) )
     903            0 :           json_decref (wallet_data);
     904            0 :         return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
     905              :       }
     906              :     }
     907              : 
     908              :     /* Sign use tokens */
     909            0 :     if (0 < poph->num_use_tokens)
     910              :     {
     911            0 :       j_tokens = json_array ();
     912            0 :       GNUNET_assert (NULL != j_tokens);
     913            0 :       for (unsigned int i = 0; i < poph->num_use_tokens; i++)
     914              :       {
     915            0 :         const struct TALER_MERCHANT_PostOrdersPayUseToken *token
     916            0 :           = &poph->use_tokens[i];
     917              :         struct TALER_TokenUseSignatureP token_sig;
     918              :         struct TALER_TokenUsePublicKeyP token_pub;
     919              :         json_t *j_token;
     920              : 
     921            0 :         TALER_wallet_token_use_sign (&poph->h_contract_terms,
     922              :                                      &wallet_data_hash,
     923              :                                      &token->token_priv,
     924              :                                      &token_sig);
     925            0 :         GNUNET_CRYPTO_eddsa_key_get_public (
     926              :           &token->token_priv.private_key,
     927              :           &token_pub.public_key);
     928            0 :         j_token = GNUNET_JSON_PACK (
     929              :           GNUNET_JSON_pack_data_auto ("token_sig",
     930              :                                       &token_sig),
     931              :           GNUNET_JSON_pack_data_auto ("token_pub",
     932              :                                       &token_pub),
     933              :           GNUNET_JSON_pack_data_auto (
     934              :             "h_issue",
     935              :             &token->issue_pub.public_key->pub_key_hash),
     936              :           TALER_JSON_pack_token_issue_sig ("ub_sig",
     937              :                                            &token->ub_sig));
     938            0 :         if (0 !=
     939            0 :             json_array_append_new (j_tokens,
     940              :                                    j_token))
     941              :         {
     942            0 :           GNUNET_break (0);
     943            0 :           json_decref (j_coins);
     944            0 :           json_decref (j_tokens);
     945            0 :           json_decref (j_output_tokens);
     946            0 :           if ( (NULL == poph->wallet_data) &&
     947              :                (NULL != wallet_data) )
     948            0 :             json_decref (wallet_data);
     949            0 :           return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
     950              :         }
     951              :       }
     952              :     }
     953              : 
     954            0 :     pay_obj = GNUNET_JSON_PACK (
     955              :       GNUNET_JSON_pack_array_steal ("coins",
     956              :                                     j_coins),
     957              :       GNUNET_JSON_pack_allow_null (
     958              :         GNUNET_JSON_pack_array_steal ("tokens",
     959              :                                       j_tokens)),
     960              :       GNUNET_JSON_pack_allow_null (
     961              :         GNUNET_JSON_pack_object_incref ("wallet_data",
     962              :                                         wallet_data)),
     963              :       GNUNET_JSON_pack_allow_null (
     964              :         GNUNET_JSON_pack_string ("session_id",
     965              :                                  poph->session_id)));
     966            0 :     if ( (NULL == poph->wallet_data) &&
     967              :          (NULL != wallet_data) )
     968            0 :       json_decref (wallet_data);
     969              :   }
     970              :   else
     971              :   {
     972              :     /* Frontend mode: coins are already signed */
     973            0 :     j_coins = json_array ();
     974            0 :     GNUNET_assert (NULL != j_coins);
     975            0 :     for (unsigned int i = 0; i < poph->num_paid_coins; i++)
     976              :     {
     977            0 :       const struct TALER_MERCHANT_PostOrdersPayPaidCoin *pc
     978            0 :         = &poph->paid_coins[i];
     979              :       struct TALER_DenominationHashP denom_hash;
     980              :       json_t *j_coin;
     981              : 
     982            0 :       TALER_denom_pub_hash (&pc->denom_pub,
     983              :                             &denom_hash);
     984            0 :       j_coin = GNUNET_JSON_PACK (
     985              :         TALER_JSON_pack_amount ("contribution",
     986              :                                 &pc->amount_with_fee),
     987              :         GNUNET_JSON_pack_data_auto ("coin_pub",
     988              :                                     &pc->coin_pub),
     989              :         GNUNET_JSON_pack_string ("exchange_url",
     990              :                                  pc->exchange_url),
     991              :         GNUNET_JSON_pack_data_auto ("h_denom",
     992              :                                     &denom_hash),
     993              :         TALER_JSON_pack_denom_sig ("ub_sig",
     994              :                                    &pc->denom_sig),
     995              :         GNUNET_JSON_pack_data_auto ("coin_sig",
     996              :                                     &pc->coin_sig));
     997            0 :       if (0 !=
     998            0 :           json_array_append_new (j_coins,
     999              :                                  j_coin))
    1000              :       {
    1001            0 :         GNUNET_break (0);
    1002            0 :         json_decref (j_coins);
    1003            0 :         return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    1004              :       }
    1005              :     }
    1006              : 
    1007              :     /* Build used tokens JSON (frontend mode) */
    1008            0 :     if (0 < poph->num_used_tokens)
    1009              :     {
    1010            0 :       j_tokens = json_array ();
    1011            0 :       GNUNET_assert (NULL != j_tokens);
    1012            0 :       for (unsigned int i = 0; i < poph->num_used_tokens; i++)
    1013              :       {
    1014            0 :         const struct TALER_MERCHANT_PostOrdersPayUsedToken *ut
    1015            0 :           = &poph->used_tokens[i];
    1016              :         json_t *j_token;
    1017              : 
    1018            0 :         j_token = GNUNET_JSON_PACK (
    1019              :           GNUNET_JSON_pack_data_auto ("token_sig",
    1020              :                                       &ut->token_sig),
    1021              :           GNUNET_JSON_pack_data_auto ("token_pub",
    1022              :                                       &ut->token_pub),
    1023              :           GNUNET_JSON_pack_data_auto (
    1024              :             "h_issue",
    1025              :             &ut->issue_pub.public_key->pub_key_hash),
    1026              :           TALER_JSON_pack_token_issue_sig ("ub_sig",
    1027              :                                            &ut->ub_sig));
    1028            0 :         if (0 !=
    1029            0 :             json_array_append_new (j_tokens,
    1030              :                                    j_token))
    1031              :         {
    1032            0 :           GNUNET_break (0);
    1033            0 :           json_decref (j_coins);
    1034            0 :           json_decref (j_tokens);
    1035            0 :           return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    1036              :         }
    1037              :       }
    1038              :     }
    1039              : 
    1040            0 :     pay_obj = GNUNET_JSON_PACK (
    1041              :       GNUNET_JSON_pack_array_steal ("coins",
    1042              :                                     j_coins),
    1043              :       GNUNET_JSON_pack_allow_null (
    1044              :         GNUNET_JSON_pack_array_steal ("tokens",
    1045              :                                       j_tokens)),
    1046              :       GNUNET_JSON_pack_allow_null (
    1047              :         GNUNET_JSON_pack_object_incref ("wallet_data",
    1048              :                                         poph->wallet_data)),
    1049              :       GNUNET_JSON_pack_allow_null (
    1050              :         GNUNET_JSON_pack_string ("session_id",
    1051              :                                  poph->session_id)));
    1052              :   }
    1053              : 
    1054            0 :   eh = TALER_MERCHANT_curl_easy_get_ (poph->url);
    1055            0 :   if ( (NULL == eh) ||
    1056              :        (GNUNET_OK !=
    1057            0 :         TALER_curl_easy_post (&poph->post_ctx,
    1058              :                               eh,
    1059              :                               pay_obj)) )
    1060              :   {
    1061            0 :     GNUNET_break (0);
    1062            0 :     json_decref (pay_obj);
    1063            0 :     if (NULL != eh)
    1064            0 :       curl_easy_cleanup (eh);
    1065            0 :     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    1066              :   }
    1067            0 :   json_decref (pay_obj);
    1068            0 :   poph->job = GNUNET_CURL_job_add2 (poph->ctx,
    1069              :                                     eh,
    1070            0 :                                     poph->post_ctx.headers,
    1071              :                                     &handle_pay_finished,
    1072              :                                     poph);
    1073            0 :   if (NULL == poph->job)
    1074            0 :     return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
    1075            0 :   return TALER_EC_NONE;
    1076              : }
    1077              : 
    1078              : 
    1079              : void
    1080            0 : TALER_MERCHANT_post_orders_pay_cancel (
    1081              :   struct TALER_MERCHANT_PostOrdersPayHandle *poph)
    1082              : {
    1083            0 :   if (NULL != poph->job)
    1084              :   {
    1085            0 :     GNUNET_CURL_job_cancel (poph->job);
    1086            0 :     poph->job = NULL;
    1087              :   }
    1088            0 :   TALER_curl_easy_post_finished (&poph->post_ctx);
    1089            0 :   if (NULL != poph->paid_coins)
    1090              :   {
    1091            0 :     for (unsigned int i = 0; i < poph->num_paid_coins; i++)
    1092              :     {
    1093            0 :       TALER_denom_pub_free (&poph->paid_coins[i].denom_pub);
    1094            0 :       TALER_denom_sig_free (&poph->paid_coins[i].denom_sig);
    1095            0 :       GNUNET_free (poph->paid_coins[i].exchange_url);
    1096              :     }
    1097            0 :     GNUNET_free (poph->paid_coins);
    1098              :   }
    1099            0 :   if (NULL != poph->coins)
    1100              :   {
    1101            0 :     for (unsigned int i = 0; i < poph->num_coins; i++)
    1102              :     {
    1103            0 :       TALER_denom_pub_free (&poph->coins[i].denom_pub);
    1104            0 :       TALER_denom_sig_free (&poph->coins[i].denom_sig);
    1105            0 :       GNUNET_free (poph->coins[i].exchange_url);
    1106              :     }
    1107            0 :     GNUNET_free (poph->coins);
    1108              :   }
    1109            0 :   for (size_t j = 0; j<poph->num_donau_bkps; j++)
    1110              :   {
    1111            0 :     struct DONAU_BlindedUniqueDonorIdentifierKeyPair *bpk
    1112            0 :       = &poph->donau_bkps[j];
    1113              : 
    1114            0 :     GNUNET_CRYPTO_blinded_message_decref (bpk->blinded_udi.blinded_message);
    1115              :   }
    1116            0 :   GNUNET_free (poph->donau_bkps);
    1117            0 :   GNUNET_free (poph->donau_url);
    1118            0 :   GNUNET_free (poph->used_tokens);
    1119            0 :   GNUNET_free (poph->use_tokens);
    1120            0 :   GNUNET_free (poph->output_tokens);
    1121            0 :   json_decref (poph->output_tokens_json);
    1122            0 :   json_decref (poph->wallet_data);
    1123            0 :   GNUNET_free (poph->session_id);
    1124            0 :   GNUNET_free (poph->order_id);
    1125            0 :   GNUNET_free (poph->url);
    1126            0 :   GNUNET_free (poph->base_url);
    1127            0 :   GNUNET_free (poph);
    1128            0 : }
    1129              : 
    1130              : 
    1131              : /* end of merchant_api_post-orders-ORDER_ID-pay-new.c */
        

Generated by: LCOV version 2.0-1