Line data Source code
1 : /*
2 : This file is part of TALER
3 : Copyright (C) 2018-2026 Taler Systems SA
4 :
5 : TALER is free software; you can redistribute it and/or modify it under the
6 : terms of the GNU 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 src/lib/merchant_api_get-private-orders-ORDER_ID.c
19 : * @brief Implementation of the GET /private/orders/$ORDER_ID request
20 : * @author Christian Grothoff
21 : */
22 : #include "platform.h"
23 : #include <curl/curl.h>
24 : #include <jansson.h>
25 : #include <microhttpd.h> /* just for HTTP status codes */
26 : #include <gnunet/gnunet_util_lib.h>
27 : #include <gnunet/gnunet_curl_lib.h>
28 : #include <taler/merchant/get-private-orders-ORDER_ID.h>
29 : #include "merchant_api_curl_defaults.h"
30 : #include <taler/taler_json_lib.h>
31 :
32 :
33 : /**
34 : * Maximum number of refund details we return.
35 : */
36 : #define MAX_REFUND_DETAILS 1024
37 :
38 : /**
39 : * Maximum number of wire details we return.
40 : */
41 : #define MAX_WIRE_DETAILS 1024
42 :
43 :
44 : /**
45 : * Handle for a GET /private/orders/$ORDER_ID operation.
46 : */
47 : struct TALER_MERCHANT_GetPrivateOrderHandle
48 : {
49 : /**
50 : * Base URL of the merchant backend.
51 : */
52 : char *base_url;
53 :
54 : /**
55 : * The full URL for this request.
56 : */
57 : char *url;
58 :
59 : /**
60 : * Handle for the request.
61 : */
62 : struct GNUNET_CURL_Job *job;
63 :
64 : /**
65 : * Function to call with the result.
66 : */
67 : TALER_MERCHANT_GetPrivateOrderCallback cb;
68 :
69 : /**
70 : * Closure for @a cb.
71 : */
72 : TALER_MERCHANT_GET_PRIVATE_ORDER_RESULT_CLOSURE *cb_cls;
73 :
74 : /**
75 : * Reference to the execution context.
76 : */
77 : struct GNUNET_CURL_Context *ctx;
78 :
79 : /**
80 : * Order ID.
81 : */
82 : char *order_id;
83 :
84 : /**
85 : * Session ID for repurchase detection, or NULL.
86 : */
87 : char *session_id;
88 :
89 : /**
90 : * Long polling timeout.
91 : */
92 : struct GNUNET_TIME_Relative timeout;
93 :
94 : /**
95 : * Long-poll ETag to suppress unchanged responses.
96 : */
97 : struct GNUNET_ShortHashCode lp_not_etag;
98 :
99 : /**
100 : * True if @e lp_not_etag was set.
101 : */
102 : bool have_lp_not_etag;
103 :
104 : /**
105 : * If true, try to obtain wire transfer status from the exchange.
106 : */
107 : bool transfer;
108 :
109 : /**
110 : * If true, allow refunded orders under already_paid_order_id.
111 : */
112 : bool allow_refunded_for_repurchase;
113 : };
114 :
115 :
116 : /**
117 : * Handle HTTP OK response for an unpaid order.
118 : *
119 : * @param oph handle for the request
120 : * @param[in,out] osr HTTP response we got
121 : */
122 : static void
123 6 : handle_unpaid (struct TALER_MERCHANT_GetPrivateOrderHandle *oph,
124 : struct TALER_MERCHANT_GetPrivateOrderResponse *osr)
125 : {
126 : struct GNUNET_JSON_Specification spec[] = {
127 6 : GNUNET_JSON_spec_mark_optional (
128 : TALER_JSON_spec_slug (
129 : "already_paid_order_id",
130 : &osr->details.ok.details.unpaid.already_paid_order_id),
131 : NULL),
132 6 : GNUNET_JSON_spec_mark_optional (
133 : TALER_JSON_spec_web_url (
134 : "already_paid_fulfillment_url",
135 : &osr->details.ok.details.unpaid.already_paid_fulfillment_url),
136 : NULL),
137 6 : GNUNET_JSON_spec_string (
138 : "taler_pay_uri",
139 : &osr->details.ok.details.unpaid.taler_pay_uri),
140 6 : GNUNET_JSON_spec_string (
141 : "summary",
142 : &osr->details.ok.details.unpaid.summary),
143 6 : GNUNET_JSON_spec_mark_optional (
144 : GNUNET_JSON_spec_object_const (
145 : "proto_contract_terms",
146 : &osr->details.ok.details.unpaid.proto_contract_terms),
147 : NULL),
148 6 : TALER_JSON_spec_web_url (
149 : "order_status_url",
150 : &osr->details.ok.details.unpaid.order_status_url),
151 6 : GNUNET_JSON_spec_timestamp (
152 : "creation_time",
153 : &osr->details.ok.details.unpaid.creation_time),
154 6 : GNUNET_JSON_spec_mark_optional (
155 : GNUNET_JSON_spec_timestamp (
156 : "pay_deadline",
157 : &osr->details.ok.details.unpaid.pay_deadline),
158 : NULL),
159 6 : GNUNET_JSON_spec_end ()
160 : };
161 :
162 6 : if (GNUNET_OK !=
163 6 : GNUNET_JSON_parse (osr->hr.reply,
164 : spec,
165 : NULL, NULL))
166 : {
167 0 : GNUNET_break_op (0);
168 0 : osr->hr.http_status = 0;
169 0 : osr->hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
170 0 : oph->cb (oph->cb_cls,
171 : osr);
172 0 : return;
173 : }
174 6 : osr->details.ok.status = TALER_MERCHANT_OSC_UNPAID;
175 6 : oph->cb (oph->cb_cls,
176 : osr);
177 : }
178 :
179 :
180 : /**
181 : * Handle HTTP OK response for a claimed order.
182 : *
183 : * @param oph handle for the request
184 : * @param[in,out] osr HTTP response we got
185 : */
186 : static void
187 9 : handle_claimed (struct TALER_MERCHANT_GetPrivateOrderHandle *oph,
188 : struct TALER_MERCHANT_GetPrivateOrderResponse *osr)
189 : {
190 : struct GNUNET_JSON_Specification spec[] = {
191 9 : GNUNET_JSON_spec_object_const (
192 : "contract_terms",
193 : &osr->details.ok.details.claimed.contract_terms),
194 9 : GNUNET_JSON_spec_mark_optional (
195 : TALER_JSON_spec_web_url (
196 : "order_status_url",
197 : &osr->details.ok.details.claimed.order_status_url),
198 : NULL),
199 9 : GNUNET_JSON_spec_end ()
200 : };
201 :
202 9 : if (GNUNET_OK !=
203 9 : GNUNET_JSON_parse (osr->hr.reply,
204 : spec,
205 : NULL, NULL))
206 : {
207 0 : GNUNET_break_op (0);
208 0 : osr->hr.http_status = 0;
209 0 : osr->hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
210 0 : oph->cb (oph->cb_cls,
211 : osr);
212 0 : return;
213 : }
214 9 : osr->details.ok.status = TALER_MERCHANT_OSC_CLAIMED;
215 9 : oph->cb (oph->cb_cls,
216 : osr);
217 : }
218 :
219 :
220 : /**
221 : * Handle HTTP OK response for a paid order.
222 : *
223 : * @param oph handle for the request
224 : * @param[in,out] osr HTTP response we got
225 : */
226 : static void
227 28 : handle_paid (struct TALER_MERCHANT_GetPrivateOrderHandle *oph,
228 : struct TALER_MERCHANT_GetPrivateOrderResponse *osr)
229 : {
230 : uint32_t hc32;
231 : uint32_t ci32;
232 : bool ci_missing;
233 : const json_t *wire_details;
234 : const json_t *refund_details;
235 : struct GNUNET_JSON_Specification spec[] = {
236 28 : GNUNET_JSON_spec_bool ("refunded",
237 : &osr->details.ok.details.paid.refunded),
238 28 : GNUNET_JSON_spec_bool ("refund_pending",
239 : &osr->details.ok.details.paid.refund_pending),
240 28 : GNUNET_JSON_spec_bool ("wired",
241 : &osr->details.ok.details.paid.wired),
242 28 : TALER_JSON_spec_amount_any ("deposit_total",
243 : &osr->details.ok.details.paid.deposit_total),
244 28 : TALER_JSON_spec_ec ("exchange_code",
245 : &osr->details.ok.details.paid.exchange_ec),
246 28 : GNUNET_JSON_spec_uint32 ("exchange_http_status",
247 : &hc32),
248 28 : TALER_JSON_spec_amount_any ("refund_amount",
249 : &osr->details.ok.details.paid.refund_amount),
250 28 : GNUNET_JSON_spec_object_const (
251 : "contract_terms",
252 : &osr->details.ok.details.paid.contract_terms),
253 28 : GNUNET_JSON_spec_mark_optional (
254 : GNUNET_JSON_spec_uint32 ("choice_index",
255 : &ci32),
256 : &ci_missing),
257 28 : GNUNET_JSON_spec_array_const ("wire_details",
258 : &wire_details),
259 28 : GNUNET_JSON_spec_array_const ("refund_details",
260 : &refund_details),
261 28 : GNUNET_JSON_spec_mark_optional (
262 : GNUNET_JSON_spec_array_const (
263 : "refunds_external",
264 : &osr->details.ok.details.paid.refunds_external),
265 : NULL),
266 28 : GNUNET_JSON_spec_mark_optional (
267 : GNUNET_JSON_spec_timestamp ("last_payment",
268 : &osr->details.ok.details.paid.last_payment),
269 : NULL),
270 28 : TALER_JSON_spec_web_url (
271 : "order_status_url",
272 : &osr->details.ok.details.paid.order_status_url),
273 28 : GNUNET_JSON_spec_end ()
274 : };
275 :
276 28 : if (GNUNET_OK !=
277 28 : GNUNET_JSON_parse (osr->hr.reply,
278 : spec,
279 : NULL, NULL))
280 : {
281 0 : GNUNET_break_op (0);
282 0 : osr->hr.http_status = 0;
283 0 : osr->hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
284 0 : oph->cb (oph->cb_cls,
285 : osr);
286 0 : return;
287 : }
288 28 : osr->details.ok.status = TALER_MERCHANT_OSC_PAID;
289 28 : osr->details.ok.details.paid.exchange_hc = (unsigned int) hc32;
290 28 : osr->details.ok.details.paid.choice_index = ci_missing
291 : ? -1
292 28 : : (int) ci32;
293 : {
294 28 : unsigned int wts_len = (unsigned int) json_array_size (wire_details);
295 28 : unsigned int ref_len = (unsigned int) json_array_size (refund_details);
296 :
297 28 : if ( (json_array_size (wire_details) != (size_t) wts_len) ||
298 : (wts_len > MAX_WIRE_DETAILS) )
299 : {
300 0 : GNUNET_break (0);
301 0 : osr->hr.http_status = 0;
302 0 : osr->hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
303 0 : oph->cb (oph->cb_cls,
304 : osr);
305 0 : return;
306 : }
307 28 : if ( (json_array_size (refund_details) != (size_t) ref_len) ||
308 : (ref_len > MAX_REFUND_DETAILS) )
309 : {
310 0 : GNUNET_break (0);
311 0 : osr->hr.http_status = 0;
312 0 : osr->hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
313 0 : oph->cb (oph->cb_cls,
314 : osr);
315 0 : return;
316 : }
317 28 : {
318 28 : struct TALER_MERCHANT_WireTransfer wts[GNUNET_NZL (wts_len)];
319 28 : struct TALER_MERCHANT_GetPrivateOrderRefundDetail ref[
320 28 : GNUNET_NZL (ref_len)];
321 :
322 28 : memset (wts,
323 : 0,
324 : sizeof (wts));
325 37 : for (unsigned int i = 0; i<wts_len; i++)
326 : {
327 9 : struct TALER_MERCHANT_WireTransfer *wt = &wts[i];
328 9 : const json_t *w = json_array_get (wire_details,
329 : i);
330 : struct GNUNET_JSON_Specification ispec[] = {
331 9 : TALER_JSON_spec_web_url ("exchange_url",
332 : &wt->exchange_url),
333 9 : GNUNET_JSON_spec_fixed_auto ("wtid",
334 : &wt->wtid),
335 9 : GNUNET_JSON_spec_timestamp ("execution_time",
336 : &wt->execution_time),
337 9 : TALER_JSON_spec_amount_any ("amount",
338 : &wt->total_amount),
339 9 : GNUNET_JSON_spec_mark_optional (
340 : TALER_JSON_spec_amount_any ("deposit_fee",
341 : &wt->deposit_fee),
342 : NULL),
343 9 : GNUNET_JSON_spec_bool ("confirmed",
344 : &wt->confirmed),
345 9 : GNUNET_JSON_spec_mark_optional (
346 : GNUNET_JSON_spec_uint64 ("expected_transfer_serial_id",
347 : &wt->expected_transfer_serial_id),
348 : NULL),
349 9 : GNUNET_JSON_spec_end ()
350 : };
351 :
352 9 : if (GNUNET_OK !=
353 9 : GNUNET_JSON_parse (w,
354 : ispec,
355 : NULL, NULL))
356 : {
357 0 : GNUNET_break_op (0);
358 0 : osr->hr.http_status = 0;
359 0 : osr->hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
360 0 : oph->cb (oph->cb_cls,
361 : osr);
362 0 : return;
363 : }
364 : }
365 :
366 36 : for (unsigned int i = 0; i<ref_len; i++)
367 : {
368 8 : struct TALER_MERCHANT_GetPrivateOrderRefundDetail *ro = &ref[i];
369 8 : const json_t *w = json_array_get (refund_details,
370 : i);
371 : struct GNUNET_JSON_Specification ispec[] = {
372 8 : TALER_JSON_spec_amount_any ("amount",
373 : &ro->refund_amount),
374 8 : GNUNET_JSON_spec_string ("reason",
375 : &ro->reason),
376 8 : GNUNET_JSON_spec_bool ("pending",
377 : &ro->pending),
378 8 : GNUNET_JSON_spec_timestamp ("timestamp",
379 : &ro->refund_time),
380 8 : GNUNET_JSON_spec_end ()
381 : };
382 :
383 8 : if (GNUNET_OK !=
384 8 : GNUNET_JSON_parse (w,
385 : ispec,
386 : NULL, NULL))
387 : {
388 0 : GNUNET_break_op (0);
389 0 : osr->hr.http_status = 0;
390 0 : osr->hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
391 0 : oph->cb (oph->cb_cls,
392 : osr);
393 0 : return;
394 : }
395 : }
396 :
397 28 : osr->details.ok.details.paid.wts = wts;
398 28 : osr->details.ok.details.paid.wts_len = wts_len;
399 28 : osr->details.ok.details.paid.refunds = ref;
400 28 : osr->details.ok.details.paid.refunds_len = ref_len;
401 28 : oph->cb (oph->cb_cls,
402 : osr);
403 : }
404 : }
405 : }
406 :
407 :
408 : /**
409 : * Function called when we're done processing the
410 : * HTTP GET /private/orders/$ORDER_ID request.
411 : *
412 : * @param cls the `struct TALER_MERCHANT_GetPrivateOrderHandle`
413 : * @param response_code HTTP response code, 0 on error
414 : * @param response response body, NULL if not in JSON
415 : */
416 : static void
417 43 : handle_get_private_order_finished (void *cls,
418 : long response_code,
419 : const void *response)
420 : {
421 43 : struct TALER_MERCHANT_GetPrivateOrderHandle *oph = cls;
422 43 : const json_t *json = response;
423 : const char *order_status;
424 43 : struct TALER_MERCHANT_GetPrivateOrderResponse osr = {
425 43 : .hr.http_status = (unsigned int) response_code,
426 : .hr.reply = json
427 : };
428 :
429 43 : oph->job = NULL;
430 43 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
431 : "Got /private/orders/$ORDER_ID response with status code %u\n",
432 : (unsigned int) response_code);
433 43 : switch (response_code)
434 : {
435 43 : case MHD_HTTP_OK:
436 : /* see below */
437 43 : break;
438 0 : case MHD_HTTP_NOT_MODIFIED:
439 0 : oph->cb (oph->cb_cls,
440 : &osr);
441 0 : TALER_MERCHANT_get_private_order_cancel (oph);
442 0 : return;
443 0 : case MHD_HTTP_ACCEPTED:
444 0 : oph->cb (oph->cb_cls,
445 : &osr);
446 0 : TALER_MERCHANT_get_private_order_cancel (oph);
447 0 : return;
448 0 : case MHD_HTTP_UNAUTHORIZED:
449 0 : osr.hr.ec = TALER_JSON_get_error_code (json);
450 0 : osr.hr.hint = TALER_JSON_get_error_hint (json);
451 0 : oph->cb (oph->cb_cls,
452 : &osr);
453 0 : TALER_MERCHANT_get_private_order_cancel (oph);
454 0 : return;
455 0 : case MHD_HTTP_NOT_FOUND:
456 0 : osr.hr.ec = TALER_JSON_get_error_code (json);
457 0 : osr.hr.hint = TALER_JSON_get_error_hint (json);
458 0 : oph->cb (oph->cb_cls,
459 : &osr);
460 0 : TALER_MERCHANT_get_private_order_cancel (oph);
461 0 : return;
462 0 : case MHD_HTTP_GATEWAY_TIMEOUT:
463 0 : osr.hr.ec = TALER_JSON_get_error_code (json);
464 0 : osr.hr.hint = TALER_JSON_get_error_hint (json);
465 0 : oph->cb (oph->cb_cls,
466 : &osr);
467 0 : TALER_MERCHANT_get_private_order_cancel (oph);
468 0 : return;
469 0 : default:
470 0 : osr.hr.ec = TALER_JSON_get_error_code (json);
471 0 : osr.hr.hint = TALER_JSON_get_error_hint (json);
472 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
473 : "Polling order status failed with HTTP status code %u/%d\n",
474 : (unsigned int) response_code,
475 : (int) osr.hr.ec);
476 0 : GNUNET_break_op (0);
477 0 : oph->cb (oph->cb_cls,
478 : &osr);
479 0 : TALER_MERCHANT_get_private_order_cancel (oph);
480 0 : return;
481 : }
482 :
483 43 : order_status = json_string_value (json_object_get (json,
484 : "order_status"));
485 43 : if (NULL == order_status)
486 : {
487 0 : GNUNET_break_op (0);
488 0 : osr.hr.http_status = 0;
489 0 : osr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
490 0 : oph->cb (oph->cb_cls,
491 : &osr);
492 0 : TALER_MERCHANT_get_private_order_cancel (oph);
493 0 : return;
494 : }
495 :
496 43 : if (0 == strcmp ("paid",
497 : order_status))
498 : {
499 28 : handle_paid (oph,
500 : &osr);
501 : }
502 15 : else if (0 == strcmp ("claimed",
503 : order_status))
504 : {
505 9 : handle_claimed (oph,
506 : &osr);
507 : }
508 6 : else if (0 == strcmp ("unpaid",
509 : order_status))
510 : {
511 6 : handle_unpaid (oph,
512 : &osr);
513 : }
514 : else
515 : {
516 0 : GNUNET_break_op (0);
517 0 : osr.hr.http_status = 0;
518 0 : osr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
519 0 : oph->cb (oph->cb_cls,
520 : &osr);
521 : }
522 43 : TALER_MERCHANT_get_private_order_cancel (oph);
523 : }
524 :
525 :
526 : struct TALER_MERCHANT_GetPrivateOrderHandle *
527 43 : TALER_MERCHANT_get_private_order_create (
528 : struct GNUNET_CURL_Context *ctx,
529 : const char *url,
530 : const char *order_id)
531 : {
532 : struct TALER_MERCHANT_GetPrivateOrderHandle *oph;
533 :
534 43 : oph = GNUNET_new (struct TALER_MERCHANT_GetPrivateOrderHandle);
535 43 : oph->ctx = ctx;
536 43 : oph->base_url = GNUNET_strdup (url);
537 43 : oph->order_id = GNUNET_strdup (order_id);
538 43 : return oph;
539 : }
540 :
541 :
542 : enum GNUNET_GenericReturnValue
543 14 : TALER_MERCHANT_get_private_order_set_options_ (
544 : struct TALER_MERCHANT_GetPrivateOrderHandle *oph,
545 : unsigned int num_options,
546 : const struct TALER_MERCHANT_GetPrivateOrderOptionValue *options)
547 : {
548 28 : for (unsigned int i = 0; i < num_options; i++)
549 : {
550 28 : const struct TALER_MERCHANT_GetPrivateOrderOptionValue *opt =
551 28 : &options[i];
552 :
553 28 : switch (opt->option)
554 : {
555 14 : case TALER_MERCHANT_GET_PRIVATE_ORDER_OPTION_END:
556 14 : return GNUNET_OK;
557 10 : case TALER_MERCHANT_GET_PRIVATE_ORDER_OPTION_SESSION_ID:
558 10 : GNUNET_free (oph->session_id);
559 10 : if (NULL != opt->details.session_id)
560 10 : oph->session_id = GNUNET_strdup (opt->details.session_id);
561 10 : break;
562 4 : case TALER_MERCHANT_GET_PRIVATE_ORDER_OPTION_TIMEOUT:
563 4 : oph->timeout = opt->details.timeout;
564 4 : break;
565 0 : case TALER_MERCHANT_GET_PRIVATE_ORDER_OPTION_TRANSFER:
566 0 : oph->transfer = opt->details.transfer;
567 0 : break;
568 0 : case TALER_MERCHANT_GET_PRIVATE_ORDER_OPTION_LP_NOT_ETAG:
569 0 : if (NULL != opt->details.lp_not_etag)
570 : {
571 0 : oph->lp_not_etag = *opt->details.lp_not_etag;
572 0 : oph->have_lp_not_etag = true;
573 : }
574 0 : break;
575 0 : case TALER_MERCHANT_GET_PRIVATE_ORDER_OPTION_ALLOW_REFUNDED_FOR_REPURCHASE:
576 : oph->allow_refunded_for_repurchase
577 0 : = opt->details.allow_refunded_for_repurchase;
578 0 : break;
579 0 : default:
580 0 : GNUNET_break (0);
581 0 : return GNUNET_NO;
582 : }
583 : }
584 0 : return GNUNET_OK;
585 : }
586 :
587 :
588 : enum TALER_ErrorCode
589 43 : TALER_MERCHANT_get_private_order_start (
590 : struct TALER_MERCHANT_GetPrivateOrderHandle *oph,
591 : TALER_MERCHANT_GetPrivateOrderCallback cb,
592 : TALER_MERCHANT_GET_PRIVATE_ORDER_RESULT_CLOSURE *cb_cls)
593 : {
594 : CURL *eh;
595 : unsigned int tms;
596 :
597 43 : oph->cb = cb;
598 43 : oph->cb_cls = cb_cls;
599 86 : tms = (unsigned int) (oph->timeout.rel_value_us
600 43 : / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us);
601 : {
602 : char *path;
603 : char timeout_ms[32];
604 : char etag_str[sizeof (struct GNUNET_ShortHashCode) * 2 + 1];
605 :
606 43 : GNUNET_snprintf (timeout_ms,
607 : sizeof (timeout_ms),
608 : "%u",
609 : tms);
610 43 : if (oph->have_lp_not_etag)
611 : {
612 : char *end;
613 :
614 0 : end = GNUNET_STRINGS_data_to_string (
615 0 : &oph->lp_not_etag,
616 : sizeof (oph->lp_not_etag),
617 : etag_str,
618 : sizeof (etag_str) - 1);
619 0 : *end = '\0';
620 : }
621 43 : GNUNET_asprintf (&path,
622 : "private/orders/%s",
623 : oph->order_id);
624 129 : oph->url = TALER_url_join (oph->base_url,
625 : path,
626 : "session_id",
627 : oph->session_id,
628 : "timeout_ms",
629 : (0 != tms)
630 : ? timeout_ms
631 : : NULL,
632 : "transfer",
633 43 : oph->transfer
634 : ? "YES"
635 : : NULL,
636 : "lp_not_etag",
637 43 : oph->have_lp_not_etag
638 : ? etag_str
639 : : NULL,
640 : "allow_refunded_for_repurchase",
641 43 : oph->allow_refunded_for_repurchase
642 : ? "YES"
643 : : NULL,
644 : NULL);
645 43 : GNUNET_free (path);
646 : }
647 43 : if (NULL == oph->url)
648 0 : return TALER_EC_GENERIC_CONFIGURATION_INVALID;
649 43 : eh = TALER_MERCHANT_curl_easy_get_ (oph->url);
650 43 : if (NULL == eh)
651 0 : return TALER_EC_GENERIC_CONFIGURATION_INVALID;
652 43 : if (0 != tms)
653 : {
654 4 : GNUNET_break (CURLE_OK ==
655 : curl_easy_setopt (eh,
656 : CURLOPT_TIMEOUT_MS,
657 : (long) (tms + 100L)));
658 : }
659 43 : oph->job = GNUNET_CURL_job_add (oph->ctx,
660 : eh,
661 : &handle_get_private_order_finished,
662 : oph);
663 43 : if (NULL == oph->job)
664 0 : return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
665 43 : return TALER_EC_NONE;
666 : }
667 :
668 :
669 : void
670 43 : TALER_MERCHANT_get_private_order_cancel (
671 : struct TALER_MERCHANT_GetPrivateOrderHandle *oph)
672 : {
673 43 : if (NULL != oph->job)
674 : {
675 0 : GNUNET_CURL_job_cancel (oph->job);
676 0 : oph->job = NULL;
677 : }
678 43 : GNUNET_free (oph->url);
679 43 : GNUNET_free (oph->order_id);
680 43 : GNUNET_free (oph->session_id);
681 43 : GNUNET_free (oph->base_url);
682 43 : GNUNET_free (oph);
683 43 : }
684 :
685 :
686 : /* end of merchant_api_get-private-orders-ORDER_ID-new.c */
|