commit 6c3adf08b475542975ee3be2802b2429ea50fa35
parent 015c8f8ffe1b3357982c3f8af22231c2b88f2269
Author: Christian Grothoff <christian@grothoff.org>
Date: Sat, 23 May 2026 22:09:04 +0200
more work on order/contract confusion
Diffstat:
16 files changed, 760 insertions(+), 1053 deletions(-)
diff --git a/src/backend/taler-merchant-httpd_get-orders-ORDER_ID.c b/src/backend/taler-merchant-httpd_get-orders-ORDER_ID.c
@@ -154,6 +154,21 @@ struct GetOrderData
struct TALER_MERCHANT_Contract *contract_terms;
/**
+ * Order of the payment we are checking. NULL when we have a contract.
+ */
+ json_t *order_json;
+
+ /**
+ * Parsed order, NULL when parsing failed.
+ */
+ struct TALER_MERCHANT_Order *order;
+
+ /**
+ * Common terms from @e order or @e contract
+ */
+ const struct TALER_MERCHANT_CommonTerms *ct;
+
+ /**
* Total refunds granted for this payment. Only initialized
* if @e refunded is set to true.
*/
@@ -237,6 +252,11 @@ struct GetOrderData
bool contract_parsed;
/**
+ * Did we parse the order?
+ */
+ bool order_parsed;
+
+ /**
* Set to true if the refunds found in the DB have
* a different currency then the main contract.
*/
@@ -312,11 +332,23 @@ suspend_god (struct GetOrderData *god)
god->contract_terms_json = NULL;
god->contract_parsed = false;
}
+ if (NULL != god->order_json)
+ {
+ json_decref (god->order_json);
+ god->order_json = NULL;
+ god->order_parsed = false;
+ }
if (NULL != god->contract_terms)
{
TALER_MERCHANT_contract_free (god->contract_terms);
god->contract_terms = NULL;
}
+ if (NULL != god->order)
+ {
+ TALER_MERCHANT_order_free (god->order);
+ god->order = NULL;
+ }
+ god->ct = NULL; /* ensure not dangling */
GNUNET_assert (! god->suspended);
god->contract_parsed = false;
god->contract_match = false;
@@ -351,6 +383,17 @@ god_cleanup (void *cls)
TALER_MERCHANT_contract_free (god->contract_terms);
god->contract_terms = NULL;
}
+ if (NULL != god->order_json)
+ {
+ json_decref (god->order_json);
+ god->order_json = NULL;
+ }
+ if (NULL != god->order)
+ {
+ TALER_MERCHANT_order_free (god->order);
+ god->order = NULL;
+ }
+ god->ct = NULL; /* ensure not dangling */
if (NULL != god->session_eh)
{
TALER_MERCHANTDB_event_listen_cancel (god->session_eh);
@@ -585,6 +628,7 @@ phase_lookup_terms (struct GetOrderData *god)
/* Convert order_id to h_contract_terms */
TALER_MERCHANTDB_preflight (TMH_db);
GNUNET_assert (NULL == god->contract_terms_json);
+ GNUNET_assert (NULL == god->order_json);
{
enum GNUNET_DB_QueryStatus qs;
@@ -689,9 +733,7 @@ phase_lookup_terms (struct GetOrderData *god)
god->order_id,
&db_claim_token,
&unused,
- (NULL == god->contract_terms_json)
- ? &god->contract_terms_json
- : NULL);
+ &god->order_json);
if (0 > qs)
{
/* single, read-only SQL statements should never cause
@@ -736,21 +778,42 @@ static void
phase_parse_contract (struct GetOrderData *god)
{
GNUNET_break (NULL == god->contract_terms);
- god->contract_terms = TALER_MERCHANT_contract_parse (
- god->contract_terms_json,
- true);
-
- if (NULL == god->contract_terms)
+ GNUNET_break (NULL == god->order);
+ if (NULL != god->contract_terms_json)
{
- phase_fail (god,
- MHD_HTTP_INTERNAL_SERVER_ERROR,
- TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID,
- god->order_id);
- return;
+ god->contract_terms = TALER_MERCHANT_contract_parse (
+ god->contract_terms_json);
+ if (NULL == god->contract_terms)
+ {
+ phase_fail (god,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID,
+ god->order_id);
+ return;
+ }
+ god->contract_parsed = true;
+ god->ct = &god->contract_terms->common;
}
- god->contract_parsed = true;
+ if (NULL != god->order_json)
+ {
+ god->order = TALER_MERCHANT_order_parse (
+ god->order_json);
+ if (NULL == god->order)
+ {
+ phase_fail (god,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID,
+ god->order_id);
+ return;
+ }
+ god->order_parsed = true;
+ god->ct = &god->order->common;
+ }
+ GNUNET_assert ( (NULL != god->order) ||
+ (NULL != god->contract_terms) );
+
if ( (NULL != god->session_id) &&
- (NULL != god->contract_terms->fulfillment_url) &&
+ (NULL != god->ct->fulfillment_url) &&
(NULL == god->session_eh) )
{
struct TMH_SessionEventP session_eh = {
@@ -765,8 +828,8 @@ phase_parse_contract (struct GetOrderData *god)
GNUNET_CRYPTO_hash (god->session_id,
strlen (god->session_id),
&session_eh.h_session_id);
- GNUNET_CRYPTO_hash (god->contract_terms->fulfillment_url,
- strlen (god->contract_terms->fulfillment_url),
+ GNUNET_CRYPTO_hash (god->ct->fulfillment_url,
+ strlen (god->ct->fulfillment_url),
&session_eh.h_fulfillment_url);
god->session_eh
= TALER_MERCHANTDB_event_listen (
@@ -821,11 +884,10 @@ phase_check_client_access (struct GetOrderData *god)
if (! (god->token_match ||
god->contract_match) )
{
-
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Neither claim token nor contract matched\n");
/* Client has no rights to this order */
- if (NULL == god->contract_terms->public_reorder_url)
+ if (NULL == god->ct->public_reorder_url)
{
/* We cannot give the client a new order, just fail */
if (! GNUNET_is_zero (&god->h_contract_terms))
@@ -872,7 +934,7 @@ phase_check_client_access (struct GetOrderData *god)
MHD_add_response_header (
reply,
MHD_HTTP_HEADER_LOCATION,
- god->contract_terms->public_reorder_url));
+ god->ct->public_reorder_url));
ret = MHD_queue_response (god->sc.con,
MHD_HTTP_FOUND,
reply);
@@ -888,7 +950,7 @@ phase_check_client_access (struct GetOrderData *god)
MHD_HTTP_ACCEPTED,
GNUNET_JSON_pack_string (
"public_reorder_url",
- god->contract_terms->public_reorder_url)));
+ god->ct->public_reorder_url)));
return;
}
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
@@ -909,15 +971,22 @@ get_order_summary (const struct GetOrderData *god)
{
const char *language_pattern;
const char *ret;
+ json_t *terms;
- language_pattern = MHD_lookup_connection_value (god->sc.con,
- MHD_HEADER_KIND,
- MHD_HTTP_HEADER_ACCEPT_LANGUAGE);
+ if (NULL != god->contract_terms_json)
+ terms = god->contract_terms_json;
+ else
+ terms = god->order_json;
+ language_pattern = MHD_lookup_connection_value (
+ god->sc.con,
+ MHD_HEADER_KIND,
+ MHD_HTTP_HEADER_ACCEPT_LANGUAGE);
if (NULL == language_pattern)
language_pattern = "en";
- ret = json_string_value (TALER_JSON_extract_i18n (god->contract_terms_json,
- language_pattern,
- "summary"));
+ ret = json_string_value (TALER_JSON_extract_i18n (
+ terms,
+ language_pattern,
+ "summary"));
if (NULL == ret)
{
/* Upon order creation (and insertion into the database), the presence
@@ -958,7 +1027,6 @@ send_pay_request (struct GetOrderData *god,
suspend_god (god);
return true;
}
-
/* Check if resource_id has been paid for in the same session
* with another order_id.
*/
@@ -995,11 +1063,10 @@ send_pay_request (struct GetOrderData *god,
{
struct MHD_Response *reply;
- GNUNET_assert (NULL != god->contract_terms->fulfillment_url);
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Redirecting to already paid order %s via fulfillment URL %s\n",
already_paid_order_id,
- god->contract_terms->fulfillment_url);
+ god->ct->fulfillment_url);
reply = MHD_create_response_from_buffer (0,
NULL,
MHD_RESPMEM_PERSISTENT);
@@ -1014,7 +1081,7 @@ send_pay_request (struct GetOrderData *god,
MHD_add_response_header (
reply,
MHD_HTTP_HEADER_LOCATION,
- god->contract_terms->fulfillment_url));
+ god->ct->fulfillment_url));
{
ret = MHD_queue_response (god->sc.con,
MHD_HTTP_FOUND,
@@ -1080,7 +1147,7 @@ send_pay_request (struct GetOrderData *god,
taler_pay_uri),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_string ("fulfillment_url",
- god->contract_terms->fulfillment_url)),
+ god->ct->fulfillment_url)),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_string ("already_paid_order_id",
already_paid_order_id)));
@@ -1137,7 +1204,7 @@ static bool
phase_redirect_to_paid_order (struct GetOrderData *god)
{
if ( (NULL != god->session_id) &&
- (NULL != god->contract_terms->fulfillment_url) )
+ (NULL != god->ct->fulfillment_url) )
{
/* Check if client paid for this fulfillment article
already within this session, but using a different
@@ -1153,11 +1220,11 @@ phase_redirect_to_paid_order (struct GetOrderData *god)
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Running re-purchase detection for %s/%s\n",
god->session_id,
- god->contract_terms->fulfillment_url);
+ god->ct->fulfillment_url);
qs = TALER_MERCHANTDB_lookup_order_by_fulfillment (
TMH_db,
god->hc->instance->settings.id,
- god->contract_terms->fulfillment_url,
+ god->ct->fulfillment_url,
god->session_id,
TALER_EXCHANGE_YNA_NO != god->allow_refunded_for_repurchase,
&already_paid_order_id);
@@ -1304,7 +1371,8 @@ phase_check_refunded (struct GetOrderData *god)
struct TALER_Amount refund_amount;
const char *refund_currency;
- switch (god->contract_terms->version)
+ GNUNET_assert (NULL != god->contract_terms);
+ switch (god->ct->version)
{
case TALER_MERCHANT_CONTRACT_VERSION_0:
refund_amount = god->contract_terms->details.v0.brutto;
@@ -1483,8 +1551,7 @@ phase_return_status (struct GetOrderData *god)
MHD_HTTP_OK,
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_string ("fulfillment_url",
- god->contract_terms->fulfillment_url
- )),
+ god->ct->fulfillment_url)),
GNUNET_JSON_pack_bool ("refunded",
god->refunded),
GNUNET_JSON_pack_bool ("refund_pending",
@@ -1502,7 +1569,8 @@ phase_return_status (struct GetOrderData *god)
char *uri;
GNUNET_assert (NULL != god->contract_terms_json);
- uri = make_taler_refund_uri (god->contract_terms->merchant_base_url,
+ GNUNET_assert (NULL != god->contract_terms);
+ uri = make_taler_refund_uri (god->ct->merchant_base_url,
god->order_id);
if (NULL == uri)
{
@@ -1565,7 +1633,9 @@ phase_return_status (struct GetOrderData *god)
context = GNUNET_JSON_PACK (
GNUNET_JSON_pack_object_incref ("contract_terms",
- god->contract_terms_json),
+ NULL != god->contract_terms_json
+ ? god->contract_terms_json
+ : god->order_json),
GNUNET_JSON_pack_string ("order_summary",
get_order_summary (god)),
TALER_JSON_pack_amount ("refund_amount",
diff --git a/src/backend/taler-merchant-httpd_get-private-orders-ORDER_ID.c b/src/backend/taler-merchant-httpd_get-private-orders-ORDER_ID.c
@@ -263,6 +263,22 @@ struct GetOrderRequestContext
struct TALER_MERCHANT_Contract *contract_terms;
/**
+ * Order terms of the payment we are checking. NULL when we have
+ * a contract.
+ */
+ json_t *order_json;
+
+ /**
+ * Parsed order details, NULL when parsing failed or we have a contract.
+ */
+ struct TALER_MERCHANT_Order *order;
+
+ /**
+ * Common terms of @e order and @e contract.
+ */
+ const struct TALER_MERCHANT_CommonTerms *ct;
+
+ /**
* Claim token of the order.
*/
struct TALER_ClaimTokenP claim_token;
@@ -515,12 +531,26 @@ gorc_cleanup (void *cls)
}
if (NULL != gorc->contract_terms_json)
+ {
json_decref (gorc->contract_terms_json);
+ gorc->contract_terms_json = NULL;
+ }
+ if (NULL != gorc->order_json)
+ {
+ json_decref (gorc->order_json);
+ gorc->order_json = NULL;
+ }
if (NULL != gorc->contract_terms)
{
TALER_MERCHANT_contract_free (gorc->contract_terms);
gorc->contract_terms = NULL;
}
+ if (NULL != gorc->order)
+ {
+ TALER_MERCHANT_order_free (gorc->order);
+ gorc->order = NULL;
+ }
+ gorc->ct = NULL; /* avoid dangling pointer */
if (NULL != gorc->wire_details)
json_decref (gorc->wire_details);
if (NULL != gorc->refund_details)
@@ -595,7 +625,7 @@ phase_init (struct GetOrderRequestContext *gorc)
&resume_by_event,
gorc);
if ( (NULL != gorc->session_id) &&
- (NULL != gorc->contract_terms->fulfillment_url) )
+ (NULL != gorc->ct->fulfillment_url) )
{
struct TMH_SessionEventP session_eh = {
.header.size = htons (sizeof (session_eh)),
@@ -609,8 +639,8 @@ phase_init (struct GetOrderRequestContext *gorc)
GNUNET_CRYPTO_hash (gorc->session_id,
strlen (gorc->session_id),
&session_eh.h_session_id);
- GNUNET_CRYPTO_hash (gorc->contract_terms->fulfillment_url,
- strlen (gorc->contract_terms->fulfillment_url),
+ GNUNET_CRYPTO_hash (gorc->ct->fulfillment_url,
+ strlen (gorc->ct->fulfillment_url),
&session_eh.h_fulfillment_url);
gorc->session_eh
= TALER_MERCHANTDB_event_listen (
@@ -743,11 +773,30 @@ phase_parse_contract (struct GetOrderRequestContext *gorc)
{
struct TMH_HandlerContext *hc = gorc->hc;
- if (NULL == gorc->contract_terms)
+ if ( (NULL == gorc->order) &&
+ (NULL != gorc->order_json) )
+ {
+ gorc->order = TALER_MERCHANT_order_parse (
+ gorc->order_json);
+
+ if (NULL == gorc->order)
+ {
+ GNUNET_break (0);
+ phase_end (gorc,
+ TALER_MHD_reply_with_error (
+ gorc->sc.con,
+ MHD_HTTP_INTERNAL_SERVER_ERROR,
+ TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID,
+ hc->infix));
+ return;
+ }
+ gorc->ct = &gorc->order->common;
+ }
+ if ( (NULL == gorc->contract_terms) &&
+ (NULL != gorc->contract_terms_json) )
{
gorc->contract_terms = TALER_MERCHANT_contract_parse (
- gorc->contract_terms_json,
- true);
+ gorc->contract_terms_json);
if (NULL == gorc->contract_terms)
{
@@ -760,12 +809,16 @@ phase_parse_contract (struct GetOrderRequestContext *gorc)
hc->infix));
return;
}
+ gorc->ct = &gorc->contract_terms->common;
}
- switch (gorc->contract_terms->version)
+ switch (gorc->ct->version)
{
case TALER_MERCHANT_CONTRACT_VERSION_0:
- gorc->contract_amount = gorc->contract_terms->details.v0.brutto;
+ gorc->contract_amount
+ = (NULL != gorc->contract_terms)
+ ? gorc->contract_terms->details.v0.brutto
+ : gorc->order->details.v0.brutto;
break;
case TALER_MERCHANT_CONTRACT_VERSION_1:
if (gorc->choice_index >= 0)
@@ -782,9 +835,10 @@ phase_parse_contract (struct GetOrderRequestContext *gorc)
NULL));
return;
}
-
gorc->contract_amount =
- gorc->contract_terms->details.v1.choices[gorc->choice_index].amount;
+ (NULL != gorc->contract_terms)
+ ? gorc->contract_terms->details.v1.choices[gorc->choice_index].amount
+ : gorc->order->details.v1.choices[gorc->choice_index].amount;
}
else
{
@@ -792,7 +846,7 @@ phase_parse_contract (struct GetOrderRequestContext *gorc)
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Choice index %i for order %s is invalid or not yet available",
gorc->choice_index,
- gorc->contract_terms->order_id);
+ gorc->ct->order_id);
}
break;
default:
@@ -808,7 +862,7 @@ phase_parse_contract (struct GetOrderRequestContext *gorc)
}
}
- if ( (! gorc->order_only) &&
+ if ( (NULL != gorc->contract_terms) &&
(GNUNET_OK !=
TALER_JSON_contract_hash (gorc->contract_terms_json,
&gorc->h_contract_terms)) )
@@ -821,8 +875,10 @@ phase_parse_contract (struct GetOrderRequestContext *gorc)
NULL));
return;
}
- GNUNET_assert (NULL != gorc->contract_terms_json);
- GNUNET_assert (NULL != gorc->contract_terms);
+ GNUNET_assert ( (NULL != gorc->contract_terms_json) ||
+ (NULL != gorc->order_json) );
+ GNUNET_assert ( (NULL != gorc->contract_terms) ||
+ (NULL != gorc->order) );
gorc->phase++;
}
@@ -982,7 +1038,7 @@ phase_check_repurchase (struct GetOrderRequestContext *gorc)
json_t *reply;
if ( (gorc->paid) ||
- (NULL == gorc->contract_terms->fulfillment_url) ||
+ (NULL == gorc->ct->fulfillment_url) ||
(NULL == gorc->session_id) )
{
/* Repurchase cannot apply */
@@ -992,11 +1048,11 @@ phase_check_repurchase (struct GetOrderRequestContext *gorc)
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"Running re-purchase detection for %s/%s\n",
gorc->session_id,
- gorc->contract_terms->fulfillment_url);
+ gorc->ct->fulfillment_url);
qs = TALER_MERCHANTDB_lookup_order_by_fulfillment (
TMH_db,
hc->instance->settings.id,
- gorc->contract_terms->fulfillment_url,
+ gorc->ct->fulfillment_url,
gorc->session_id,
TALER_EXCHANGE_YNA_NO !=
gorc->allow_refunded_for_repurchase,
@@ -1018,7 +1074,7 @@ phase_check_repurchase (struct GetOrderRequestContext *gorc)
GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
"No already paid order for %s/%s\n",
gorc->session_id,
- gorc->contract_terms->fulfillment_url);
+ gorc->ct->fulfillment_url);
gorc->phase++;
return;
}
@@ -1062,7 +1118,7 @@ phase_check_repurchase (struct GetOrderRequestContext *gorc)
GNUNET_JSON_pack_string ("already_paid_order_id",
already_paid_order_id),
GNUNET_JSON_pack_string ("already_paid_fulfillment_url",
- gorc->contract_terms->fulfillment_url),
+ gorc->ct->fulfillment_url),
/* undefined for unpaid v1 contracts */
GNUNET_JSON_pack_allow_null (
TALER_JSON_pack_amount ("total_amount",
@@ -1072,11 +1128,11 @@ phase_check_repurchase (struct GetOrderRequestContext *gorc)
GNUNET_JSON_pack_object_incref ("proto_contract_terms",
gorc->contract_terms_json),
GNUNET_JSON_pack_string ("summary",
- gorc->contract_terms->summary),
+ gorc->ct->summary),
GNUNET_JSON_pack_timestamp ("pay_deadline",
- gorc->contract_terms->pay_deadline),
+ gorc->ct->pay_deadline),
GNUNET_JSON_pack_timestamp ("creation_time",
- gorc->contract_terms->timestamp));
+ gorc->ct->timestamp));
GNUNET_free (order_status_url);
GNUNET_free (taler_pay_uri);
@@ -1168,9 +1224,9 @@ phase_unpaid_finish (struct GetOrderRequestContext *gorc)
TALER_JSON_pack_amount ("total_amount",
&gorc->contract_amount)),
GNUNET_JSON_pack_string ("summary",
- gorc->contract_terms->summary),
+ gorc->ct->summary),
GNUNET_JSON_pack_timestamp ("creation_time",
- gorc->contract_terms->timestamp));
+ gorc->ct->timestamp));
check_reply (gorc,
reply);
json_decref (reply);
@@ -1584,7 +1640,7 @@ phase_check_local_transfers (struct GetOrderRequestContext *gorc)
TMH_notify_order_change (hc->instance,
TMH_OSF_PAID
| TMH_OSF_WIRED,
- gorc->contract_terms->timestamp,
+ gorc->ct->timestamp,
gorc->order_serial);
}
}
@@ -1630,7 +1686,7 @@ phase_reply_result (struct GetOrderRequestContext *gorc)
{
GNUNET_break (GNUNET_YES ==
TALER_amount_is_zero (&gorc->contract_amount));
- gorc->last_payment = gorc->contract_terms->timestamp;
+ gorc->last_payment = gorc->ct->timestamp;
}
{
json_t *reply;
diff --git a/src/backend/taler-merchant-httpd_get-private-orders.c b/src/backend/taler-merchant-httpd_get-private-orders.c
@@ -462,7 +462,7 @@ add_order (void *cls,
struct GNUNET_TIME_Timestamp creation_time)
{
struct TMH_PendingOrder *po = cls;
- json_t *contract_terms = NULL;
+ json_t *terms = NULL;
struct TALER_PrivateContractHashP h_contract_terms;
enum GNUNET_DB_QueryStatus qs;
char *order_id = NULL;
@@ -470,6 +470,7 @@ add_order (void *cls,
bool paid;
bool wired;
struct TALER_MERCHANT_Contract *contract = NULL;
+ struct TALER_MERCHANT_Order *order = NULL;
int16_t choice_index = -1;
struct ProcessRefundsClosure prc = {
.ec = TALER_EC_NONE
@@ -478,6 +479,7 @@ add_order (void *cls,
char amount_buf[128];
char refund_buf[128];
char pending_buf[128];
+ const struct TALER_MERCHANT_CommonTerms *ct = NULL;
/* Bail early if we already have an error */
if (TALER_EC_NONE != po->result)
@@ -522,7 +524,7 @@ add_order (void *cls,
po->instance_id,
order_id,
NULL,
- &contract_terms,
+ &terms,
&os,
&paid,
&wired,
@@ -530,7 +532,17 @@ add_order (void *cls,
NULL,
&choice_index);
if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
+ {
GNUNET_break (os == order_serial);
+ contract = TALER_MERCHANT_contract_parse (terms);
+ if (NULL == contract)
+ {
+ GNUNET_break (0);
+ po->result = TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID;
+ goto cleanup;
+ }
+ ct = &contract->common;
+ }
}
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
{
@@ -544,7 +556,18 @@ add_order (void *cls,
order_id,
NULL,
&unused,
- &contract_terms);
+ &terms);
+ if (GNUNET_DB_STATUS_SUCCESS_ONE_RESULT == qs)
+ {
+ order = TALER_MERCHANT_order_parse (terms);
+ if (NULL == order)
+ {
+ GNUNET_break (0);
+ po->result = TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID;
+ goto cleanup;
+ }
+ ct = &order->common;
+ }
}
if (GNUNET_DB_STATUS_SUCCESS_NO_RESULTS == qs)
{
@@ -560,20 +583,13 @@ add_order (void *cls,
goto cleanup;
}
- contract = TALER_MERCHANT_contract_parse (contract_terms,
- true);
- if (NULL == contract)
- {
- GNUNET_break (0);
- po->result = TALER_EC_MERCHANT_GENERIC_DB_CONTRACT_CONTENT_INVALID;
- goto cleanup;
- }
if (paid)
{
const struct TALER_Amount *brutto;
- switch (contract->version)
+ GNUNET_assert (NULL != contract);
+ switch (ct->version)
{
case TALER_MERCHANT_CONTRACT_VERSION_0:
brutto = &contract->details.v0.brutto;
@@ -617,17 +633,20 @@ add_order (void *cls,
}
if (0 > TALER_amount_cmp (&prc.total_refund_amount,
brutto) &&
- GNUNET_TIME_absolute_is_future (contract->refund_deadline.abs_time))
+ GNUNET_TIME_absolute_is_future (
+ contract->common.refund_deadline.abs_time))
refundable = true;
}
/* compute amount totals */
amount = NULL;
- switch (contract->version)
+ switch (ct->version)
{
case TALER_MERCHANT_CONTRACT_VERSION_0:
{
- amount = &contract->details.v0.brutto;
+ amount = (NULL != contract)
+ ? &contract->details.v0.brutto
+ : &order->details.v0.brutto;
if (TALER_amount_is_zero (amount) &&
(po->of.wired != TALER_EXCHANGE_YNA_ALL) )
@@ -659,11 +678,12 @@ add_order (void *cls,
case TALER_MERCHANT_CONTRACT_VERSION_1:
if (-1 == choice_index)
choice_index = 0; /* default choice */
- GNUNET_assert (choice_index < contract->details.v1.choices_len);
+ if (NULL != contract)
{
struct TALER_MERCHANT_ContractChoice *choice
= &contract->details.v1.choices[choice_index];
+ GNUNET_assert (choice_index < contract->details.v1.choices_len);
amount = &choice->amount;
/* Accumulate order total */
accumulate_total (po,
@@ -680,6 +700,19 @@ add_order (void *cls,
goto cleanup;
}
}
+ else
+ {
+ struct TALER_MERCHANT_OrderChoice *choice
+ = &order->details.v1.choices[choice_index];
+
+ GNUNET_assert (choice_index < order->details.v1.choices_len);
+ amount = &choice->amount;
+ /* Accumulate order total */
+ accumulate_total (po,
+ amount);
+ if (TALER_EC_NONE != po->result)
+ goto cleanup;
+ }
break;
default:
GNUNET_break (0);
@@ -709,7 +742,7 @@ add_order (void *cls,
po->pa,
GNUNET_JSON_PACK (
GNUNET_JSON_pack_string ("order_id",
- contract->order_id),
+ order_id),
GNUNET_JSON_pack_uint64 ("row_id",
order_serial),
GNUNET_JSON_pack_timestamp ("timestamp",
@@ -729,7 +762,7 @@ add_order (void *cls,
? &prc.pending_refund_amount
: NULL)),
GNUNET_JSON_pack_string ("summary",
- contract->summary),
+ ct->summary),
GNUNET_JSON_pack_bool ("refundable",
refundable),
GNUNET_JSON_pack_bool ("paid",
@@ -737,7 +770,7 @@ add_order (void *cls,
break;
case POF_CSV:
{
- size_t len = strlen (contract->summary);
+ size_t len = strlen (ct->summary);
size_t wpos = 0;
char *esummary;
struct tm *tm;
@@ -747,16 +780,16 @@ add_order (void *cls,
esummary = GNUNET_malloc (2 * len + 1);
for (size_t off = 0; off<len; off++)
{
- if ('"' == contract->summary[off])
+ if ('"' == ct->summary[off])
esummary[wpos++] = '"';
- esummary[wpos++] = contract->summary[off];
+ esummary[wpos++] = ct->summary[off];
}
t = GNUNET_TIME_timestamp_to_s (creation_time);
tm = localtime (&t);
GNUNET_buffer_write_fstr (
&po->csv,
"%s,%llu,%04u-%02u-%02u,%02u:%02u (%s),%llu,%s,%s,%s,\"%s\",%s,%s\r\n",
- contract->order_id,
+ order_id,
(unsigned long long) order_serial,
tm->tm_year + 1900,
tm->tm_mon + 1,
@@ -776,7 +809,7 @@ add_order (void *cls,
}
case POF_XML:
{
- char *esummary = TALER_escape_xml (contract->summary);
+ char *esummary = TALER_escape_xml (ct->summary);
char creation_time_s[128];
const struct tm *tm;
time_t tt;
@@ -797,7 +830,7 @@ add_order (void *cls,
"<Cell><Data ss:Type=\"String\">%s</Data></Cell>"
"<Cell ss:Formula=\"=%s()\"><Data ss:Type=\"Boolean\">%s</Data></Cell>"
"</Row>\n",
- contract->order_id,
+ order_id,
creation_time_s,
amount_buf,
paid ? refund_buf : "",
@@ -810,8 +843,13 @@ add_order (void *cls,
} /* end switch po->format */
cleanup:
- json_decref (contract_terms);
+ json_decref (terms);
GNUNET_free (order_id);
+ if (NULL != order)
+ {
+ TALER_MERCHANT_order_free (order);
+ order = NULL;
+ }
if (NULL != contract)
{
TALER_MERCHANT_contract_free (contract);
diff --git a/src/backend/taler-merchant-httpd_post-orders-ORDER_ID-pay.c b/src/backend/taler-merchant-httpd_post-orders-ORDER_ID-pay.c
@@ -1059,7 +1059,7 @@ batch_deposit_transaction (
dr->details.ok.deposit_timestamp,
&pc->check_contract.h_contract_terms,
eg->exchange_url,
- pc->check_contract.contract_terms->wire_deadline,
+ pc->check_contract.contract_terms->common.wire_deadline,
&dr->details.ok.accumulated_total_without_fee,
&eg->wire_fee,
&pc->check_contract.wm->h_wire,
@@ -1096,7 +1096,7 @@ batch_deposit_transaction (
&dc->deposit_fee,
&dc->refund_fee,
GNUNET_TIME_absolute_add (
- pc->check_contract.contract_terms->wire_deadline.abs_time,
+ pc->check_contract.contract_terms->common.wire_deadline.abs_time,
GNUNET_TIME_randomize (GNUNET_TIME_UNIT_MINUTES)));
if (qs < 0)
return qs;
@@ -1220,8 +1220,8 @@ notify_kyc_required (const struct ExchangeGroup *eg)
char *extra;
hws = GNUNET_STRINGS_data_to_string_alloc (
- &eg->pc->check_contract.contract_terms->h_wire,
- sizeof (eg->pc->check_contract.contract_terms->h_wire));
+ &eg->pc->check_contract.contract_terms->common.h_wire,
+ sizeof (eg->pc->check_contract.contract_terms->common.h_wire));
GNUNET_asprintf (&extra,
"%s %s",
hws,
@@ -1413,16 +1413,24 @@ do_batch_deposits (struct ExchangeGroup *eg)
all coins are done. */
{
struct TALER_EXCHANGE_DepositContractDetail dcd = {
- .wire_deadline = pc->check_contract.contract_terms->wire_deadline,
- .merchant_payto_uri = pc->check_contract.wm->payto_uri,
+ .wire_deadline
+ = pc->check_contract.contract_terms->common.wire_deadline,
+ .merchant_payto_uri
+ = pc->check_contract.wm->payto_uri,
.extra_wire_subject_metadata
= pc->check_contract.wm->extra_wire_subject_metadata,
- .wire_salt = pc->check_contract.wm->wire_salt,
- .h_contract_terms = pc->check_contract.h_contract_terms,
- .wallet_data_hash = pc->parse_wallet_data.h_wallet_data,
- .wallet_timestamp = pc->check_contract.contract_terms->timestamp,
- .merchant_pub = hc->instance->merchant_pub,
- .refund_deadline = pc->check_contract.contract_terms->refund_deadline
+ .wire_salt
+ = pc->check_contract.wm->wire_salt,
+ .h_contract_terms
+ = pc->check_contract.h_contract_terms,
+ .wallet_data_hash
+ = pc->parse_wallet_data.h_wallet_data,
+ .wallet_timestamp
+ = pc->check_contract.contract_terms->common.timestamp,
+ .merchant_pub
+ = hc->instance->merchant_pub,
+ .refund_deadline
+ = pc->check_contract.contract_terms->common.refund_deadline
};
/* Collect up to TALER_MAX_COINS eligible coins for this batch */
struct TALER_EXCHANGE_CoinDepositDetail cdds[group_size];
@@ -1674,7 +1682,7 @@ process_pay_with_keys (
is_age_restricted_denom = (0 != denom_details->key.age_mask.bits);
if (is_age_restricted_denom &&
- (0 < pc->check_contract.contract_terms->minimum_age))
+ (0 < pc->check_contract.contract_terms->common.minimum_age))
{
/* Minimum age given and restricted coin provided: We need to verify the
* minimum age */
@@ -1698,7 +1706,7 @@ process_pay_with_keys (
if (GNUNET_OK !=
TALER_age_commitment_verify (
&dc->age_commitment,
- pc->check_contract.contract_terms->minimum_age,
+ pc->check_contract.contract_terms->common.minimum_age,
&dc->minimum_age_sig))
code = TALER_EC_MERCHANT_POST_ORDERS_ID_PAY_AGE_VERIFICATION_FAILED;
AGE_FAIL:
@@ -1929,11 +1937,11 @@ phase_success_response (struct PayContext *pc)
/* Build the response */
pos_confirmation = (NULL == pc->check_contract.pos_key)
? NULL
- : TALER_build_pos_confirmation (pc->check_contract.pos_key,
- pc->check_contract.pos_alg,
- &pc->validate_tokens.brutto,
- pc->check_contract.contract_terms->timestamp
- );
+ : TALER_build_pos_confirmation (
+ pc->check_contract.pos_key,
+ pc->check_contract.pos_alg,
+ &pc->validate_tokens.brutto,
+ pc->check_contract.contract_terms->common.timestamp);
pay_end (pc,
TALER_MHD_REPLY_JSON_PACK (
pc->connection,
@@ -1996,7 +2004,7 @@ phase_payment_notification (struct PayContext *pc)
0);
}
if ( (NULL != pc->parse_pay.session_id) &&
- (NULL != pc->check_contract.contract_terms->fulfillment_url) )
+ (NULL != pc->check_contract.contract_terms->common.fulfillment_url) )
{
struct TMH_SessionEventP session_eh = {
.header.size = htons (sizeof (session_eh)),
@@ -2007,14 +2015,14 @@ phase_payment_notification (struct PayContext *pc)
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Notifying clients about session change to %s for %s\n",
pc->parse_pay.session_id,
- pc->check_contract.contract_terms->fulfillment_url);
+ pc->check_contract.contract_terms->common.fulfillment_url);
GNUNET_CRYPTO_hash (pc->parse_pay.session_id,
strlen (pc->parse_pay.session_id),
&session_eh.h_session_id);
- GNUNET_CRYPTO_hash (pc->check_contract.contract_terms->fulfillment_url,
- strlen (pc->check_contract.contract_terms->
- fulfillment_url),
- &session_eh.h_fulfillment_url);
+ GNUNET_CRYPTO_hash (
+ pc->check_contract.contract_terms->common.fulfillment_url,
+ strlen (pc->check_contract.contract_terms->common.fulfillment_url),
+ &session_eh.h_fulfillment_url);
TALER_MERCHANTDB_event_notify (TMH_db,
&session_eh.header,
NULL,
@@ -2396,10 +2404,10 @@ phase_compute_money_pots (struct PayContext *pc)
TALER_amount_set_zero (pc->parse_pay.dc[0].cdd.amount.currency,
&assigned));
GNUNET_assert (NULL != contract);
- for (size_t i = 0; i<contract->products_len; i++)
+ for (size_t i = 0; i<contract->common.products_len; i++)
{
const struct TALER_MERCHANT_ProductSold *product
- = &contract->products[i];
+ = &contract->common.products[i];
const struct TALER_Amount *price = NULL;
/* find price in the right currency */
@@ -2460,14 +2468,14 @@ phase_compute_money_pots (struct PayContext *pc)
}
if ( (! TALER_amount_is_zero (&left)) &&
- (0 != contract->default_money_pot) )
+ (0 != contract->common.default_money_pot) )
{
GNUNET_log (GNUNET_ERROR_TYPE_INFO,
"Computing money pot %llu increment as %s\n",
- (unsigned long long) contract->default_money_pot,
+ (unsigned long long) contract->common.default_money_pot,
TALER_amount2s (&left));
increment_pot (pc,
- contract->default_money_pot,
+ contract->common.default_money_pot,
&left);
}
}
@@ -3192,10 +3200,11 @@ phase_execute_pay_transaction (struct PayContext *pc)
}
}
- TMH_notify_order_change (hc->instance,
- TMH_OSF_CLAIMED | TMH_OSF_PAID,
- pc->check_contract.contract_terms->timestamp,
- pc->check_contract.order_serial);
+ TMH_notify_order_change (
+ hc->instance,
+ TMH_OSF_CLAIMED | TMH_OSF_PAID,
+ pc->check_contract.contract_terms->common.timestamp,
+ pc->check_contract.order_serial);
{
enum GNUNET_DB_QueryStatus qs;
json_t *jhook;
@@ -3613,8 +3622,8 @@ handle_output_token (struct PayContext *pc,
TMH_db,
pc->hc->instance->settings.id,
family->slug,
- pc->check_contract.contract_terms->timestamp,
- pc->check_contract.contract_terms->pay_deadline,
+ pc->check_contract.contract_terms->common.timestamp,
+ pc->check_contract.contract_terms->common.pay_deadline,
&details);
switch (qs)
{
@@ -3637,9 +3646,9 @@ handle_output_token (struct PayContext *pc,
"Token-family key for %s not found at [%llu,%llu]\n",
family->slug,
(unsigned long long)
- pc->check_contract.contract_terms->timestamp.abs_time.abs_value_us,
+ pc->check_contract.contract_terms->common.timestamp.abs_time.abs_value_us,
(unsigned long long)
- pc->check_contract.contract_terms->pay_deadline.abs_time.abs_value_us
+ pc->check_contract.contract_terms->common.pay_deadline.abs_time.abs_value_us
);
GNUNET_break (0);
pay_end (pc,
@@ -3837,7 +3846,7 @@ phase_validate_tokens (struct PayContext *pc)
/* We haven't seen a donau output yet. */
pc->validate_tokens.donau_output_index = -1;
- switch (pc->check_contract.contract_terms->version)
+ switch (pc->check_contract.contract_terms->common.version)
{
case TALER_MERCHANT_CONTRACT_VERSION_0:
/* No tokens to validate */
@@ -4175,7 +4184,7 @@ append_output_token_sig (void *cls,
0,
sizeof (out));
GNUNET_assert (TALER_MERCHANT_CONTRACT_VERSION_1 ==
- pc->check_contract.contract_terms->version);
+ pc->check_contract.contract_terms->common.version);
choice = &pc->check_contract.contract_terms->details.v1
.choices[pc->parse_wallet_data.choice_index];
output = &choice->outputs[pc->output_index_gen];
@@ -4374,15 +4383,16 @@ phase_check_contract (struct PayContext *pc)
TALER_MERCHANT_contract_free (pc->check_contract.contract_terms);
pc->check_contract.contract_terms = NULL;
}
- qs = TALER_MERCHANTDB_lookup_contract_terms2 (TMH_db,
- pc->hc->instance->settings.id,
- pc->order_id,
- &pc->check_contract.contract_terms_json,
- &pc->check_contract.order_serial,
- &paid,
- NULL,
- &pc->check_contract.pos_key,
- &pc->check_contract.pos_alg);
+ qs = TALER_MERCHANTDB_lookup_contract_terms2 (
+ TMH_db,
+ pc->hc->instance->settings.id,
+ pc->order_id,
+ &pc->check_contract.contract_terms_json,
+ &pc->check_contract.order_serial,
+ &paid,
+ NULL,
+ &pc->check_contract.pos_key,
+ &pc->check_contract.pos_alg);
if (0 > qs)
{
/* single, read-only SQL statements should never cause
@@ -4432,8 +4442,7 @@ phase_check_contract (struct PayContext *pc)
as later phases need it. */
pc->check_contract.contract_terms = TALER_MERCHANT_contract_parse (
- pc->check_contract.contract_terms_json,
- true);
+ pc->check_contract.contract_terms_json);
if (NULL == pc->check_contract.contract_terms)
{
@@ -4463,7 +4472,7 @@ phase_check_contract (struct PayContext *pc)
/* Check fundamentals */
{
- switch (pc->check_contract.contract_terms->version)
+ switch (pc->check_contract.contract_terms->common.version)
{
case TALER_MERCHANT_CONTRACT_VERSION_0:
{
@@ -4530,11 +4539,10 @@ phase_check_contract (struct PayContext *pc)
}
}
- if (GNUNET_TIME_timestamp_cmp (pc->check_contract.contract_terms->
- wire_deadline,
- <,
- pc->check_contract.contract_terms->
- refund_deadline))
+ if (GNUNET_TIME_timestamp_cmp (
+ pc->check_contract.contract_terms->common.wire_deadline,
+ <,
+ pc->check_contract.contract_terms->common.refund_deadline))
{
/* This should already have been checked when creating the order! */
GNUNET_break (0);
@@ -4546,8 +4554,8 @@ phase_check_contract (struct PayContext *pc)
NULL));
return;
}
- if (GNUNET_TIME_absolute_is_past (pc->check_contract.contract_terms->
- pay_deadline.abs_time))
+ if (GNUNET_TIME_absolute_is_past (
+ pc->check_contract.contract_terms->common.pay_deadline.abs_time))
{
/* too late */
pay_end (pc,
@@ -4564,8 +4572,10 @@ phase_check_contract (struct PayContext *pc)
struct TMH_WireMethod *wm;
wm = pc->hc->instance->wm_head;
- while (0 != GNUNET_memcmp (&pc->check_contract.contract_terms->h_wire,
- &wm->h_wire))
+ while (0 !=
+ GNUNET_memcmp (
+ &pc->check_contract.contract_terms->common.h_wire,
+ &wm->h_wire))
wm = wm->next;
if (NULL == wm)
{
diff --git a/src/backend/taler-merchant-httpd_post-private-orders.c b/src/backend/taler-merchant-httpd_post-private-orders.c
@@ -493,7 +493,7 @@ struct OrderContext
* from by selecting the respective index when signing the deposit
* confirmation.
*/
- struct TALER_MERCHANT_ContractChoice *choices;
+ struct TALER_MERCHANT_OrderChoice *choices;
/**
* Length of the @e choices array.
@@ -972,7 +972,7 @@ clean_order (void *cls)
}
for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
{
- TALER_MERCHANT_contract_choice_free (&oc->parse_choices.choices[i]);
+ TALER_MERCHANT_order_choice_free (&oc->parse_choices.choices[i]);
}
GNUNET_array_grow (oc->parse_choices.choices,
oc->parse_choices.choices_len,
@@ -2223,11 +2223,9 @@ output_contract_choices (struct OrderContext *oc)
oc->set_max_fee.details.v1.max_fees[i];
GNUNET_assert (0 == json_array_append_new (
choices,
- TALER_MERCHANT_json_from_contract_choice (
- &oc->parse_choices.choices[i],
- false)));
+ TALER_MERCHANT_json_from_order_choice (
+ &oc->parse_choices.choices[i])));
}
-
return choices;
}
@@ -3627,7 +3625,7 @@ add_donau_url (void *cls,
*/
static bool
add_donau_output (struct OrderContext *oc,
- struct TALER_MERCHANT_ContractOutput *output)
+ struct TALER_MERCHANT_OrderOutput *output)
{
enum GNUNET_DB_QueryStatus qs;
@@ -3696,7 +3694,7 @@ phase_parse_choices (struct OrderContext *oc)
json_array_size (jchoices));
for (unsigned int i = 0; i<oc->parse_choices.choices_len; i++)
{
- struct TALER_MERCHANT_ContractChoice *choice
+ struct TALER_MERCHANT_OrderChoice *choice
= &oc->parse_choices.choices[i];
const char *error_name;
unsigned int error_line;
@@ -3797,15 +3795,15 @@ phase_parse_choices (struct OrderContext *oc)
size_t idx;
json_array_foreach ((json_t *) jinputs, idx, jinput)
{
- struct TALER_MERCHANT_ContractInput input = {
+ struct TALER_MERCHANT_OrderInput input = {
.details.token.count = 1
};
if (GNUNET_OK !=
- TALER_MERCHANT_parse_choice_input ((json_t *) jinput,
- &input,
- idx,
- true))
+ TALER_MERCHANT_parse_order_choice_input (
+ (json_t *) jinput,
+ &input,
+ idx))
{
GNUNET_break_op (0);
reply_with_error (oc,
@@ -3853,15 +3851,15 @@ phase_parse_choices (struct OrderContext *oc)
size_t idx;
json_array_foreach ((json_t *) joutputs, idx, joutput)
{
- struct TALER_MERCHANT_ContractOutput output = {
+ struct TALER_MERCHANT_OrderOutput output = {
.details.token.count = 1
};
if (GNUNET_OK !=
- TALER_MERCHANT_parse_choice_output ((json_t *) joutput,
- &output,
- idx,
- true))
+ TALER_MERCHANT_parse_order_choice_output (
+ (json_t *) joutput,
+ &output,
+ idx))
{
reply_with_error (oc,
MHD_HTTP_BAD_REQUEST,
@@ -3877,6 +3875,8 @@ phase_parse_choices (struct OrderContext *oc)
break;
case TALER_MERCHANT_CONTRACT_OUTPUT_TYPE_DONATION_RECEIPT:
output.details.donation_receipt.amount = choice->amount;
+ // FIXME: This is also already a transformation,
+ // not reflected in the "Order" type!
if (! add_donau_output (oc,
&output))
{
@@ -3895,6 +3895,12 @@ phase_parse_choices (struct OrderContext *oc)
if (0 == output.details.token.valid_at.abs_time.abs_value_us)
output.details.token.valid_at
= GNUNET_TIME_timestamp_get ();
+ // FIXME: This is another transformation,
+ // not reflected in the "Order" type!
+ // => need yet another type for the data that is
+ // actually POSTed to this endpoint!
+ // (Note: the 'metadata' is another one that
+ // is currently *wrong*!)
if (GNUNET_OK !=
add_output_token_family (oc,
output.details.token.token_family_slug,
diff --git a/src/backend/taler-merchant-httpd_post-templates-TEMPLATE_ID.c b/src/backend/taler-merchant-httpd_post-templates-TEMPLATE_ID.c
@@ -1390,7 +1390,7 @@ handle_phase_compute_price (struct UseContext *uc)
for (size_t i = 0; i < tcp->choices_len; i++)
{
/* Make deep copy, we're going to MODIFY it! */
- struct TALER_MERCHANT_ContractChoice choice
+ struct TALER_MERCHANT_OrderChoice choice
= tcp->choices[i];
choice.no_tip = uc->parse_request.no_tip;
@@ -1417,8 +1417,7 @@ handle_phase_compute_price (struct UseContext *uc)
GNUNET_assert (0 ==
json_array_append_new (
choices,
- TALER_MERCHANT_json_from_contract_choice (&choice,
- true)));
+ TALER_MERCHANT_json_from_order_choice (&choice)));
}
if (0 == json_array_size (choices))
{
diff --git a/src/include/taler/taler_merchant_util.h b/src/include/taler/taler_merchant_util.h
@@ -1337,10 +1337,21 @@ struct TALER_MERCHANT_MetaData
/**
- * Struct to hold contract terms.
+ * Struct to hold terms common to both orders and contracts.
*/
-struct TALER_MERCHANT_Contract
+struct TALER_MERCHANT_CommonTerms
{
+
+ /**
+ * Merchant public key.
+ */
+ struct TALER_MerchantPublicKeyP merchant_pub;
+
+ /**
+ * The hash of the merchant instance's wire details.
+ */
+ struct TALER_MerchantWireHashP h_wire;
+
/**
* URL where the same contract could be ordered again (if available).
*/
@@ -1359,7 +1370,7 @@ struct TALER_MERCHANT_Contract
/**
* Metadata about the merchant.
*/
- struct TALER_MERCHANT_Metadata merchant;
+ struct TALER_MERCHANT_MetaData merchant;
/**
* Summary of the contract.
@@ -1389,9 +1400,26 @@ struct TALER_MERCHANT_Contract
json_t *fulfillment_message_i18n;
/**
- * Length of the @e products array.
+ * Wire transfer method identifier for the wire method associated with
+ * @e h_wire.
*/
- size_t products_len;
+ char *wire_method;
+
+ /**
+ * Exchanges that the merchant accepts even if it does not accept any auditors that audit them.
+ * TODO: appropriate type
+ */
+ json_t *exchanges;
+
+ /**
+ * Delivery location.
+ */
+ json_t *delivery_location;
+
+ /**
+ * Extra data that is only interpreted by the merchant frontend.
+ */
+ json_t *extra;
/**
* Array of products that are part of the purchase.
@@ -1399,6 +1427,11 @@ struct TALER_MERCHANT_Contract
struct TALER_MERCHANT_ProductSold *products;
/**
+ * Length of the @e products array.
+ */
+ size_t products_len;
+
+ /**
* Timestamp of the contract.
*/
struct GNUNET_TIME_Timestamp timestamp;
@@ -1437,31 +1470,36 @@ struct TALER_MERCHANT_Contract
struct GNUNET_TIME_Timestamp max_pickup_time;
/**
- * Merchant public key.
+ * Default money pot to use for this product, applies to the
+ * amount remaining that was not claimed by money pots of
+ * products or taxes. Not useful to wallets, only for
+ * merchant-internal accounting. If zero, the remaining
+ * account is simply not accounted for in any money pot.
*/
- struct TALER_MerchantPublicKeyP merchant_pub;
+ uint64_t default_money_pot;
/**
- * The hash of the merchant instance's wire details.
+ * Specified version of the contract.
*/
- struct TALER_MerchantWireHashP h_wire;
+ enum TALER_MERCHANT_ContractVersion version;
/**
- * Wire transfer method identifier for the wire method associated with
- * @e h_wire.
+ * Minimum age the buyer must have (in years).
*/
- char *wire_method;
+ uint8_t minimum_age;
- /**
- * Exchanges that the merchant accepts even if it does not accept any auditors that audit them.
- * TODO: appropriate type
- */
- json_t *exchanges;
+};
+
+/**
+ * Struct to hold contract terms.
+ */
+struct TALER_MERCHANT_Contract
+{
/**
- * Delivery location.
+ * Terms common with contracts and orders.
*/
- json_t *delivery_location;
+ struct TALER_MERCHANT_CommonTerms common;
/**
* Nonce generated by the wallet and echoed by the merchant
@@ -1470,30 +1508,6 @@ struct TALER_MERCHANT_Contract
char *nonce;
/**
- * Extra data that is only interpreted by the merchant frontend.
- */
- json_t *extra;
-
- /**
- * Minimum age the buyer must have (in years).
- */
- uint8_t minimum_age;
-
- /**
- * Default money pot to use for this product, applies to the
- * amount remaining that was not claimed by money pots of
- * products or taxes. Not useful to wallets, only for
- * merchant-internal accounting. If zero, the remaining
- * account is simply not accounted for in any money pot.
- */
- uint64_t default_money_pot;
-
- /**
- * Specified version of the contract.
- */
- enum TALER_MERCHANT_ContractVersion version;
-
- /**
* Details depending on the @e version.
*/
union
@@ -1570,151 +1584,11 @@ struct TALER_MERCHANT_Contract
*/
struct TALER_MERCHANT_Order
{
- /**
- * URL where the same order could be ordered again (if available).
- */
- char *public_reorder_url;
-
- /**
- * Our order ID.
- */
- char *order_id;
-
- /**
- * Merchant base URL.
- */
- char *merchant_base_url;
-
- /**
- * Metadata about the merchant.
- */
- struct TALER_MERCHANT_Metadata merchant;
-
- /**
- * Summary of the contract.
- */
- char *summary;
-
- /**
- * Internationalized summary.
- */
- json_t *summary_i18n;
-
- /**
- * URL that will show that the contract was successful
- * after it has been paid for.
- */
- char *fulfillment_url;
-
- /**
- * Message shown to the customer after paying for the contract.
- * Either fulfillment_url or fulfillment_message must be specified.
- */
- char *fulfillment_message;
-
- /**
- * Map from IETF BCP 47 language tags to localized fulfillment messages.
- */
- json_t *fulfillment_message_i18n;
/**
- * Length of the @e products array.
- */
- size_t products_len;
-
- /**
- * Array of products that are part of the purchase.
- */
- struct TALER_MERCHANT_ProductSold *products;
-
- /**
- * Timestamp of the contract.
- */
- struct GNUNET_TIME_Timestamp timestamp;
-
- /**
- * Deadline for refunds.
- */
- struct GNUNET_TIME_Timestamp refund_deadline;
-
- /**
- * Specifies for how long the wallet should try to get an
- * automatic refund for the purchase.
- */
- struct GNUNET_TIME_Relative auto_refund;
-
- /**
- * Payment deadline.
- */
- struct GNUNET_TIME_Timestamp pay_deadline;
-
- /**
- * Wire transfer deadline.
- */
- struct GNUNET_TIME_Timestamp wire_deadline;
-
- /**
- * Delivery date.
- */
- struct GNUNET_TIME_Timestamp delivery_date;
-
- /**
- * Latest time until which the good or service may be
- * picked up by the customer. This is usually for digital
- * goods where the customer has a finite window for downloading.
- */
- struct GNUNET_TIME_Timestamp max_pickup_time;
-
- /**
- * Merchant public key.
- */
- struct TALER_MerchantPublicKeyP merchant_pub;
-
- /**
- * The hash of the merchant instance's wire details.
- */
- struct TALER_MerchantWireHashP h_wire;
-
- /**
- * Wire transfer method identifier for the wire method associated with
- * @e h_wire.
- */
- char *wire_method;
-
- /**
- * Exchanges that the merchant accepts even if it does not accept any auditors that audit them.
- * TODO: appropriate type
- */
- json_t *exchanges;
-
- /**
- * Delivery location.
- */
- json_t *delivery_location;
-
- /**
- * Extra data that is only interpreted by the merchant frontend.
- */
- json_t *extra;
-
- /**
- * Minimum age the buyer must have (in years).
+ * Terms common with contracts and orders.
*/
- uint8_t minimum_age;
-
- /**
- * Default money pot to use for this product, applies to the
- * amount remaining that was not claimed by money pots of
- * products or taxes. Not useful to wallets, only for
- * merchant-internal accounting. If zero, the remaining
- * account is simply not accounted for in any money pot.
- */
- uint64_t default_money_pot;
-
- /**
- * Specified version of the contract.
- */
- enum TALER_MERCHANT_ContractVersion version;
+ struct TALER_MERCHANT_CommonTerms common;
/**
* Details depending on the @e version.
@@ -1789,13 +1663,49 @@ struct TALER_MERCHANT_Order
/**
+ * Parse common terms (of orders and contracts) in @a input to
+ * initialize @a ct.
+ *
+ * @param[out] ct common terms to initialize
+ * @param[in] input JSON object containing contract terms
+ * @return true on success, false if @a input is malformed
+ */
+bool
+TALER_MERCHANT_common_terms_parse (
+ struct TALER_MERCHANT_CommonTerms *ct,
+ json_t *input);
+
+
+/**
+ * Release memory in @a ct, but not @a ct itself.
+ *
+ * @param[in,out] ct common terms to clean up
+ */
+void
+TALER_MERCHANT_common_terms_free (
+ struct TALER_MERCHANT_CommonTerms *ct);
+
+
+/**
+ * Get JSON representation of merchant details.
+ *
+ * @param[in] merchant metadata to serialize
+ * @return JSON object with merchant details; NULL on error
+ */
+json_t *
+TALER_MERCHANT_metadata_to_json (
+ const struct TALER_MERCHANT_MetaData *merchant);
+
+
+/**
* Parse JSON contract terms in @a input.
*
* @param[in] input JSON object containing contract terms
* @return parsed contract terms; NULL if @a input is malformed
*/
struct TALER_MERCHANT_Contract *
-TALER_MERCHANT_contract_parse (json_t *input);
+TALER_MERCHANT_contract_parse (
+ json_t *input);
/**
@@ -1805,7 +1715,8 @@ TALER_MERCHANT_contract_parse (json_t *input);
* @return parsed contract terms; NULL if @a input is malformed
*/
struct TALER_MERCHANT_Order *
-TALER_MERCHANT_order_parse (json_t *input);
+TALER_MERCHANT_order_parse (
+ json_t *input);
/**
@@ -1817,8 +1728,9 @@ TALER_MERCHANT_order_parse (json_t *input);
* @return spec for parsing a contract input type
*/
struct GNUNET_JSON_Specification
-TALER_MERCHANT_json_spec_cit (const char *name,
- enum TALER_MERCHANT_ContractInputType *cit);
+TALER_MERCHANT_json_spec_cit (
+ const char *name,
+ enum TALER_MERCHANT_ContractInputType *cit);
/**
@@ -1836,6 +1748,19 @@ TALER_MERCHANT_spec_contract_version (
/**
+ * Provide specification to parse given JSON object to merchant details in the
+ * order terms. All fields from @a order are copied.
+ *
+ * @param name name of the merchant details field in the JSON
+ * @param[out] order where the merchant details have to be written
+ */
+struct GNUNET_JSON_Specification
+TALER_MERCHANT_spec_merchant_details (
+ const char *name,
+ struct TALER_MERCHANT_MetaData *merchant);
+
+
+/**
* Provide specification to parse given JSON array to order
* choices. All fields from @a choices elements are copied.
*
@@ -1866,6 +1791,21 @@ TALER_MERCHANT_spec_contract_choices (
/**
+ * Provide specification to parse given JSON array to token families in the
+ * contract terms. All fields from @a families items are copied.
+ *
+ * @param name name of the token families field in the JSON
+ * @param[out] families where the token families array has to be written
+ * @param[out] families_len length of the @a families array
+ */
+struct GNUNET_JSON_Specification
+TALER_MERCHANT_spec_token_families (
+ const char *name,
+ struct TALER_MERCHANT_ContractTokenFamily **families,
+ unsigned int *families_len);
+
+
+/**
* Parse JSON contract terms choice input.
*
* @param[in] root JSON object containing choice input
@@ -1904,7 +1844,8 @@ TALER_MERCHANT_parse_order_choice_input (
* entries are valid Taxes.
*/
bool
-TALER_MERCHANT_taxes_array_valid (const json_t *taxes);
+TALER_MERCHANT_taxes_array_valid (
+ const json_t *taxes);
/**
@@ -1916,8 +1857,9 @@ TALER_MERCHANT_taxes_array_valid (const json_t *taxes);
* @return #GNUNET_OK on success
*/
enum GNUNET_GenericReturnValue
-TALER_MERCHANT_parse_product_sold (const json_t *p,
- struct TALER_MERCHANT_ProductSold *r);
+TALER_MERCHANT_parse_product_sold (
+ const json_t *p,
+ struct TALER_MERCHANT_ProductSold *r);
/**
@@ -1929,8 +1871,9 @@ TALER_MERCHANT_parse_product_sold (const json_t *p,
* @return spec for parsing a contract output type
*/
struct GNUNET_JSON_Specification
-TALER_MERCHANT_json_spec_cot (const char *name,
- enum TALER_MERCHANT_ContractOutputType *cot);
+TALER_MERCHANT_json_spec_cot (
+ const char *name,
+ enum TALER_MERCHANT_ContractOutputType *cot);
/**
@@ -2075,12 +2018,24 @@ TALER_MERCHANT_order_choice_free (
/**
+ * Free all the fields in the given @a family, but not @a family itself, since
+ * it is normally part of an array.
+ *
+ * @param[in] family contract token family to free
+ */
+void
+TALER_MERCHANT_contract_token_family_free (
+ struct TALER_MERCHANT_ContractTokenFamily *family);
+
+
+/**
* Release memory inside of @a product, but not @a product itself.
*
* @param[in] product data structure to clean up
*/
void
-TALER_MERCHANT_product_sold_free (struct TALER_MERCHANT_ProductSold *product);
+TALER_MERCHANT_product_sold_free (
+ struct TALER_MERCHANT_ProductSold *product);
/**
@@ -2089,7 +2044,8 @@ TALER_MERCHANT_product_sold_free (struct TALER_MERCHANT_ProductSold *product);
* @param[in] contract contract to free
*/
void
-TALER_MERCHANT_contract_free (struct TALER_MERCHANT_Contract *contract);
+TALER_MERCHANT_contract_free (
+ struct TALER_MERCHANT_Contract *contract);
/**
@@ -2098,7 +2054,8 @@ TALER_MERCHANT_contract_free (struct TALER_MERCHANT_Contract *contract);
* @param[in] order order to free
*/
void
-TALER_MERCHANT_order_free (struct TALER_MERCHANT_Order *order);
+TALER_MERCHANT_order_free (
+ struct TALER_MERCHANT_Order *order);
#endif
diff --git a/src/util/contract_parse.c b/src/util/contract_parse.c
@@ -31,11 +31,10 @@
enum GNUNET_GenericReturnValue
-TALER_MERCHANT_parse_choice_input (
+TALER_MERCHANT_parse_contract_choice_input (
json_t *root,
struct TALER_MERCHANT_ContractInput *input,
- size_t index,
- bool order)
+ size_t index)
{
const char *ename;
unsigned int eline;
@@ -105,11 +104,10 @@ TALER_MERCHANT_parse_choice_input (
enum GNUNET_GenericReturnValue
-TALER_MERCHANT_parse_choice_output (
+TALER_MERCHANT_parse_contract_choice_output (
json_t *root,
struct TALER_MERCHANT_ContractOutput *output,
- size_t index,
- bool order)
+ size_t index)
{
const char *ename;
unsigned int eline;
@@ -152,10 +150,8 @@ TALER_MERCHANT_parse_choice_output (
GNUNET_JSON_spec_timestamp ("valid_at",
&output->details.token.valid_at),
NULL),
- (! order)
- ? GNUNET_JSON_spec_uint ("key_index",
- &output->details.token.key_index)
- : GNUNET_JSON_spec_end (),
+ GNUNET_JSON_spec_uint ("key_index",
+ &output->details.token.key_index),
GNUNET_JSON_spec_end ()
};
@@ -184,10 +180,8 @@ TALER_MERCHANT_parse_choice_output (
TALER_JSON_spec_amount_any ("amount",
&output->details.donation_receipt.amount),
NULL),
- (! order)
- ? GNUNET_JSON_spec_array_const ("donau_urls",
- &donau_urls)
- : GNUNET_JSON_spec_end (),
+ GNUNET_JSON_spec_array_const ("donau_urls",
+ &donau_urls),
GNUNET_JSON_spec_end ()
};
@@ -248,7 +242,7 @@ TALER_MERCHANT_parse_choice_output (
* @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
*/
static enum GNUNET_GenericReturnValue
-parse_choices (
+parse_contract_choices (
void *cls,
json_t *root,
struct GNUNET_JSON_Specification *ospec)
@@ -348,10 +342,9 @@ parse_choices (
};
if (GNUNET_OK !=
- TALER_MERCHANT_parse_choice_input ((json_t *) jinput,
- &input,
- idx,
- false))
+ TALER_MERCHANT_parse_contract_choice_input ((json_t *) jinput,
+ &input,
+ idx))
{
GNUNET_break (0);
return GNUNET_SYSERR;
@@ -384,10 +377,9 @@ parse_choices (
};
if (GNUNET_OK !=
- TALER_MERCHANT_parse_choice_output ((json_t *) joutput,
- &output,
- idx,
- false))
+ TALER_MERCHANT_parse_contract_choice_output ((json_t *) joutput,
+ &output,
+ idx))
{
GNUNET_break (0);
return GNUNET_SYSERR;
@@ -417,14 +409,14 @@ parse_choices (
struct GNUNET_JSON_Specification
-TALER_MERCHANT_spec_choices (
+TALER_MERCHANT_spec_contract_choices (
const char *name,
struct TALER_MERCHANT_ContractChoice **choices,
unsigned int *choices_len)
{
struct GNUNET_JSON_Specification ret = {
.cls = (void *) choices_len,
- .parser = &parse_choices,
+ .parser = &parse_contract_choices,
.field = name,
.ptr = choices,
};
@@ -475,87 +467,6 @@ TALER_MERCHANT_contract_choice_free (
}
-enum GNUNET_GenericReturnValue
-TALER_MERCHANT_find_token_family_key (
- const char *slug,
- struct GNUNET_TIME_Timestamp valid_after,
- const struct TALER_MERCHANT_ContractTokenFamily *families,
- unsigned int families_len,
- struct TALER_MERCHANT_ContractTokenFamily *family,
- struct TALER_MERCHANT_ContractTokenFamilyKey *key)
-{
- for (unsigned int i = 0; i < families_len; i++)
- {
- const struct TALER_MERCHANT_ContractTokenFamily *fami
- = &families[i];
-
- if (0 != strcmp (fami->slug,
- slug))
- continue;
- if (NULL != family)
- *family = *fami;
- for (unsigned int k = 0; k < fami->keys_len; k++)
- {
- struct TALER_MERCHANT_ContractTokenFamilyKey *ki = &fami->keys[k];
-
- if (GNUNET_TIME_timestamp_cmp (ki->valid_after,
- ==,
- valid_after))
- {
- if (NULL != key)
- *key = *ki;
- return GNUNET_OK;
- }
- }
- /* matching family found, but no key. */
- return GNUNET_NO;
- }
-
- /* no matching family found */
- return GNUNET_SYSERR;
-}
-
-
-/**
- * Free all the fields in the given @a family, but not @a family itself, since
- * it is normally part of an array.
- *
- * @param[in] family contract token family to free
- */
-static void
-contract_token_family_free (
- struct TALER_MERCHANT_ContractTokenFamily *family)
-{
- GNUNET_free (family->slug);
- GNUNET_free (family->name);
- GNUNET_free (family->description);
- if (NULL != family->description_i18n)
- {
- json_decref (family->description_i18n);
- family->description_i18n = NULL;
- }
- for (unsigned int i = 0; i < family->keys_len; i++)
- TALER_token_issue_pub_free (&family->keys[i].pub);
- GNUNET_free (family->keys);
-
- switch (family->kind)
- {
- case TALER_MERCHANT_CONTRACT_TOKEN_KIND_INVALID:
- break;
- case TALER_MERCHANT_CONTRACT_TOKEN_KIND_DISCOUNT:
- for (unsigned int i = 0; i < family->details.discount.expected_domains_len;
- i++)
- GNUNET_free (family->details.discount.expected_domains[i]);
- break;
- case TALER_MERCHANT_CONTRACT_TOKEN_KIND_SUBSCRIPTION:
- for (unsigned int i = 0; i < family->details.subscription.
- trusted_domains_len; i++)
- GNUNET_free (family->details.subscription.trusted_domains[i]);
- break;
- }
-}
-
-
/**
* Parse v0-specific fields of @a input JSON into @a contract.
*
@@ -633,7 +544,7 @@ parse_contract_v1 (
struct TALER_MERCHANT_Contract *contract)
{
struct GNUNET_JSON_Specification espec[] = {
- TALER_MERCHANT_spec_choices (
+ TALER_MERCHANT_spec_contract_choices (
"choices",
&contract->details.v1.choices,
&contract->details.v1.choices_len),
@@ -666,108 +577,27 @@ parse_contract_v1 (
struct TALER_MERCHANT_Contract *
-TALER_MERCHANT_contract_parse (json_t *input,
- bool nonce_optional)
+TALER_MERCHANT_contract_parse (json_t *input)
{
struct TALER_MERCHANT_Contract *contract
= GNUNET_new (struct TALER_MERCHANT_Contract);
- const json_t *products = NULL;
struct GNUNET_JSON_Specification espec[] = {
- TALER_MERCHANT_spec_contract_version ("version",
- &contract->version),
- GNUNET_JSON_spec_string_copy ("summary",
- &contract->summary),
- /* FIXME: do i18n_str validation in the future */
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_object_copy ("summary_i18n",
- &contract->summary_i18n),
- NULL),
- GNUNET_JSON_spec_string_copy ("order_id",
- &contract->order_id),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string_copy ("public_reorder_url",
- &contract->public_reorder_url),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string_copy ("fulfillment_url",
- &contract->fulfillment_url),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string_copy ("fulfillment_message",
- &contract->fulfillment_message),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_object_copy ("fulfillment_message_i18n",
- &contract->fulfillment_message_i18n),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_array_const ("products",
- &products),
- NULL),
- GNUNET_JSON_spec_timestamp ("timestamp",
- &contract->timestamp),
- GNUNET_JSON_spec_timestamp ("refund_deadline",
- &contract->refund_deadline),
- GNUNET_JSON_spec_timestamp ("pay_deadline",
- &contract->pay_deadline),
- GNUNET_JSON_spec_timestamp ("wire_transfer_deadline",
- &contract->wire_deadline),
- GNUNET_JSON_spec_fixed_auto ("merchant_pub",
- &contract->merchant_pub),
- GNUNET_JSON_spec_string_copy ("merchant_base_url",
- &contract->merchant_base_url),
- TALER_MERCHANT_spec_merchant_details ("merchant",
- &contract->merchant),
- GNUNET_JSON_spec_fixed_auto ("h_wire",
- &contract->h_wire),
- GNUNET_JSON_spec_string_copy ("wire_method",
- &contract->wire_method),
- GNUNET_JSON_spec_array_copy ("exchanges",
- &contract->exchanges),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_object_copy ("delivery_location",
- &contract->delivery_location),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_timestamp ("delivery_date",
- &contract->delivery_date),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_timestamp ("max_pickup_time",
- &contract->max_pickup_time),
- NULL),
- (nonce_optional)
- ? GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string_copy ("nonce",
- &contract->nonce),
- NULL)
- : GNUNET_JSON_spec_string_copy ("nonce",
- &contract->nonce),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_relative_time ("auto_refund",
- &contract->auto_refund),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_object_copy ("extra",
- &contract->extra),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_uint8 ("minimum_age",
- &contract->minimum_age),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_uint64 ("default_money_pot",
- &contract->default_money_pot),
- NULL),
+ GNUNET_JSON_spec_string_copy ("nonce",
+ &contract->nonce),
GNUNET_JSON_spec_end ()
};
-
enum GNUNET_GenericReturnValue res;
const char *ename;
unsigned int eline;
GNUNET_assert (NULL != input);
- contract->max_pickup_time = GNUNET_TIME_UNIT_FOREVER_TS;
+ if (! TALER_MERCHANT_common_terms_parse (&contract->common,
+ input))
+ {
+ GNUNET_break (0);
+ GNUNET_free (contract);
+ return NULL;
+ }
res = GNUNET_JSON_parse (input,
espec,
&ename,
@@ -780,32 +610,7 @@ TALER_MERCHANT_contract_parse (json_t *input,
ename);
goto cleanup;
}
- if (NULL != products)
- {
- contract->products_len = json_array_size (products);
- if (0 != contract->products_len)
- {
- size_t i;
- json_t *p;
-
- contract->products = GNUNET_new_array (contract->products_len,
- struct TALER_MERCHANT_ProductSold);
- json_array_foreach (products, i, p)
- {
- if (GNUNET_OK !=
- TALER_MERCHANT_parse_product_sold (p,
- &contract->products[i]))
- {
- GNUNET_break (0);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse product at offset %u\n",
- (unsigned int) i);
- goto cleanup;
- }
- }
- }
- }
- switch (contract->version)
+ switch (contract->common.version)
{
case TALER_MERCHANT_CONTRACT_VERSION_0:
res = parse_contract_v0 (input,
@@ -838,56 +643,8 @@ TALER_MERCHANT_contract_free (
{
if (NULL == contract)
return;
- GNUNET_free (contract->public_reorder_url);
- GNUNET_free (contract->order_id);
- GNUNET_free (contract->merchant_base_url);
- GNUNET_free (contract->merchant.name);
- GNUNET_free (contract->merchant.website);
- GNUNET_free (contract->merchant.email);
- GNUNET_free (contract->merchant.logo);
- if (NULL != contract->merchant.address)
- {
- json_decref (contract->merchant.address);
- contract->merchant.address = NULL;
- }
- if (NULL != contract->merchant.jurisdiction)
- {
- json_decref (contract->merchant.jurisdiction);
- contract->merchant.jurisdiction = NULL;
- }
- GNUNET_free (contract->summary);
- GNUNET_free (contract->fulfillment_url);
- GNUNET_free (contract->fulfillment_message);
- if (NULL != contract->fulfillment_message_i18n)
- {
- json_decref (contract->fulfillment_message_i18n);
- contract->fulfillment_message_i18n = NULL;
- }
- if (NULL != contract->products)
- {
- for (size_t i = 0; i<contract->products_len; i++)
- TALER_MERCHANT_product_sold_free (&contract->products[i]);
- GNUNET_free (contract->products);
- }
- GNUNET_free (contract->wire_method);
- if (NULL != contract->exchanges)
- {
- json_decref (contract->exchanges);
- contract->exchanges = NULL;
- }
- if (NULL != contract->delivery_location)
- {
- json_decref (contract->delivery_location);
- contract->delivery_location = NULL;
- }
GNUNET_free (contract->nonce);
- if (NULL != contract->extra)
- {
- json_decref (contract->extra);
- contract->extra = NULL;
- }
-
- switch (contract->version)
+ switch (contract->common.version)
{
case TALER_MERCHANT_CONTRACT_VERSION_0:
break;
@@ -900,9 +657,10 @@ TALER_MERCHANT_contract_free (
for (unsigned int i = 0;
i < contract->details.v1.token_authorities_len;
i++)
- contract_token_family_free (&contract->details.v1.token_authorities[i]);
+ TALER_MERCHANT_contract_token_family_free (&contract->details.v1.token_authorities[i]);
GNUNET_free (contract->details.v1.token_authorities);
break;
}
+ TALER_MERCHANT_common_terms_free (&contract->common);
GNUNET_free (contract);
}
diff --git a/src/util/contract_serialize.c b/src/util/contract_serialize.c
@@ -19,7 +19,6 @@
* @author Iván Ávalos
* @author Christian Grothoff
*/
-
#include "platform.h"
#include <gnunet/gnunet_json_lib.h>
#include <gnunet/gnunet_common.h>
@@ -28,36 +27,6 @@
#include "taler/taler_util.h"
#include "taler/taler_merchant_util.h"
-/**
- * Get JSON representation of merchant details.
- *
- * @param[in] contract contract terms
- * @return JSON object with merchant details; NULL on error
- */
-static json_t *
-json_from_merchant_details (
- const struct TALER_MERCHANT_Contract *contract)
-{
- return GNUNET_JSON_PACK (
- GNUNET_JSON_pack_string ("name",
- contract->merchant.name),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("email",
- contract->merchant.email)),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("website",
- contract->merchant.website)),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("logo",
- contract->merchant.logo)),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_object_steal ("address",
- contract->merchant.address)),
- GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_object_steal ("jurisdiction",
- contract->merchant.jurisdiction)));
-}
-
/**
* Get JSON representation of contract choice input.
@@ -156,8 +125,7 @@ json_from_contract_output (
json_t *
TALER_MERCHANT_json_from_contract_choice (
- const struct TALER_MERCHANT_ContractChoice *choice,
- bool order)
+ const struct TALER_MERCHANT_ContractChoice *choice)
{
json_t *inputs;
json_t *outputs;
@@ -191,29 +159,12 @@ TALER_MERCHANT_json_from_contract_choice (
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_object_incref ("description_i18n",
choice->description_i18n)),
- (order)
- ? GNUNET_JSON_pack_allow_null (
- TALER_JSON_pack_amount (
- "max_fee",
- /* workaround for nullable amount */
- (GNUNET_OK ==
- TALER_amount_is_valid (&choice->max_fee))
- ? &choice->max_fee
- : NULL))
- : TALER_JSON_pack_amount ("max_fee",
- &choice->max_fee),
- (order)
- ? GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_array_steal ("inputs",
- inputs))
- : GNUNET_JSON_pack_array_steal ("inputs",
- inputs),
- (order)
- ? GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_array_steal ("outputs",
- outputs))
- : GNUNET_JSON_pack_array_steal ("outputs",
- outputs));
+ TALER_JSON_pack_amount ("max_fee",
+ &choice->max_fee),
+ GNUNET_JSON_pack_array_steal ("inputs",
+ inputs),
+ GNUNET_JSON_pack_array_steal ("outputs",
+ outputs));
}
@@ -375,8 +326,7 @@ json_from_contract_v1 (
GNUNET_assert (0 == json_array_append_new (
choices,
TALER_MERCHANT_json_from_contract_choice (
- &input->details.v1.choices[i],
- false)));
+ &input->details.v1.choices[i])));
families = json_object ();
GNUNET_assert (0 != families);
@@ -485,13 +435,13 @@ TALER_MERCHANT_product_sold_serialize (
json_t *
TALER_MERCHANT_contract_serialize (
- const struct TALER_MERCHANT_Contract *input,
- bool nonce_optional)
+ const struct TALER_MERCHANT_Contract *input)
{
+ struct TALER_MERCHANT_CommonTerms *ct = &input->common;
json_t *details;
json_t *products;
- switch (input->version)
+ switch (ct->version)
{
case TALER_MERCHANT_CONTRACT_VERSION_0:
details = json_from_contract_v0 (input);
@@ -503,99 +453,97 @@ TALER_MERCHANT_contract_serialize (
GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
"unknown contract type version %d",
- input->version);
+ ct->version);
GNUNET_assert (0);
return NULL;
success:
products = json_array ();
GNUNET_assert (NULL != products);
- for (size_t i = 0; i<input->products_len; i++)
+ for (size_t i = 0; i<ct->products_len; i++)
{
GNUNET_assert (
0 ==
json_array_append_new (products,
TALER_MERCHANT_product_sold_serialize (
- &input->products[i])));
+ &ct->products[i])));
}
return GNUNET_JSON_PACK (
GNUNET_JSON_pack_uint64 ("version",
- input->version),
+ ct->version),
GNUNET_JSON_pack_string ("summary",
- input->summary),
+ ct->summary),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_object_steal ("summary_i18n",
- input->summary_i18n)),
+ ct->summary_i18n)),
GNUNET_JSON_pack_string ("order_id",
- input->order_id),
+ ct->order_id),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_string ("public_reorder_url",
- input->public_reorder_url)),
+ ct->public_reorder_url)),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_string ("fulfillment_url",
- input->fulfillment_url)),
+ ct->fulfillment_url)),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_string ("fulfillment_message",
- input->fulfillment_message)),
+ ct->fulfillment_message)),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_object_steal ("fulfillment_message_i18n",
- input->fulfillment_message_i18n)),
+ ct->fulfillment_message_i18n)),
GNUNET_JSON_pack_array_steal ("products",
products),
GNUNET_JSON_pack_timestamp ("timestamp",
- input->timestamp),
+ ct->timestamp),
GNUNET_JSON_pack_timestamp ("refund_deadline",
- input->refund_deadline),
+ ct->refund_deadline),
GNUNET_JSON_pack_timestamp ("pay_deadline",
- input->pay_deadline),
+ ct->pay_deadline),
GNUNET_JSON_pack_timestamp ("wire_transfer_deadline",
- input->wire_deadline),
+ ct->wire_deadline),
GNUNET_JSON_pack_data_auto ("merchant_pub",
- &input->merchant_pub.eddsa_pub),
+ &ct->merchant_pub.eddsa_pub),
GNUNET_JSON_pack_string ("merchant_base_url",
- input->merchant_base_url),
- GNUNET_JSON_pack_object_steal ("merchant",
- json_from_merchant_details (input)),
+ ct->merchant_base_url),
+ GNUNET_JSON_pack_object_steal (
+ "merchant",
+ TALER_MERCHANT_metadata_to_json (
+ &input->common.merchant)),
GNUNET_JSON_pack_data_auto ("h_wire",
- &input->h_wire),
+ &ct->h_wire),
GNUNET_JSON_pack_string ("wire_method",
- input->wire_method),
+ ct->wire_method),
GNUNET_JSON_pack_array_steal ("exchanges",
- input->exchanges),
+ ct->exchanges),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_object_steal ("delivery_location",
- input->delivery_location)),
+ ct->delivery_location)),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_timestamp ("delivery_date",
- input->delivery_date)),
+ ct->delivery_date)),
GNUNET_JSON_pack_allow_null (
- GNUNET_TIME_absolute_is_never (input->max_pickup_time.abs_time)
+ GNUNET_TIME_absolute_is_never (ct->max_pickup_time.abs_time)
? GNUNET_JSON_pack_string ("dummy",
NULL)
: GNUNET_JSON_pack_timestamp ("max_pickup_time",
- input->max_pickup_time)),
- (nonce_optional)
- ? GNUNET_JSON_pack_allow_null (
- GNUNET_JSON_pack_string ("nonce",
- input->nonce))
- : GNUNET_JSON_pack_string ("nonce",
- input->nonce),
+ ct->max_pickup_time)),
+ GNUNET_JSON_pack_string ("nonce",
+ input->nonce),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_time_rel ("auto_refund",
- input->auto_refund)),
+ ct->auto_refund)),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_object_steal ("extra",
- input->extra)),
+ ct->extra)),
GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_uint64 ("minimum_age",
- input->minimum_age)),
- (0 == input->default_money_pot)
+ ct->minimum_age)),
+ (0 == ct->default_money_pot)
? GNUNET_JSON_pack_allow_null (
GNUNET_JSON_pack_string ("dummy",
NULL))
: GNUNET_JSON_pack_uint64 ("default_money_pot",
- input->default_money_pot),
+ ct->default_money_pot),
GNUNET_JSON_pack_object_steal (NULL,
details));
}
diff --git a/src/util/merchant_parse.c b/src/util/merchant_parse.c
@@ -1,3 +1,35 @@
+/*
+ This file is part of TALER
+ (C) 2024, 2025 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 3, 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ TALER; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
+*/
+/**
+ * @file src/util/merchant_parse.c
+ * @brief shared logic for merchant metadata parsing
+ * @author Iván Ávalos
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include <gnunet/gnunet_common.h>
+#include <gnunet/gnunet_json_lib.h>
+#include <jansson.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <taler/taler_json_lib.h>
+#include <taler/taler_util.h>
+#include "taler/taler_merchant_util.h"
+
+
/**
* Parse merchant details of given JSON order terms.
*
@@ -59,16 +91,35 @@ parse_merchant_details (void *cls,
}
-/**
- * Provide specification to parse given JSON object to merchant details in the
- * order terms. All fields from @a order are copied.
- *
- * @param name name of the merchant details field in the JSON
- * @param[out] order where the merchant details have to be written
- */
+json_t *
+TALER_MERCHANT_metadata_to_json (
+ const struct TALER_MERCHANT_MetaData *merchant)
+{
+ return GNUNET_JSON_PACK (
+ GNUNET_JSON_pack_string ("name",
+ merchant->name),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("email",
+ merchant->email)),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("website",
+ merchant->website)),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_string ("logo",
+ merchant->logo)),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_object_steal ("address",
+ merchant->address)),
+ GNUNET_JSON_pack_allow_null (
+ GNUNET_JSON_pack_object_steal ("jurisdiction",
+ merchant->jurisdiction)));
+}
+
+
struct GNUNET_JSON_Specification
-TALER_MERCHANT_spec_merchant_details (const char *name,
- struct TALER_MERCHANT_MetaData *merchant)
+TALER_MERCHANT_spec_merchant_details (
+ const char *name,
+ struct TALER_MERCHANT_MetaData *merchant)
{
struct GNUNET_JSON_Specification ret = {
.parser = &parse_merchant_details,
diff --git a/src/util/meson.build b/src/util/meson.build
@@ -15,14 +15,21 @@ endforeach
libtalermerchantutil_SOURCES = [
'amount_quantity.c',
+ 'common_terms_parse.c',
'contract_parse.c',
'contract_serialize.c',
+ 'contract_version_parse.c',
'json.c',
+ 'merchant_parse.c',
'mfa.c',
+ 'order_parse.c',
'os_installation.c',
+ 'product_parse.c',
'template_parse.c',
- 'value_kinds.c',
+ 'token_family_parse.c',
+ 'util.c',
'validators.c',
+ 'value_kinds.c',
]
libtalermerchantutil = library(
diff --git a/src/util/order_parse.c b/src/util/order_parse.c
@@ -31,11 +31,10 @@
enum GNUNET_GenericReturnValue
-TALER_MERCHANT_parse_choice_input (
+TALER_MERCHANT_parse_order_choice_input (
json_t *root,
struct TALER_MERCHANT_OrderInput *input,
- size_t index,
- bool order)
+ size_t index)
{
const char *ename;
unsigned int eline;
@@ -105,11 +104,10 @@ TALER_MERCHANT_parse_choice_input (
enum GNUNET_GenericReturnValue
-TALER_MERCHANT_parse_choice_output (
+TALER_MERCHANT_parse_order_choice_output (
json_t *root,
struct TALER_MERCHANT_OrderOutput *output,
- size_t index,
- bool order)
+ size_t index)
{
const char *ename;
unsigned int eline;
@@ -152,10 +150,6 @@ TALER_MERCHANT_parse_choice_output (
GNUNET_JSON_spec_timestamp ("valid_at",
&output->details.token.valid_at),
NULL),
- (! order)
- ? GNUNET_JSON_spec_uint ("key_index",
- &output->details.token.key_index)
- : GNUNET_JSON_spec_end (),
GNUNET_JSON_spec_end ()
};
@@ -184,10 +178,6 @@ TALER_MERCHANT_parse_choice_output (
TALER_JSON_spec_amount_any ("amount",
&output->details.donation_receipt.amount),
NULL),
- (! order)
- ? GNUNET_JSON_spec_array_const ("donau_urls",
- &donau_urls)
- : GNUNET_JSON_spec_end (),
GNUNET_JSON_spec_end ()
};
@@ -248,7 +238,7 @@ TALER_MERCHANT_parse_choice_output (
* @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
*/
static enum GNUNET_GenericReturnValue
-parse_choices (
+parse_order_choices (
void *cls,
json_t *root,
struct GNUNET_JSON_Specification *ospec)
@@ -348,10 +338,9 @@ parse_choices (
};
if (GNUNET_OK !=
- TALER_MERCHANT_parse_choice_input ((json_t *) jinput,
- &input,
- idx,
- false))
+ TALER_MERCHANT_parse_order_choice_input ((json_t *) jinput,
+ &input,
+ idx))
{
GNUNET_break (0);
return GNUNET_SYSERR;
@@ -384,10 +373,9 @@ parse_choices (
};
if (GNUNET_OK !=
- TALER_MERCHANT_parse_choice_output ((json_t *) joutput,
- &output,
- idx,
- false))
+ TALER_MERCHANT_parse_order_choice_output ((json_t *) joutput,
+ &output,
+ idx))
{
GNUNET_break (0);
return GNUNET_SYSERR;
@@ -417,14 +405,14 @@ parse_choices (
struct GNUNET_JSON_Specification
-TALER_MERCHANT_spec_choices (
+TALER_MERCHANT_spec_order_choices (
const char *name,
struct TALER_MERCHANT_OrderChoice **choices,
unsigned int *choices_len)
{
struct GNUNET_JSON_Specification ret = {
.cls = (void *) choices_len,
- .parser = &parse_choices,
+ .parser = &parse_order_choices,
.field = name,
.ptr = choices,
};
@@ -475,87 +463,6 @@ TALER_MERCHANT_order_choice_free (
}
-enum GNUNET_GenericReturnValue
-TALER_MERCHANT_find_token_family_key (
- const char *slug,
- struct GNUNET_TIME_Timestamp valid_after,
- const struct TALER_MERCHANT_OrderTokenFamily *families,
- unsigned int families_len,
- struct TALER_MERCHANT_OrderTokenFamily *family,
- struct TALER_MERCHANT_OrderTokenFamilyKey *key)
-{
- for (unsigned int i = 0; i < families_len; i++)
- {
- const struct TALER_MERCHANT_OrderTokenFamily *fami
- = &families[i];
-
- if (0 != strcmp (fami->slug,
- slug))
- continue;
- if (NULL != family)
- *family = *fami;
- for (unsigned int k = 0; k < fami->keys_len; k++)
- {
- struct TALER_MERCHANT_OrderTokenFamilyKey *ki = &fami->keys[k];
-
- if (GNUNET_TIME_timestamp_cmp (ki->valid_after,
- ==,
- valid_after))
- {
- if (NULL != key)
- *key = *ki;
- return GNUNET_OK;
- }
- }
- /* matching family found, but no key. */
- return GNUNET_NO;
- }
-
- /* no matching family found */
- return GNUNET_SYSERR;
-}
-
-
-/**
- * Free all the fields in the given @a family, but not @a family itself, since
- * it is normally part of an array.
- *
- * @param[in] family order token family to free
- */
-static void
-order_token_family_free (
- struct TALER_MERCHANT_OrderTokenFamily *family)
-{
- GNUNET_free (family->slug);
- GNUNET_free (family->name);
- GNUNET_free (family->description);
- if (NULL != family->description_i18n)
- {
- json_decref (family->description_i18n);
- family->description_i18n = NULL;
- }
- for (unsigned int i = 0; i < family->keys_len; i++)
- TALER_token_issue_pub_free (&family->keys[i].pub);
- GNUNET_free (family->keys);
-
- switch (family->kind)
- {
- case TALER_MERCHANT_CONTRACT_TOKEN_KIND_INVALID:
- break;
- case TALER_MERCHANT_CONTRACT_TOKEN_KIND_DISCOUNT:
- for (unsigned int i = 0; i < family->details.discount.expected_domains_len;
- i++)
- GNUNET_free (family->details.discount.expected_domains[i]);
- break;
- case TALER_MERCHANT_CONTRACT_TOKEN_KIND_SUBSCRIPTION:
- for (unsigned int i = 0; i < family->details.subscription.
- trusted_domains_len; i++)
- GNUNET_free (family->details.subscription.trusted_domains[i]);
- break;
- }
-}
-
-
/**
* Parse v0-specific fields of @a input JSON into @a order.
*
@@ -633,11 +540,11 @@ parse_order_v1 (
struct TALER_MERCHANT_Order *order)
{
struct GNUNET_JSON_Specification espec[] = {
- TALER_MERCHANT_spec_choices (
+ TALER_MERCHANT_spec_order_choices (
"choices",
&order->details.v1.choices,
&order->details.v1.choices_len),
- spec_token_families (
+ TALER_MERCHANT_spec_token_families (
"token_families",
&order->details.v1.token_authorities,
&order->details.v1.token_authorities_len),
@@ -666,146 +573,22 @@ parse_order_v1 (
struct TALER_MERCHANT_Order *
-TALER_MERCHANT_order_parse (json_t *input,
- bool nonce_optional)
+TALER_MERCHANT_order_parse (json_t *input)
{
struct TALER_MERCHANT_Order *order
= GNUNET_new (struct TALER_MERCHANT_Order);
- const json_t *products = NULL;
- struct GNUNET_JSON_Specification espec[] = {
- TALER_MERCHANT_spec_contract_version ("version",
- &order->version),
- GNUNET_JSON_spec_string_copy ("summary",
- &order->summary),
- /* FIXME: do i18n_str validation in the future */
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_object_copy ("summary_i18n",
- &order->summary_i18n),
- NULL),
- GNUNET_JSON_spec_string_copy ("order_id",
- &order->order_id),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string_copy ("public_reorder_url",
- &order->public_reorder_url),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string_copy ("fulfillment_url",
- &order->fulfillment_url),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string_copy ("fulfillment_message",
- &order->fulfillment_message),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_object_copy ("fulfillment_message_i18n",
- &order->fulfillment_message_i18n),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_array_const ("products",
- &products),
- NULL),
- GNUNET_JSON_spec_timestamp ("timestamp",
- &order->timestamp),
- GNUNET_JSON_spec_timestamp ("refund_deadline",
- &order->refund_deadline),
- GNUNET_JSON_spec_timestamp ("pay_deadline",
- &order->pay_deadline),
- GNUNET_JSON_spec_timestamp ("wire_transfer_deadline",
- &order->wire_deadline),
- GNUNET_JSON_spec_fixed_auto ("merchant_pub",
- &order->merchant_pub),
- GNUNET_JSON_spec_string_copy ("merchant_base_url",
- &order->merchant_base_url),
- TALER_MERCHANT_spec_merchant_details ("merchant",
- &order->merchant),
- GNUNET_JSON_spec_fixed_auto ("h_wire",
- &order->h_wire),
- GNUNET_JSON_spec_string_copy ("wire_method",
- &order->wire_method),
- GNUNET_JSON_spec_array_copy ("exchanges",
- &order->exchanges),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_object_copy ("delivery_location",
- &order->delivery_location),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_timestamp ("delivery_date",
- &order->delivery_date),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_timestamp ("max_pickup_time",
- &order->max_pickup_time),
- NULL),
- (nonce_optional)
- ? GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_string_copy ("nonce",
- &order->nonce),
- NULL)
- : GNUNET_JSON_spec_string_copy ("nonce",
- &order->nonce),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_relative_time ("auto_refund",
- &order->auto_refund),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_object_copy ("extra",
- &order->extra),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_uint8 ("minimum_age",
- &order->minimum_age),
- NULL),
- GNUNET_JSON_spec_mark_optional (
- GNUNET_JSON_spec_uint64 ("default_money_pot",
- &order->default_money_pot),
- NULL),
- GNUNET_JSON_spec_end ()
- };
-
- enum GNUNET_GenericReturnValue res;
- const char *ename;
- unsigned int eline;
+ enum GNUNET_GenericReturnValue res
+ = GNUNET_SYSERR;
GNUNET_assert (NULL != input);
- order->max_pickup_time = GNUNET_TIME_UNIT_FOREVER_TS;
- res = GNUNET_JSON_parse (input,
- espec,
- &ename,
- &eline);
- if (GNUNET_OK != res)
+ if (! TALER_MERCHANT_common_terms_parse (&order->common,
+ input))
{
GNUNET_break (0);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse order at field %s\n",
- ename);
- goto cleanup;
- }
- if (NULL != products)
- {
- order->products_len = json_array_size (products);
- if (0 != order->products_len)
- {
- size_t i;
- json_t *p;
-
- order->products = GNUNET_new_array (order->products_len,
- struct TALER_MERCHANT_ProductSold);
- json_array_foreach (products, i, p)
- {
- if (GNUNET_OK !=
- TALER_MERCHANT_parse_product_sold (p,
- &order->products[i]))
- {
- GNUNET_break (0);
- GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
- "Failed to parse product at offset %u\n",
- (unsigned int) i);
- goto cleanup;
- }
- }
- }
+ GNUNET_free (order);
+ return NULL;
}
- switch (order->version)
+ switch (order->common.version)
{
case TALER_MERCHANT_CONTRACT_VERSION_0:
res = parse_order_v0 (input,
@@ -838,56 +621,7 @@ TALER_MERCHANT_order_free (
{
if (NULL == order)
return;
- GNUNET_free (order->public_reorder_url);
- GNUNET_free (order->order_id);
- GNUNET_free (order->merchant_base_url);
- GNUNET_free (order->merchant.name);
- GNUNET_free (order->merchant.website);
- GNUNET_free (order->merchant.email);
- GNUNET_free (order->merchant.logo);
- if (NULL != order->merchant.address)
- {
- json_decref (order->merchant.address);
- order->merchant.address = NULL;
- }
- if (NULL != order->merchant.jurisdiction)
- {
- json_decref (order->merchant.jurisdiction);
- order->merchant.jurisdiction = NULL;
- }
- GNUNET_free (order->summary);
- GNUNET_free (order->fulfillment_url);
- GNUNET_free (order->fulfillment_message);
- if (NULL != order->fulfillment_message_i18n)
- {
- json_decref (order->fulfillment_message_i18n);
- order->fulfillment_message_i18n = NULL;
- }
- if (NULL != order->products)
- {
- for (size_t i = 0; i<order->products_len; i++)
- TALER_MERCHANT_product_sold_free (&order->products[i]);
- GNUNET_free (order->products);
- }
- GNUNET_free (order->wire_method);
- if (NULL != order->exchanges)
- {
- json_decref (order->exchanges);
- order->exchanges = NULL;
- }
- if (NULL != order->delivery_location)
- {
- json_decref (order->delivery_location);
- order->delivery_location = NULL;
- }
- GNUNET_free (order->nonce);
- if (NULL != order->extra)
- {
- json_decref (order->extra);
- order->extra = NULL;
- }
-
- switch (order->version)
+ switch (order->common.version)
{
case TALER_MERCHANT_CONTRACT_VERSION_0:
break;
@@ -900,9 +634,10 @@ TALER_MERCHANT_order_free (
for (unsigned int i = 0;
i < order->details.v1.token_authorities_len;
i++)
- order_token_family_free (&order->details.v1.token_authorities[i]);
+ TALER_MERCHANT_contract_token_family_free (&order->details.v1.token_authorities[i]);
GNUNET_free (order->details.v1.token_authorities);
break;
}
+ TALER_MERCHANT_common_terms_free (&order->common);
GNUNET_free (order);
}
diff --git a/src/util/product_parse.c b/src/util/product_parse.c
@@ -21,7 +21,8 @@
#include "platform.h"
#include <string.h>
#include "taler/taler_merchant_util.h"
-
+#include <gnunet/gnunet_json_lib.h>
+#include <taler/taler_json_lib.h>
/**
* Parse the given unit quantity string @a s and store the result in @a q.
diff --git a/src/util/template_parse.c b/src/util/template_parse.c
@@ -348,7 +348,7 @@ TALER_MERCHANT_template_contract_free (
return;
case TALER_MERCHANT_TEMPLATE_TYPE_PAIVANA:
for (unsigned int i = 0; i<tc->details.paivana.choices_len; i++)
- TALER_MERCHANT_contract_choice_free (&tc->details.paivana.choices[i]);
+ TALER_MERCHANT_order_choice_free (&tc->details.paivana.choices[i]);
GNUNET_array_grow (tc->details.paivana.choices,
tc->details.paivana.choices_len,
0);
diff --git a/src/util/token_family_parse.c b/src/util/token_family_parse.c
@@ -21,6 +21,83 @@
#include "platform.h"
#include <string.h>
#include "taler/taler_merchant_util.h"
+#include <taler/taler_json_lib.h>
+#include <gnunet/gnunet_json_lib.h>
+
+
+void
+TALER_MERCHANT_contract_token_family_free (
+ struct TALER_MERCHANT_ContractTokenFamily *family)
+{
+ GNUNET_free (family->slug);
+ GNUNET_free (family->name);
+ GNUNET_free (family->description);
+ if (NULL != family->description_i18n)
+ {
+ json_decref (family->description_i18n);
+ family->description_i18n = NULL;
+ }
+ for (unsigned int i = 0; i < family->keys_len; i++)
+ TALER_token_issue_pub_free (&family->keys[i].pub);
+ GNUNET_free (family->keys);
+
+ switch (family->kind)
+ {
+ case TALER_MERCHANT_CONTRACT_TOKEN_KIND_INVALID:
+ break;
+ case TALER_MERCHANT_CONTRACT_TOKEN_KIND_DISCOUNT:
+ for (unsigned int i = 0; i < family->details.discount.expected_domains_len;
+ i++)
+ GNUNET_free (family->details.discount.expected_domains[i]);
+ break;
+ case TALER_MERCHANT_CONTRACT_TOKEN_KIND_SUBSCRIPTION:
+ for (unsigned int i = 0; i < family->details.subscription.
+ trusted_domains_len; i++)
+ GNUNET_free (family->details.subscription.trusted_domains[i]);
+ break;
+ }
+}
+
+
+enum GNUNET_GenericReturnValue
+TALER_MERCHANT_find_token_family_key (
+ const char *slug,
+ struct GNUNET_TIME_Timestamp valid_after,
+ const struct TALER_MERCHANT_ContractTokenFamily *families,
+ unsigned int families_len,
+ struct TALER_MERCHANT_ContractTokenFamily *family,
+ struct TALER_MERCHANT_ContractTokenFamilyKey *key)
+{
+ for (unsigned int i = 0; i < families_len; i++)
+ {
+ const struct TALER_MERCHANT_ContractTokenFamily *fami
+ = &families[i];
+
+ if (0 != strcmp (fami->slug,
+ slug))
+ continue;
+ if (NULL != family)
+ *family = *fami;
+ for (unsigned int k = 0; k < fami->keys_len; k++)
+ {
+ struct TALER_MERCHANT_ContractTokenFamilyKey *ki = &fami->keys[k];
+
+ if (GNUNET_TIME_timestamp_cmp (ki->valid_after,
+ ==,
+ valid_after))
+ {
+ if (NULL != key)
+ *key = *ki;
+ return GNUNET_OK;
+ }
+ }
+ /* matching family found, but no key. */
+ return GNUNET_NO;
+ }
+
+ /* no matching family found */
+ return GNUNET_SYSERR;
+}
/**
@@ -305,14 +382,6 @@ parse_token_families (void *cls,
}
-/**
- * Provide specification to parse given JSON array to token families in the
- * contract terms. All fields from @a families items are copied.
- *
- * @param name name of the token families field in the JSON
- * @param[out] families where the token families array has to be written
- * @param[out] families_len length of the @a families array
- */
struct GNUNET_JSON_Specification
TALER_MERCHANT_spec_token_families (
const char *name,
diff --git a/src/util/util.c b/src/util/util.c
@@ -21,6 +21,8 @@
#include "platform.h"
#include <string.h>
#include "taler/taler_merchant_util.h"
+#include <taler/taler_json_lib.h>
+#include <gnunet/gnunet_json_lib.h>
bool