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: 52.1 % 447 233
Test Date: 2026-09-11 17:45:24 Functions: 85.7 % 7 6

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

Generated by: LCOV version 2.0-1