summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2020-04-26 22:01:24 +0200
committerChristian Grothoff <christian@grothoff.org>2020-04-26 22:01:24 +0200
commitfc57cccaa0295c0aeb640953bf00baccbc6d6f49 (patch)
treee42016c6bb7c539dcc46ac96fdff0e9c7de8ee90
parentf799df31e066a23a0df8f4d062470526710741dd (diff)
downloadmerchant-fc57cccaa0295c0aeb640953bf00baccbc6d6f49.tar.gz
merchant-fc57cccaa0295c0aeb640953bf00baccbc6d6f49.tar.bz2
merchant-fc57cccaa0295c0aeb640953bf00baccbc6d6f49.zip
implement GET /orders in libtalermerchant
-rw-r--r--src/backend/Makefile.am2
-rw-r--r--src/backend/taler-merchant-httpd.c2
-rw-r--r--src/backend/taler-merchant-httpd.h8
-rw-r--r--src/backend/taler-merchant-httpd_private-post-orders.c47
-rw-r--r--src/include/taler_merchant_service.h116
-rw-r--r--src/include/taler_merchantdb_plugin.h97
-rw-r--r--src/lib/Makefile.am1
-rw-r--r--src/lib/merchant_api_get_orders.c436
8 files changed, 652 insertions, 57 deletions
diff --git a/src/backend/Makefile.am b/src/backend/Makefile.am
index 7be26748..74c3b201 100644
--- a/src/backend/Makefile.am
+++ b/src/backend/Makefile.am
@@ -37,6 +37,8 @@ taler_merchant_httpd_SOURCES = \
taler-merchant-httpd_private-get-products.h \
taler-merchant-httpd_private-get-products-ID.c \
taler-merchant-httpd_private-get-products-ID.h \
+ taler-merchant-httpd_private-get-orders.c \
+ taler-merchant-httpd_private-get-orders.h \
taler-merchant-httpd_private-patch-instances-ID.c \
taler-merchant-httpd_private-patch-instances-ID.h \
taler-merchant-httpd_private-patch-products-ID.c \
diff --git a/src/backend/taler-merchant-httpd.c b/src/backend/taler-merchant-httpd.c
index 9005b161..2534e07d 100644
--- a/src/backend/taler-merchant-httpd.c
+++ b/src/backend/taler-merchant-httpd.c
@@ -35,6 +35,7 @@
#include "taler-merchant-httpd_private-get-instances-ID.h"
#include "taler-merchant-httpd_private-get-products.h"
#include "taler-merchant-httpd_private-get-products-ID.h"
+#include "taler-merchant-httpd_private-get-orders.h"
#include "taler-merchant-httpd_private-patch-instances-ID.h"
#include "taler-merchant-httpd_private-patch-products-ID.h"
#include "taler-merchant-httpd_private-post-instances.h"
@@ -406,6 +407,7 @@ do_shutdown (void *cls)
struct TMH_SuspendedConnection *sc;
(void) cls;
+ TMH_force_get_orders_resume ();
#if 0
TMH_force_pc_resume ();
TMH_force_trh_resume ();
diff --git a/src/backend/taler-merchant-httpd.h b/src/backend/taler-merchant-httpd.h
index 4d4aa7df..a6867e24 100644
--- a/src/backend/taler-merchant-httpd.h
+++ b/src/backend/taler-merchant-httpd.h
@@ -213,14 +213,6 @@ struct TMH_RequestHandler
/**
- * Each MHD response handler that sets the "connection_cls" to a
- * non-NULL value must use a struct that has this struct as its first
- * member. This struct contains a single callback, which will be
- * invoked to clean up the memory when the contection is completed.
- */
-struct TMH_HandlerContext;
-
-/**
* Signature of a function used to clean up the context
* we keep in the "connection_cls" of MHD when handling
* a request.
diff --git a/src/backend/taler-merchant-httpd_private-post-orders.c b/src/backend/taler-merchant-httpd_private-post-orders.c
index af75999a..99e2a584 100644
--- a/src/backend/taler-merchant-httpd_private-post-orders.c
+++ b/src/backend/taler-merchant-httpd_private-post-orders.c
@@ -831,14 +831,8 @@ merge_inventory (struct MHD_Connection *connection,
}
{
- bool have_total = false;
- bool want_total;
- struct TALER_Amount total;
json_t *np = json_array ();
- want_total = (NULL == json_object_get (order,
- "total"));
-
for (unsigned int i = 0; i<inventory_products_length; i++)
{
struct TALER_MERCHANTDB_ProductDetails pd;
@@ -898,52 +892,11 @@ merge_inventory (struct MHD_Connection *connection,
GNUNET_assert (0 ==
json_array_append_new (np,
p));
- if (have_total)
- {
- if (0 <
- TALER_amount_add (&total,
- &total,
- &pd.price))
- {
- GNUNET_break (0);
- json_decref (np);
- return TALER_MHD_reply_with_error (connection,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_ORDERS_TOTAL_SUM_FAILED,
- "failed to add up product prices");
- }
- }
- else
- {
- have_total = true;
- total = pd.price;
- }
-
}
GNUNET_free (pd.description);
GNUNET_free (pd.unit);
json_decref (pd.address);
}
- if ( (have_total) &&
- (want_total) )
- {
- GNUNET_assert (0 ==
- json_object_set_new (order,
- "total",
- TALER_JSON_from_amount (&total)));
- }
- if ( (! have_total) &&
- (want_total) )
- {
- GNUNET_break_op (0);
- json_decref (np);
- return TALER_MHD_reply_with_error (
- connection,
- MHD_HTTP_BAD_REQUEST,
- TALER_EC_ORDERS_TOTAL_MISSING,
- "total missing in order, and we could not calculate it");
- }
-
/* merge into existing products list */
{
json_t *xp;
diff --git a/src/include/taler_merchant_service.h b/src/include/taler_merchant_service.h
index 8976210e..bc5eae14 100644
--- a/src/include/taler_merchant_service.h
+++ b/src/include/taler_merchant_service.h
@@ -1200,6 +1200,122 @@ TALER_MERCHANT_orders_post_cancel (
/**
+ * Handle for a GET /orders operation.
+ */
+struct TALER_MERCHANT_OrdersGetHandle;
+
+/**
+ * Individual order (minimal information returned via GET /orders).
+ */
+struct TALER_MERCHANT_OrderEntry
+{
+ /**
+ * Order identifier.
+ */
+ const char *order_id;
+
+};
+
+
+/**
+ * Function called with the result of the GET /orders operation.
+ *
+ * @param cls closure
+ * @param hr HTTP response details
+ * @param orders_length length of the @a orders array
+ * @param orders array of orders the requested instance has made
+ */
+typedef void
+(*TALER_MERCHANT_OrdersGetCallback)(
+ void *cls,
+ const struct TALER_MERCHANT_HttpResponse *hr,
+ unsigned int orders_length,
+ const struct TALER_MERCHANT_OrderEntry orders[]);
+
+
+/**
+ * Make a GET /orders request.
+ *
+ * @param ctx the context
+ * @param backend_url HTTP base URL for the backend
+ * @param cb function to call with the backend's inventory information
+ * @param cb_cls closure for @a cb
+ * @return the request handle; NULL upon error
+ */
+struct TALER_MERCHANT_OrdersGetHandle *
+TALER_MERCHANT_orders_get (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ TALER_MERCHANT_OrdersGetCallback cb,
+ void *cb_cls);
+
+
+/**
+ * Possible values for a binary filter.
+ */
+enum TALER_MERCHANT_YesNoAll
+{
+ /**
+ * If condition is yes.
+ */
+ TALER_MERCHANT_YNA_YES = 1,
+
+ /**
+ * If condition is no.
+ */
+ TALER_MERCHANT_YNA_NO = 2,
+
+ /**
+ * Condition disabled.
+ */
+ TALER_MERCHANT_YNA_ALL = 3
+};
+
+
+/**
+ * Make a GET /orders request with filters.
+ *
+ * @param ctx the context
+ * @param backend_url HTTP base URL for the backend
+ * @param paid filter on payment status
+ * @param refunded filter on refund status
+ * @param wired filter on wire transfer status
+ * @param date range limit by date
+ * @param start_row range limit by order table row
+ * @param delta range from which @a date and @a start_row apply, positive
+ * to return delta items after the given limit(s), negative to
+ * return delta items before the given limit(s)
+ * @param timeout how long to wait (long polling) of zero results match the query
+ * @param cb function to call with the backend's inventory information
+ * @param cb_cls closure for @a cb
+ * @return the request handle; NULL upon error
+ */
+struct TALER_MERCHANT_OrdersGetHandle *
+TALER_MERCHANT_orders_get2 (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ enum TALER_MERCHANT_YesNoAll paid,
+ enum TALER_MERCHANT_YesNoAll refunded,
+ enum TALER_MERCHANT_YesNoAll wired,
+ struct GNUNET_TIME_Absolute date,
+ uint64_t start_row,
+ int64_t delta,
+ struct GNUNET_TIME_Relative timeout,
+ TALER_MERCHANT_OrdersGetCallback cb,
+ void *cb_cls);
+
+
+/**
+ * Cancel GET /orders operation.
+ *
+ * @param pgh operation to cancel
+ */
+void
+TALER_MERCHANT_orders_get_cancel (
+ struct TALER_MERCHANT_OrdersGetHandle *pgh);
+
+
+/**
* Handle for a DELETE /orders/$ID operation.
*/
struct TALER_MERCHANT_OrderDeleteHandle;
diff --git a/src/include/taler_merchantdb_plugin.h b/src/include/taler_merchantdb_plugin.h
index c74b67c9..956c526a 100644
--- a/src/include/taler_merchantdb_plugin.h
+++ b/src/include/taler_merchantdb_plugin.h
@@ -218,6 +218,83 @@ struct TALER_MERCHANTDB_ProductDetails
};
+/**
+ * Possible values for a binary filter.
+ */
+enum TALER_MERCHANTDB_YesNoAll
+{
+ /**
+ * If condition is yes.
+ */
+ TALER_MERCHANTDB_YNA_YES = 1,
+
+ /**
+ * If condition is no.
+ */
+ TALER_MERCHANTDB_YNA_NO = 2,
+
+ /**
+ * Condition disabled.
+ */
+ TALER_MERCHANTDB_YNA_ALL = 3
+};
+
+
+/**
+ * Filter preferences.
+ */
+struct TALER_MERCHANTDB_OrderFilter
+{
+ /**
+ * Filter by payment status.
+ */
+ enum TALER_MERCHANTDB_YesNoAll paid;
+
+ /**
+ * Filter by refund status.
+ */
+ enum TALER_MERCHANTDB_YesNoAll refunded;
+
+ /**
+ * Filter by wire transfer status.
+ */
+ enum TALER_MERCHANTDB_YesNoAll wired;
+
+ /**
+ * Filter orders by date, exact meaning depends on @e delta.
+ */
+ struct GNUNET_TIME_Absolute date;
+
+ /**
+ * Filter orders by order serial number, exact meaning depends on @e delta.
+ */
+ uint64_t start_row;
+
+ /**
+ * takes value of the form N (-N), so that at most N values strictly older
+ * (younger) than start and date are returned.
+ */
+ int64_t delta;
+
+ /**
+ * Timeout for long-polling.
+ */
+ struct GNUNET_TIME_Relative timeout;
+
+};
+
+
+/**
+ * Typically called by `lookup_orders`.
+ *
+ * @param cls a `json_t *` JSON array to build
+ * @param order_id ID of the order
+ */
+typedef void
+(*TALER_MERCHANTDB_OrdersCallback)(void *cls,
+ const char *order_id);
+
+
/* **************** OLD: ******************** */
/**
@@ -628,13 +705,12 @@ struct TALER_MERCHANTDB_Plugin
const char *instance_id,
const char *order_id);
-
/**
* Retrieve order given its @a order_id and the @a instance_id.
*
* @param cls closure
* @param instance_id instance to obtain order of
- * @param order id order id used to perform the lookup
+ * @param order_id order id used to perform the lookup
* @param[out] contract_terms where to store the retrieved contract terms,
* NULL to only test if the order exists
* @return transaction status
@@ -645,6 +721,23 @@ struct TALER_MERCHANTDB_Plugin
const char *order_id,
json_t **contract_terms);
+ /**
+ * Retrieve orders given the @a instance_id.
+ *
+ * @param cls closure
+ * @param instance_id instance to obtain order of
+ * @param of filter to apply when looking up orders
+ * @param[out] contract_terms where to store the retrieved contract terms,
+ * NULL to only test if the order exists
+ * @return transaction status
+ */
+ enum GNUNET_DB_QueryStatus
+ (*lookup_orders)(void *cls,
+ const char *instance_id,
+ const struct TALER_MERCHANTDB_OrderFilter *of,
+ TALER_MERCHANTDB_OrdersCallback cb,
+ void *cb_cls);
+
/**
* Insert order into db.
diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am
index 82ea7677..2911c758 100644
--- a/src/lib/Makefile.am
+++ b/src/lib/Makefile.am
@@ -22,6 +22,7 @@ libtalermerchant_la_SOURCES = \
merchant_api_get_instances.c \
merchant_api_get_product.c \
merchant_api_get_products.c \
+ merchant_api_get_orders.c \
merchant_api_lock_product.c \
merchant_api_patch_instance.c \
merchant_api_patch_product.c \
diff --git a/src/lib/merchant_api_get_orders.c b/src/lib/merchant_api_get_orders.c
new file mode 100644
index 00000000..1b65b995
--- /dev/null
+++ b/src/lib/merchant_api_get_orders.c
@@ -0,0 +1,436 @@
+/*
+ This file is part of TALER
+ Copyright (C) 2014-2018, 2020 Taler Systems SA
+
+ TALER is free software; you can redistribute it and/or modify it under the
+ terms of the GNU Lesser General Public License as published by the Free Software
+ Foundation; either version 2.1, or (at your option) any later version.
+
+ TALER is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License along with
+ TALER; see the file COPYING.LGPL. If not, see
+ <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file lib/merchant_api_get_orders.c
+ * @brief Implementation of the GET /orders request of the merchant's HTTP API
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <curl/curl.h>
+#include <jansson.h>
+#include <microhttpd.h> /* just for HTTP status codes */
+#include <gnunet/gnunet_util_lib.h>
+#include <gnunet/gnunet_curl_lib.h>
+#include "taler_merchant_service.h"
+#include <taler/taler_json_lib.h>
+#include <taler/taler_signatures.h>
+
+
+/**
+ * Handle for a GET /orders operation.
+ */
+struct TALER_MERCHANT_OrdersGetHandle
+{
+ /**
+ * The url for this request.
+ */
+ char *url;
+
+ /**
+ * Handle for the request.
+ */
+ struct GNUNET_CURL_Job *job;
+
+ /**
+ * Function to call with the result.
+ */
+ TALER_MERCHANT_OrdersGetCallback cb;
+
+ /**
+ * Closure for @a cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Reference to the execution context.
+ */
+ struct GNUNET_CURL_Context *ctx;
+
+};
+
+
+/**
+ * Parse order information from @a ia.
+ *
+ * @param ia JSON array (or NULL!) with order data
+ * @param ogh operation handle
+ * @return #GNUNET_OK on success
+ */
+static int
+parse_orders (const json_t *ia,
+ struct TALER_MERCHANT_OrdersGetHandle *ogh)
+{
+ unsigned int oes_len = json_array_size (ia);
+ struct TALER_MERCHANT_OrderEntry oes[oes_len];
+ size_t index;
+ json_t *value;
+ int ret;
+
+ ret = GNUNET_OK;
+ json_array_foreach (ia, index, value) {
+ struct TALER_MERCHANT_OrderEntry *ie = &oes[index];
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_string ("order_id",
+ &ie->order_id),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (value,
+ spec,
+ NULL, NULL))
+ {
+ GNUNET_break_op (0);
+ ret = GNUNET_SYSERR;
+ continue;
+ }
+ if (GNUNET_SYSERR == ret)
+ break;
+ }
+ if (GNUNET_OK == ret)
+ {
+ struct TALER_MERCHANT_HttpResponse hr = {
+ .http_status = MHD_HTTP_OK
+ };
+
+ ogh->cb (ogh->cb_cls,
+ &hr,
+ oes_len,
+ oes);
+ ogh->cb = NULL; /* just to be sure */
+ }
+ return ret;
+}
+
+
+/**
+ * Function called when we're done processing the
+ * HTTP /orders request.
+ *
+ * @param cls the `struct TALER_MERCHANT_OrdersGetHandle`
+ * @param response_code HTTP response code, 0 on error
+ * @param json response body, NULL if not in JSON
+ */
+static void
+handle_get_orders_finished (void *cls,
+ long response_code,
+ const void *response)
+{
+ struct TALER_MERCHANT_OrdersGetHandle *ogh = cls;
+ const json_t *json = response;
+ struct TALER_MERCHANT_HttpResponse hr = {
+ .http_status = (unsigned int) response_code,
+ .reply = json
+ };
+
+ ogh->job = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Got /orders response with status code %u\n",
+ (unsigned int) response_code);
+ switch (response_code)
+ {
+ case MHD_HTTP_OK:
+ {
+ json_t *orders;
+ struct GNUNET_JSON_Specification spec[] = {
+ GNUNET_JSON_spec_json ("orders",
+ &orders),
+ GNUNET_JSON_spec_end ()
+ };
+
+ if (GNUNET_OK !=
+ GNUNET_JSON_parse (json,
+ spec,
+ NULL, NULL))
+ {
+ hr.http_status = 0;
+ hr.ec = TALER_EC_INVALID_RESPONSE;
+ }
+ else
+ {
+ if ( (! json_is_array (orders)) ||
+ (GNUNET_OK ==
+ parse_orders (orders,
+ ogh)) )
+ {
+ GNUNET_JSON_parse_free (spec);
+ TALER_MERCHANT_orders_get_cancel (ogh);
+ return;
+ }
+ else
+ {
+ hr.http_status = 0;
+ hr.ec = TALER_EC_INVALID_RESPONSE;
+ }
+ }
+ GNUNET_JSON_parse_free (spec);
+ break;
+ }
+ default:
+ /* unexpected response code */
+ hr.ec = TALER_JSON_get_error_code (json);
+ hr.hint = TALER_JSON_get_error_hint (json);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Unexpected response code %u/%d\n",
+ (unsigned int) response_code,
+ (int) hr.ec);
+ break;
+ }
+ ogh->cb (ogh->cb_cls,
+ &hr,
+ 0,
+ NULL);
+ TALER_MERCHANT_orders_get_cancel (ogh);
+}
+
+
+/**
+ * Make a GET /orders request.
+ *
+ * @param ctx the context
+ * @param backend_url HTTP base URL for the backend
+ * @param cb function to call with the backend's inventory information
+ * @param cb_cls closure for @a cb
+ * @return the request handle; NULL upon error
+ */
+struct TALER_MERCHANT_OrdersGetHandle *
+TALER_MERCHANT_orders_get (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ TALER_MERCHANT_OrdersGetCallback cb,
+ void *cb_cls)
+{
+ return TALER_MERCHANT_orders_get2 (ctx,
+ backend_url,
+ TALER_MERCHANT_YNA_ALL,
+ TALER_MERCHANT_YNA_ALL,
+ TALER_MERCHANT_YNA_ALL,
+ GNUNET_TIME_UNIT_FOREVER_ABS,
+ UINT64_MAX,
+ -20, /* default is most recent 20 entries */
+ GNUNET_TIME_UNIT_ZERO,
+ cb,
+ cb_cls);
+}
+
+
+/**
+ * Make a GET /orders request with filters.
+ *
+ * @param ctx the context
+ * @param backend_url HTTP base URL for the backend
+ * @param paid filter on payment status
+ * @param refunded filter on refund status
+ * @param wired filter on wire transfer status
+ * @param date range limit by date
+ * @param start_row range limit by order table row
+ * @param delta range from which @a date and @a start_row apply, positive
+ * to return delta items after the given limit(s), negative to
+ * return delta items before the given limit(s)
+ * @param timeout how long to wait (long polling) of zero results match the query
+ * @param cb function to call with the backend's inventory information
+ * @param cb_cls closure for @a cb
+ * @return the request handle; NULL upon error
+ */
+struct TALER_MERCHANT_OrdersGetHandle *
+TALER_MERCHANT_orders_get2 (
+ struct GNUNET_CURL_Context *ctx,
+ const char *backend_url,
+ enum TALER_MERCHANT_YesNoAll paid,
+ enum TALER_MERCHANT_YesNoAll refunded,
+ enum TALER_MERCHANT_YesNoAll wired,
+ struct GNUNET_TIME_Absolute date,
+ uint64_t start_row,
+ int64_t delta,
+ struct GNUNET_TIME_Relative timeout,
+ TALER_MERCHANT_OrdersGetCallback cb,
+ void *cb_cls)
+{
+ struct TALER_MERCHANT_OrdersGetHandle *ogh;
+ CURL *eh;
+ unsigned int timeout_ms = timeout.rel_value_us
+ / GNUNET_TIME_UNIT_MILLISECONDS.rel_value_us;
+
+ GNUNET_assert (NULL != backend_url);
+ if (0 == delta)
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ ogh = GNUNET_new (struct TALER_MERCHANT_OrdersGetHandle);
+ ogh->ctx = ctx;
+ ogh->cb = cb;
+ ogh->cb_cls = cb_cls;
+
+ /* build ogh->url with the various optional arguments */
+ {
+ struct GNUNET_Buffer buf = { 0 };
+ bool first = true;
+ /**
+ * Macro to append @a a and @a b to @a buf, using
+ * the right separators between key (@a a) and
+ * value (@a b). Uses "first" to decide between
+ * using "?" and "&" as the separator.
+ *
+ * @param a a key
+ * @param b a value
+ */
+#define APPEND(a,b) \
+ do { \
+ if (first) \
+ GNUNET_buffer_write_str (&buf, \
+ "?"); \
+ else \
+ GNUNET_buffer_write_str (&buf, \
+ "&"); \
+ first = false; \
+ GNUNET_buffer_write_str (&buf, (a)); \
+ GNUNET_buffer_write_str (&buf, "="); \
+ GNUNET_buffer_write_str (&buf, (b)); \
+ } while (0)
+
+ {
+ char *url;
+
+ url = TALER_url_join (backend_url,
+ "private/orders",
+ NULL);
+ if (NULL == url)
+ goto finished;
+ GNUNET_buffer_write_str (&buf,
+ url);
+ GNUNET_free (url);
+ }
+ if (TALER_MERCHANT_YNA_ALL != paid)
+ APPEND ("paid",
+ (TALER_MERCHANT_YNA_YES == paid) ? "yes" : "no");
+ if (TALER_MERCHANT_YNA_ALL != refunded)
+ APPEND ("refunded",
+ (TALER_MERCHANT_YNA_YES == refunded) ? "yes" : "no");
+ if (TALER_MERCHANT_YNA_ALL != wired)
+ APPEND ("wired",
+ (TALER_MERCHANT_YNA_YES == wired) ? "yes" : "no");
+ if (delta > 0)
+ {
+ if (0 != date.abs_value_us)
+ {
+ const char *str;
+
+ str = GNUNET_STRINGS_absolute_time_to_string (date);
+ APPEND ("date",
+ str);
+ }
+ if (0 != start_row)
+ {
+ char cbuf[30];
+
+ GNUNET_snprintf (cbuf,
+ sizeof (cbuf),
+ "%llu",
+ (unsigned long long) start_row);
+ APPEND ("start",
+ cbuf);
+ }
+ }
+ else
+ {
+ if (GNUNET_TIME_UNIT_FOREVER_ABS.abs_value_us != date.abs_value_us)
+ {
+ const char *str;
+
+ str = GNUNET_STRINGS_absolute_time_to_string (date);
+ APPEND ("date",
+ str);
+ }
+ if (UINT64_MAX != start_row)
+ {
+ char cbuf[30];
+
+ GNUNET_snprintf (cbuf,
+ sizeof (cbuf),
+ "%llu",
+ (unsigned long long) start_row);
+ APPEND ("start",
+ cbuf);
+ }
+ }
+ if (-20 != delta)
+ {
+ char cbuf[30];
+
+ GNUNET_snprintf (cbuf,
+ sizeof (cbuf),
+ "%lld",
+ (long long) delta);
+ APPEND ("delta",
+ cbuf);
+ }
+ if (0 != timeout_ms)
+ {
+ char cbuf[30];
+
+ GNUNET_snprintf (cbuf,
+ sizeof (cbuf),
+ "%llu",
+ (unsigned long long) timeout_ms);
+ APPEND ("timeout_ms",
+ cbuf);
+ }
+ ogh->url = GNUNET_buffer_reap_str (&buf);
+#undef APPEND
+ }
+
+finished:
+ if (NULL == ogh->url)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Could not construct request URL.\n");
+ GNUNET_free (ogh);
+ return NULL;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Requesting URL '%s'\n",
+ ogh->url);
+ eh = curl_easy_init ();
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_setopt (eh,
+ CURLOPT_URL,
+ ogh->url));
+ ogh->job = GNUNET_CURL_job_add (ctx,
+ eh,
+ GNUNET_YES,
+ &handle_get_orders_finished,
+ ogh);
+ return ogh;
+}
+
+
+/**
+ * Cancel /orders request. Must not be called by clients after
+ * the callback was invoked.
+ *
+ * @param ogh request to cancel.
+ */
+void
+TALER_MERCHANT_orders_get_cancel (
+ struct TALER_MERCHANT_OrdersGetHandle *ogh)
+{
+ if (NULL != ogh->job)
+ GNUNET_CURL_job_cancel (ogh->job);
+ GNUNET_free (ogh->url);
+ GNUNET_free (ogh);
+}