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 merchant_api_get-private-orders-ORDER_ID-new.c
19 : * @brief Implementation of the GET /private/orders/$ORDER_ID request
20 : * @author Christian Grothoff
21 : */
22 : #include "taler/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 0 : handle_unpaid (struct TALER_MERCHANT_GetPrivateOrderHandle *oph,
124 : struct TALER_MERCHANT_GetPrivateOrderResponse *osr)
125 : {
126 : struct GNUNET_JSON_Specification spec[] = {
127 0 : GNUNET_JSON_spec_mark_optional (
128 : GNUNET_JSON_spec_string (
129 : "already_paid_order_id",
130 : &osr->details.ok.details.unpaid.already_paid_order_id),
131 : NULL),
132 0 : GNUNET_JSON_spec_mark_optional (
133 : GNUNET_JSON_spec_string (
134 : "already_paid_fulfillment_url",
135 : &osr->details.ok.details.unpaid.already_paid_fulfillment_url),
136 : NULL),
137 0 : GNUNET_JSON_spec_string (
138 : "taler_pay_uri",
139 : &osr->details.ok.details.unpaid.taler_pay_uri),
140 0 : GNUNET_JSON_spec_string (
141 : "summary",
142 : &osr->details.ok.details.unpaid.summary),
143 0 : 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 0 : GNUNET_JSON_spec_string (
149 : "order_status_url",
150 : &osr->details.ok.details.unpaid.order_status_url),
151 0 : GNUNET_JSON_spec_timestamp (
152 : "creation_time",
153 : &osr->details.ok.details.unpaid.creation_time),
154 0 : GNUNET_JSON_spec_mark_optional (
155 : GNUNET_JSON_spec_timestamp (
156 : "pay_deadline",
157 : &osr->details.ok.details.unpaid.pay_deadline),
158 : NULL),
159 0 : GNUNET_JSON_spec_end ()
160 : };
161 :
162 0 : if (GNUNET_OK !=
163 0 : 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 0 : osr->details.ok.status = TALER_MERCHANT_OSC_UNPAID;
175 0 : 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 0 : handle_claimed (struct TALER_MERCHANT_GetPrivateOrderHandle *oph,
188 : struct TALER_MERCHANT_GetPrivateOrderResponse *osr)
189 : {
190 : struct GNUNET_JSON_Specification spec[] = {
191 0 : GNUNET_JSON_spec_object_const (
192 : "contract_terms",
193 : &osr->details.ok.details.claimed.contract_terms),
194 0 : GNUNET_JSON_spec_mark_optional (
195 : GNUNET_JSON_spec_string (
196 : "order_status_url",
197 : &osr->details.ok.details.claimed.order_status_url),
198 : NULL),
199 0 : GNUNET_JSON_spec_end ()
200 : };
201 :
202 0 : if (GNUNET_OK !=
203 0 : 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 0 : osr->details.ok.status = TALER_MERCHANT_OSC_CLAIMED;
215 0 : 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 0 : 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 0 : GNUNET_JSON_spec_bool ("refunded",
237 : &osr->details.ok.details.paid.refunded),
238 0 : GNUNET_JSON_spec_bool ("refund_pending",
239 : &osr->details.ok.details.paid.refund_pending),
240 0 : GNUNET_JSON_spec_bool ("wired",
241 : &osr->details.ok.details.paid.wired),
242 0 : TALER_JSON_spec_amount_any ("deposit_total",
243 : &osr->details.ok.details.paid.deposit_total),
244 0 : TALER_JSON_spec_ec ("exchange_code",
245 : &osr->details.ok.details.paid.exchange_ec),
246 0 : GNUNET_JSON_spec_uint32 ("exchange_http_status",
247 : &hc32),
248 0 : TALER_JSON_spec_amount_any ("refund_amount",
249 : &osr->details.ok.details.paid.refund_amount),
250 0 : GNUNET_JSON_spec_object_const (
251 : "contract_terms",
252 : &osr->details.ok.details.paid.contract_terms),
253 0 : GNUNET_JSON_spec_mark_optional (
254 : GNUNET_JSON_spec_uint32 ("choice_index",
255 : &ci32),
256 : &ci_missing),
257 0 : GNUNET_JSON_spec_array_const ("wire_details",
258 : &wire_details),
259 0 : GNUNET_JSON_spec_array_const ("refund_details",
260 : &refund_details),
261 0 : GNUNET_JSON_spec_mark_optional (
262 : GNUNET_JSON_spec_timestamp ("last_payment",
263 : &osr->details.ok.details.paid.last_payment),
264 : NULL),
265 0 : GNUNET_JSON_spec_string (
266 : "order_status_url",
267 : &osr->details.ok.details.paid.order_status_url),
268 0 : GNUNET_JSON_spec_end ()
269 : };
270 :
271 0 : if (GNUNET_OK !=
272 0 : GNUNET_JSON_parse (osr->hr.reply,
273 : spec,
274 : NULL, NULL))
275 : {
276 0 : GNUNET_break_op (0);
277 0 : osr->hr.http_status = 0;
278 0 : osr->hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
279 0 : oph->cb (oph->cb_cls,
280 : osr);
281 0 : return;
282 : }
283 0 : osr->details.ok.status = TALER_MERCHANT_OSC_PAID;
284 0 : osr->details.ok.details.paid.exchange_hc = (unsigned int) hc32;
285 0 : osr->details.ok.details.paid.choice_index = ci_missing
286 : ? -1
287 0 : : (int) ci32;
288 : {
289 0 : unsigned int wts_len = (unsigned int) json_array_size (wire_details);
290 0 : unsigned int ref_len = (unsigned int) json_array_size (refund_details);
291 :
292 0 : if ( (json_array_size (wire_details) != (size_t) wts_len) ||
293 : (wts_len > MAX_WIRE_DETAILS) )
294 : {
295 0 : GNUNET_break (0);
296 0 : osr->hr.http_status = 0;
297 0 : osr->hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
298 0 : oph->cb (oph->cb_cls,
299 : osr);
300 0 : return;
301 : }
302 0 : if ( (json_array_size (refund_details) != (size_t) ref_len) ||
303 : (ref_len > MAX_REFUND_DETAILS) )
304 : {
305 0 : GNUNET_break (0);
306 0 : osr->hr.http_status = 0;
307 0 : osr->hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
308 0 : oph->cb (oph->cb_cls,
309 : osr);
310 0 : return;
311 : }
312 0 : {
313 0 : struct TALER_MERCHANT_WireTransfer wts[GNUNET_NZL (wts_len)];
314 0 : struct TALER_MERCHANT_GetPrivateOrderRefundDetail ref[
315 0 : GNUNET_NZL (ref_len)];
316 :
317 0 : for (unsigned int i = 0; i<wts_len; i++)
318 : {
319 0 : struct TALER_MERCHANT_WireTransfer *wt = &wts[i];
320 0 : const json_t *w = json_array_get (wire_details,
321 : i);
322 : struct GNUNET_JSON_Specification ispec[] = {
323 0 : TALER_JSON_spec_web_url ("exchange_url",
324 : &wt->exchange_url),
325 0 : GNUNET_JSON_spec_fixed_auto ("wtid",
326 : &wt->wtid),
327 0 : GNUNET_JSON_spec_timestamp ("execution_time",
328 : &wt->execution_time),
329 0 : TALER_JSON_spec_amount_any ("amount",
330 : &wt->total_amount),
331 0 : GNUNET_JSON_spec_mark_optional (
332 : TALER_JSON_spec_amount_any ("deposit_fee",
333 : &wt->deposit_fee),
334 : NULL),
335 0 : GNUNET_JSON_spec_bool ("confirmed",
336 : &wt->confirmed),
337 0 : GNUNET_JSON_spec_mark_optional (
338 : GNUNET_JSON_spec_uint64 ("expected_transfer_serial_id",
339 : &wt->expected_transfer_serial_id),
340 : NULL),
341 0 : GNUNET_JSON_spec_end ()
342 : };
343 :
344 0 : if (GNUNET_OK !=
345 0 : GNUNET_JSON_parse (w,
346 : ispec,
347 : NULL, NULL))
348 : {
349 0 : GNUNET_break_op (0);
350 0 : osr->hr.http_status = 0;
351 0 : osr->hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
352 0 : oph->cb (oph->cb_cls,
353 : osr);
354 0 : return;
355 : }
356 : }
357 :
358 0 : for (unsigned int i = 0; i<ref_len; i++)
359 : {
360 0 : struct TALER_MERCHANT_GetPrivateOrderRefundDetail *ro = &ref[i];
361 0 : const json_t *w = json_array_get (refund_details,
362 : i);
363 : struct GNUNET_JSON_Specification ispec[] = {
364 0 : TALER_JSON_spec_amount_any ("amount",
365 : &ro->refund_amount),
366 0 : GNUNET_JSON_spec_string ("reason",
367 : &ro->reason),
368 0 : GNUNET_JSON_spec_bool ("pending",
369 : &ro->pending),
370 0 : GNUNET_JSON_spec_timestamp ("timestamp",
371 : &ro->refund_time),
372 0 : GNUNET_JSON_spec_end ()
373 : };
374 :
375 0 : if (GNUNET_OK !=
376 0 : GNUNET_JSON_parse (w,
377 : ispec,
378 : NULL, NULL))
379 : {
380 0 : GNUNET_break_op (0);
381 0 : osr->hr.http_status = 0;
382 0 : osr->hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
383 0 : oph->cb (oph->cb_cls,
384 : osr);
385 0 : return;
386 : }
387 : }
388 :
389 0 : osr->details.ok.details.paid.wts = wts;
390 0 : osr->details.ok.details.paid.wts_len = wts_len;
391 0 : osr->details.ok.details.paid.refunds = ref;
392 0 : osr->details.ok.details.paid.refunds_len = ref_len;
393 0 : oph->cb (oph->cb_cls,
394 : osr);
395 : }
396 : }
397 : }
398 :
399 :
400 : /**
401 : * Function called when we're done processing the
402 : * HTTP GET /private/orders/$ORDER_ID request.
403 : *
404 : * @param cls the `struct TALER_MERCHANT_GetPrivateOrderHandle`
405 : * @param response_code HTTP response code, 0 on error
406 : * @param response response body, NULL if not in JSON
407 : */
408 : static void
409 0 : handle_get_private_order_finished (void *cls,
410 : long response_code,
411 : const void *response)
412 : {
413 0 : struct TALER_MERCHANT_GetPrivateOrderHandle *oph = cls;
414 0 : const json_t *json = response;
415 : const char *order_status;
416 0 : struct TALER_MERCHANT_GetPrivateOrderResponse osr = {
417 0 : .hr.http_status = (unsigned int) response_code,
418 : .hr.reply = json
419 : };
420 :
421 0 : oph->job = NULL;
422 0 : GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
423 : "Got /private/orders/$ORDER_ID response with status code %u\n",
424 : (unsigned int) response_code);
425 0 : switch (response_code)
426 : {
427 0 : case MHD_HTTP_OK:
428 : /* see below */
429 0 : break;
430 0 : case MHD_HTTP_NOT_MODIFIED:
431 0 : oph->cb (oph->cb_cls,
432 : &osr);
433 0 : TALER_MERCHANT_get_private_order_cancel (oph);
434 0 : return;
435 0 : case MHD_HTTP_ACCEPTED:
436 0 : oph->cb (oph->cb_cls,
437 : &osr);
438 0 : TALER_MERCHANT_get_private_order_cancel (oph);
439 0 : return;
440 0 : case MHD_HTTP_UNAUTHORIZED:
441 0 : osr.hr.ec = TALER_JSON_get_error_code (json);
442 0 : osr.hr.hint = TALER_JSON_get_error_hint (json);
443 0 : oph->cb (oph->cb_cls,
444 : &osr);
445 0 : TALER_MERCHANT_get_private_order_cancel (oph);
446 0 : return;
447 0 : case MHD_HTTP_NOT_FOUND:
448 0 : osr.hr.ec = TALER_JSON_get_error_code (json);
449 0 : osr.hr.hint = TALER_JSON_get_error_hint (json);
450 0 : oph->cb (oph->cb_cls,
451 : &osr);
452 0 : TALER_MERCHANT_get_private_order_cancel (oph);
453 0 : return;
454 0 : case MHD_HTTP_GATEWAY_TIMEOUT:
455 0 : osr.hr.ec = TALER_JSON_get_error_code (json);
456 0 : osr.hr.hint = TALER_JSON_get_error_hint (json);
457 0 : oph->cb (oph->cb_cls,
458 : &osr);
459 0 : TALER_MERCHANT_get_private_order_cancel (oph);
460 0 : return;
461 0 : default:
462 0 : osr.hr.ec = TALER_JSON_get_error_code (json);
463 0 : osr.hr.hint = TALER_JSON_get_error_hint (json);
464 0 : GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
465 : "Polling order status failed with HTTP status code %u/%d\n",
466 : (unsigned int) response_code,
467 : (int) osr.hr.ec);
468 0 : GNUNET_break_op (0);
469 0 : oph->cb (oph->cb_cls,
470 : &osr);
471 0 : TALER_MERCHANT_get_private_order_cancel (oph);
472 0 : return;
473 : }
474 :
475 0 : order_status = json_string_value (json_object_get (json,
476 : "order_status"));
477 0 : if (NULL == order_status)
478 : {
479 0 : GNUNET_break_op (0);
480 0 : osr.hr.http_status = 0;
481 0 : osr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
482 0 : oph->cb (oph->cb_cls,
483 : &osr);
484 0 : TALER_MERCHANT_get_private_order_cancel (oph);
485 0 : return;
486 : }
487 :
488 0 : if (0 == strcmp ("paid",
489 : order_status))
490 : {
491 0 : handle_paid (oph,
492 : &osr);
493 : }
494 0 : else if (0 == strcmp ("claimed",
495 : order_status))
496 : {
497 0 : handle_claimed (oph,
498 : &osr);
499 : }
500 0 : else if (0 == strcmp ("unpaid",
501 : order_status))
502 : {
503 0 : handle_unpaid (oph,
504 : &osr);
505 : }
506 : else
507 : {
508 0 : GNUNET_break_op (0);
509 0 : osr.hr.http_status = 0;
510 0 : osr.hr.ec = TALER_EC_GENERIC_INVALID_RESPONSE;
511 0 : oph->cb (oph->cb_cls,
512 : &osr);
513 : }
514 0 : TALER_MERCHANT_get_private_order_cancel (oph);
515 : }
516 :
517 :
518 : struct TALER_MERCHANT_GetPrivateOrderHandle *
519 0 : TALER_MERCHANT_get_private_order_create (
520 : struct GNUNET_CURL_Context *ctx,
521 : const char *url,
522 : const char *order_id)
523 : {
524 : struct TALER_MERCHANT_GetPrivateOrderHandle *oph;
525 :
526 0 : oph = GNUNET_new (struct TALER_MERCHANT_GetPrivateOrderHandle);
527 0 : oph->ctx = ctx;
528 0 : oph->base_url = GNUNET_strdup (url);
529 0 : oph->order_id = GNUNET_strdup (order_id);
530 0 : return oph;
531 : }
532 :
533 :
534 : enum GNUNET_GenericReturnValue
535 0 : TALER_MERCHANT_get_private_order_set_options_ (
536 : struct TALER_MERCHANT_GetPrivateOrderHandle *oph,
537 : unsigned int num_options,
538 : const struct TALER_MERCHANT_GetPrivateOrderOptionValue *options)
539 : {
540 0 : for (unsigned int i = 0; i < num_options; i++)
541 : {
542 0 : const struct TALER_MERCHANT_GetPrivateOrderOptionValue *opt =
543 0 : &options[i];
544 :
545 0 : switch (opt->option)
546 : {
547 0 : case TALER_MERCHANT_GET_PRIVATE_ORDER_OPTION_END:
548 0 : return GNUNET_OK;
549 0 : case TALER_MERCHANT_GET_PRIVATE_ORDER_OPTION_SESSION_ID:
550 0 : GNUNET_free (oph->session_id);
551 0 : if (NULL != opt->details.session_id)
552 0 : oph->session_id = GNUNET_strdup (opt->details.session_id);
553 0 : break;
554 0 : case TALER_MERCHANT_GET_PRIVATE_ORDER_OPTION_TIMEOUT:
555 0 : oph->timeout = opt->details.timeout;
556 0 : break;
557 0 : case TALER_MERCHANT_GET_PRIVATE_ORDER_OPTION_TRANSFER:
558 0 : oph->transfer = opt->details.transfer;
559 0 : break;
560 0 : case TALER_MERCHANT_GET_PRIVATE_ORDER_OPTION_LP_NOT_ETAG:
561 0 : if (NULL != opt->details.lp_not_etag)
562 : {
563 0 : oph->lp_not_etag = *opt->details.lp_not_etag;
564 0 : oph->have_lp_not_etag = true;
565 : }
566 0 : break;
567 0 : case TALER_MERCHANT_GET_PRIVATE_ORDER_OPTION_ALLOW_REFUNDED_FOR_REPURCHASE:
568 : oph->allow_refunded_for_repurchase
569 0 : = opt->details.allow_refunded_for_repurchase;
570 0 : break;
571 0 : default:
572 0 : GNUNET_break (0);
573 0 : return GNUNET_NO;
574 : }
575 : }
576 0 : return GNUNET_OK;
577 : }
578 :
579 :
580 : enum TALER_ErrorCode
581 0 : TALER_MERCHANT_get_private_order_start (
582 : struct TALER_MERCHANT_GetPrivateOrderHandle *oph,
583 : TALER_MERCHANT_GetPrivateOrderCallback cb,
584 : TALER_MERCHANT_GET_PRIVATE_ORDER_RESULT_CLOSURE *cb_cls)
585 : {
586 : CURL *eh;
587 : unsigned int tms;
588 :
589 0 : oph->cb = cb;
590 0 : oph->cb_cls = cb_cls;
591 0 : tms = (unsigned int) (oph->timeout.rel_value_us
592 0 : / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us);
593 : {
594 : char *path;
595 : char timeout_ms[32];
596 : char etag_str[sizeof (struct GNUNET_ShortHashCode) * 2 + 1];
597 :
598 0 : GNUNET_snprintf (timeout_ms,
599 : sizeof (timeout_ms),
600 : "%u",
601 : tms);
602 0 : if (oph->have_lp_not_etag)
603 : {
604 : char *end;
605 :
606 0 : end = GNUNET_STRINGS_data_to_string (
607 0 : &oph->lp_not_etag,
608 : sizeof (oph->lp_not_etag),
609 : etag_str,
610 : sizeof (etag_str) - 1);
611 0 : *end = '\0';
612 : }
613 0 : GNUNET_asprintf (&path,
614 : "private/orders/%s",
615 : oph->order_id);
616 0 : oph->url = TALER_url_join (oph->base_url,
617 : path,
618 : "session_id",
619 : oph->session_id,
620 : "timeout_ms",
621 : (0 != tms)
622 : ? timeout_ms
623 : : NULL,
624 : "transfer",
625 0 : oph->transfer
626 : ? "YES"
627 : : NULL,
628 : "lp_not_etag",
629 0 : oph->have_lp_not_etag
630 : ? etag_str
631 : : NULL,
632 : "allow_refunded_for_repurchase",
633 0 : oph->allow_refunded_for_repurchase
634 : ? "YES"
635 : : NULL,
636 : NULL);
637 0 : GNUNET_free (path);
638 : }
639 0 : if (NULL == oph->url)
640 0 : return TALER_EC_GENERIC_CONFIGURATION_INVALID;
641 0 : eh = TALER_MERCHANT_curl_easy_get_ (oph->url);
642 0 : if (NULL == eh)
643 0 : return TALER_EC_GENERIC_CONFIGURATION_INVALID;
644 0 : if (0 != tms)
645 : {
646 0 : GNUNET_break (CURLE_OK ==
647 : curl_easy_setopt (eh,
648 : CURLOPT_TIMEOUT_MS,
649 : (long) (tms + 100L)));
650 : }
651 0 : oph->job = GNUNET_CURL_job_add (oph->ctx,
652 : eh,
653 : &handle_get_private_order_finished,
654 : oph);
655 0 : if (NULL == oph->job)
656 0 : return TALER_EC_GENERIC_INTERNAL_INVARIANT_FAILURE;
657 0 : return TALER_EC_NONE;
658 : }
659 :
660 :
661 : void
662 0 : TALER_MERCHANT_get_private_order_cancel (
663 : struct TALER_MERCHANT_GetPrivateOrderHandle *oph)
664 : {
665 0 : if (NULL != oph->job)
666 : {
667 0 : GNUNET_CURL_job_cancel (oph->job);
668 0 : oph->job = NULL;
669 : }
670 0 : GNUNET_free (oph->url);
671 0 : GNUNET_free (oph->order_id);
672 0 : GNUNET_free (oph->session_id);
673 0 : GNUNET_free (oph->base_url);
674 0 : GNUNET_free (oph);
675 0 : }
676 :
677 :
678 : /* end of merchant_api_get-private-orders-ORDER_ID-new.c */
|