merchant_api_wallet_get_order.c (8914B)
1 /* 2 This file is part of TALER 3 Copyright (C) 2018, 2020, 2022 Taler Systems SA 4 5 TALER is free software; you can redistribute it and/or modify it under the 6 terms of the GNU Lesser General Public License as published by the Free Software 7 Foundation; either version 2.1, or (at your option) any later version. 8 9 TALER is distributed in the hope that it will be useful, but WITHOUT ANY 10 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 11 A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. 12 13 You should have received a copy of the GNU Lesser General Public License along with 14 TALER; see the file COPYING.LGPL. If not, see 15 <http://www.gnu.org/licenses/> 16 */ 17 /** 18 * @file merchant_api_wallet_get_order.c 19 * @brief Implementation of the GET /orders/$ID request 20 * @author Christian Grothoff 21 * @author Marcello Stanisci 22 * @author Florian Dold 23 */ 24 #include "platform.h" 25 #include <curl/curl.h> 26 #include <jansson.h> 27 #include <microhttpd.h> /* just for HTTP status codes */ 28 #include <gnunet/gnunet_util_lib.h> 29 #include <gnunet/gnunet_curl_lib.h> 30 #include "taler_merchant_service.h" 31 #include "merchant_api_curl_defaults.h" 32 #include "merchant_api_common.h" 33 #include <taler/taler_json_lib.h> 34 #include <taler/taler_signatures.h> 35 36 37 /** 38 * @brief A GET /orders/$ID handle 39 */ 40 struct TALER_MERCHANT_OrderWalletGetHandle 41 { 42 43 /** 44 * The url for this request. 45 */ 46 char *url; 47 48 /** 49 * Handle for the request. 50 */ 51 struct GNUNET_CURL_Job *job; 52 53 /** 54 * Function to call with the result. 55 */ 56 TALER_MERCHANT_OrderWalletGetCallback cb; 57 58 /** 59 * Closure for @a cb. 60 */ 61 void *cb_cls; 62 63 /** 64 * Reference to the execution context. 65 */ 66 struct GNUNET_CURL_Context *ctx; 67 }; 68 69 70 /** 71 * Convenience function to call the callback in @a owgh with an error code of 72 * @a ec and the exchange body being set to @a reply. 73 * 74 * @param owgh handle providing callback 75 * @param ec error code to return to application 76 * @param reply JSON reply we got from the exchange, can be NULL 77 */ 78 static void 79 cb_failure (struct TALER_MERCHANT_OrderWalletGetHandle *owgh, 80 enum TALER_ErrorCode ec, 81 const json_t *reply) 82 { 83 struct TALER_MERCHANT_OrderWalletGetResponse owgr = { 84 .hr.ec = ec, 85 .hr.reply = reply 86 }; 87 88 owgh->cb (owgh->cb_cls, 89 &owgr); 90 } 91 92 93 /** 94 * Function called when we're done processing the GET /check-payment request. 95 * 96 * @param cls the `struct TALER_MERCHANT_OrderWalletGetHandle` 97 * @param response_code HTTP response code, 0 on error 98 * @param response response body, should be NULL 99 */ 100 static void 101 handle_wallet_get_order_finished (void *cls, 102 long response_code, 103 const void *response) 104 { 105 struct TALER_MERCHANT_OrderWalletGetHandle *owgh = cls; 106 const json_t *json = response; 107 108 owgh->job = NULL; 109 switch (response_code) 110 { 111 case MHD_HTTP_OK: 112 { 113 struct TALER_MERCHANT_OrderWalletGetResponse owgr = { 114 .hr.reply = json, 115 .hr.http_status = MHD_HTTP_OK 116 }; 117 struct GNUNET_JSON_Specification spec[] = { 118 GNUNET_JSON_spec_bool ("refunded", 119 &owgr.details.ok.refunded), 120 GNUNET_JSON_spec_bool ("refund_pending", 121 &owgr.details.ok.refund_pending), 122 TALER_JSON_spec_amount_any ("refund_amount", 123 &owgr.details.ok.refund_amount), 124 GNUNET_JSON_spec_end () 125 }; 126 127 if (GNUNET_OK != 128 GNUNET_JSON_parse (json, 129 spec, 130 NULL, NULL)) 131 { 132 GNUNET_break_op (0); 133 cb_failure (owgh, 134 TALER_EC_GENERIC_REPLY_MALFORMED, 135 json); 136 TALER_MERCHANT_wallet_order_get_cancel (owgh); 137 return; 138 } 139 owgh->cb (owgh->cb_cls, 140 &owgr); 141 GNUNET_JSON_parse_free (spec); 142 break; 143 } 144 case MHD_HTTP_PAYMENT_REQUIRED: 145 { 146 struct TALER_MERCHANT_OrderWalletGetResponse owgr = { 147 .hr.reply = json, 148 .hr.http_status = MHD_HTTP_PAYMENT_REQUIRED 149 }; 150 151 /* Status is: unpaid */ 152 owgr.details.payment_required.taler_pay_uri 153 = json_string_value (json_object_get (json, 154 "taler_pay_uri")); 155 owgr.details.payment_required.already_paid_order_id 156 = json_string_value (json_object_get (json, 157 "already_paid_order_id")); 158 if (NULL == owgr.details.payment_required.taler_pay_uri) 159 { 160 GNUNET_break_op (0); 161 cb_failure (owgh, 162 TALER_EC_GENERIC_REPLY_MALFORMED, 163 json); 164 break; 165 } 166 owgh->cb (owgh->cb_cls, 167 &owgr); 168 break; 169 } 170 default: 171 { 172 struct TALER_MERCHANT_OrderWalletGetResponse owgr = { 173 .hr.reply = json, 174 .hr.http_status = response_code 175 }; 176 177 TALER_MERCHANT_parse_error_details_ (response, 178 response_code, 179 &owgr.hr); 180 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 181 "Checking order status failed with HTTP status code %u/%d\n", 182 (unsigned int) response_code, 183 (int) owgr.hr.ec); 184 GNUNET_break_op (0); 185 owgh->cb (owgh->cb_cls, 186 &owgr); 187 break; 188 } 189 } 190 TALER_MERCHANT_wallet_order_get_cancel (owgh); 191 } 192 193 194 struct TALER_MERCHANT_OrderWalletGetHandle * 195 TALER_MERCHANT_wallet_order_get ( 196 struct GNUNET_CURL_Context *ctx, 197 const char *backend_url, 198 const char *order_id, 199 const struct TALER_PrivateContractHashP *h_contract, 200 struct GNUNET_TIME_Relative timeout, 201 const char *session_id, 202 const struct TALER_Amount *min_refund, 203 bool await_refund_obtained, 204 TALER_MERCHANT_OrderWalletGetCallback cb, 205 void *cb_cls) 206 { 207 struct TALER_MERCHANT_OrderWalletGetHandle *owgh; 208 unsigned int tms; 209 210 GNUNET_assert (NULL != backend_url); 211 GNUNET_assert (NULL != order_id); 212 owgh = GNUNET_new (struct TALER_MERCHANT_OrderWalletGetHandle); 213 owgh->ctx = ctx; 214 owgh->cb = cb; 215 owgh->cb_cls = cb_cls; 216 tms = (unsigned int) (timeout.rel_value_us 217 / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us); 218 { 219 char timeout_ms[32]; 220 struct GNUNET_CRYPTO_HashAsciiEncoded h_contract_s; 221 char *path; 222 223 GNUNET_CRYPTO_hash_to_enc (&h_contract->hash, 224 &h_contract_s); 225 GNUNET_snprintf (timeout_ms, 226 sizeof (timeout_ms), 227 "%u", 228 tms); 229 GNUNET_asprintf (&path, 230 "orders/%s", 231 order_id); 232 owgh->url = TALER_url_join (backend_url, 233 path, 234 "h_contract", 235 h_contract_s.encoding, 236 "session_id", 237 session_id, 238 "timeout_ms", 239 (0 != tms) 240 ? timeout_ms 241 : NULL, 242 "refund", 243 (NULL != min_refund) 244 ? TALER_amount2s (min_refund) 245 : NULL, 246 "await_refund_obtained", 247 await_refund_obtained 248 ? "yes" 249 : NULL, 250 NULL); 251 GNUNET_free (path); 252 } 253 if (NULL == owgh->url) 254 { 255 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, 256 "Could not construct request URL.\n"); 257 GNUNET_free (owgh); 258 return NULL; 259 } 260 261 { 262 CURL *eh; 263 264 eh = TALER_MERCHANT_curl_easy_get_ (owgh->url); 265 if (0 != tms) 266 { 267 GNUNET_break (CURLE_OK == 268 curl_easy_setopt (eh, 269 CURLOPT_TIMEOUT_MS, 270 (long) (tms + 100L))); 271 } 272 273 GNUNET_log (GNUNET_ERROR_TYPE_INFO, 274 "Checking order status at %s\n", 275 owgh->url); 276 if (NULL == (owgh->job = 277 GNUNET_CURL_job_add (ctx, 278 eh, 279 &handle_wallet_get_order_finished, 280 owgh))) 281 { 282 GNUNET_break (0); 283 GNUNET_free (owgh->url); 284 GNUNET_free (owgh); 285 return NULL; 286 } 287 } 288 return owgh; 289 } 290 291 292 void 293 TALER_MERCHANT_wallet_order_get_cancel ( 294 struct TALER_MERCHANT_OrderWalletGetHandle *owgh) 295 { 296 if (NULL != owgh->job) 297 { 298 GNUNET_CURL_job_cancel (owgh->job); 299 owgh->job = NULL; 300 } 301 GNUNET_free (owgh->url); 302 GNUNET_free (owgh); 303 } 304 305 306 /* end of merchant_api_wallet_get_order.c */