Line data Source code
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 0 : cb_failure (struct TALER_MERCHANT_OrderWalletGetHandle *owgh,
80 : enum TALER_ErrorCode ec,
81 : const json_t *reply)
82 : {
83 0 : struct TALER_MERCHANT_OrderWalletGetResponse owgr = {
84 : .hr.ec = ec,
85 : .hr.reply = reply
86 : };
87 :
88 0 : owgh->cb (owgh->cb_cls,
89 : &owgr);
90 0 : }
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 28 : handle_wallet_get_order_finished (void *cls,
102 : long response_code,
103 : const void *response)
104 : {
105 28 : struct TALER_MERCHANT_OrderWalletGetHandle *owgh = cls;
106 28 : const json_t *json = response;
107 :
108 28 : owgh->job = NULL;
109 28 : switch (response_code)
110 : {
111 20 : case MHD_HTTP_OK:
112 : {
113 20 : struct TALER_MERCHANT_OrderWalletGetResponse owgr = {
114 : .hr.reply = json,
115 : .hr.http_status = MHD_HTTP_OK
116 : };
117 : struct GNUNET_JSON_Specification spec[] = {
118 20 : GNUNET_JSON_spec_bool ("refunded",
119 : &owgr.details.ok.refunded),
120 20 : GNUNET_JSON_spec_bool ("refund_pending",
121 : &owgr.details.ok.refund_pending),
122 20 : TALER_JSON_spec_amount_any ("refund_amount",
123 : &owgr.details.ok.refund_amount),
124 20 : GNUNET_JSON_spec_end ()
125 : };
126 :
127 20 : if (GNUNET_OK !=
128 20 : GNUNET_JSON_parse (json,
129 : spec,
130 : NULL, NULL))
131 : {
132 0 : GNUNET_break_op (0);
133 0 : cb_failure (owgh,
134 : TALER_EC_GENERIC_REPLY_MALFORMED,
135 : json);
136 0 : TALER_MERCHANT_wallet_order_get_cancel (owgh);
137 0 : return;
138 : }
139 20 : owgh->cb (owgh->cb_cls,
140 : &owgr);
141 20 : GNUNET_JSON_parse_free (spec);
142 20 : break;
143 : }
144 8 : case MHD_HTTP_PAYMENT_REQUIRED:
145 : {
146 8 : 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 8 : = json_string_value (json_object_get (json,
154 : "taler_pay_uri"));
155 : owgr.details.payment_required.already_paid_order_id
156 8 : = json_string_value (json_object_get (json,
157 : "already_paid_order_id"));
158 8 : if (NULL == owgr.details.payment_required.taler_pay_uri)
159 : {
160 0 : GNUNET_break_op (0);
161 0 : cb_failure (owgh,
162 : TALER_EC_GENERIC_REPLY_MALFORMED,
163 : json);
164 0 : break;
165 : }
166 8 : owgh->cb (owgh->cb_cls,
167 : &owgr);
168 8 : break;
169 : }
170 0 : default:
171 : {
172 0 : struct TALER_MERCHANT_OrderWalletGetResponse owgr = {
173 : .hr.reply = json,
174 : .hr.http_status = response_code
175 : };
176 :
177 0 : TALER_MERCHANT_parse_error_details_ (response,
178 : response_code,
179 : &owgr.hr);
180 0 : 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 0 : GNUNET_break_op (0);
185 0 : owgh->cb (owgh->cb_cls,
186 : &owgr);
187 0 : break;
188 : }
189 : }
190 28 : TALER_MERCHANT_wallet_order_get_cancel (owgh);
191 : }
192 :
193 :
194 : struct TALER_MERCHANT_OrderWalletGetHandle *
195 28 : 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 28 : GNUNET_assert (NULL != backend_url);
211 28 : GNUNET_assert (NULL != order_id);
212 28 : owgh = GNUNET_new (struct TALER_MERCHANT_OrderWalletGetHandle);
213 28 : owgh->ctx = ctx;
214 28 : owgh->cb = cb;
215 28 : owgh->cb_cls = cb_cls;
216 56 : tms = (unsigned int) (timeout.rel_value_us
217 28 : / 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 28 : GNUNET_CRYPTO_hash_to_enc (&h_contract->hash,
224 : &h_contract_s);
225 28 : GNUNET_snprintf (timeout_ms,
226 : sizeof (timeout_ms),
227 : "%u",
228 : tms);
229 28 : GNUNET_asprintf (&path,
230 : "orders/%s",
231 : order_id);
232 32 : 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 4 : ? TALER_amount2s (min_refund)
245 : : NULL,
246 : "await_refund_obtained",
247 : await_refund_obtained
248 : ? "yes"
249 : : NULL,
250 : NULL);
251 28 : GNUNET_free (path);
252 : }
253 28 : if (NULL == owgh->url)
254 : {
255 0 : GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
256 : "Could not construct request URL.\n");
257 0 : GNUNET_free (owgh);
258 0 : return NULL;
259 : }
260 :
261 : {
262 : CURL *eh;
263 :
264 28 : eh = TALER_MERCHANT_curl_easy_get_ (owgh->url);
265 28 : if (0 != tms)
266 : {
267 8 : GNUNET_break (CURLE_OK ==
268 : curl_easy_setopt (eh,
269 : CURLOPT_TIMEOUT_MS,
270 : (long) (tms + 100L)));
271 : }
272 :
273 28 : GNUNET_log (GNUNET_ERROR_TYPE_INFO,
274 : "Checking order status at %s\n",
275 : owgh->url);
276 28 : if (NULL == (owgh->job =
277 28 : GNUNET_CURL_job_add (ctx,
278 : eh,
279 : &handle_wallet_get_order_finished,
280 : owgh)))
281 : {
282 0 : GNUNET_break (0);
283 0 : GNUNET_free (owgh->url);
284 0 : GNUNET_free (owgh);
285 0 : return NULL;
286 : }
287 : }
288 28 : return owgh;
289 : }
290 :
291 :
292 : void
293 28 : TALER_MERCHANT_wallet_order_get_cancel (
294 : struct TALER_MERCHANT_OrderWalletGetHandle *owgh)
295 : {
296 28 : if (NULL != owgh->job)
297 : {
298 0 : GNUNET_CURL_job_cancel (owgh->job);
299 0 : owgh->job = NULL;
300 : }
301 28 : GNUNET_free (owgh->url);
302 28 : GNUNET_free (owgh);
303 28 : }
304 :
305 :
306 : /* end of merchant_api_wallet_get_order.c */
|